feat(custody): evidence used_fallback from runtime + gate cloud egress - #38
Conversation
…cloud egress
m28 residuals — two m27 honesty/harness fixes, model-independent.
1. used_fallback evidenced (never synthesized):
- SDK runrecord.ts: readUsedFallback (boolean-only, else null),
assembleRunRecord (runtime run result > caseforge control-flow > unknown),
writeCaseforgeRun/readCaseforgeRun/attestUsedFallback + caseforge_run.json.
- investigate records provenance at each verified run dir, reading the
runtime run_result.json emitted by the opencode lane.
- verify surfaces `used_fallback: yes|no|unknown (source: ...)`; informational,
unknown when unrecorded (no fabricated `no`).
2. operator cloud-ack gate:
- SDK cloudAckGate + CASEFORGE_CLOUD_ACK (default off) / --cloud-ack flag.
- investigate refuses any outward cloud route unless acknowledged, after the
privacy router and before any OAuth/spawn (no egress on refusal). Local
routes never require it.
Tests first (RED->GREEN): selftest 183 passed, 0 failed (+28). Deterministic
engine stays the local default. docs/M28_RESIDUALS.md records the PREPARED (not
run) operator cloud command.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e7e7a650d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await finalizeVerdictJson(runDir, env.VERDICT_DFIR_HOME) | ||
| // Agent/runtime produced this run — used_fallback comes from its run result | ||
| // (engineUsedFallback=false: caseforge's deterministic engine did not fire). | ||
| await recordRunProvenance(runDir, false) |
There was a problem hiding this comment.
Do not synthesize no fallback for agent runs
When the agent/opencode path produces a run but does not emit run_result.json (or emits one without a boolean used_fallback), this false is passed through assembleRunRecord as a caseforge control-flow fact, so caseforge_run.json records used_fallback: false and verify reports no instead of unknown. That recreates the exact unaudited used_fallback=0 claim this change is meant to avoid; only the deterministic fallback path is caseforge-known, so the non-fallback agent path should omit/pass null unless the runtime result actually carries the boolean.
Useful? React with 👍 / 👎.
Summary
used_fallbackfrom the runtime run result (or caseforge control-flow) into caseforge-owned run artifacts;caseforge verifysurfaces yes/no/unknown with source — never synthesizes false.CASEFORGE_CLOUD_ACK/--cloud-ack(default off) after privacy routing, before OAuth/spawn.engine/(subtree is a separate PR).Test plan
npm run typecheck(sdk + tui + cli) cleannode scripts/selftest.mjs— 183 passed, 0 failed (re-run m5-team)Non-goals