feat(token-id-capture): resolve each call's parent at request time - #2180
feat(token-id-capture): resolve each call's parent at request time#2180ananthsub wants to merge 12 commits into
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
ecdccec to
3d810f7
Compare
3d810f7 to
2dd3cc3
Compare
2dd3cc3 to
5815504
Compare
5815504 to
a9a579d
Compare
a9a579d to
7219fc9
Compare
32711d6 to
b117be3
Compare
ebe8fdc to
6b2f71c
Compare
1 similar comment
cmunley1
left a comment
There was a problem hiding this comment.
left a comment but dont think it is blocking, more of a unlikely edge case
|
/claude review |
|
SHIP WITH CARE Request-time parent lineage for token capture: a shared lineage store resolves which recorded call a request continues (fingerprint over model-authored turns, verified by a conversation digest), stamps Two findings, both inline, neither a hard blocker but both worth resolving before this drives training data at scale:
Also confirm the num_workers>1 guard has been exercised with a real multi-worker rollout, not just unit tests — the CLAUDE.md bar for capture/training changes is real rollouts, and the file-lock + read-after-write assumption across uvicorn workers is exactly the kind of thing green unit tests do not prove. |
|
/claude review |
|
Review incomplete: the PR base SHA changed during review (captured merge-base |
|
/claude review |
Identifies which recorded call a request continues, from what the harness already sends: hashing the model-authored turns finds the call that produced the last one, and the conversation those turns arrived with is verified before the match is used, so a compacted or rewritten history does not resolve. The record gains parent_call_id, cum_len and digest, and the builder prefers a verified link over inferring one from token prefixes, which makes a chain exact rather than inferred and tells a retry from the call the harness kept. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
…t messages alone The parent check read only the message list. Anthropic sends the system prompt as `system` and the tool schema as `tools`, both siblings of that list, and the chat template renders both into the prompt. A harness that changed either mid-rollout, which Claude Code does on a plan-mode toggle or an MCP attach, still matched, so the call could be handed a prefix rendered under instructions or tools the harness had already replaced. Carry both as a leading pseudo-turn so conversation_digest covers them. Its role is not `assistant`, so the fingerprint the index keys on is unchanged. Tools are normalized to plain data first, since they arrive as dicts on one call and as models on the next and two strings for one schema would break a chain that never changed. Also fail closed when a node has no recorded context digest rather than treating the request as a continuation. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Expose a transport-neutral lineage protocol, use a locked file implementation for Gym-local capture, and require external multi-worker deployments to configure a shared adapter instead of silently losing parent links. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Require adapter implementations to fail closed on ambiguity and make repeated lineage publication idempotent across local and external stores. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Append shared lineage records once and cache only newly published tails in each worker. Fall back to verified token-prefix matching when a recorded parent was filtered from the build, while retaining quarantine for contradictory lineage. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Describe cross-worker consistency, append-only local storage, and the distinct missing-parent and digest-mismatch outcomes with short standalone comments. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Persist root, resolved, and unresolved outcomes at the token publication boundary so multi-worker readers reconstruct only verified lineage. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Use a metadata-only LRU resolver with bounded lock striping, canonical fingerprints, and fail-closed reconstruction so multi-worker continuations resolve without retaining token arrays in memory. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Keep operational comments concise while retaining the failure modes and invariants that explain why the resolver fails closed. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Keep deterministic wire-contract hashes in an allowlisted Python fixture and stamp synthetic rollout records with the explicit root decision required by schema v3. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Exercise the normal custom-sink configuration contract instead of opting collector-only tests into unresolved continuation handling. Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Resolves each model call's parent at request time from entries already committed by
TokenSink.put. It does not create a second lineage write path.Multi-worker publication and resolution
sequenceDiagram participant H as Harness participant W1 as Model worker 1 participant B as Shared token backend participant W2 as Model worker 2 H->>W1: first request without model-authored history W1->>B: resolve(request items) B-->>W1: ROOT W1->>W1: run inference and stamp ROOT and continuation metadata W1->>B: TokenSink.put(TokenEntry) B-->>W1: record durable and resolver-visible W1-->>H: response A H->>W2: continuation echoing response A W2->>B: fetch newly committed entry metadata W2->>W2: refresh bounded metadata-only index W2->>W2: fingerprint lookup and context-digest verification alt one token-identity candidate W2->>B: lazily load winning call tokens B-->>W2: winning TokenEntry and ancestors when needed W2->>W2: verify cumulative digest and mark record RESOLVED else no safe unique candidate W2->>W2: record UNRESOLVED(reason) end W2->>W2: run inference and stamp the child decision W2->>B: TokenSink.put(child TokenEntry) W2-->>H: response BROOT,RESOLVED, andUNRESOLVEDare the only outcome stages. Diagnostic reasons are persisted for analysis but do not weaken reconstruction behavior.Summary
TokenEntry(schema version 3).TokenSink.put(entry)as the single durable publication boundary.LineageStoreis a read-only view over sink-committed entries and has no served-pathrecord()operation.IncrementalLineageStorefor file, queue, KV, or service adapters. Backends implement entry refresh and lazy load hooks while inheriting Gym's canonical matcher, locking, bounded LRU, and digest checks.flockfor cross-process visibility.UNRESOLVED.ROOTas a valid chain start and follows only verifiedRESOLVEDlinks.UNRESOLVED, a digest conflict, or missing resolution metadata creates a masked fragment. Prefix matching is retained only to recover a recordedRESOLVEDlink whose direct parent is absent from the current build.Depends on #2341. Required by #2181.