feat(harness): add managed Agent SDK feasibility probe - #649
Conversation
Add an isolated experimental Agent SDK runtime with exact-model pinning, fail-closed local permissions, deterministic MCP probes, bounded cancellation, and disposable workspace evidence. Closes: SAP-2632
Ensure an L1 result cannot pass when a built-in tool was requested but failed. Refs: SAP-2632
Use fresh canonical config roots, normalize attacker-controlled evidence, execute canonicalized file targets, and require complete permission evidence for L1 qualification.\n\nRefs: SAP-2632
Replace the incomplete canUseTool-only boundary with a universal PreToolUse policy, fail closed on managed hook settings, and add hermetic SDK loopback coverage plus durable correlation and inference-turn evidence.\n\nRefs: SAP-2632
|
Resolved the three blocking review findings in commit 6af3cf6:
Hermetic verification under Node 22.23.2:
No live model or paid gateway calls were made. The PR remains draft and is ready for re-review. |
|
Resolved the remaining prompt-handoff review finding in commit 043b30e. promptEmbedded now flips immediately before queryFactory invocation, so it is true when the factory receives the marked prompt even if that factory throws; it remains false when settings preflight skips the factory entirely. The type documentation, README, and both regressions now use the same handed-to/received-by semantics. Node 22.23.2 verification: managed-agent suite 52/52 passed, Harness typecheck passed, Prettier passed, and git diff check passed. No live or paid calls were made. Ready for re-review; PR remains draft. |
|
SAP-2632 remediation is pushed in b9d3e77.\n\nWhat changed:\n- Added content-free policy diagnostics that distinguish PreToolUse guard rejection reasons from a genuinely missing hook callback. Diagnostics cannot satisfy strict policy coverage and expose no raw IDs or tool inputs.\n- Added termination evidence preserving the underlying query/construction/iteration/abort/event-normalization outcome and whether an SDK result was observed before any policy_violation override.\n- Tightened the deterministic L1 prompt to exact paths, exact Edit arguments, exact call counts/order, explicit error continuation, and no substitutions/retries/extra paths.\n- Added a real pinned @anthropic-ai/claude-agent-sdk 0.3.228 + Node 22.23.2 localhost fake-gateway regression. It confirms SDK schema prevalidation can reject a malformed Edit before PreToolUse, while the paired tool error remains visible and strict coverage still fails. A separate valid Edit control reaches PreToolUse and succeeds.\n- Added focused tests for prompt determinism, guard paths, diagnostic privacy, termination evidence, and unchanged strict coverage.\n\nHermetic verification under exact Node 22.23.2:\n- focused managed-agent spike: 57/57\n- full Harness unit suite: 2,152/2,152\n- Harness perf: 4/4\n- typecheck, build, Prettier, git diff check, and scoped secret scan: pass\n- lint: 0 errors; one pre-existing unrelated unused-import warning in packages/harness/src/server/rest.test.ts\n\nNo live model/gateway calls or paid retries were made. The paid certification campaign remains stopped pending independent review. |
Require exact L1 and Bash-only L2 evidence, derive cancellation targets only from the SDK process tree, and preserve the existing Zod v3 REST error contract while the Agent SDK uses Zod v4.\n\nRefs: SAP-2632
|
Review remediations are implemented in
Verification with Node 22.23.2:
One full-suite attempt hit the existing macOS temp-directory cleanup race in No live gateway/model calls or paid retries were run. The certification campaign remains stopped. |
Certify only the reviewed detached POSIX fixture group, bind raw abort to immediate STOP/KILL, fail closed on unknown containment, and keep iterator close and confirmation inside one deadline.\n\nRefs: SAP-2632
|
Second process-safety remediation pushed in What changed:
Hermetic verification under Node 22.23.2:
No live gateway, paid-model, or credential-bearing calls were run. |
Keep the cancellation deadline referenced and launch POSIX SDK commands through an observer-owned supervisor so fast inner-root exits cannot orphan same-group descendants.\n\nRefs: SAP-2632
|
Final safety-review remediation pushed in Resolved blockers:
Adversarial evidence:
Hermetic verification under Node 22.23.2:
Two unrelated full-suite timing flakes appeared on earlier attempts ( No live gateway, paid-model, or credential-bearing calls were run. |
Make the L1 gate fail closed on the frozen v2 prompt, exact correlated operation trace, exact workspace and final-byte evidence, and the one bounded verification Read exception. Preserve content-free permission evidence and SDK-normalized path handling. Refs: SAP-2632
Reject traces that preserve request order but violate the semantic completion barriers needed to prove multi-turn tool recovery. Keep valid SDK batching by allowing completion permutations within each phase. Refs: SAP-2632
|
Independent-review remediation pushed in |
Correlate each normalized primary permission event with its matching tool completion so separately valid substreams cannot conceal post-execution authorization evidence. Preserve both observed SDK permission/request orderings. Refs: SAP-2632
|
Second independent-review blocker fixed in |
|
Certification-v2 live campaign result at exact head Passing L1 evidence:
Blocking L2 result:
This means SAP-2632 currently satisfies L1 for both models but does not satisfy L2's safe-cancellation/no-orphan acceptance criterion. The campaign remains stopped. Any fix and any further paid run require a separately reviewed change and fresh explicit authorization. Restricted artifacts remain outside git with mode |
Let the Agent SDK complete its bounded graceful shutdown before host fallback cleanup. Add a private authenticated registration path for the exact E0.4 L2 fixture so detached tool groups remain containable across early query failures and late registration. Refs: SAP-2632
|
L2 orphan-process remediation is pushed in Root cause and fix:
Hermetic Node 22.23.2 verification with no live gateway/model/BQ calls:
The PR remains draft and the paid campaign remains stopped. This code requires CI and independent review before any separately authorized live L2 rerun; no prior failed result is reclassified. |
Require fresh kernel-backed ancestry and lifetime evidence before signaling the exact L2 fixture group. Preserve one absolute deadline across readiness, SDK shutdown, and host cleanup while failing closed on incomplete observation. Refs: SAP-2632
Refs SAP-2632
Broadcast tool self-termination over every authenticated live channel and make the supervisor handle IPC that disconnected before bootstrap. Refs SAP-2632
|
Final process-safety review remediation is pushed in What changed:
Fresh exact-Node
Two independent exact-SHA reviews approved this commit for CI/live certification with P0=0, P1=0, P2=0. No live gateway/model calls were made. The PR remains draft pending fully green CI and a fresh fixed-order L1/L2 campaign with gateway reconciliation. |
Refs SAP-2632
Refs SAP-2632
|
Follow-up process-channel remediation is pushed at exact head What changed:
Two independent exact-SHA reviews approved with P0=0, P1=0, P2=0. Fresh Node 22.23.2 verification:
No live gateway/model calls were made. The PR remains draft while CI and a fresh exact-SHA fixed-order L1/L2 campaign complete. |
SAP-2632 v4 live campaign resultThe exact-head campaign for commit 6a0ae05 executed under explicit authorization with a strict no-retry, stop-on-first-failure policy. Result
Failed checks:
The preceding Read/Edit/Write operations, expected outside/symlink denials, MCP nonce echo, planned MCP failure/recovery, exact workspace delta, dirty/untracked preservation, query close, and terminal completion all succeeded. The final Bash request was denied by the host policy as reason invalid_input with operation bash:unregistered, so the Bash completion was an error instead of the required success. Safety evidence
Evidence hashes:
This is a valid no-go result for the frozen campaign, not a flaky pass candidate. The next engineering step is to determine the real SDK Bash input shape that reached the permission boundary, add a hermetic regression for it, and prepare a newly reviewed exact-head campaign if the implementation changes. |
Follow-up diagnosis: Bash schema mismatchThe pinned Agent SDK 0.3.228 declares BashInput with required command plus optional timeout, description, run_in_background, and dangerouslyDisableSandbox fields. Its description field documentation explicitly tells the model to provide a concise description, including for simple git commands. The current permission boundary requires the raw Bash input to have exactly one key: command. The live evidence recorded invalid_input and bash:unregistered for the final Bash request. Because the evidence contract intentionally discards raw tool inputs, it cannot prove which optional field was present; however, the failure is consistent with a valid model-facing SDK Bash shape being rejected by the stricter host shape. A safe repair should not simply allow arbitrary extras. Recommended boundary:
Relevant code: permissions.ts currently applies hasExactKeys(input, ["command"]) in both classification and policy evaluation; sdk-tools.d.ts declares the wider BashInput schema. |
Accept only the pinned SDK Bash fields, reject unsafe controls, and canonicalize allowed execution to the exact allowlisted command. Refs: SAP-2632
Summary
@sapiom/harness/experimental/managed-agent-spikeprogrammatic Agent SDK runtime without changing Harness PTY, session, server, or UI contracts.0.3.228, Claude Code runtime2.1.228, the exact two eval-only model aliases, the direct Sapiom gateway origin, isolated SDK configuration, and a positive child-environment allowlist that excludes ambient Claude/Sapiom credentials.PreToolUsehook. Use canonical containment, exact Bash equality, an MCP allowlist, bounded cancellation, and content-free structural evidence. Never use bypass permissions.L1 certification contract v2
Commit
64748b8replaced the diagnostic exact-trace-v1 gate with an independently versioned, fail-closed L1 contract:managed-agent-l1-prompt-v2andmanaged-agent-l1-evaluator-v2while retaining result-envelope contract version 1.PreToolUsedecision with the same tool and coherent decision, reason, operation ID, and outcome. Reject fallback evidence, duplicates, orphans, omissions, retries, and every other extra operation.{ role, matched }.Review remediation: semantic completion order
Commit
8cf5874closes a false-pass found by independent review. The previous evaluator proved request order and one completion per request but could accept[all requests][all completions]with one claimed inference turn.The evaluator now enforces the protocol's partial order while preserving valid SDK batching:
echo_nonce, and the firstfail_oncecall may batch and complete in any order, but all must complete before the recovery retry.fail_onceretry must complete before Bash is requested, and Bash must complete.4 + optionalReadCount.Regression tests accept maximally batched valid traces with no optional Read and with each permitted optional role. They reject the original all-requests-first counterexample, every completion-before-own-request position, every phase barrier delayed on either optional branch, insufficient inference turns, event/evidence mismatches, and invalid Bash/result/terminal ordering. L2 evaluation is unchanged.
Commit
e38ae7acloses a second cross-stream false-pass found by independent re-review. The prior check compared the tool and permission event substreams independently, so it could accept a primary permission event moved after that tool's completion while both substream projections remained intact. The evaluator now maps each exact permission event's chronological index to its matching completion and requirespermission < completionfor every tool-use ID. It deliberately does not constrain permission relative to the request event: both hook-before-yield and yield-before-hook observation orders pass when authorization still precedes completion.The added regressions move each of all 11 canonical primary permission events, plus the optional Read permission, after its own completion while preserving both substream projections. Both valid permission/request orderings remain accepted.
Hermetic verification through
e38ae7aAll commands used Node
22.23.2and made no live gateway/model call:64748b8: 31 expected failures while all four valid maximally batched traces passed8cf5874: exactly 12 expected failures for all 11 canonical permissions plus the optional Read; both valid permission/request orderings passede38ae7a: 116/116 tests passede38ae7a: 10/10 files, 187/187 tests passed, including 2/2 real bundled-SDK loopback tests8cf5874: 151/151 files, 2,271/2,271 tests passed8cf5874: 4/4 tests passedpnpm --filter @sapiom/harness typecheck: passedpnpm --filter @sapiom/harness build: passedpnpm --filter @sapiom/harness lint: 0 errors; one pre-existing unrelated warning insrc/server/rest.test.tsgit diff --check, and diff-scoped gitleaks scan: passedExact-trace-v1 diagnostic and stopped live campaign
The independently reviewed v1 campaign produced:
The exact-trace-v1 evaluator correctly rejected the fourth run because it allowed no extra call. The campaign stopped immediately. No L2 run occurred. Those runs remain diagnostic history and do not count toward the v2 acceptance repetitions.
No new live or paid call was made while designing, implementing, or verifying v2 or either chronology remediation.
Certification-v2 live campaign — stopped on L2
After independent review, fully green CI at exact head
e38ae7a1278814c62ae9060c2f4c4f07cdc06e98, and explicit START authorization, the v2 matrix ran once in its fixed order. The four required L1 repetitions all passed:fallback_fired=falsethroughout, $0.09485632, 227,758 prompt tokens, 4,571 completion tokens, and 232,329 total tokensThe fifth attempt, Sonnet 5 L2 repetition 1, failed and stopped the campaign. The SDK requested the exact allowed Bash tool and the policy hook allowed it, but the query ended as
query_error/iteration_abortedbefore a tool completion, cancellation request, or SDK result was observed. The inner probe reported quiescent teardown in 63 ms, but the independent outer supervisor found a newly orphaned three-process fixture group after its ten-second survivor deadline. The exact group was isolated, frozen, killed, and confirmed absent. This is a real containment/cancellation gate failure, not a passing L2 result.Per the pre-authorized stop rules, there was no retry, no gateway provenance reconciliation for the failed attempt, and no MiniMax M3 L2 attempt. Restricted evidence remains outside git in a mode-
0600campaign bundle; a fresh redacted scan found no credential leaks.Scope boundaries
This remains a non-UI feasibility subpath. It does not alter
HarnessAdapter,SessionManager,TaskManager, REST, WebSockets, desktop boot, or existing Claude Code/Codex PTY flows. It does not add the Assistant/Builder parent-child runtime, persistence, checkpoints, packaging certification, model picker, billing, or UI.Why this PR remains draft
The v2 campaign proves L1 for both target models, but SAP-2632 is not complete because the first Sonnet L2 attempt failed the independent no-survivor gate and MiniMax M3 L2 was intentionally left unexecuted. The PR remains draft and the campaign remains stopped. Any remediation and any new paid run require a separately reviewed change and fresh explicit authorization; no existing result may be reclassified or retried silently.
Related
SAP-2632
Certification v4 follow-up: Bash input compatibility
The next authorized certification campaign stopped on its first paid attempt, Sonnet 5 L1 repetition 1, at head
6a0ae05fcbc289dc9ae51fae55421b678aeed21c. The model completed every other required L1 operation, but its final Bash request was denied asinvalid_input/bash:unregistered. The pinned Agent SDK permits optional Bash fields such asdescription, while the host policy accepted only an exact one-key{ command }object. Raw input values were intentionally not retained, so the exact optional field remains an inference; the schema/policy mismatch and denial reason are proven.Current head
830811cc97386f83b0d95fd3ec6fa965e11df8b7fixes that mismatch without broadening shell authority:command,timeout,description,run_in_background, anddangerouslyDisableSandbox.run_in_background: true, anddangerouslyDisableSandbox: true.{ command }, stripping all optional fields before execution.canUseToolfallback, L2 boundary, content-free evidence, and the pinned real-SDK loopback path.Fresh verification used certification Node 22.23.2 and made no live gateway, paid model, or BigQuery call:
src/server/rest.test.ts.git diff --check, and diff-scoped gitleaks passed.The PR remains draft. This patch is locally and hermetically verified, but no live certification result has been reclassified and no campaign has been rerun. Any new paid campaign must use a newly frozen exact-head bundle, independent review, and fresh explicit authorization; the authorization bound to
6a0ae05f…cannot authorize830811cc….