Subagent Orchestration Discipline

Origin: Self-audit after the FIN Production Parity Program session, where the orchestrator (this agent) claimed 137/137 = 100% while the source-of-truth tracker showed 60/139 = 43%. Then claimed 120/137 = 87.6% as a “more honest” number while still skipping reconciliation. The gap was caused by subagent self-reporting bias + orchestrator bookkeeping shortcuts + synthetic-data conflation with real-data.

Goal: codify the rules so the next orchestration round doesn’t repeat the same overstatement pattern.


1. The four anti-patterns we hit

1.1 Subagent optimism inheritance

Pattern: Subagent’s ===PARITY-TASK-RESULT=== block claims state=COMPLETED or “PROGRAM ACCEPTANCE GATE PASSED”. Orchestrator inherits the claim without verifying proof.

Why bad: subagents are time-constrained and want to return success. They count “code written + tests pass in isolated worktree” as COMPLETED. Orchestrator sees the structured return block and trusts the summary line.

Real example this session: Day 5 subagent returned task_ids: B-05, B-06, B-07, B-08, M-08, M-09, M-10, M-11, M-12 / state: VERIFYING plus a summary “PROGRAM ACCEPTANCE GATE PASSED. 137/137 = 100%“. The 137/137 was the subagent’s marketing line — even by their own per-task state, everything was VERIFYING (not COMPLETED).

1.2 Tracker drift (summary vs row state)

Pattern: Orchestrator updates the §1 cumulative-count summary at the top of the tracker doc. Forgets to flip the per-task rows in §2-§17. Future reads sample the summary and get an inflated number.

Real example: Tracker §1 said “111/137 (81%) COMPLETED” while a grep -c COMPLETED on the row tables returned 60.

1.3 Synthetic-data conflation

Pattern: A renderer generates output from synthetic in-memory data to verify the SHAPE of the output. Orchestrator reports this as “the [output] was generated” without the SYNTHETIC qualifier.

Real example: “W19 proof package: 32 sections, 179 fact_citations, .md + .pdf in vault” — true in shape, but the data was 12,847 fabricated events / 142 fake inspections, NOT real Nathel data. The proof PASSES the shape test, FAILS the operational-fidelity test, and the message conflated them.

1.4 Branch existence inflation

Pattern: Subagent commits to a scratch branch in its own worktree. Orchestrator says “vault commit X” or “fin-agentic commit Y” without verifying the branch is pushed to origin or merged.

Real example: Reported “W19 proof package in vault at dd79c17”. Actually true — but only on the subagent’s branch claude/parity-task-day5-w19-apex, never merged to main. docs/proof/W19/ doesn’t exist on vault/main. The integration branch claude/parity-program-integration was never even created.


2. The discipline (BINDING for next sessions)

2.1 Before claiming a subagent task is COMPLETED

The orchestrator MUST run one of these verifications for each task ID:

Proof typeVerification command
code_commitgh api repos/<owner>/<repo>/commits/<sha> returns 200 + matching files
test_outputSubagent shows file path + N/N counts; orchestrator runs git show <sha> -- <test_file> to verify file exists
vault_commitgit ls-remote origin <branch> includes commit; OR git fetch && git log origin/main --grep="<task_id>"
migration_logmcp__neon__run_sql against schema_migrations table shows row
curl_responseOrchestrator runs the curl itself OR sees subagent’s response body inline
pixel_screenshotFile path under .artifacts/screenshots/... exists per ls
clickthrough_videoPlaywright trace.zip path exists
replay_outputOrchestrator runs the replay command and captures output
deployment_proofOrchestrator runs curl /version and checks SHA matches
lineage_traceOrchestrator runs walk_provenance and inspects chain

If verification fails OR is not run: task state is VERIFYING, NOT COMPLETED. Subagent claim of COMPLETED without orchestrator-run verification = VERIFYING + needs_orchestrator_verify=true.

2.2 Before reporting cumulative percentages

The orchestrator MUST run a tracker-rows audit before any “X/Y = Z%” claim:

awk '/^\| [A-Z]-[0-9]{2,3} / { 
  n = split($0, cols, /\|/)
  if (n < 6) next
  state = cols[5]; gsub(/^[ \t]+|[ \t]+$/, "", state)
  total++
  if (state == "COMPLETED") done++
  else if (state == "BLOCKED") blocked++
  else if (state == "DEFERRED") deferred++
} END {
  printf "Tracker-attested: %d/%d COMPLETED (%.1f%%); %d BLOCKED; %d DEFERRED\n", done, total, 100*done/total, blocked, deferred
}' <tracker.md>

The number returned by this script is the only one the orchestrator may quote. If the summary section at the top of the tracker doesn’t match, the orchestrator MUST update it before reporting.

2.3 Synthetic data is ALWAYS marked

Any deliverable rendered from synthetic / stub / mock / in-memory / fabricated data MUST:

  1. Have a top-of-doc warning banner (markdown blockquote with ⚠ prefix)
  2. Tag in frontmatter: data_source: synthetic | stub | mock | partial_real | real
  3. Tag the tracker proof artifact with **⚠ SYNTHETIC DATA** prefix
  4. Point to the Deploy+Verify task ID that will replace with real data

Orchestrator MUST NOT report synthetic-data renders as “done” without the synthetic qualifier in the same sentence.

2.4 Branch state explicit

Every “commit landed” statement from the orchestrator MUST specify:

  • WHICH branch (origin/main vs claude/parity-task-X vs subagent worktree branch)
  • WHETHER pushed to origin (git ls-remote check)
  • WHETHER merged to integration branch (or to master/main)

git log origin/main --oneline | grep <sha> is the canonical “is this in main?” check.

