Repository navigation
feat(pcc-node): OT-2 command trace as kernel-signed, job-bound evidence (R46, #52 command_trace) - #417
Draft
LamaSu wants to merge 4 commits into
Draft
feat(pcc-node): OT-2 command trace as kernel-signed, job-bound evidence (R46, #52 command_trace)#417LamaSu wants to merge 4 commits into
LamaSu wants to merge 4 commits into
Conversation
…ce (R46, #52 command_trace) Sensors asked refvertical to draft the OT-2 command-trace producer (#2814). command_trace.py reads GET /runs/{id}/commands page by page from cursor 0 and fails closed on an incomplete list. Each command becomes one log_hash_chain_entry through LogCapture: kernel-signed, chained, full disclosure. Every event commits payload.jobId, payload.kernelId and payload.protocolHash, source.kernelId is the accepting kernel, and it carries its own hashEvent hash, so LO-EV-9 binds a bundle of them to one job. Pure producer: fetching is injected; nothing signs a bundle or talks to the gateway. Not wired into job_executor (that is N4b-robot, stacked on #333/#343). Tests 22/22, including hashEvent/hashBundle goldens computed with packages/spec/src/util/canonical.ts. Checked locally against the real verifiers (not committed): #341 verifyEvidenceSubjectBinding binds the job and refuses another job, another kernel or an edited event; #336 verifyLogChain validates the chain with Ed25519 signatures and breaks at an edited command. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFEKdAcSGUnfrgiwtP21GP
…stamps the settlement unit and challenge (LO-EV-9) Evidence's reserved-field rule (#3219, #3223): payload.jobId is always the PCC job; the Opentrons run id travels as opentronsRunId. When the gateway assigns settlementUnitId and challengeNonce (0x + 64 lowercase hex), every event carries them; malformed values are refused. Tests 27/27, with the hashEvent/hashBundle goldens recomputed by packages/spec/src/util/canonical.ts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFEKdAcSGUnfrgiwtP21GP
Owner
Author
|
@
Re-verified on this head against the real verifiers (local, not committed):
|
…ompleted commands are timed by the run's end Sensors' review of #417 (bus #3461, returns/pcc-sensors-review-417.md): - F1: every event now has an id, <opentronsRunId>:<commandId>, and a source.deviceType of "instrument", the value the kernel's Opentrons adapter reports (packages/kernel/src/opentrons/adapter.ts, on master and on #426). EvidenceEventSchema.safeParse passes on every event; on fbdab3d it failed with "id: Required" and "source.deviceType: Required". - F2, option (a): an entry is timed by the command's completedAt. A command that never completed is timed by run_ended_at, the run's own completedAt. run_ended_at is required in that case and may not be earlier than any completion, so capturedAt never runs backwards for that entry. createdAt stays in rawContent. Times are parsed as ISO-8601 with a zone, and a malformed time fails closed. - The TS goldens are recomputed with packages/spec's hashEvent and hashBundle. deviceType is part of the hashed source; id is not hashed, as in TS. Verified: 34 command-trace tests and 23 log-capture parity tests pass. With the TS spec (run through tsx), every event passes EvidenceEventSchema, Python and TS agree on hashEvent and hashBundle, and verifyEvidenceSubjectBinding (#341) returns ok. Against fbdab3d, 8 of the tests fail, each on the property it names. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…idence #3553) Evidence ruled (#3553, relayed by sensors #3693) that capturedAt must be non-decreasing along a #52 chain (equal is fine), and the #52 verifier enforces it. Yesterday's rule timed a never-completed command by the run's end. That breaks the order whenever completed commands follow it (Opentrons error recovery), and it invents a time the command never had. - A completed command is timed by its own completedAt. A list whose completions run backwards fails closed. - A command that never completed is timed by its createdAt, clamped to no earlier than the entry before it. No completion is invented; its real fields stay in rawContent. - run_ended_at is gone. Verified: 35 command-trace tests and 23 log-capture parity tests pass. With yesterday's code, a failed command followed by a recovered one gives capturedAt 06.000 then 05.000, which is decreasing; the new code keeps it non-decreasing. The TS checks still pass: EvidenceEventSchema, hash parity and subject binding. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
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.
Draft. Not for merge before wave D. This is R46's OT-2 command-trace producer (evidence #52
machine.execution_log,logKind: command_trace). Sensors asked refvertical to draft it for their review (bus #2814), and it is the lab vertical's route to a real tier 1 (evidence #3090). Base: masterac86a404. It changes nothing that runs today.What it does
packages/pcc-node/pcc_node/command_trace.py:fetch_run_commandsreadsGET /runs/{runId}/commandspage by page, always fromcursor=0. Without a cursor the robot starts at its current command. It fails closed on:totalLength, or one that changes mid-read;totalLength, or a short read;build_command_trace_eventsturns each command, in the robot's order, into onelog_hash_chain_entrythrough the existingLogCapture: kernel-signed, chained from GENESIS, full disclosure (rawContentis present).rawContentis the canonical JSON of the command's recorded fields, and a command that never completed is timed bycreatedAt.payload.jobId,payload.kernelIdandpayload.protocolHash. Itssourceis{kernelId, deviceId}, and it carries its ownhash(thehashEventmirror).hash_bundlemirrorshashBundle.It is a pure producer: fetching is injected, and nothing here signs a bundle or calls the gateway. Wiring it into
job_executor's Opentrons path is N4b-robot (with b34f6239), stacked on #333/#343 (adk).Verified
tests/test_command_trace.py22/22: paging and fail-closed cases, chain order and links, Ed25519 signatures, the per-event commitments, tamper checks, and Python/TS hash goldens computed withpackages/spec/src/util/canonical.ts. The full pcc-node suite gives 358 passed / 2 failed; both failures are on master too, and ci+fix(pcc-node): run the Python suite in CI; headless start; tests keep keys in tmp (N52) #388 fixes them.verifyEvidenceSubjectBinding: binds to its job and kernel (ok, 3 events). It refuses another job (job-mismatch), another kernel (kernel-mismatch) and an edited event (event-hash-mismatch).verifyLogChain(sensors said to test against feat(spec): MeasurementProfileV1 — capture parameters committed before execution (LO-SE-2) #336, not master):valid: true, with every Ed25519 signature checked over the UTF-8entryHash. Editing one command's volume breaks the chain at entry 1.Review
sensors (7a438686), as the #52 owner. adk (4f6668ed) owns pcc-node.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FFEKdAcSGUnfrgiwtP21GP