[#154] Fix session lifecycle gaps from verification - #38
Closed
may-team-engineer-bob[bot] wants to merge 23 commits into
Closed
may-team-engineer-bob[bot] wants to merge 23 commits into
may-team-engineer-bob[bot] wants to merge 23 commits into
Conversation
stop_session_handler was missing the deactivation watcher spawn that stop_bulk_handler already had, causing sessions stopped via the single- session endpoint to remain stuck in Finalizing forever. Extract collect_newly_finalizing and spawn_deactivation_watchers helpers shared by both handlers to eliminate the duplicated pattern. Ref: #154 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds member-level coding-agent/skills/ to the .claude/skills/ assembly path in ConfigAssembler, so skills from team/members/<member>/coding-agent/skills/ are symlinked into the session workspace alongside team-level skills. Includes two tests covering member-only and combined team+member assembly. Ref: #154
… relay Add AppTokenProvider trait and AppCredentialWriter implementation so that HydrationWorkspaceOps can write hosts.yml to the member credential directory when a GitHub App token is available. Extracts hosts_yml_content() to remove format-string duplication between prod and test writers. Ref: #154
…on auth - AppCredentialWriter writes hosts.yml to <credential_base>/<member>/gh/hosts.yml (gh/ subdir required by D-02 for direct GH_CONFIG_DIR pointing) - inject_app_credentials_from_shared_dir sets GH_CONFIG_DIR to <credential_dir>/gh when hosts.yml is present; no unused team/member name params - CredentialRelay::gh_dir_for() encapsulates hosts.yml existence check - HydrationWorkspaceOps::gh_config_dir_for_member() delegates to gh_dir_for() - Remove dead workspace_base field from HydrationWorkspaceOps struct - Fix mutex poisoning cascade in tests (unwrap_or_else pattern) Ref: #154
…ands into .claude/ - Project-level agents (projects/<name>/coding-agent/agents/) merged into .claude/agents/ - Project-level skills (projects/<name>/coding-agent/skills/) merged into .claude/skills/ - Member-level commands (members/<member>/coding-agent/commands/) merged into .claude/commands/ - Member-level settings.local.json copied to .claude/settings.local.json - Extract merge_sources_into helper: eliminates duplicated for/is_dir/create_dir_all/merge loops - Extract project_ca_dirs method: removes duplicated project-level path construction Ref: #154
…r code-task 01 - Remove deactivation.rs::finalize_session() — zero production callers; production path uses spawn_deactivation_watcher() in sessions_api.rs - Remove deactivation.rs::push_to_recovery_branch() — dead stub - Remove manager.rs::deactivate_session() and DeactivateResult — zero production callers; session deactivation is handled by stop handlers - Remove push_and_refresh_dirty() — only called by deactivate_session() - Remove workspace/util push_with_rebase_retry() and DEFAULT_MAX_RETRIES — now dead after push_and_refresh_dirty() removal - Remove all tests exercising the removed dead code paths - Move retained_to_finalizing_is_valid_transition, new_session_while_old_is_finalizing, and new_session_while_old_is_failed tests to manager.rs where they belong Ref: #154
…ode-task 07b D10 previously checked MEMBER_BASE/.config/gh and WS_A/.config/gh (old paths that no longer exist in the session model). These fallbacks masked CT-03 brokenness by succeeding via system gh auth even when AppCredentialWriter had not written credentials to the D-02 shared path. Fix: check exclusively at <sessions_base>/credentials/<member>/gh/hosts.yml (the D-02 shared credential path written by AppCredentialWriter). If absent, note that credential_resolver is not yet wired in run.rs rather than silently falling back to an unrelated gh auth location. Also adds phase-d-session to the Justfile `all` target, replacing the now- obsolete phase-d (which tested `bm teams sync` — a removed command). This ensures the session lifecycle tests (D01-D21 all PASS) run as part of the standard exploratory test suite. Ref: #154
…AssemblyConfig Add project_names field to HydrationWorkspaceConfig and HydrationWorkspaceOps so that project-level coding-agent assets (agents, skills) are assembled into the .claude/ directory during workspace hydration. Previously hydrate_workspace() hardcoded project_names: vec![], silently skipping all project-level assets. Ref: #154 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…#154] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…de-task 03 - resolve_app_credentials_and_deliver returns credential_base/<member>/gh (D-02 path) - inject_app_credentials delegates to shared dir when credential_dir is provided - AppCredentialWriter uses atomic write (tmp file + rename) to replace read-only hosts.yml - Tests: 3 unit tests cover D-02 path for all 3 entry points Ref: #154
devguyio
approved these changes
Jun 10, 2026
devguyio
left a comment
There was a problem hiding this comment.
💻 dev — 2026-06-10T14:34:13Z
CT-154-03 APPROVED: Credential write-path migrated to D-02 shared path
Changes reviewed (commit bc73b66)
start_members.rs:
resolve_app_credentials_and_delivernow takescredential_base: &Path, returnscredential_base/<member>/gh(D-02 path) instead ofws/.config/ghexchange_tokenextracted with#[cfg(not(test))]/#[cfg(test)]variants — enables unit testing without real JWT/HTTP- Production placeholder:
credential_base = ws.clone()with comment pointing toDaemonPaths::sessions_base()/credentialsas the correct future wiring ✓
chat/mod.rs:
inject_app_credentialsgainscredential_dir: Option<&Path>— routes to shared dir when provided, falls back to legacy workspace path whenNone#[allow(dead_code)]removed frominject_app_credentials_from_shared_dir(now live) ✓- Existing callers pass
None(correct — daemon credential wiring is deferred) ✓
hydration.rs:
AppCredentialWriteruses atomic write: tmp file +fs::rename— correctly replaces read-onlyhosts.yml✓
daemon/api.rs:
credential_base = ws.clone()placeholder with inline doc pointing to the ephemeral session path ✓
Tests
- 3 unit tests cover all 3 entry points ✓
- 1143 unit tests pass, 0 fail ✓
- 8/8 E2E pass, clippy clean ✓
- Squashed from 3 TDD phase commits ✓
All story 154 code-tasks complete. Routing to shepherd for gap reconciliation.
…ial_resolver [Ref: #154] Implements AppTokenProvider backed by the formation keyring: reads client_id, private_key, and installation_id from KeyValueCredentialStore and exchanges them for a GitHub App installation token. Uses a cfg-split exchange_token (synthetic token in tests, real JWT/HTTP exchange in production). Wires credential_resolver in daemon/run.rs using the local formation's credential store so sessions receive credentials from the keyring. Adds Send + Sync supertrait to KeyValueCredentialStore (all implementations already satisfy it). Exports AppTokenProvider and KeyringAppTokenProvider from the workspace module. Fixes prepare_launch_credentials to pass shared_credential_dir through to inject_app_credentials. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
may-team-engineer-bob
Bot
force-pushed
the
feature/fix-154-stop-session-deactivation-watcher
branch
from
June 10, 2026 15:55
8266c0e to
e348913
Compare
… #154] CredentialRefreshable trait enables test injection without real HTTP calls. active_member_names reads Active sessions from registry, de-duped. refresh_active_session_credentials iterates members non-fatally, collecting (member, error) pairs without aborting on first failure. run_credential_refresh_loop runs one pass then checks shutdown signal, sleeping the interval between passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…credential dir [Ref: #154] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…k 11-v2 Remove start_members_handler, start_loop_handler, run_token_refresh_loop, attempt_token_refresh, and cache_app_credentials from the daemon API. Remove the /api/members/start and /api/loops/start routes from the router. Remove start_members() and start_loop() client methods and their orphaned request/response types (StartMembersRequest, StartMembersResponse, StartLoopRequest, StartLoopResponse). Route bm-agent loop start through the sessions API (start_session) instead of the removed loop endpoint. Stub linux::start_members() — permanent workspace launch is eradicated in favour of the sessions API. Ref: #154
- launch_members_oneshot(): sessions Option<&SessionsApiState> → &SessionsApiState - handle_member_launch(): sessions Option<SessionsApiState> → &SessionsApiState - Remove legacy else-branch (permanent workspace formation path) from launch_members_oneshot - Remove start_local_members() from formation/start_members.rs (zero production callers) - Remove orphaned helpers: resolve_bridge_credentials, BridgeCredentials, discover_members, AppCredentialsCached, resolve_app_credentials_and_deliver, exchange_token - Mark is_brain_member/check_robot_enabled_mismatch as test-only (re-exports + cfg_attr) - Update call sites in daemon/run.rs: Some(sessions) → &sessions [Ref: #154]
…de-task 13 Implement CredentialRefreshable for SessionsApiState and add ensure_credentials() to HydrationWorkspaceOps, then spawn run_credential_refresh_loop after the retention GC loop in run.rs. Removes all #[allow(dead_code)] annotations from the refresh loop, trait, and impl block. Ref: #154 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…code-task 14 [Ref: #154]
…de-task 15 [Ref: #154] CT-06 AC-3 requires gh api user to succeed using the credential relay token. The test previously only verified hosts.yml path existence; now also asserts gh api user --jq .login exits 0 using GH_CONFIG_DIR from the agent env.
…code-task 16 [Ref: #154]
…7 [Ref: #154] Convert e2e, e2e-step, and e2e-verbose recipes to bash script blocks that call 'eval "$(direnv export bash 2>/dev/null)" || true' before env var checks, so 'just e2e' and 'just test' automatically load TESTS_GH_TOKEN and friends from the workspace .envrc via direnv.
…-task 18 [Ref: #154]
… and Playwright E2E tests [Ref: #154] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 tasks
🛡️ sentinel — 2026-06-11T00:30:28ZSuperseded by #39 (squash/ct03 — reconciled fix-154 + ct03 branches). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements all gap fixes identified during verification of story #154 (ephemeral workspaces).
Code-Tasks Implemented
.claude/assembly to ConfigAssembler (team, member, project levels + commands + settings.local.json)bm-agentwork-item lock commandslist,finalize, remove--history)Key Changes
stop_session_handlerspawns deactivation watcher child process so finalization fires on stop (AC-02)ConfigAssemblerassembles.claude/agents/,.claude/skills/,.claude/commands/,.claude/settings.json,.claude/settings.local.jsonfrom team, member, and project-levelcoding-agent/directories (AC-08)AppCredentialWriterwriteshosts.ymlto<sessions_base>/credentials/<member>/gh/(D-02 shared path);CredentialRelay::gh_dir_for()encapsulates existence check (AC-09)inject_app_credentials_from_shared_dir()setsGH_CONFIG_DIRto the shared credential dir (AC-09)bm-agent lock acquire/releasecommands with daemon API endpoints (AC-13)bm session listandbm session finalizeadded;bm status --historyremoved (AC-17, AC-18, AC-23)phase-d-sessionadded toallJustfile targetTest Results
credential_resolver: Nonein run.rs not yet wired end-to-end)Closes #154 (pending QE verification)