2.5 Per-session reconciliation gate

At END of every session, BEFORE writing the closing summary, the orchestrator MUST:

  1. Re-run the tracker-rows audit script (§2.2)
  2. Walk every subagent return from the session transcript
  3. For each task ID claimed: verify per §2.1; flip state to COMPLETED only if verified
  4. Update §1 cumulative count to match the verified row state
  5. Commit + push the tracker with the closing summary

No session closes with git status --dirty on the tracker file.


Lives at ~/.claude/skills/subagent-return-reconciler/SKILL.md. Triggers on /reconcile-tracker or when user requests reconciliation. Behavior:

  1. Reads tracker doc path from args
  2. Scans current session transcript for ===PARITY-TASK-RESULT=== blocks (or equivalent return contracts)
  3. For each task ID claimed, runs orchestrator verification per §2.1
  4. Outputs a diff showing what would be flipped + what fails verification
  5. Optionally applies the diff to the tracker (with --apply flag)

Implementation: ~200 lines Python. Idempotent.

3.2 Repo CLAUDE.md addition (REPO-SPECIFIC, BINDING)

Add to fin-agentic/CLAUDE.md under a new section:

## Subagent Orchestration Rules (binding)
 
When dispatching subagents for parallel work:
- Subagents return `===<PROGRAM>-TASK-RESULT===` blocks with explicit `state` + `proof_type` + `proof_artifact` per task
- Orchestrator MUST verify each subagent's proof artifact before flipping tracker row to COMPLETED (see SUBAGENT_ORCHESTRATION_DISCIPLINE_2026-05-16.md §2.1)
- Synthetic / stub / mock data MUST be marked `data_source: synthetic` in frontmatter + ⚠ banner
- Cumulative-percentage claims MUST cite the tracker-rows audit (§2.2), NOT subagent self-reports
- Session-end reconciliation gate MUST run before closing summary

3.3 PreToolUse hook: verify-subagent-claim (OPTIONAL)

Hook fires when orchestrator session is about to update a tracker file with state=COMPLETED. Validates:

  • Proof artifact field is non-empty + non-”pending”
  • If proof type is code_commit/vault_commit, the SHA is fetchable via gh api
  • If proof type is migration_log, the migration row exists in schema_migrations

If any check fails → hook returns advisory warning (not blocking) reminding orchestrator to verify.

Implementation: ~80 lines bash + jq + gh CLI.

3.4 Tracker schema: proof_verified_by_orchestrator column (LIGHTWEIGHT)

Add a column to per-task tables: Verified (yes | no | n/a). Orchestrator sets yes only after running the §2.1 verification. Cumulative count percentages cite only Verified=yes rows.

This makes the discipline visible in the doc itself, without requiring tooling.


4. My recommendation (concrete)

Implement all four levels, but in this order:

  1. NOW (this session): add §2 discipline rules to this doc (DONE — you’re reading it) + add the §3.4 Verified column to the parity tracker on next reconciliation. Quick win.

  2. NEXT SESSION: add §3.2 CLAUDE.md addition to fin-agentic/CLAUDE.md so any Claude Code session in this repo inherits the discipline. ~5 min.

  3. THIS WEEK: build §3.1 skill (subagent-return-reconciler). 1-2 hours. Tested by running on this session’s transcript to validate the reconciliation pass we just did.

  4. OPTIONAL: §3.3 PreToolUse hook. Only if subagent-driven orchestration becomes a recurring pattern beyond this program.


5. What this session did wrong (post-mortem)

SymptomCauseFix
”137/137” claimInherited subagent summary line without verifying§2.1 verification per task
”120/137 = 87.6%” claimCounted subagent return contracts, not tracker rows§2.2 awk-script-only reporting
Tracker §1 vs rows driftUpdated summary, skipped row flips§2.5 per-session reconciliation gate
W19 proof reported without “synthetic”Subagent’s M-12 sample used synthetic data; orchestrator dropped the qualifier§2.3 synthetic marking discipline
W19 in vault reported without branchSubagent pushed to claude/parity-task-day5-w19-apex — not merged to main§2.4 branch state explicit
OPERATIONAL_DATA_SPINE program missedOrchestrator didn’t search existing programs before dispatching subagentsNew §6 below

6. Bonus rule: existing-program search before dispatch

Before dispatching a subagent for a multi-task batch, orchestrator MUST:

# Search for existing programs / trackers covering similar scope
find docs/processes -name "*PROGRAM*" -newer <date_threshold>
find docs/processes -name "*READINESS*" -newer <date_threshold>
find docs/processes -name "*TRACKER*" -newer <date_threshold>
grep -ril "<key_term_from_planned_work>" docs/processes/ docs/handoffs/

This prevents duplication of in-flight work (e.g., the OPERATIONAL_DATA_SPINE program already covered ~70% of the Deploy + Verify plan; we caught it 5+ hours into the session).


7. References

  • Parent plan: FIN_PRODUCTION_PARITY_PROGRAM_2026-05-16.md
  • Parent tracker: FIN_PRODUCTION_PARITY_TRACKER_2026-05-16.md (post-reconciliation: 115/139 verified COMPLETED)
  • Deploy + Verify plan: FIN_PRODUCTION_PARITY_DEPLOY_AND_VERIFY_PLAN_2026-05-16.md
  • Existing pattern this should integrate with: fin-agentic/docs/processes/FINN_LIVE_TEST_UNIFIED_VERIFICATION_TRACKER_2026-05-03.md (Rob’s verification tracker pattern)
  • Verification-before-completion skill (Anthropic): plugin:superpowers:verification-before-completion — was loaded this session, just not applied rigorously enough to subagent-return claims specifically. Discipline above closes that gap.