Skip to content

feat(gateway): wire device-signed (#236) evidence through #52 verifier to settlement — ready but gated (SEAM-2) - #244

Merged
LamaSu merged 4 commits into
masterfrom
feat/seam2-device-signed-evidence-settlement
Jul 11, 2026
Merged

LamaSu merged 4 commits into
masterfrom
feat/seam2-device-signed-evidence-settlement

Conversation

@LamaSu

@LamaSu LamaSu commented Jul 10, 2026

Copy link
Copy Markdown
Owner

SEAM-2 — wire device-signed (#236) evidence into settlement. Ready but GATED.

The operator node already produces real Ed25519-signed evidence, but two gateway paths threw that signature away and anchored settlement on a fabricated gateway placeholder. This builds the mechanism to anchor on the device's own key, and leaves it OFF behind the still-stubbed #52 verifier — the money path is unchanged today.

The two inert paths (before)

  1. operator-relay.ts POST /api/operator/evidence stored the node's bundle inert: assuranceTier:0, a fabricated bundleHash = \sha256-${bundleId}`, and kernelSignature.value:"operator-relay-auto"— the real Ed25519 signature inreq.body.evidence` was discarded.
  2. paid-job-flow.ts /complete rebuilt the bundle and signed it with the ZERO address 0x0000…0000 / "gateway-auto-sign", then fed that to driveSettlement.

The wiring built (packages/gateway/src/services/device-evidence-settlement.ts, unit-tested)

  • Path 1: capture the node's real device Ed25519 signature + real bundleHash when the pushed evidence carries a signed bundle (extractNodeSignedBundle); fall back to the placeholder for old / non-bundle nodes. The stored assuranceTier stays 0 on purpose — an unverified bundle "actually supports" only the tier-0 floor, and resume-settlement's ?? latestBundle.assuranceTier fallback must not escalate the release tier from an unverified claim (fails closed).
  • Path 2: resolveSettlementEvidence chooses the settlement anchor. When a captured device bundle's signature verifies against the kernel's registered signer (normalizeRegisteredSigner chore: impl-alfa-2 post-cascade lockfile + release-please health audit #47 → tweetnacl Ed25519), settlement anchors on the device's hash + signature; otherwise it falls back to the gateway anchor. Threaded through the stored bundle, the IPFS archive, the oracle verify hash, and driveSettlement.

WHAT STAYED GATED (the safety gate — verified, not flipped)

SEAM-2 is ready-but-gated pending a real device on deployed infra. The post-deploy live proof is the harness rehearse-loop.mjs A6 rehearsal — that flips the gate once a real device clears #52. No code change needed to turn it on.

Tests

Verification (own worktree)

  • pnpm --filter @pcc/gateway test: 2063 passed, 6 skipped. The 1 failing test + 2 failing suites are pre-existing, environment-only (a Windows C:\C:\…status.ts double-drive path bug that passes on Linux CI; unbuilt @pcc/verifier/dist/capture/* subpaths) — none touch evidence/settlement.
  • pnpm --filter @pcc/gateway typecheck: exit 0, 0 errors (deps built).

🤖 Generated with Claude Code

@LamaSu
LamaSu enabled auto-merge July 11, 2026 19:29
LamaSu added 4 commits July 11, 2026 15:24
…ism)

The ready-but-gated core: verifyDeviceSignedEvidence (registered-signer #47 ->
Ed25519 verify), the composite gate (machine.execution_log #52 verifierStatus
live AND SEAM2_DEVICE_EVIDENCE_SETTLEMENT flag, both default OFF), and
resolveSettlementEvidence (fails closed to the gateway anchor). Reads the #52
verifierStatus, never flips it — #233 stays stubbed.

implementer-seam2
…hs (gated)

Path 1 (operator-relay POST /api/operator/evidence): capture the node's REAL
device Ed25519 signature + real bundleHash instead of the 'operator-relay-auto'
placeholder. Stored tier stays 0 on purpose — unverified evidence supports only
the tier-0 floor; the resume-settlement '?? latestBundle.assuranceTier' fallback
must not escalate release tier from an unverified claim (fails closed).

Path 2 (paid-job-flow /complete): resolveSettlementEvidence chooses the anchor.
Gate CLOSED by default (#52 verifierStatus stub AND SEAM2 flag unset) => gateway
fallback, byte-identical to before. Gate open => device hash+signature anchors,
after verifying against the kernel's registered signer. Fails closed.

Adds registeredSignerInputFromColumns helper. #233/verifierStatus untouched.

implementer-seam2
…ation

Unit: gate holds (real stubbed #52 + flag set => still closed), gate untouched
(#52-#55 verifierStatus stub), wiring correct (device sig -> settlement anchor,
mocked + REAL tweetnacl Ed25519), fail-closed (wrong key/tamper/unregistered),
path-1 parser. Integration: operator-relay captures the real device signature
(deviceSigned:true, stored value != placeholder, tier stays 0), placeholder
fallback for non-bundle evidence.

implementer-seam2
…hive sites

StoredSignature (algorithm:string) -> the spec Signature union at the two
archiveBundle calls (EvidenceBundle wants signer:Address, algorithm:ed25519|
secp256k1). DB insert keeps StoredSignature (column type is algorithm:string).

implementer-seam2
@LamaSu
LamaSu force-pushed the feat/seam2-device-signed-evidence-settlement branch from d1e0c3f to fcee88e Compare July 11, 2026 23:02
@LamaSu
LamaSu merged commit e7aab1d into master Jul 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant