Skip to content

feat(orchestrator): extract engine-free sealApproval() pure function#92

Merged
BrettNye merged 1 commit into
mainfrom
feat/seal-approval-pure-fn
Jun 26, 2026
Merged

feat(orchestrator): extract engine-free sealApproval() pure function#92
BrettNye merged 1 commit into
mainfrom
feat/seal-approval-pure-fn

Conversation

@BrettNye

Copy link
Copy Markdown
Contributor

Why

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 (submitRun → tick → quorum). An external orchestrator that keeps its own control flow (the "additive seam" thesis proven by examples/langgraph-changeorder in #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

  • New audit/approval.tssealApproval(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 (including 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).

Net −23 lines of duplication removed (+ the new module/test).

Acceptance (from the task)

  • HumanApprovalExecutor uses the new fn, no behaviour change — parity test + pattern-quorum-human int test green.
  • langgraph-changeorder/seam.ts imports it, drops the hand-rolled block + TODO.
  • Stock verifyBundle binds the approval unchanged (no verifier change).

Verification

  • Orchestrator: lint + typecheck clean, 757 tests green.
  • Demo: typecheck clean, 5 tests green, and sealed / verify (VERIFIED) / tamper (rejected) artifacts all run.

🤖 Generated with Claude Code

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>
@BrettNye BrettNye merged commit 114aef1 into main Jun 26, 2026
5 checks passed
@BrettNye BrettNye deleted the feat/seal-approval-pure-fn branch June 26, 2026 05:29
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