Conversation
The PR description includes a sufficient representative real-CLI verification record. |
The PR description includes a sufficient representative real-CLI verification record. |
… the main checkout (Tencent#955)
2ecf408 to
b177c7a
Compare
Neither previously reported ownership issue is resolved in the current diff. The PR description’s representative real-CLI verification record is sufficient. |
The previously reported same-command ownership/trust issues are resolved for unchanged hook layouts. The PR description includes sufficient representative real-CLI verification. |
Previously reported ownership, bare-repository, configured-path, and reordered-group issues are resolved. The PR description includes sufficient representative real-CLI verification. |
The previously reported same-command ownership/trust, bare-repository, configured-path placement, reordered-group, legacy-option, and missing-HOME removal issues are resolved. The PR description includes sufficient representative real-CLI verification. |
The previously reported issues are otherwise resolved. The PR description includes sufficient representative real-CLI verification. |
In the main checkout, classify team-only entries by exact built-ins and manifest records instead of marker substrings, so member commands such as 'teamai pull --silent && ./notify' survive reconcile and uninstall. Sweep a coincident legacy Codex file when Codex is excluded from the main pass, and have uninstall reconcile that file once under both ownerships.
The previously reported marker-substring ownership issue is resolved. The PR description includes sufficient representative real-CLI verification. |
The previously reported Claude ownership issue is resolved in the current diff. The PR description includes sufficient representative real-CLI verification. |
Summary
Codex silently skips untrusted or modified hooks, so a reminder alone leaves SessionStart and project rule delivery inactive. Auto-trust is on by default through
codex app-server;codexTrustEnabled: falsein the member'sconfig.yamlopts out. Trust queries use the main checkout even when the current worktree has no.codex/; doctor reads the current worktree without writing trust.Type of Change
Test Plan
npm run buildpassesnpx tsc --noEmitpassesnpm run lintpassesnpx vitest runon8042fbb6: 372 files pass, 7,258 tests pass, 1 skippednpm run test:e2eonb177c7a0: 80 files pass, 453 tests pass, 26 skipped; not rerun locally for the review follow-ups belowBefore: New regression tests failed because a pull in a worktree without
.codex/cached success without trusting the main hook, absent requested hooks returnedtrusted, and a member command containingteamai pullreceived trust.After: Public pull regression, exact command selection, missing-hook retry, cross-checkout cache, interactive/silent/dry-run pull, init/bootstrap, doctor diagnostics, project realpath/untrusted tests, app-server initialization cleanup, and
hooks injectfallback trust pass. A rejecting app-server previously kepthooks injectalive after the warning; the rebuilt CLI now exits cleanly.Real CLI verification on macOS with Codex 0.159.3, isolated HOME and CODEX_HOME under
/private/tmp/tai955-final-7c2k9l5h, CLAUDE_CONFIG_DIR unset, local git provider:Built CLI:
init https://git.example.com/demo/team.git --provider git --scope project --agent codex,claude.hooks/listreports HOME and main team hooks trusted.Added a worktree without
.codex/, introduced a new team hook, and ranpull --forcethere before SessionStart. Main hook keys are trusted; worktree still has no.codex/. HOME SessionStart is trusted and loaded there.Ran
hook-dispatch session-start --tool codexwith that worktree's payload and waited for the background dispatch..codex/is created; worktreehooks/listreports the main team hooks trusted.Removed the worktree and ran
pull --force: all hooks remain trusted; HOME Codex/Claude files contain no old$PWDgates.Set the new hook's trusted hash to a wrong value through
config/batchWrite:doctor --jsonreportsCodex trusts the teamai hooks: ok=false.pull --forcerestores trusted status.Broke the local team hook YAML, removed HOME Codex hooks, and invalidated built-in hashes.
hooks injectexits 1 without overall success; recreated built-ins are trusted.Local verification artifacts:
/tmp/tai955/e2e-final.py,/tmp/tai955/e2e-final.log, and/tmp/tai955/{build,tsc,lint,tests}-final.log. Extra providers and tools are left to CI; no full provider/tool matrix was run locally.E2E follow-up evidence
npm run build && npm run test:e2ereproduced CI's seven failures: 4 files failed, 394 tests passed, 26 skipped. Claude/Codex team-hook assertions still read HOME. The [feat] Scope hooks, MCP servers and env variables by project: a project's entries reach every member of the role #668 delivery test stopped before rebinding to billing, so the nextmcp listassertion saw checkout; its provenance assertion is unchanged.b177c7a0, after rebasing ontoorigin/mainatbae48e5c,npm run build,npx tsc --noEmit,npm run lint,npx vitest run(372 files, 7,228 passed, 1 skipped), andnpm run test:e2e(80 files, 453 passed, 26 skipped) all pass. The four affected real-CLI files pass all 18 tests. They verify ungated Claude/Codex team hooks in the main checkout, HOME built-ins, CodeBuddy's HOME cwd gates, namespace overrides/rebinds, idempotence/removal, and one shared main-checkout file in a real linked worktree.hooks removedeleted the other project's CodeBuddy hook. This predates [bug] Codex never runs teamai hooks: they need manual trust, and a pull invalidates it #955; removal now passes the same existing project filter as injection. User/self behavior is unchanged. Usage guides and the core troubleshooting reference document the removal boundary.The rebases preserve #947 rule-cleanup guidance, #950 Claude other-host protection, and #955 automatic trust/main-checkout layout. #929/#931 source changes are inherited from main. Exact Claude command assertions include the other-host prefix; a real-shell control proves the main-checkout hook skips Cursor only when Cursor owns its hooks, and runs from a linked worktree without a cwd gate. Five focused E2E files pass all 25 tests. All checks above were rerun after the final rebase.
All follow-up test commands unset
CLAUDE_CONFIG_DIRandCODEX_HOME; unit/E2E runs use temporary HOME directories. No real~/.claude,~/.claude2or~/.codexwas used. Layout fixtures for #373/#264 opt out of Codex trust to test file ownership independently. Remote-provider tests requiring credentials remain skipped. Logs in/tmp/tai958-verification/:build-host.log,tsc-host.log,lint-host.log,unit-host-final.log,e2e-host-final.log; original reproduction:e2e-before.log; removal negative control:removal-red.log; focused verification:host-target-green.log. This follow-up did not rerun live Claude/Codex sessions; automated suites use a fake or unavailable Codex app-server. The earlier live Codex record above is preserved.Hook ownership review follow-up
9ae91686,npm run build,npx tsc --noEmit,npm run lint, andnpx vitest runpass: 372 files, 7,233 passed, 1 Windows-only test skipped. New tests cover different events, identical entries under the same event, matcher/timeout differences, repeat/update/removal, ambiguous legacy records and alternating internal Codex projects. Exact ownership applies only to public Codex; other tools retain their HOME layout/gates. The legacy replacement fixture now supplies its ownership manifest instead of claiming an unrecorded command.CLAUDE_CONFIG_DIRandCODEX_HOMEunset, in both user and project scope.hooks injectpreserves member entries sharing the team command; their Codex keys never receive a trusted hash, while the generated team key does. Repeated injection, a team-command update andhooks removeretain those member entries and their options. Both fixtures pass. Artifacts:/private/tmp/tai958-owned-lsmem0u8; script and log:/tmp/tai958-review/verify-owned-hooks.py,real-cli-final.log.The full E2E suite was not rerun locally for this focused correction. Its previous CI run on
b177c7a0passed with 453 tests and 26 skips. The current correction has the focused real-CLI record above; live agent sessions and credentialed providers were not exercised. Logs in/tmp/tai958-review/:trust-red.log,project-red.log,legacy-red.log,internal-red.log, and{build,tsc,lint,unit}-final.log. No real~/.claude,~/.claude2or~/.codexwas used.Checkout and path review follow-up
79b01c80,npm run build,npx tsc --noEmit,npm run lintandnpx vitest runpass: 372 files, 7,239 tests passed, 1 skipped. Public-interface tests cover actual Git bare anchors, project placement/trust, separate workspace ownership, uninstall discovery, custom project targets with default HOME built-ins, repeat/update/removal and moved Codex definitions. Trust and doctor use the configured target; when Codex does not load a custom path, trust fails with that path and doctor reportsnot loaded.CLAUDE_CONFIG_DIRandCODEX_HOMEunset.hooks injectwrites Claude/Codex team hooks into the actual worktrees, grants trust to those worktrees and never writes or trusts the bare directory. Inserting an unrelated member group before a managed Codex entry and reinjecting leaves one team copy. Removing from one workspace preserves its member hook and the sibling workspace's team hook. A custom-path fixture verifies ungated/idempotent project files, default HOME built-ins and removal at the configured paths, withcodexTrustEnabled: false. Both fixtures pass. Artifacts:/private/tmp/tai958-checkout-nx4uo_lq; script and log:/tmp/tai958-review-next/verify-checkout-hooks.py,real-cli.log.The full E2E suite was not rerun locally for this focused correction, as requested. The preceding CI run on
9ae91686passed, including fork-safe E2E with 453 tests passed and 26 skipped. This head has the representative CLI verification above; live agent sessions and credentialed providers were not exercised. Logs in/tmp/tai958-review-next/:reorder-red.log,bare-red.log,paths-red.log,bare-ownership-red.log,bare-discovery-red.log, and{build,tsc,lint,unit}.log. No real~/.claude,~/.claude2or~/.codexwas used.Legacy upgrade and removal review follow-up
timeout,additionalContextLimit, or both. A linked-worktree removal test failed after the HOME roots were deleted.c7d0a467,npm run build,npx tsc --noEmit,npm run lintandnpx vitest runpass: 372 files, 7,245 tests passed, 1 skipped. Tests cover migration/update/removal, trust and direct removal before the first upgraded reconcile, legacy collisions differing only in unrecorded options, multi-handler member groups and missing-HOME main-checkout cleanup. Modern ownership still requires the complete recorded definition; legacy recovery requires a unique match on its recorded fields. Ambiguous entries remain untouched and untrusted.CLAUDE_CONFIG_DIRandCODEX_HOMEunset. A legacy hook carrying timeout/context options migrates to one current entry; repeat/update/removal and direct legacy removal preserve member hooks under other events/matchers. Only the generated team key receives trust. After deleting HOME Claude/Codex roots,hooks removefrom a linked worktree removes main-checkout team hooks, retains member hooks and leaves the missing roots absent. Both fixtures pass. Script/log:/tmp/tai958-legacy-review/verify-legacy-hooks.py,real-cli.log; artifacts:/private/tmp/tai958-legacy-hfmcxb7c.The full E2E suite was not rerun locally for this focused correction, as requested. The earlier CI run on
9ae91686passed fork-safe E2E with 453 tests passed and 26 skipped. Live agent sessions and credentialed providers were not exercised. Logs:/tmp/tai958-legacy-review/{legacy-red,legacy-green,remove-red,focused-green,build,tsc,lint,unit}.log. No real~/.claude,~/.claude2or~/.codexwas used.Pre-#370 ownership review follow-up
a9ab3f21,npm run build,npx tsc --noEmit,npm run lintandnpx vitest runpass: 372 files, 7,251 tests passed, 1 skipped. Tests cover injection and direct removal from main/linked worktrees, no duplicates on repeat, removal after upgrade, consumption of old gated ownership and preservation of same-command member hooks plus other tools' legacy records. Main-only manifests consume old gates; HOME still retains other projects' gates. Warning tests cover hook and MCP-only outcomes without assuming a path.CLAUDE_CONFIG_DIRandCODEX_HOMEunset. Pre-fix(hooks): unify hook-injection scope so project-scope init installs the SessionStart hook #370 fixtures pass upgrade/repeat/update/removal and direct removal from both main and linked worktree. The old gate is consumed, only the generated team key is trusted, member hooks remain untrusted/preserved, and unrelated legacy ownership remains. A custom-path project explicitly marked untrusted receives the generic warning and keeps its untrusted choice. Script/log:/tmp/tai958-transfer-review/verify-transfer.py,real-cli.log; artifacts:/private/tmp/tai958-transfer-us51wi64.The full E2E suite was not rerun locally for this focused correction, as requested. The earlier CI run on
9ae91686passed fork-safe E2E with 453 tests passed and 26 skipped. Live agent sessions and credentialed providers were not exercised. Logs:/tmp/tai958-transfer-review/{red,focused-green,build,tsc,lint,unit}.log. No real~/.claude,~/.claude2or~/.codexwas used.Main-checkout cleanup ownership follow-up
teamai pull --silent && ./notifyorteamai hook-dispatch session-start --tool codex && ./notifyin the main checkout were deleted on the first reconcile (Claude and Codex cases failed). With Codex excluded, the old gated hook, built-in and legacy record survived (three selection cases failed). Uninstall deleted the member hook through the legacy pass (one case failed).8042fbb6,npx tsc --noEmit,npm run lintandnpx vitest runpass: 372 files, 7,258 tests passed, 1 skipped. Tests cover repeat, update and removal preserving member entries; excluded-Codex sweeps leaving no HOME Codex file or trust; and a single uninstall reconcile under both manifests.Found by an adversarial review against
mainplus two reported P1s. The full E2E suite and a real-CLI run were not repeated for this follow-up, as requested; the earlier CI run on9ae91686passed fork-safe E2E. Logs:/tmp/tai958-adversarial-review/adversarial-report.md,{marker-red,followup-red}.log. No real~/.claude,~/.claude2or~/.codexwas used.Related Issues
Fixes #955
Related: #954
Notes for Reviewers
Standards and Spec reviewed the whole branch in parallel. Both confirmed P2 findings were corrected; no findings remain.
Project trust uses the main checkout's realpath only when teamai has project hooks or managed Codex project MCP records. An explicit
untrustedchoice remains unchanged. #954 owns writing project MCP and its doctor check; this PR provides the shared project-trust API.Built-ins stay in HOME. A new Codex worktree gets team hooks from its second session, after SessionStart seeds
.codex/. Trust written during SessionStart also takes effect in the next session. Claude reads the main checkout immediately; other tools keep their existing layout. Legacy gates for live checkouts and disappeared directories are removed.Merge Danger
Door: two-way. Code and layouts can be rolled back; trust already written to Codex config persists until the member changes it.
Blast Radius: hooks. The default now grants trust to teamai's exact managed hooks and, where needed, their project configuration.