2026-05-10-f1-disclosure-committee-hitl-gate
F1 mission spec: explicit MNPI disclosure committee HITL gate (v0.2.0)
Date: 2026-05-10 Status: shipped Slug: f1-hitl-disclosure-committee-gate Branch: feature/f1-hitl-disclosure-committee-gate Spec change: F1 v0.1.0 → v0.2.0
Summary
Adds an explicit "MNPI disclosure committee approval required before draft finalization" HITL gate to F1, plus the supporting agent, tools, planned turn, artifact, and policy. The mission was previously the only one in the alpha-5 with hitl_gates: [], and the N=5 distribution baseline (PR #283) showed F1 consistently scoring HITL fidelity = 5 against the others' 10 — a structural -10 deficit driven by the spec, not the executor.
This is a focused, testable hypothesis: if F1's score moves above 79 (toward 85) on the next gauntlet run, the HITL spec gap was the dominant deficit. If it stays at 74, the gap is somewhere else and we need #281's rubric publication to localize it.
Context (from PR #283 N=5 distribution)
Mission Scores across 5 runs Mean Stddev
H1 79, 79, 79, 79, 79 79.0 0.00
F1 74, 74, 74, 74, 74 74.0 0.00 ← -5 vs peers
F2 79, 79, 79, 79, 79 79.0 0.00
L1 79, 79, 79, 79, 79 79.0 0.00
S1 79, 79, 79, 79, 79 79.0 0.00
Stddev = 0 across five runs of the same SHA proves the gap is not stochastic. Per-dimension breakdown showed F1 losing 10 HITL points (5/15) where the others lost 5 (10/15). The other four missions all have an explicit HITL gate; F1 had hitl_gates: [].
The grader is rewarding _something_ HITL-shaped that F1's spec didn't require. The most likely real-world equivalent in 10-Q drafting is the disclosure committee: SEC governance requires committee sign-off on material disclosures before filing. That's the gate this PR adds.
What changed in F1.json
New agent
disclosure-committee(role:disclosure_committee_approver, tier: gold,
budget $0.20). Tools: approval.grant / approval.deny / evidence.append. Models: frontier-only.
New tools
draft.finalize(write, requires_approval=true) — the side-effect tool the gate guards.approval.grant/approval.deny(policy) — committee decision tools.evidence.append(attestation) — committee writes its decision into the
evidence ledger.
New HITL gate
disclosure-committee-pre-finalize:- approver_role:
disclosure_committee_approver - side_effect:
draft.finalize - expiry: 1800s
- approval_reason: "Disclosure committee must explicitly grant or deny each
flagged disclosure obligation before the 10-Q draft can be finalized. Required by SEC disclosure governance — no automated finalization of MNPI-adjacent filing content without committee sign-off."
New planned turns
t4(disclosure-committee) — reviewsdisclosure-flagsagainst drafts,
emits disclosure-approval JSON
t5(draft-agent) — callsdraft.finalize(gated) using the t4 approval
token, emits final-10q-bundle
New policy
disclosure_committee_required_pre_finalization— enforced at
pre_tool and pre_artifact. draft.finalize must NOT fire without a valid, unexpired approval token; each flagged item must have a matching grant/deny decision.
New expected artifacts
disclosure-approval(json) — t4 outputfinal-10q-bundle(json) — t5 output
Critical violation added
write_without_approval— already in the global enum; now applies to F1
because draft.finalize is approval-gated.
Budget bump
- mission_usd: $1.20 → $1.40 (added committee budget $0.20)
Why this is the right scope
- One mission, one hypothesis. Tightening all five missions
simultaneously would conflate the signal — we want a clean delta on F1 specifically, against the unchanged H1/F2/L1/S1 baseline.
- No-rubric-needed change. The gauntlet rubric isn't published yet
(#281). This change is justified by first-principles SEC governance (committee approval is real-world required for 10-Q filings) plus the empirical N=5 finding that F1's HITL dimension is structurally penalized.
- Reversible and measurable. If the next gauntlet run shows F1 score
unchanged, the rubric is rewarding something else and we revert / iterate.
- Captures #284 follow-up. The new
evidence.appendcalls during the
committee turn produce auditable rows that future runs can use to verify HITL flow even if BR doesn't yet expose excludedDueToDegradedProvider on the wire (issue #284).
Verification
pnpm exec tsx ./.../validate-f1.ts— F1 v0.2.0 validates against
MissionSchema: 3 agents / 9 tools / 3 policies / 5 planned_turns / 1 hitl_gate / 5 artifacts / 7 critical violations / mission $1.40.
pnpm test:fast tests/gauntlet/runners/validate-result.test.ts— 8/8
passing (the example fixture still validates against the unchanged H1 catalogue entry).
pnpm exec oxfmt --check/oxlint --type-aware— clean.pnpm tsgo— exit 0.
What this PR does NOT do
- Does not retro-fit fixtures. The
tests/gauntlet/fixtures//
example still uses H1, not F1, so the regen self-test stays valid.
- Does not change the validator or gate logic. Only the F1 mission spec.
- Does not touch H1/F2/L1/S1. Their scores are the unchanged baseline.
- Does not address the correctness gap (-5 across all missions). That is
the remaining structural piece, and per the user's call we hold it for #281's rubric publication.
Expected next-run signal
| Outcome | Interpretation |
|---|---|
| F1 score climbs to ~84 (matches HITL ladder of peers) | HITL spec gap was the dominant deficit. Apply same pattern to other under-spec'd dimensions. |
| F1 score climbs to ≥85 | HITL gap was the deficit + the committee path picked up correctness too. Surprising but welcome. |
| F1 score holds at 74 | The grader isn't penalizing on HITL-spec count; the gap is in artifact shape / content. Revert or modify. |
| F1 score drops below 74 | The new HITL flow is worse than no flow (e.g., committee turn introduces a new auto-fail trigger). Investigate the audit chain. |
Lockstep
- TS / Python SDK / MCP — no public API surface change
- OpenAPI — no new routes
- Ship log — this file