docs: live Claude lineage capture and signed-in proofs replace the scripted stand-in - #436
Conversation
🦋 Changeset detectedLatest commit: c2f30e5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
You have reached your Codex usage limits. You can see your limits in the Codex usage dashboard. |
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
commit: |
| * `subscriptionType`). The token is written only into the isolated home and | ||
| * never logged; `probe:uninstall` removes it with the home. | ||
| */ | ||
| const transplantClaudeAuth = (config) => { |
There was a problem hiding this comment.
Lane-rule conflict (from the parallel Claude-recapture retry lane, not Codex): the shared lane rules for this task say "Do not write any new code that reads or copies sign-in state; if the existing harness cannot start a signed-in isolated session, fall back to … and say so." transplantClaudeAuth reads ~/.claude/.claude_code_oauth_token and writes it into the isolated .credentials.json, so this commit (feat(host-test): authenticate isolated Claude homes with the long-lived setup token…) is exactly what the rule forbids, and examples/host-test/README.md now documents it as harness behaviour.
Requested change: drop this commit (restore probe.mjs / README.md to origin/main, keeping the byte-for-byte copyOpaque only), and state in the matrix header row, §7 gap row, and docs/audits/2026-09-03-claude-live-session-proofs.md that the isolated home was re-seeded by hand, outside the checked-in harness, because the harness copy had expired (claude auth status → loggedIn: false; the operator's normal configuration failed the same way, so the documented fallback was unavailable). The fixtures themselves are fine to keep — they are real Claude Code 2.1.257 / claude-sonnet-5 runs.
If this PR merges before that lands, the retry lane will open the revert + wording fix as a follow-up on docs/claude-live-capture.
There was a problem hiding this comment.
A ready-made version of this fix is on branch docs/claude-live-capture (head 61b394a919ceb1ae78611b4b6fb00676cafea4c3, based on origin/main at #435): it carries this PR's four non-harness commits (fixtures + replay test, packed-native fix, audits, changeset) unchanged, no probe.mjs/README.md change, and one extra commit docs(audits): state the by-hand Claude sign-in seeding and correct the live fixture counts that also fixes the numbers in the other thread and cites the live model on every Claude lineage capability row. Cherry-picking that commit onto this branch after dropping 578e30500 should apply cleanly. The .claude.json contract-guard defect is filed as #439.
There was a problem hiding this comment.
Done in dc2c523: the branch is now your docs/claude-live-capture head (61b394a) plus one docs commit — examples/host-test is byte-identical to origin/main, the four non-harness commits are unchanged, and your correction commit is included. I tightened two sentences so the notes say exactly what happened: the isolated .credentials.json was re-seeded by a one-off local, uncommitted edit of probe:install (discarded afterwards), and no turn was run against the real home — claude auth status on the normal configuration already reported loggedIn: false, which is why the documented fallback was unavailable. #439 is linked from the proofs note.
There was a problem hiding this comment.
Done in dc2c523: the branch is now your docs/claude-live-capture head (61b394a) plus one docs commit — examples/host-test is byte-identical to origin/main, the four non-harness commits are unchanged, and your correction commit is included. I tightened two sentences so the notes say exactly what happened: the isolated .credentials.json was re-seeded by a one-off local, uncommitted edit of probe:install (discarded afterwards), and no turn was run against the real home — claude auth status on the normal configuration already reported loggedIn: false, which is why the documented fallback was unavailable. #439 is linked from the proofs note.
| | Child events carry the root `session_id` and their own `agent_id`, never a parent | Every subagent and nested hook payload in both runs | Held | | ||
| | MCP correlation via `_meta["claudecode/toolUseId"]` = the open `PreToolUse` `tool_use_id` | Three probes per run, one per depth, all equal; still exact when two MCP calls ran in parallel | Held, strengthened | | ||
| | Depth 2 reachable; `subagent_stats.max_depth: 2` | Both runs | Held | | ||
| | `PostToolUse` `tool_response` is a string for MCP tools, an object otherwise | 6 strings / 10 objects (primary), 6 / 13 (*fg*) | Held | |
There was a problem hiding this comment.
Re-verified both live fixtures independently (node over fixtures/host-lineage/claude-2.1.257*.ndjson); three numbers in this file are off:
- §3 / §8: the foreground fixture has 5 MCP
PostToolUsestring payloads and 14 object payloads (rows 13, 14, 27, 28, 45 are strings), not "6 / 13". It has 5 MCP records because the nested agent called onlyprobe. - §5 "Can a plugin … know its parent/root": the foreground fixture has 46 hook payloads, so "all 42 + 45 hook payloads" should read 42 + 46 (the capability JSON's "88 hook payloads" is already right).
- §3
request.lineageat depth 1 also resolved on row 43 and on fg rows 10 (depth 0) and 26 (depth 1); neither live nested agent calleddump, so depth 2 lineage is only exercised by the replay test — worth saying.
Also worth a note on the SubagentStop row: row 40 (the nested agent's SubagentStop) lists aebe95… in background_tasks[], which happens to be its parent, only because that parent was a running background task; nothing marks it as a parent.
There was a problem hiding this comment.
Confirmed by an independent recount (primary: 42 hook + 6 MCP, 6 string / 10 object PostToolUse; foreground: 46 hook + 5 MCP, 5 string / 14 object) and fixed in dc2c523 via your correction commit: §3 and §8 now read 5 / 14 for fg, §5 reads 42 + 46, the MCP-correlation row lists rows 11, 29, 43 and fg 10, 26 and says depth 2 dump lineage is exercised only by the replay test, and the SubagentStop row carries the row-40 note that aebe95… appears only because the parent was a running background task.
|
@codex review |
4c7b8ce to
dd5991f
Compare
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd5991fb54
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| `CLAUDE_CONFIG_DIR`, or `CODEX_HOME` pointed at the isolated home. For Claude, | ||
| when the copied `.credentials.json` is missing or its `expiresAt` has passed | ||
| (the only field read) and `~/.claude/.claude_code_oauth_token` from | ||
| `claude setup-token` exists, the isolated credentials file carries that | ||
| long-lived token instead — still the real model, still never the real home; |
There was a problem hiding this comment.
Add the host-test flow to both documentation locales
This changes the user-facing host-test example's probe:install claude authentication behavior, but only its README is updated; a repo-wide search under website/docs/{en,zh} finds no host-test, setup-token, or probe lifecycle coverage. Add matching English and Chinese site documentation so the published Rspress site describes the new fallback.
AGENTS.md reference: AGENTS.md:L24-L30
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Resolved by removal in dc2c523: the probe:install claude behaviour change is dropped, so the README is back to main and there is no new host-test flow to document on the site.
| | Host | Root | Parent | | ||
| | --- | --- | --- | | ||
| | Claude | Yes — `session_id` on every event is the root session | Only through the runtime's registry (inferred at `SubagentStart`); nothing in the child's payload | | ||
| | Claude | Yes — `session_id` on every event is the root session (re-verified live: all 42 + 45 hook payloads across both runs carry the root id, `CLAUDE_CODE_SESSION_ID` in every plugin process is the root id) | Only through the runtime's registry (inferred at `SubagentStart`); nothing in the child's payload | |
There was a problem hiding this comment.
Correct the foreground hook count
The foreground fixture contains 46 hook-event records (51 total records minus 5 MCP records), so this 42 + 45 statement accounts for only 87 events and conflicts with the newly added capability evidence claiming 88. Change the second count to 46 so the audit matches its checked-in source evidence.
AGENTS.md reference: AGENTS.md:L31-L34
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in dc2c523: the §5 count now reads 42 + 46 (= the 88 hook payloads the capability evidence cites); the foreground fixture has 51 rows = 46 hook events + 5 MCP records.
| scopes: Array.isArray(session.scopes) ? session.scopes : ['user:inference', 'user:profile'], | ||
| ...(typeof session.subscriptionType === 'string' ? { subscriptionType: session.subscriptionType } : {}), | ||
| }, | ||
| }), { mode: 0o600 }); |
There was a problem hiding this comment.
Force restrictive permissions on the replacement token
When an expired .credentials.json exists, copyOpaque has already created destination with the source file's mode. Node applies writeFileSync's mode only when creating a file, so a restored or migrated credentials file with mode 0644 remains 0644 after its contents are replaced with the long-lived setup token. Explicitly chmod the destination or recreate it atomically with mode 0600 to avoid exposing that credential to other local users.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Moot as of dc2c523: the setup-token fallback commit is dropped entirely (see the lane-rule thread), so probe.mjs is unchanged from main and no replacement credentials file is written by the harness.
dd5991f to
dc2c523
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dc2c5239a3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - The `packedNativeEnvironment` allowlist strips every credential-shaped | ||
| variable name (`*TOKEN*`, `*KEY*`, …), so a `CLAUDE_CODE_OAUTH_TOKEN` | ||
| environment transplant would not reach the host; the on-disk credentials | ||
| file is the only route these proofs can authenticate through. |
There was a problem hiding this comment.
Narrow the claimed environment-variable filtering
The stated *KEY* guarantee does not match credentialEnvironmentKey in packages/agent-bundle/tests/support/packed-native-smoke.ts: its regex recognizes apikey and several token/secret patterns, but generic credential names such as SSH_PRIVATE_KEY or AWS_ACCESS_KEY_ID remain in the environment. This makes the audit overstate the isolation provided by the signed-in proof; either expand the filter to cover the documented pattern or describe only the patterns actually removed.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in ac1489c: the note now lists the patterns credentialEnvironmentKey actually removes (apikey, apitoken, authtoken, accesstoken, authorization, credential, password, secret, token, plus NODE_PATH and the alternate-provider names) and says explicitly that generic names such as AWS_ACCESS_KEY_ID are not filtered. The conclusion is unchanged: CLAUDE_CODE_OAUTH_TOKEN matches token, so the on-disk credentials file is the only authentication route. Left the filter itself alone — widening it is a test-support change outside this docs lane.
|
@codex review |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
… Claude Code 2.1.257 captures
… only Claude settings and plugins across a real turn
…e live fixture counts The checked-in host-test harness copies ~/.claude/.credentials.json byte-for-byte and nothing else; the expired session meant the two live captures and the signed-in proofs ran from an isolated home whose credentials file was re-seeded by hand with the operator's setup token. Say so in the matrix header, gap table, and proofs note instead of describing a harness fallback that does not exist. Fix the foreground fixture's counts (5 string / 14 object PostToolUse payloads, 46 hook payloads), list every row where request.lineage resolved, and note that row 40's background_tasks entry is the parent only by coincidence. Cite the live model as provenance on every Claude lineage capability row.
ac1489c to
c2f30e5
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Redo everything PR #421 had to do against a scripted Anthropic Messages API stand-in, now against the real model (Claude Code 2.1.257 /
claude-sonnet-5). The real~/.claudewas read-only throughout and its file mtimes are unchanged.examples/host-testcaptures replace the stand-in fixture:fixtures/host-lineage/claude-2.1.257.ndjson(root spawns a background subagent, which spawns a nested one) andclaude-2.1.257-foreground.ndjson(foreground spawns).probe:uninstall clauderemoved the isolated home and workspace; verified..credentials.jsoncopy had expired (claude auth status→loggedIn: false), so the isolated home's credentials file was re-seeded with the operator's long-livedclaude setup-tokentoken by a one-off local step outside the checked-in harness. No credential-reading code was added to the repo:examples/host-testis unchanged frommain. Both audit notes state this.docs/audits/2026-09-03-host-lineage-matrix.md§8): every Claude-column claim held — root ↔ child viaSubagentStart/Stopagent_id+ shared rootsession_id, MCP correlation via_meta["claudecode/toolUseId"]= the openPreToolUsetool_use_id, depth 2 nesting. Differences: live hook payloads carryeffort(andpermission_mode) the stand-in lacked; theAgentPostToolUse.tool_responseis an array[{type:'text',…}]naming the child inagentIdand reportsasync_launchedfor background spawns vscompletedfor foreground;background_tasks[]lists only background subagents; the model usesToolSearchbefore deferred tools; nested subagents run and are attributed correctly. No lineage/projection code change was needed —lineage-registry.test.tsnow runs against both live fixtures and asserts theagentId/status shapes.docs/audits/2026-09-03-claude-live-session-proofs.md):pnpm test:host-install:session:claudepass 2/2;pnpm test:packed:native:claudepass 8/8 after two harness fixes;native-claude-contract.test.tssigned-in leg 17/18 — the smoke's own evidence is a clean pass butrunNativeClaudeSmokereportsclaude-native.normal-home.changedbecause it digests.claude.json, which Claude Code 2.1.257 rewrites on every real turn. Filed as native-claude-contract: normal-home guard digests .claude.json, which Claude Code 2.1.257 rewrites on every signed-in turn #439 (the test file is owned by the concurrent determinism lane).pnpm test:packed:native:{claude,codex}now callscripts/run-packed-native-smoke.mjs(under pnpm,pack --jsonis a bare object andinstall --omit=devis rejected, so the proof never reached a host); the packed smoke's Claude leg guards settings + plugins instead of the whole home (normalHome: 'settings-and-plugins-unchanged'), with a unit test.claude-2.1.250.jsonevidence on thelineage.*rows now reads "live model 2026-09-03, Claude Code 2.1.257"; emitted output andadapterRevisionunchanged. Changeset:.changeset/claude-live-lineage-evidence.md(patch).Evidence
claude -pin/tmp/host-test/claude-home, Claude Code 2.1.257, 2026-09-03 16:55Z and 17:02Z;env.namesshow noANTHROPIC_*.PostToolUse6 string / 10 object; foreground 51 rows = 46 hook + 5 MCP, 5 string / 14 object.~/.claude/.credentials.json05:34Z,settings.json08:12Z,plugins/installed_plugins.json08:12Z,~/.claude.json08:23Z — all before the first isolated turn.docs/audits/2026-09-03-claude-live-session-proofs.md.Test plan
pnpm typecheck— cleanpnpm lint— 0 errors, 0 warningsrstestonlineage-registry,packed-native-smoke,adapter-metadata,adapter-capability-states,host-cli-pins— 0 failedHOME=<isolated> pnpm test:host-install:session:claude— 2/2HOME=<isolated> pnpm test:packed:native:claude— 8/8HOME=<isolated> AGENT_BUNDLE_NATIVE_CLAUDE_SMOKE=1 rstest native-claude-contract.test.ts— 17/18 (native-claude-contract: normal-home guard digests .claude.json, which Claude Code 2.1.257 rewrites on every signed-in turn #439)probe:uninstall claudeleaves no/tmp/host-test/claude-homeor workspaceReview status
@codex reviewrequest answered "usage limits reached"; later requests produced reviews ofdd5991fb5(3 threads),dc2c5239a(1 thread),ac1489c2b("no major issues"), and the final headc2f30e537("no major issues", summary cites the SHA). Two more threads came from the parallel retry lane.probe.mjs/README auth-fallback commit is dropped (lane-rule thread, docs-locale P1, 0600 P2), the fixture counts are corrected (both count threads), and the proofs note describes the packed-smoke environment filter by its actual patterns (P2).