feat(orchestrator): extract engine-free sealApproval() pure function#92
Merged
Conversation
The approval seal (canonicalize → SHA-256 → pangolin://<ns>/approval/a/<hash>,
referenced via outputRefs.approval) only existed inside
HumanApprovalExecutor.reconcile(), which fires only when Pangolin's run-engine
drives it. An external orchestrator that keeps its own control flow (the
"additive seam" thesis — see examples/langgraph-changeorder) could not call it
and had to hand-replicate ~10 lines, which would drift if the ref scheme changed.
- New audit/approval.ts: `sealApproval(record, {namespace?}) => {ref, bytes}` —
the single source of truth for the seal, engine-free. ApprovalRecord moves here
(its pure home); human-approval.ts re-exports it so every existing import
(incl. the package index) keeps resolving.
- HumanApprovalExecutor.reconcile() now calls sealApproval — no behaviour change,
proven by a byte-for-byte parity test (the pure fn's ref/bytes equal the
executor's sealed output) plus the unchanged pattern-quorum-human int test.
- index exports sealApproval + SealApprovalOptions/SealApprovalResult.
- examples/langgraph-changeorder/seam.ts drops its replicated block + TODO(pangolin)
and calls sealApproval directly; the bundle still verifies (byte-compatible).
Additive, no verifier change: stock verifyBundle binds the approval unmodified.
Orchestrator 757 tests green (lint+typecheck clean); demo 5 tests + sealed/verify/
tamper artifacts green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Why
The approval seal — canonicalize → SHA-256 →
pangolin://<ns>/approval/a/<hash>, referenced viaoutputRefs.approval— only existed insideHumanApprovalExecutor.reconcile(), which fires only when Pangolin's run-engine drives it (submitRun→ tick → quorum). An external orchestrator that keeps its own control flow (the "additive seam" thesis proven byexamples/langgraph-changeorderin #90) couldn't call it and had to hand-replicate ~10 lines — duplication that would drift if the ref scheme ever changed. This was the follow-up filed from #90.What
audit/approval.ts—sealApproval(record, { namespace? }) => { ref, bytes }, the single source of truth for the seal, engine-free.ApprovalRecordmoves here (its pure home);human-approval.tsre-exports it so every existing import (including the package index) keeps resolving.HumanApprovalExecutor.reconcile()now callssealApproval— no behaviour change, proven by a byte-for-byte parity test (the pure fn'sref/bytesequal the executor's sealed output) plus the unchangedpattern-quorum-humanint test.sealApproval+SealApprovalOptions/SealApprovalResult.examples/langgraph-changeorder/seam.tsdrops its replicated block +TODO(pangolin)and callssealApprovaldirectly; the bundle still verifies (byte-compatible).Net −23 lines of duplication removed (+ the new module/test).
Acceptance (from the task)
HumanApprovalExecutoruses the new fn, no behaviour change — parity test +pattern-quorum-humanint test green.langgraph-changeorder/seam.tsimports it, drops the hand-rolled block +TODO.verifyBundlebinds the approval unchanged (no verifier change).Verification
sealed/verify(VERIFIED) /tamper(rejected) artifacts all run.🤖 Generated with Claude Code