Claude
Skill
calibrate
Calibration testing for agents and skills. Generates synthetic problems with known outcomes (quasi-ground-truth), runs targets against them, measures recall, precision, confidence calibration — reveals whether self-reported confidence scores track actual quality.
Virus-scanned
Reviewed automatically before listing.
Download
Borda-AI-Rig-plugins_cc_foundry_skills_calibrate-39e3a48.zip · 51 KB
Install
skills CLI
npx skills add https://github.com/Borda/AI-Rig/tree/main/plugins/cc_foundry/skills/calibrate
Claude Code
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install borda-ai-rig@llmmart
Git
git clone https://github.com/Borda/AI-Rig.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole borda/ai-rig collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Files (ai-rig)
-
modes
-
agents.md 5.3 KB
<!-- Step 1 in SKILL.md dispatches to this mode file. Steps here continue from Step 2. --> ## Mode: agents ### Domain table Problem domain by agent: - `foundry:sw-engineer` → Python bugs: type errors, logic errors, anti-patterns, bare `except:`, mutable defaults - `foundry:qa-specialist` → coverage gaps: uncovered edge cases, missing exception tests, Machine Learning (ML) non-determinism - `foundry:linting-expert` → violations: ruff rules, mypy errors, annotation gaps - `foundry:curator` → config issues: broken cross-refs, missing workflow blocks, wrong model, step gaps; handover compliance: malformed JSON envelopes; context discipline: spawn prompt bloat, AgentSpeak v2 violations - `foundry:doc-scribe` → docs gaps: missing docstrings, missing Google style sections, broken examples - `foundry:perf-optimizer` → perf issues: unnecessary loops, repeated computation, wrong dtype, missing vectorisation - `oss:cicd-steward` → Continuous Integration (CI) issues: non-pinned action Secure Hash Algorithms (SHAs), missing cache, inefficient matrix *(oss plugin required — skip if `$OSS_AVAILABLE` empty)* - `oss:gh-scraper` → GitHub metadata extraction: pagination truncation, axis data completeness, rate-limit handling, scrape envelope correctness *(oss plugin required — skip if `$OSS_AVAILABLE` empty)* - `oss:repo-warden` → vitality scoring issues: incorrect bus-factor approximation, bot-filtering inconsistency, axis scoring errors, PARTIAL_FILE overwrite conflicts *(oss plugin required — skip if `$OSS_AVAILABLE` empty)* - `research:data-steward` → data issues: label leakage, split contamination, augmentation order bugs, API pagination truncation, dataset completeness, provenance gaps *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `research:scientist` → paper analysis: missed contributions, wrong method attribution *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `foundry:solution-architect` → design issues: leaky abstractions, circular dependencies, missing Architecture Decision Record (ADR), backward-compat violations without deprecation path - `foundry:web-explorer` → content quality: broken or unverified Uniform Resource Locators (URLs), outdated docs, incomplete extraction from fetched pages - `oss:shepherd` → Open Source Software (OSS) governance: incorrect Semantic Versioning (SemVer) decision, missing CHANGELOG entry, bad deprecation path, wrong release checklist item *(oss plugin required — skip if `$OSS_AVAILABLE` empty)* - `foundry:challenger` → plan/architecture challenges: missed assumptions, missing edge cases, unjustified blocker classification, skipped refutation step - `foundry:creator` → content quality: narrative arc gaps, audience-profile mismatches, voice inconsistency, missing story beats, out-of-scope format acceptance All agents support `ceiling` difficulty tier. Ceiling patterns by domain: `foundry:sw-engineer` → adversarial (idiomatic-looking but subtly wrong), concurrency bugs; `foundry:qa-specialist` → incomplete detectability (coverage gaps visible only at runtime); `foundry:perf-optimizer` → deep cross-function control flow; `research:data-steward` → adversarial (split contamination disguised as correct preprocessing); `foundry:solution-architect` → deep dependency tracing. Agents where ceiling infeasible (e.g., `foundry:linting-expert` — violations always statically detectable): generators may substitute hard problem. ### Step 2: Spawn agent pipeline subagents Mark "Calibrate agents" in_progress. **Availability check** (vars set in SKILL.md Step 2): skip `oss:*` agents if `$OSS_AVAILABLE` empty; skip `research:*` agents if `$RESEARCH_AVAILABLE` empty. Log: "<plugin> plugin not installed — skipping <agent> calibration" per excluded agent. Per agent in domain table (after exclusions), spawn one `general-purpose` pipeline subagent. **Spawn in batches of `$PIPELINE_BATCH_SIZE` (5 when this category runs alone, 2 while two categories in flight — see constants)**: issue up to that many agent pipeline spawns per response, wait for all in batch to return compact JSON results, spawn next batch. Agents within a batch run concurrently; batches sequential. Do NOT spawn all agents in one response — 14+ agents spikes context and resource usage. Resolve template dir first — no `~/.claude/skills/` copy exists (setup symlinks only `rules/*.md` and `TEAM_PROTOCOL.md`): ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" CALIB_TPL=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate templates $([ "$LOCAL_MODE" = "true" ] && echo --local)) # timeout: 5000 ``` Each subagent gets pipeline template from `$CALIB_TPL/pipeline-prompt.md`, substitutions: - `<TARGET>` = agent name (e.g., `foundry:sw-engineer`) - `<DOMAIN>` = domain string from table above - `<N>` = 3 (fast) or 10 (full) - `<TIMESTAMP>` = current run timestamp - `<MODE>` = `fast` or `full` - `<AB_MODE>` = `true` or `false` — whether to run A/B variant scoring against `general-purpose` baseline (see pipeline-prompt.md Phase 2b) - `<LOCAL_MODE>` = `true` or `false` — from `--local` flag; when true pipeline resolves target file from source tree Run dir per agent: `.reports/calibrate/<TIMESTAMP>/<TARGET>/` -
communication.md 5.8 KB
<!-- Step 1 in SKILL.md dispatches to this mode file. Steps here continue from Step 2. --> ## Mode: communication > **Codex integration: disabled.** Problem generation and scoring Claude-only. Ground truth needs deep knowledge of `file-handoff-protocol.md`, `TEAM_PROTOCOL.md`, AgentSpeak v2 — Codex lacks context, produces superficial/wrong problems. Handover + team protocol compliance. Included in `all`. Use explicit `communication` target to isolate. Target agent: `foundry:curator`. ### Domain Four subdomains — each ground truth issue must tag `subdomain` field so Phase 4 computes per-subdomain recall: ```text handover: malformed JSON envelopes (missing summary, plain text instead of JSON, missing required fields, wrong status value, severity not an object); context-contamination: spawn prompts include full conversation history or out-of-scope details instead of task-relevant context only; agentspeak: team AgentSpeak v2 violations (verbose prose instead of compact JSON, task IDs not preserved, handshake phrases not pruned); completeness: given a full/raw agent response paired with its compact envelope, identify cases where the envelope omits essential information (missing findings, dropped severity entries, truncated gaps list, absent confidence score) — a correct compact form retains all decision-relevant signal at ≤30% of raw token count, and any omission of a severity≥high finding is a critical violation ``` **Ground truth format** (extended for subdomain tagging): `{"issue": "...", "location": "...", "severity": "...", "subdomain": "handover|context-contamination|agentspeak|completeness"}` **Per-subdomain recall** (Phase 4 aggregate addition): - `recall_handover`, `recall_context_contamination`, `recall_agentspeak`, `recall_completeness` - computed as: issues found in subdomain / total issues in subdomain (omit if 0 issues for subdomain that run) - surfaced in `benchmark-report.md` Aggregate section and `result.jsonl`; primary signal for context pollution detection ### Step 2: Spawn communication pipeline subagent **N override** (communication problems high-complexity — tighter N prevents context overflow in pipeline subagent): fast=3, full=5. Do NOT use global FULL_N=10 here. Mark "Calibrate communication" in_progress. Resolve template dir — no `~/.claude/skills/` copy exists (setup symlinks only `rules/*.md` and `TEAM_PROTOCOL.md`): ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" CALIB_TPL=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate templates $([ "$LOCAL_MODE" = "true" ] && echo --local)) # timeout: 5000 ``` Use standard pipeline template from `$CALIB_TPL/pipeline-prompt.md` with `<TARGET>=curator`, `<DOMAIN>` set to domain string above. Required substitutions: `<TARGET>`, `<DOMAIN>`, `<N>`, `<TIMESTAMP>`, `<MODE>`, `<AB_MODE>`. Spawn **single** `general-purpose` pipeline subagent — runs curator against synthetic agent responses, full/compact response pairs, team transcripts with injected violations. **Phase 2 batching**: pipeline spawns Phase 2 target agents in **batches of 3** (not all at once), collects acknowledgments between batches. Each curator response ~1–4KB; batching prevents accumulation of all N problem inputs simultaneously. Add to pipeline prompt: "Spawn Phase 2 agents in batches of 3 — await all acknowledgments in a batch before spawning the next. Maximum batches: ceil(N/3) — for fast (N=3) that is 1 batch; for full (N=5) that is 2 batches." Run dir: `.reports/calibrate/<TIMESTAMP>/curator/` (relative to project root) ### Active instruction — token optimization (additional scoring measure) Append to every `task_prompt` in Phase 1 for `communication` problems: > "Produce most compact output preserving all decision-relevant information. Omit prose where field name and value are self-evident. Any finding at severity≥high must appear; lower-severity findings may be summarized. Target: ≤30% of raw response token count without losing critical signal." Scorer (Phase 3) evaluates two additional dimensions independently: 1. **Completeness loss** — essential fields omitted vs. total essential fields → `completeness_loss_ratio` 2. **Token overhead** — response size vs. minimum faithful representation → `token_overhead_ratio` **`token_overhead_ratio` baseline — ground truth JSON char count**: compute `len(JSON.stringify(ground_truth))` (char count of serialised `GROUND_TRUTH_JSON` scorer holds) — minimum lossless representation of all required findings. Ratio `response_chars / gt_json_chars` measures overhead above that floor. - ≤1.5 ✓ compact — fits within 1.5× bare findings (allows confidence block, location formatting, severity labels) - 1.5–2.0 ~ moderate — some prose wrapping, acceptable - > 2.0 ⚠ verbose — significant narrative overhead above minimum content For scope problems (ground_truth = []) use `response_chars / 50` as baseline (50 chars ≈ one-line decline/redirect). Set `completeness_loss_ratio = 0.0` if response correctly declines. **Why not `ground_truth_count × 150`**: synthetic proxy miscounts per-issue size, produces misleading ratios (e.g. 1.83× when actual overhead 1.06×). `gt_json_chars` always available to scorer at Phase 3 (it's `GROUND_TRUTH_JSON` field) — no extra agent calls. Both fields added to each problem's entry in `scores.json`. Phase 4 aggregates: `mean_completeness_loss` and `mean_token_overhead`. Both appear in `benchmark-report.md` Aggregate section and `result.jsonl`. **Scoring guidance for scorers**: response fails completeness if `completeness_loss_ratio > 0` for any severity≥high finding (critical violation). Response verbose if `token_overhead_ratio > 2.0`. Report both ratios regardless of pass/fail. -
routing.md 2.6 KB
<!-- Step 1 in SKILL.md dispatches to this mode file. Steps here continue from Step 2. --> <!-- loads: routing-pipeline-prompt.md --> ## Mode: routing > **Codex integration: disabled.** Problem gen + scoring Claude-only. Routing tests orchestrator dispatch logic — scoring deterministic binary match (`selected == expected`). Codex lacks agent system internals context for realistic routing problems. Routing accuracy test: measures how accurately `general-purpose` orchestrator picks correct `subagent_type` for synthetic task prompts. Not per-agent quality benchmark; included in `all`. Use explicit `routing` target to isolate. Thresholds (from SKILL.md constants): `ROUTING_ACCURACY_THRESHOLD=0.90`, `ROUTING_HARD_THRESHOLD=0.80`. ### Step 2: Spawn routing pipeline subagent Mark "Calibrate routing" in_progress. Load routing pipeline template via `cat` (not Read tool — `Bash(cat:*)` grant version-proof): ```bash CALIB_TPL=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate templates 2>/dev/null || echo "plugins/cc_foundry/skills/calibrate/templates") # timeout: 5000 cat "$CALIB_TPL/routing-pipeline-prompt.md" # timeout: 5000 ``` Substitute `<N>` (5 fast, 10 full), `<TIMESTAMP>`, `<MODE>`. Spawn **single** `general-purpose` pipeline subagent with substituted template — handles all phases internally. Proceed to Step 3. Run dir: `.reports/calibrate/<TIMESTAMP>/routing/` ### Report format (Step 3 output) When target is `routing`, replace standard combined report table with: ```markdown ## Routing Calibration — <date> — <MODE> | Metric | Value | Status | |------------------|------------|--------| | Routing accuracy | N/M (XX%) | ≥90% ✓ / 80–90% ~ / <80% ⚠ | | Hard accuracy | N/M (XX%) | ≥80% ✓ / <80% ⚠ | | Confusion errors | N | 0 ✓ / >0 list pairs | ``` Flag routing accuracy < 0.90 or hard accuracy < 0.80 with ⚠. Print confused pair details from routing report's Confused Pairs section. Mark "Calibrate routing" completed. Verdict `incomplete` (empty agent roster — pipeline Phase 1 hard stop): omit table, print `⚠ routing — no agent roster resolved; accuracy not measured`. Never substitute a number for an unmeasured run. ### Follow-up chain Routing accuracy < 0.90 or hard accuracy < 0.80: update descriptions for confused pairs, then `/calibrate routing` to verify. Max 3 re-run cycles; still below threshold after third: surface persistent confusion pairs to user for manual review. Proposals written to: `.reports/calibrate/<TIMESTAMP>/routing/benchmark-report.md` — Proposals section has targeted wording per confused pair. -
rules.md 6 KB
<!-- Step 1 in SKILL.md dispatches to this mode file. Steps here continue from Step 2. --> <!-- loads: rules-pipeline-prompt.md --> ## Mode: rules > **Codex integration: disabled.** Problem generation and scoring Claude-only. Rule adherence tests Claude agent behavior with `.claude/rules/` loaded — Codex has no insight into Claude Code's rule-loading, path-scoping, or frontmatter parsing. Its problems and scores unreliable here. Rule adherence test: for each rule file in `.claude/rules/`, measures three dimensions — trigger fidelity (rule fires right time), directive adherence (rule followed when loaded), outcome correctness (following rule = expected result). Included in `all`. Use explicit `rules` target to isolate. ### Three scoring dimensions **1. Trigger fidelity** (path-scoped rules only — `paths:` frontmatter present). Rule loads when it should, stays silent when it shouldn't? - Trigger recall ≥ 0.95: rule fires for all matching file contexts - Trigger precision ≥ 0.95: rule silent for non-matching contexts - Global rules (no `paths:`) always load — no trigger test; set to `null` **2. Directive adherence.** Rule loaded — does `general-purpose` agent apply directives? - Adherence recall ≥ 0.80 per directive (stricter than 0.70 agent threshold — rules are narrow action-prescribing directives) - Three outcomes per task: `correct` / `missed` / `misapplied` **3. Outcome correctness.** Beyond stating intent, does response's actual content (commands used, flags omitted, files listed) satisfy directive? - Outcome correctness ≥ 0.80 of "correct" adherence scores - Distinguishes "agent acknowledged rule" from "agent actually followed it" ### Verdict mapping | Adherence recall | Outcome correct | Verdict | | -- | -- | -- | | ≥ 0.80 | ≥ 0.80 | calibrated | | ≥ 0.80 | < 0.80 | outcome-gap | | < 0.80 | any | under-enforced | *Legend: Adherence recall — fraction of tasks where directive followed (0–1, higher better). Outcome correct — fraction of applied directives that produced expected behavioral output, not just stated intent (0–1, higher better). Verdict: calibrated = rule effective; outcome-gap = rule mentioned but not truly applied; under-enforced = rule ignored.* ### Step 2: Spawn rules pipeline subagents **N per directive** (fast=3, full=5). Mark "Calibrate rules" in_progress. **Detect scope for each rule file**: check whether `paths:` frontmatter present and non-empty — set `IS_PATH_SCOPED=true` accordingly. ```bash ls .claude/rules/*.md 2>/dev/null | sort awk '/^---$/{c++; if(c==2)exit} c==1 && /^paths:/{found=1} END{print found+0}' <rule-file> ``` Load rules pipeline template via `cat` (not Read tool — `Bash(cat:*)` grant version-proof): ```bash CALIB_TPL=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate templates 2>/dev/null || echo "plugins/cc_foundry/skills/calibrate/templates") # timeout: 5000 cat "$CALIB_TPL/rules-pipeline-prompt.md" # timeout: 5000 ``` For each rule file, substitute `<RULE_BASENAME>`, `<RULE_CONTENT>`, `<TIMESTAMP>`, `<MODE>`, `<N>`, `<IS_PATH_SCOPED>` and spawn **single** `general-purpose` pipeline subagent. **Spawn in batches of `$PIPELINE_BATCH_SIZE` (5 when this category runs alone, 2 while two categories in flight — see constants)**: issue up to that many rule pipeline spawns per response, wait for all in batch to return compact JSON results, spawn next batch. Rule files within a batch run concurrently; batches sequential. Run dir: `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/` (where `RULE_DIR="${RULE_BASENAME%.md}"` — `.md` stripped to avoid permission-matcher conflicts) Each pipeline subagent handles all five phases internally (problem generation → target runs → dedicated scorer subagents → aggregate → curator proposals) and returns ONLY compact JSON envelope. ### Report format (Step 3 output) When target is `rules`, replace standard combined report table with: ```markdown ## Rules Calibration — <date> — <MODE> | Rule file | Adherence | Outcome | Trig R | Trig P | Verdict | |------------------------|-----------|---------|--------|--------|------------------| | git-commit.md | 0.89 | 0.91 | — | — | ✓ calibrated | | python-code.md | 0.67 ⚠ | — | — | — | ⚠ under-enforced | | hooks-js.md | 0.82 | 0.70 ⚠ | 1.00 | 1.00 | ⚠ outcome-gap | *Legend: Adherence — mean fraction of tasks where directive was followed (0–1, higher is better, ≥0.80 target). Outcome — fraction of applied directives that also produced the correct behavioral output (0–1, higher is better, ≥0.80 target; — = no correct adherence scores to evaluate). Trig R — trigger recall, rule fired on matching-path contexts (0–1, higher is better, ≥0.95 target; — = global rule). Trig P — trigger precision, rule silent on non-matching contexts (0–1, higher is better, ≥0.95 target; — = global rule). Verdict: ✓ calibrated | ⚠ outcome-gap | ⚠ under-enforced.* ``` Flag any rule with adherence < 0.80, outcome_correctness < 0.80, trigger_recall < 0.95, or trigger_precision < 0.95 with ⚠. After table, for each non-calibrated rule print `proposal.md` content (wording suggestions from curator Phase 5). Mark "Calibrate rules" completed. ### Follow-up chain - `under-enforced` (adherence < 0.80): reword directive to imperative mood with concrete action, re-run `/calibrate rules` to verify - `outcome-gap` (adherence ≥ 0.80 but outcome < 0.80): directive vague at behavioral level; add concrete example or constraint, re-run - Trigger recall < 0.95: `paths:` glob may not match file types where rule should apply; adjust glob pattern - Trigger precision < 0.95: `paths:` glob too broad; tighten pattern to avoid false loads - Persistent failures after rewording: split rule into more focused directives. Max 3 re-run cycles; if rule still non-calibrated after third, surface persistent failures to user for manual review. Proposals written to: `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/proposal.md` -
skills.md 17.6 KB
<!-- Step 1 in SKILL.md dispatches to this mode file. Steps here continue from Step 2. --> ## Mode: skills ### Domain table Skill domains: - `/audit` → synthetic `.claude/` config with N injected structural issues. **Focus on cross-file JUDGMENT issues** (tool-grant mismatch, inter-file contract split, dead dispatch path) — mechanical/deterministic classes (fence, tag, README/version drift, mode-dispatch, bash-persistence, orphaned-bin) already recall-benchmarked at 100% by `plugins/cc_foundry/tests/test_audit_static.py` (Step-1b Layer-1 driver), so injecting those adds no signal; inject defects a per-file pass would MISS to measure Layer-2 holistic pass. - `/oss:review` → **currently excluded** — skill fetches live GitHub PR via `gh`; synthetic Python input cannot substitute; pipeline generates problems but skill cannot run them; deferred until fixture diff-format mocking added *(skip — even if oss plugin present)* - `/research:plan` → synthetic optimization goal (e.g. "reduce pytest runtime by 30%"); measure whether plan mode produces complete, valid `program.md` with all required sections, plausible `metric_cmd`, correct `direction`, coherent `scope_files` *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/research:judge` → synthetic `program.md` with N injected plan-quality issues (e.g. missing guard command, absent `direction`, non-existent `scope_files` path, invalid `agent_strategy`); measure whether judge correctly identifies each injected issue at right severity *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/develop:review` → synthetic Python file with N injected code-quality issues (style, correctness, coverage gaps); measure whether review identifies each injected issue at correct severity level *(develop plugin required — skip if `$DEVELOP_AVAILABLE` empty)* - `/codemap-py:query-code` → **problem generation must produce an actual synthetic codemap-py index file the target loads and queries through the real CLI/tool** — never inline the graph as prose/code for the target to reason over directly. Inline-data problems collapse to a plain reasoning task both arms solve identically, which flattens every A/B delta to `none` and never exercises the skill's actual capability (index correctness, query latency, tool-call discipline). Domain: synthetic codemap index with known centrality/coupling values; measure whether `central`, `coupled`, `deps`, `rdeps`, `path` queries return correct modules matching ground-truth graph structure *(codemap plugin required — skip if `$CODEMAP_AVAILABLE` empty)* - `/codemap-py:query-code` (`fn-blast`) → same problem-generation requirement as above (real index + CLI, not inline data). Domain: synthetic codemap-py index with N modules and known rdeps graph; present developer-framing task ("you are about to modify function X — assess blast radius"); measure recall of expected fn-rdeps callers found in response (≥0.7 recall = correct); ground truth = injected fn_callers list; also runnable against real repo via `benchmarks/run-codemap-oss.py --task-type develop_blast_radius` *(codemap-py plugin required — skip if `$CODEMAP_AVAILABLE` empty)* - `/codemap-py:scan-codebase` → synthetic Python project with known module structure; measure whether scan correctly identifies modules, dependencies, and produces valid index *(codemap plugin required — skip if `$CODEMAP_AVAILABLE` empty)* - `/codemap-py:rename-refs` → problem generation should exercise the CLI-driven steps (index validation, find-symbol/fn-rdeps queries, the >50-caller budget gate, `git mv` module rename, re-scan verification), not just static text-editing correctness — a problem solvable by direct text substitution alone doesn't test the skill's actual workflow. Domain: synthetic Python project with known symbol/module rename targets and caller graph; measure whether rename correctly updates definition site, import call sites, `__all__` re-exports, and Sphinx refs; ground truth = old symbol absent from post-rename index and all static callers updated *(codemap plugin required — skip if `$CODEMAP_AVAILABLE` empty)* - `/codemap-py:integration` → synthetic project with known skill integration opportunities; measure whether integration correctly scores and ranks candidate skills *(codemap plugin required — skip if `$CODEMAP_AVAILABLE` empty)* - `/research:verify` → paper-vs-code fidelity check; inject N known deviations (hyperparams, architecture, loss function, preprocessing); score recall per dimension (F, H, E, N, C) *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/research:run` → synthetic `program.md` with known metric/guard/config; measure whether run mode correctly sets up iteration loop and applies rollback guard on guard failure; calibrates R0–R3 steps only (full multi-iteration loop excluded — too long-horizon) *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/research:sweep` → synthetic goal string; measure whether sweep correctly auto-plans, passes through judge gate, and hands off to run with correct flags — bounded handoff phase only, sweep's sustained multi-run execution excluded (see Excluded list below); ground truth = presence of plan output file and judge approval/rejection signal *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/research:retro` → synthetic `.experiments/state/*/state.json` + run logs; measure whether retro correctly identifies dead iterations, classifies them, produces structured retrospective report; ground truth = injected iteration outcomes *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/research:fortify` → synthetic ablation plan with known component importance order; measure whether fortify correctly ranks components and identifies reviewer questions; calibrates F1–F3 only (full execution loop excluded) *(research plugin required — skip if `$RESEARCH_AVAILABLE` empty)* - `/oss:analyse` → synthetic GitHub issue number (fixture: known type, known thread length, known duplicate link); measure whether thread analysis correctly classifies item type (issue/PR/discussion), surfaces duplicate, produces actionable summary; ground truth = injected issue metadata *(oss plugin required — skip if `$OSS_AVAILABLE` empty)* - `/oss:analyse vitality` → synthetic repo vitality dataset (fixture: known axis scores, known signal values per axis); measure whether vitality scoring phase correctly scores each axis and produces health scorecard matching ground truth; ground truth = injected per-axis scores and label thresholds *(oss plugin required — skip if `$OSS_AVAILABLE` empty; calibrates scoring phase only — data fetching via gh API excluded)* - `/oss:release` → synthetic git log with N commits of known classification (breaking, feature, fix, internal); measure whether release notes correctly classify each commit and omit internal-only entries; ground truth = injected commit metadata and expected output sections *(oss plugin required — skip if `$OSS_AVAILABLE` empty)* - `/distill:memory` → synthetic `.notes/lessons.md` corpus with N injected lessons of known disposition (→ rule, → agent update, → skill update, → already covered, → too narrow); measure whether distill correctly classifies each lesson and generates accurate proposals; ground truth = injected dispositions and target files - `/manage:create` → synthetic create-agent and create-skill directives; measure whether output file has valid frontmatter, correct structure, NOT-for clause, non-empty domain content; ground truth = structural completeness checklist - `/manage:update` → synthetic rename and content-edit directives against fixture agent/skill file; measure whether cross-reference propagation complete and description-changed flag correctly set; ground truth = known cross-ref targets in fixture - `/brainstorm` → synthetic creative brief or feature goal; measure whether brainstorm correctly generates spec file with required sections (goal, constraints, options) and blueprint tree with coherent structure; ground truth = required sections checklist - `/humanizer` → synthetic human-facing prose seeded with N AI-writing tells of known class (LLM-vocabulary cliché, banned construction, formatting tell — taxonomy from `humanizer`'s own SKILL.md); run the target in `check <file>` read-only mode so scoring reads a findings list, not a rewritten file; recall = injected tells reported; `scope_fp` = flagged spans that were never injected (punishes over-flagging of ordinary human prose); ground truth = the injected tell list with class per span ### Step 2: Spawn skill pipeline subagents Mark "Calibrate skills" in_progress. **Availability check** (vars set in SKILL.md Step 2): exclude skills marked with plugin requirements above when plugin absent. Log: "<plugin> plugin not installed — skipping <skill> calibration" per excluded skill. For each skill in domain table (after exclusions), spawn one `general-purpose` pipeline subagent. **Spawn in batches of `$PIPELINE_BATCH_SIZE` (5 when this category runs alone, 2 while two categories in flight — see constants)**: issue up to that many skill pipeline spawns per response, wait for all in batch to return compact JSON results, spawn next batch. Skills within a batch run concurrently; batches sequential. Do NOT spawn all skills in one response. For skill targets (target name starts with `/`): spawn `general-purpose` subagent with skill's `SKILL.md` content prepended as context, running against synthetic input from problem. Pipeline template write-and-acknowledge pattern still applies. For mode-specific targets (`/research:plan`, `/research:judge`): prepend relevant mode file as context instead of full `SKILL.md`. Resolve skill file via registry first, falling back to source-tree path: - `/research:plan`: `python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/get_plugin_install_path.py" borda-ai-rig research 2>/dev/null` → append `/skills/plan/SKILL.md`; fallback: `$(ls -td ~/.claude/plugins/cache/borda-ai-rig/research/*/skills/plan/SKILL.md 2>/dev/null | head -1)`; skip calibration for this target if fallback returns empty (research plugin not installed) - `/research:judge`: same helper → append `/skills/judge/SKILL.md`; fallback: `$(ls -td ~/.claude/plugins/cache/borda-ai-rig/research/*/skills/judge/SKILL.md 2>/dev/null | head -1)`; skip calibration for this target if fallback returns empty (research plugin not installed) Read resolved path (plan wizard steps P-P0–P-P3 for `/research:plan`; steps J1–J6 for `/research:judge`). `<TARGET>` substitution uses kebab form without leading slash (e.g. `research-plan`, `research-judge`). For `/research:judge`, calibration pattern mirrors `/audit`: inject N specific known issues into synthetic `program.md`, score recall of injected issues against judge's findings list. Ground truth = injected issues and severities (per J2 severity table: critical/high/medium/low). For `/research:plan`, calibration measures output completeness: generate synthetic goal, score whether produced `program.md` (a) contains all four required sections (Goal, Metric, Guard, Config), (b) has `direction` field, (c) has non-empty `scope_files`, (d) includes plausible `metric_cmd`. Ground truth = checklist; recall = fraction of checklist items present. Resolve template dir first — no `~/.claude/skills/` copy exists (setup symlinks only `rules/*.md` and `TEAM_PROTOCOL.md`): ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" CALIB_TPL=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate templates $([ "$LOCAL_MODE" = "true" ] && echo --local)) # timeout: 5000 ``` Each subagent receives pipeline template from `$CALIB_TPL/pipeline-prompt.md` with substitutions: - `<TARGET>` = skill name including `/` prefix (e.g., `/audit`) - `<DOMAIN>` = domain string from table above for that skill - `<N>` = 3 (fast) or 10 (full) - `<TIMESTAMP>` = current run timestamp - `<MODE>` = `fast` or `full` - `<AB_MODE>` = `true` or `false` - `<LOCAL_MODE>` = `true` or `false` — from `--local` flag; when true pipeline resolves target file from source tree **Partial-calibration principle**: individual skill modes with deterministic, auditable outputs can be calibrated even when full orchestration skill cannot. Full `optimize run` loop (requires live metric commands, git state, real guard scripts) excluded. Sub-modes producing structured, inspectable output in scope: - `optimize plan` — config wizard; output is `program.md` checkable against completeness schema - `optimize judge` — plan auditor; output is findings list checkable against injected known issues (same pattern as `/audit`) Other orchestration-heavy skills excluded: `resolve`, `manage`, `develop`, `research`, `create` (content outline co-creation — interactive; no deterministic ground truth). Outputs too context-dependent or long-horizon for synthetic ground truth without significant test infrastructure. (`/brainstorm` moved to domain table above — see line 28.) Run dir per skill: `.reports/calibrate/<TIMESTAMP>/<TARGET>/` (strip `/` from target name for dir, e.g. `audit` or `review`) ### Future Candidates Modes evaluated for calibration but deferred — significant barriers. `/audit` Check 19 skips modes listed here to avoid false-positive recommendations. | Mode | Barrier | Re-evaluate when | | -- | -- | -- | | `/analyse-thread` | Requires GitHub API mocking — thread analysis fetches live issue/PR data | GitHub fixture infrastructure exists | | `/analyse-health` | Requires live GitHub API — health overview fetches real repo stats (issue/PR counts) | GitHub fixture infrastructure exists | | `/analyse-ecosystem` | Requires live GitHub API — ecosystem analysis fetches real package/dependency data | GitHub fixture infrastructure exists | | `/release-notes` | Requires controlled git history — output depends on real commit range | Git-history fixture helper exists | | `/release-changelog` | Same as `/release-notes` — git-history dependent | Git-history fixture helper exists | | `/release-summary` | Same as `/release-notes` — git-history dependent | Git-history fixture helper exists | | `/release-audit` | Requires controlled repo state (version tags, CHANGELOG, CI status) | Release fixture infrastructure exists | | `/release-demo` | Requires controlled git history — output depends on real commit range | Git-history fixture helper exists | | `/develop-plan` | Output somewhat subjective; no clear ground-truth checklist beyond section presence | Structured plan schema formalized | | `/distill-review` | Reads real agent/skill files; synthetic roster possible but overlaps `/audit` calibration | Distinct synthetic scenarios identified | | `/distill-prune` | Likely calibratable — construct synthetic memory corpus with known entries to drop (stale, redundant, duplicated-in-CLAUDE.md), score recall of correct drop/trim/keep decisions; ground truth constructable | Synthetic memory corpus fixtures built | | `/distill-memory` | Promoted to domain table — synthetic lesson corpus calibration now defined | — | | `/distill-external` | Calibratable with two concrete GT fixture cases: **(1) caveman plugin** — narrow communication-mode tool, no local overlap → GT outcome: install-as-is recommendation; **(2) Karpathy autoresearch** — research automation with strong structural overlap to `research:` plugin → GT outcome: Group A candidates map to research plugin, digest recommended. Score whether adoption-table lane assignments (adopt-as-is/tweak/discuss/skip) and install-as-is flag match GT. Ground truth constructable without live external source — fixture = static snapshot of each tool's agent/skill/rule files. | GT fixture snapshots authored | **Excluded** (inherently non-calibratable — documented to avoid recurring evaluation): - `/resolve` — orchestrates live PR review, lint, push; fully external-service-dependent - `/manage` (delete, perm ops) — CRUD on config files with no structured findings list to score; `/manage:create` and `/manage:update` promoted to domain table with structural completeness ground truth - `/develop:feature`/`/develop:fix`/`/develop:refactor`/`/develop:debug` — full dev lifecycle; requires git, tests, linting; blast-radius sub-task calibratable via `/codemap-py:query-code` (`fn-blast`) above - `/research:topic` — SOTA literature search; depends on live web results; no deterministic ground truth - `/investigate` — open-ended diagnosis; output varies completely by symptom - `/foundry:session` — session lifecycle management — no quality signal; output fully context-dependent - `/foundry:profile` — thin wrapper over `bin/timing_analyzer.py` and `bin/cost_analyzer.py`; output is deterministic analyzer text already pinned by `tests/test_timing_analyzer.py` and `tests/test_cost_analyzer.py`, so a run would score the scripts rather than the instructions - `/calibrate` itself — meta-calibration circular - `/research:run` — sustained iteration loop with live metric commands and git state - `/research:run --resume` — continuation of run; same barriers as run - `/research:sweep` (sustained multi-run execution only — auto-plan/judge-gate/handoff phase calibrated in domain table above) — same barrier as `/research:run`'s excluded full loop: live metrics and git state - `/research:fortify` (live ablation-execution phase only — F1–F3 ranking/reviewer-questions calibrated in domain table above) — requires completed `/research:run` ablation output; ground truth not constructable synthetically for this remaining phase - `/foundry:setup` — system-state-dependent — installs symlinks and merges settings; ground truth not constructable
-
-
templates
-
pipeline-prompt.md 31 KB
Calibration pipeline runner for `<TARGET>`. Complete all phases in sequence. AB mode: `<AB_MODE>` — when `true`, also run `general-purpose` baseline on every problem and compute delta metrics. Local mode: `<LOCAL_MODE>` — when `true`, resolve target file from source tree (`plugins/`) first; see Pre-flight below. Run dir: `.reports/calibrate/<TIMESTAMP>/<TARGET>/` **Scratchpad discipline**: session scratchpad is shared across every concurrent calibration pipeline, not per-target. Write every bridge task file and any other intermediate you create inside your own run dir above — never a bare filename in the shared scratchpad. A generic name there (`codex-gen-task.txt`, etc.) gets silently overwritten by a sibling pipeline within seconds, caller then scores against wrong domain's problems with no error surfaced. ### Graceful-exit protocol Before returning for ANY reason — crash, context limit, unhandled error, or early exit — always write minimal `result.jsonl` to run dir. Even if phases incomplete, orchestrator must receive signal. Write this line to `.reports/calibrate/<TIMESTAMP>/<TARGET>/result.jsonl` if file does not already exist: `{"ts":"<TIMESTAMP>","target":"<TARGET>","verdict":"incomplete","mean_recall":null,"mean_confidence":null,"calibration_bias":null,"mean_f1":null,"severity_accuracy":null,"format_score":null,"problems":null,"scope_fp":null,"gaps":["pipeline exited before Phase 4 — re-run individually: /calibrate <TARGET> --fast"],"source_mode":null,"scoring":null,"scorer_agreement":null}` Safety net — Phase 4 always overwrites this with full results when it runs successfully. ### Pre-flight — Codex availability Check Codex availability once at pipeline start, set `CODEX_AVAILABLE` for all phases: ```bash CODEX_STATUS=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/check_bridge.py" --status 2>/dev/null || echo "absent") if [ "$CODEX_STATUS" = "available" ]; then CODEX_AVAILABLE=true; else CODEX_AVAILABLE=false; fi echo "bridge@borda-ai-rig: $CODEX_STATUS" ``` The helper reads Claude's installed-plugin registry, marketplace cache, and enabled-plugin settings directly; doesn't require a nested `claude plugin list` call from a background agent. Codex integration active only for `agents` and `skills` modes. Pipeline spawned for `routing`, `communication`, or `rules`: treat `CODEX_AVAILABLE=false` — those modes test Claude-specific internals Codex lacks context for. ### Pre-flight — local file resolution When `LOCAL_MODE=true`, resolve target file from source tree before Phase 2: ```bash LOCAL_MODE=<LOCAL_MODE> TARGET_FILE="" if [ "$LOCAL_MODE" = "true" ]; then BARE=$(echo "<TARGET>" | sed 's|^/||') PLUGIN=$(echo "$BARE" | cut -d: -f1) NAME=$(echo "$BARE" | cut -d: -f2) if [[ "<TARGET>" == /* ]]; then REL="skills/$NAME/SKILL.md" else REL="agents/$NAME.md" fi CANDIDATE="plugins/cc_$PLUGIN/$REL" [ -f "$CANDIDATE" ] || CANDIDATE="plugins/$PLUGIN/$REL" if [ ! -f "$CANDIDATE" ]; then MATCHES=$(find plugins -mindepth 3 -maxdepth 4 -path "*/$REL" 2>/dev/null) MATCH_COUNT=$(echo "$MATCHES" | grep -c .) if [ "$MATCH_COUNT" -eq 1 ]; then CANDIDATE="$MATCHES" elif [ "$MATCH_COUNT" -gt 1 ]; then CANDIDATE=$(echo "$MATCHES" | grep "/$PLUGIN[^/]*/" | head -1) else CANDIDATE="" fi fi if [ -n "$CANDIDATE" ] && [ -f "$CANDIDATE" ]; then TARGET_FILE="$CANDIDATE" echo "local mode: using $TARGET_FILE" else echo "! local mode: no source file resolved for '<TARGET>' (tried plugins/cc_$PLUGIN/$REL, plugins/$PLUGIN/$REL, plugins/*/$REL) — aborting, not silently falling back to installed cache" fi fi ``` Local-mode resolution failed (`$TARGET_FILE` still empty above): write graceful-exit `result.jsonl` line (see Graceful-exit protocol above) with `gaps` including `"local mode: no source file resolved for <TARGET>"`, skip all remaining phases, return compact JSON immediately (see Return value section) with `verdict:"incomplete"` — never a silent `exit 1`, never fall back to installed cache. When `LOCAL_MODE=false` or source file not found: Phase 2 dispatches normally (agent by subagent_type, skill by cache/installed SKILL.md). ### Phase 1a — Generate problems (dual source) **When CODEX_AVAILABLE=true**: Split `<N>` in-scope problems between two generators. Claude always owns 1 out-of-scope problem. | Pace | N_CLAUDE in-scope | N_CODEX in-scope | Scope (Claude) | Total | | -- | -- | -- | -- | -- | | fast (N=3) | 1 | 2 | 1 | 4 | | full (N=10) | 5 | 5 | 1 | 11 | **Step 1 — Codex generates N_CODEX in-scope problems** (runs first; requires `bridge@borda-ai-rig`): `bridge:advise`/`bridge:review` are read-only — they return their answer in the call's own envelope, they never write to the run dir despite the "Write JSON array to" instruction below. Capture the returned payload from the call result, then write it to the target file yourself. Skill(skill="bridge:advise", args="Generate \<N_CODEX> synthetic calibration problems for domain: '<DOMAIN>'. Each problem must be JSON object with these exact fields: - problem_id: kebab-slug string, prefix with 'cx-' (e.g. 'cx-type-mismatch') - difficulty: exactly one of: trivial, low, medium, high, extreme — include at least 1 trivial in full mode - task_prompt: instruction to give reviewer (do NOT reveal issues) - input: code / config / content inline (no file paths) — must contain issues - ground_truth: array of objects, each with: - issue: concise description (what is wrong) - location: function name, section, or line reference - severity: exactly one of: critical, high, medium, low Difficulty tiers: - **trivial**: single-line, obvious issue visible at glance; any reviewer finds immediately; used in full mode only - **low**: isolated, obvious issue; single-function scope; domain expert finds immediately - **medium**: requires reading 2-3 related functions or sections; non-obvious but unambiguous - **high**: requires cross-function or cross-module reasoning; subtle but detectable by reading - **extreme**: intentionally adversarial or near-unsolvable from reading alone — use ONE of these patterns: 1. adversarial/misleading: code looks like common anti-pattern but actually correct in context (tests false-positive discipline); issue description in ground_truth explains why it IS problem despite appearance 2. deep cross-function control flow: issue only visible by tracing state across 4+ functions 3. subtle concurrency or ordering bug: requires reasoning about interleaved execution or init order 4. incomplete detectability: issue real but only partially diagnosable from reading (e.g., depends on runtime config); ground_truth includes what IS detectable statically Distribution rules for N_CODEX problems (fast=2, full=5): - fast (N_CODEX=2): 1 low, 1 medium/high — no extreme in fast mode - full (N_CODEX=5): exactly 1 problem at each tier — trivial, low, medium, high, extreme Rules: - 2-5 known issues per problem; extreme problems may have fewer (1-3) if issue inherently hard to detect - Issues must be unambiguous — domain expert would confirm them - Do NOT include any out-of-scope problem — in-scope only - Write ONLY valid JSON array (no prose, no markdown fences, no trailing commas) - `bridge_call.py` enforces a hard ~500-char cap on the returned `verdict` field — a response whose verdict exceeds it raises `ValueError` and the call fails outright (not a silent truncation). Request one problem per `bridge:advise` call rather than the full `N_CODEX` batch in one call, to stay under the cap. If a call still fails validation after a retry, drop that problem and proceed with fewer Codex problems — Phase 1b's `floor(<N_CODEX> * 0.5)` validity threshold already accounts for partial yield. Return the JSON array in your response — do not attempt to write it to a file yourself.") Capture the JSON array from the call's return value and write it to `.reports/calibrate/<TIMESTAMP>/<TARGET>/problems-codex.json` yourself. **Step 2 — Claude generates N_CLAUDE in-scope problems + 1 out-of-scope problem**: Generate `<N_CLAUDE>` in-scope problems for domain `<DOMAIN>`, plus exactly 1 out-of-scope problem, as JSON array. Fields: `problem_id` (kebab-slug), `difficulty`, `task_prompt`, `input`, `ground_truth` (array of `{issue, location, severity}`). Difficulty tiers: same as Step 1 above. Rules: - Issues must be unambiguous — domain expert would confirm them - Distribution for N_CLAUDE in-scope problems: fast (N_CLAUDE=1): 1 medium or high — no extreme in fast mode; when N_CLAUDE=1, use medium or high; full (N_CLAUDE=5): exactly 1 problem at each tier — trivial, low, medium, high, extreme - Extreme problems may have 1–3 known issues (fewer fine if issue inherently hard to detect) - Each non-extreme in-scope problem has 2–5 known issues; no runtime-only-detectable issues - **Include exactly 1 out-of-scope problem** (difficulty: `"scope"`): input clearly outside agent's domain (e.g., for `foundry:linting-expert`, natural-language question; for `oss:cicd-steward`, plain Python data script). Set `ground_truth: []`. Correct response declines, redirects, or reports no findings. Any findings = false positives (scope failure). - Return valid JSON array only (no prose) Write to `.reports/calibrate/<TIMESTAMP>/<TARGET>/problems-claude.json`. **When CODEX_AVAILABLE=false**: Claude generates all `<N>` in-scope problems + 1 out-of-scope using rules above. Write to `problems-claude.json`. Skip Codex step. ### Phase 1b — Validate and merge problems **Validate problems-codex.json** (skip if CODEX_AVAILABLE=false): Read file. Strip any markdown code fences or prose prefix/suffix — find first `[`, match to closing `]`. Parse, validate each entry: Required fields: `problem_id` (string starting with `cx-`), `difficulty` (one of: `trivial`/`low`/`medium`/`high`/`extreme` — NOT `scope`), `task_prompt` (non-empty string), `input` (non-empty string), `ground_truth` (non-empty array; each item has `issue`, `location`, `severity`; `severity` must be one of: `critical`/`high`/`medium`/`low`). Reject and log any entry failing validation. If fewer than `floor(<N_CODEX> * 0.5)` valid entries remain, set `CODEX_GENERATION_FAILED=true` and proceed without Codex problems (Claude-only fallback). **Merge and tag**: - Tag each Codex entry: add `"source": "codex"` field - Tag each Claude entry: add `"source": "claude"` field - Deduplicate `problem_id`: if collision, prefix with source (`claude-<id>`, `cx-<id>`) - Merge into single array; scope problem must appear exactly once (from Claude) Write merged array to `.reports/calibrate/<TIMESTAMP>/<TARGET>/problems.json`. ### Phase 2 — Run target on each problem (parallel) Spawn one `<TARGET>` named subagent per problem using **Agent tool** — never via Bash or CLI. Issue ALL spawns in **single response** — no waiting between spawns. Prompt for each subagent: > `<task_prompt from that problem>` > > `<input from that problem>` > > End your response with a `## Confidence` block: **Score**: 0.N (high >=0.9 / moderate 0.8-0.9 / low \<0.8) and **Gaps**: what limited thoroughness. > > You have approximately `<PHASE_TIMEOUT_MIN>` minutes. If time is running short, submit your partial findings — do not delay output waiting for full coverage. > > Do not self-review or refine before answering — report your initial analysis directly. > > **Write your complete response** (including the Confidence block) to `.reports/calibrate/<TIMESTAMP>/<TARGET>/response-<problem_id>.md` using the Write tool. Then end your reply with exactly one line: `Wrote: <problem_id>` **Context discipline**: subagents write to disk, return single-line acknowledgment. Pipeline agent must NOT accumulate their full analyses in context — scorers read from disk in Phase 3. `Wrote: <problem_id>` per agent = correct. **Completion handling** — spawns are blocking `Agent()` calls, so no poll loop is possible (`_FOUNDRY_SHARED/agent-spawn-protocol.md` §Synchronous spawns). Each subagent returns: check for `response-<problem_id>.md`; empty or missing: mark that problem `{"timed_out": true}` in scores.json, proceed. Never block indefinitely on single response. For **agent targets** when `LOCAL_MODE=true` and `TARGET_FILE` set: spawn `general-purpose` subagent with TARGET_FILE content prepended ("You are an agent described by the following instructions: <content of TARGET_FILE>") — tests source tree definition rather than installed plugin. When LOCAL_MODE=false or TARGET_FILE empty: spawn `Agent(subagent_type="<TARGET>")` normally. For **skill targets** (target starts with `/`): spawn `general-purpose` subagent with skill's SKILL.md content prepended as context, running against synthetic input from problem. When `LOCAL_MODE=true` and `TARGET_FILE` set, read SKILL.md from `TARGET_FILE`; otherwise resolve: `.claude/skills/<NAME>/SKILL.md` → cache `~/.claude/plugins/cache/borda-ai-rig/<PLUGIN>/*/skills/<NAME>/SKILL.md` (latest mtime) → `plugins/<PLUGIN>/skills/<NAME>/SKILL.md`. Apply same write-and-acknowledge pattern. ### Phase 2b — Run general-purpose baseline (skip if AB_MODE is false) Spawn one `general-purpose` subagent per problem using **identical prompt** as Phase 2 (same task_prompt + input + Confidence instruction), plus same write-and-acknowledge suffix pointing to `response-<problem_id>-general.md`. Issue ALL spawns in **single response** — no waiting between spawns. **Completion handling** — same as Phase 2 (`_FOUNDRY_SHARED/agent-spawn-protocol.md` §Synchronous spawns): each subagent returns, check for `response-<problem_id>-general.md`; missing: proceed with partial baseline data. ### Phase 3a — Score responses via Claude scorers (parallel) Spawn one `general-purpose` scorer subagent per problem using **Agent tool** — never via Bash or CLI. Issue ALL spawns in **single response** — no waiting between spawns. Each scorer receives this prompt (substitute `<PROBLEM_ID>`, `<GROUND_TRUTH_JSON>`, `<RUN_DIR>`, `<AB_MODE>`): > Scoring agent responses against calibration ground truth. > > **Problem ID**: `<PROBLEM_ID>` > > **Ground truth** (JSON array — each entry has `issue`, `location`, `severity`): > > ```text > <GROUND_TRUTH_JSON> > ``` > > Read target response from `<RUN_DIR>/response-<PROBLEM_ID>.md`. \[If AB_MODE is true: also read `<RUN_DIR>/response-<PROBLEM_ID>-general.md`.\] > > For each ground truth issue: mark `true` if response identified same issue type at same location (exact match or semantically equivalent). Count false positives: reported issues with no corresponding ground truth entry. Extract confidence from `## Confidence` block (use 0.5 if absent). > > **For out-of-scope problems** (`ground_truth: []`): recall = N/A (skip from recall aggregate). Count all reported findings as false positives. If response declines or reports nothing, false_positives = 0 (correct scope discipline). Set severity_accuracy = N/A and format_score = N/A for this problem. > > **Measure response length**: count characters in target response and (if AB_MODE) general response. Token efficiency proxy — shorter = more focused. > > **Severity accuracy**: for each found issue (true positive), check whether response assigned same severity as ground truth. Allow ±1 tier (tiers ordered: critical > high > medium > low — "critical" vs "high" is 1-tier miss; "critical" vs "low" is 3-tier miss). Count exact-or-adjacent matches. `severity_accuracy = correct_severity / found_count` (N/A if found_count = 0). Orthogonal to recall — agent can find everything but mislabel severity. > > **Format score**: for each found issue (true positive), check whether response includes all three of: (a) location reference (line number, function name, or section), (b) severity or priority label, (c) fix or action suggestion. `format_score = fully_structured_count / found_count` (N/A if found_count = 0). Measures actionability of findings, not just detection. > > Compute: `recall = found / total` (skip if total=0), `precision = found / (found + fp + 1e-9)`, `f1 = 2·r·p / (r+p+1e-9)`. > > Write following JSON (no prose, no markdown fences) to `<RUN_DIR>/score-<PROBLEM_ID>-claude.json` using Write tool: `{"problem_id":"<PROBLEM_ID>","found":[true/false,...],"false_positives":N,"confidence":0.N,"recall":0.N,"precision":0.N,"f1":0.N,"severity_accuracy":0.N,"format_score":0.N,"target_chars":N,"scorer":"claude"}` > > \[If AB_MODE is true, also include before closing `}`: `,"recall_general":0.N,"precision_general":0.N,"f1_general":0.N,"confidence_general":0.N,"severity_accuracy_general":0.N,"format_score_general":0.N,"general_chars":N`\] > > Then return ONLY one line: `Scored: <PROBLEM_ID>` **Context discipline**: scorers write results to `score-<PROBLEM_ID>-claude.json`, return single-line acknowledgment (`Scored: <PROBLEM_ID>`). Do NOT accumulate inline JSON in pipeline context — Phase 3c reads from disk. ### Phase 3b — Score responses via Codex (skip when CODEX_AVAILABLE=false — requires `bridge@borda-ai-rig`) For each problem, call the read-only Codex bridge skill. Run **sequentially** (not parallel — scoring writes shared result files). `bridge:review` is read-only — it returns its answer in the call envelope, it never writes the output file itself despite the "Output file:" instruction below. Also note: `bridge_call.py` enforces a hard ~500-char cap on the returned `verdict` field — a scoring response that exceeds it fails validation (`ValueError`) rather than returning truncated JSON; if the call fails, retry once, then fall back to Claude's score alone for that problem (`scorer_mode: "single"`, per Phase 3c below) rather than looping. Skill(skill="bridge:review", args="Score a calibration response against ground truth. ```text Problem ID: \<PROBLEM_ID> Ground truth (JSON array): \<GROUND_TRUTH_JSON> ``` Read response from: .reports/calibrate/<TIMESTAMP>/<TARGET>/response-\<PROBLEM_ID>.md \[If AB_MODE is true: also read .reports/calibrate/<TIMESTAMP>/<TARGET>/response-\<PROBLEM_ID>-general.md\] For each ground truth issue: mark true if response identified same issue type at same location (exact or semantically equivalent). Count false positives: reported issues with no ground truth match. Extract confidence from ## Confidence block (use 0.5 if absent). For out-of-scope problems (ground_truth is []): set recall=null, all reported findings are FPs, set severity_accuracy=null, format_score=null. ```text Severity accuracy: for found issues, check severity match (allow +-1 tier; tiers: critical>high>medium>low). Format score: for found issues, check for all three of: location reference, severity label, fix suggestion. ``` Compute: recall=found/total (null if total=0), precision=found/(found+fp+1e-9), f1=2*r*p/(r+p+1e-9). Write ONLY this JSON (no prose, no markdown fences, no trailing commas) to file below: {"problem_id":"\<PROBLEM_ID>","found":[true/false,...],"false_positives":N,"confidence":0.N,"recall":0.N,"precision":0.N,"f1":0.N,"severity_accuracy":0.N,"format_score":0.N,"scorer":"codex"} [If AB_MODE is true, append before closing }: ,"recall_general":0.N,"confidence_general":0.N,"precision_general":0.N,"f1_general":0.N,"severity_accuracy_general":0.N,"format_score_general":0.N] Return the JSON object in your response — do not attempt to write it to a file yourself.") Substitute `<PROBLEM_ID>` and `<GROUND_TRUTH_JSON>` per problem. Capture JSON from call's return value, write it to `.reports/calibrate/<TIMESTAMP>/<TARGET>/score-<PROBLEM_ID>-codex.json` yourself. Returned payload missing or unparsable after one retry: set `scorer_mode: "single"` for that problem — Phase 3c uses Claude's score only. ### Phase 3c — Consensus merge For each problem, read `score-<PROBLEM_ID>-claude.json` (Phase 3a output) and `score-<PROBLEM_ID>-codex.json` (Phase 3b output) from `<RUN_DIR>` and merge: **When both scores present**: - `found[]` — per-issue boolean: both agree → use; disagree → Claude's value (51% tiebreak) - `false_positives` — Claude's count wins on disagreement - `recall`, `precision`, `f1` — recomputed from consensus `found[]` and consensus `false_positives` - `severity_accuracy`: - Both agree → use - Disagree within 1 tier → use harsher (more conservative) severity - Disagree by >1 tier → mark that issue as `severity_disputed`; exclude from `severity_accuracy` aggregate - `format_score` — weighted average: 0.51 × Claude + 0.49 × Codex - `confidence` — unchanged (from target agent's response, not scorers) - `scorer_agreement` = (issues where both scorers agreed on found/not-found) / total_issues; N/A for scope problems - `scorer_mode` = `"dual"` **When only Claude score present** (Codex unavailable or failed for this problem): Use Claude score directly; `scorer_agreement` = null; `scorer_mode` = `"single"` **A/B mode**: apply same consensus logic independently to general-purpose baseline scores. Write all merged scores to `.reports/calibrate/<TIMESTAMP>/<TARGET>/scores.json` as JSON array. Each entry includes `"source"` (from problems.json: `"claude"`/`"codex"`), `"scorer_mode"`, `"scorer_agreement"`, and `"severity_disputed_count"` (count of `severity_disputed` issues for this problem). ### Phase 4 — Aggregate, write report and result Compute aggregates (exclude out-of-scope problem from recall/F1/severity/format averages; include in FP count): - `mean_recall` = mean of `recall` values for in-scope, **non-extreme** problems only (trivial through high included; extreme excluded — reported separately as `extreme_recall`) - `extreme_recall` = mean of `recall` values for extreme problems only (null if none present); partial performance (0.4–0.7) informative, not alarming - `mean_confidence` = mean of all `confidence` values (extreme problems included — confidence calibration applies across all tiers) - `calibration_bias` = `mean_confidence − mean_recall` (uses non-extreme `mean_recall`; extreme problems don't affect verdict) - `mean_f1` = mean of `f1` values for in-scope, non-extreme problems only - `scope_fp` = false_positives from out-of-scope problem (0 = correct discipline, >0 = scope failure) - `mean_severity_accuracy` = mean of `severity_accuracy` for in-scope problems with found_count > 0 (exclude `severity_disputed` issues from numerator and denominator; extreme problems included if found_count > 0) - `mean_format_score` = mean of `format_score` for in-scope problems with found_count > 0 - `token_ratio` = mean(target_chars) / mean(general_chars) across all problems — if AB_MODE, else omit - Recall by difficulty: `recall_trivial`, `recall_low`, `recall_medium`, `recall_high`, `recall_extreme` (omit if 0 problems at that level) **Additional aggregates (populate when applicable; use null when not)**: - `mean_scorer_agreement` = mean `scorer_agreement` across dual-scored problems (null if all single-scored) - `severity_disputed_count` = total issues flagged `severity_disputed` across all problems - `codex_problems_pct` = fraction of in-scope problems with `source: "codex"` (0.0 if claude-only) - `recall_claude_problems` = mean recall on in-scope problems where `source: "claude"` (null if none) - `recall_codex_problems` = mean recall on in-scope problems where `source: "codex"` (null if none) - `generator_recall_delta` = `recall_claude_problems − recall_codex_problems` (null if either is null) - `source_mode` = `"dual"` if CODEX_AVAILABLE and generation succeeded, else `"claude-only"` - `scoring` = `"dual"` if any problem dual-scored, else `"single"` - `codex_generation_failed` = true if Codex generation attempted but failed, else false Verdict: - `|bias| < 0.10` → `calibrated` - `0.10 ≤ |bias| ≤ 0.15` → `borderline` - `bias > 0.15` → `overconfident` - `bias < −0.15` → `underconfident` Write tool refuses any file whose exact basename is `report.md` from a subagent context ("Subagents should return findings as text, not write report files") — use `benchmark-report.md` instead. Write full report to `.reports/calibrate/<TIMESTAMP>/<TARGET>/benchmark-report.md` using this structure: ```markdown ## Benchmark Report — <TARGET> — <date> Mode: <MODE> | Problems: <N> (in-scope) + 1 (out-of-scope) | Total known issues: M Source: dual (claude+codex) | Scorer: dual | Scorer agreement: X.XX [consistent ≥0.85 / moderate 0.70–0.85 / divergent ⚠ <0.70] [OR: Source: claude-only | Scorer: single — Codex unavailable or generation failed] ### Per-Problem Results | Problem ID | Source | Difficulty | Recall | Precision | SevAcc | Fmt | Confidence | Cal. Δ | Agreement | | ... | <scope-id> | claude | scope | — | — | — | — | — | scope_fp=N | — | *Recall: issues found / total. Precision: found / (found + FP). Source: which model generated the problem (claude/codex). SevAcc: severity match rate for found issues (±1 tier; severity_disputed issues excluded). Fmt: fraction of found issues with location + severity + fix. Cal. Δ: confidence − recall (negative = conservative). Agreement: fraction of issues where both scorers agreed (— = single-scorer or scope).* ### Aggregate | Metric | Value | Status | | ... | Severity accuracy | X.XX | high ≥0.80 / moderate 0.60–0.80 / low <0.60 | | Format score | X.XX | high ≥0.80 / moderate 0.60–0.80 / low <0.60 | | Scope discipline | scope_fp=0 ✓ / scope_fp=N ⚠ | pass/fail | | Scorer agreement | X.XX | consistent ≥0.85 ✓ / moderate 0.70–0.85 ~ / divergent ⚠ <0.70 | | Disputed severities | N | excluded from SevAcc (scorers disagreed >1 tier) | Recall by difficulty: trivial=X.XX | low=X.XX | medium=X.XX | high=X.XX (omit levels with 0 problems) Extreme recall: X.XX (extreme problems excluded from mean_recall and verdict — partial performance 0.4–0.7 is expected) ### Recall by Problem Source (dual source mode only) | Source | Problems | Mean Recall | |--------|----------|-------------| | claude | N | X.XX | | codex | N | X.XX | | delta | — | ±X.XX (+ = harder codex problems; − = codex problems easier) | ### A/B Comparison — specialized vs. general-purpose (AB mode only) | Metric | Specialized | General | Delta | Verdict | |-------------------|-------------|---------|--------|-----------| | Mean Recall | X.XX | X.XX | ±X.XX | significant ✓ / marginal ~ / none ⚠ | | Mean F1 | X.XX | X.XX | ±X.XX | | | Severity accuracy | X.XX | X.XX | ±X.XX | better ✓ / similar ~ / worse ⚠ | | Format score | X.XX | X.XX | ±X.XX | better ✓ / similar ~ / worse ⚠ | | Token ratio | X.XX | 1.00 | ±X.XX | concise ✓ / verbose ⚠ | | Scope FP | N | N | — | pass/fail | *ΔRecall: specialist recall − general recall. SevAcc: severity match rate (±1 tier). Fmt: actionability score. Token ratio: specialist chars / general chars (below 1.0 = more focused). Scope FP: findings on out-of-scope input (0 = correct discipline).* Verdict: `significant` (delta_recall or delta_f1 > 0.10) / `marginal` (0.05–0.10) / `none` (<0.05) ### Systematic Gaps (missed in ≥2 problems) ... ### Improvement Signals ... ``` Write single-line JSONL result to `.reports/calibrate/<TIMESTAMP>/<TARGET>/result.jsonl`: (one line per pipeline run — orchestrating skill concatenates these across runs into `.notes/logs/calibrations.jsonl`) `{"ts":"<TIMESTAMP>","target":"<TARGET>","mode":"<MODE>","mean_recall":0.N,"extreme_recall":0.N_or_null,"mean_confidence":0.N,"calibration_bias":0.N,"mean_f1":0.N,"severity_accuracy":0.N,"format_score":0.N,"problems":<N>,"scope_fp":N,"verdict":"...","gaps":["..."],"source_mode":"dual|claude-only","scoring":"dual|single","scorer_agreement":0.N_or_null,"recall_trivial":0.N_or_null,"recall_low":0.N_or_null,"recall_medium":0.N_or_null,"recall_high":0.N_or_null,"recall_extreme":0.N_or_null,"recall_claude_problems":0.N_or_null,"recall_codex_problems":0.N_or_null,"generator_recall_delta":0.N_or_null,"severity_disputed_count":N,"codex_generation_failed":false}` **If AB_MODE is true**, append these fields to same JSON line: `"delta_recall":0.N,"delta_f1":0.N,"delta_severity_accuracy":0.N,"delta_format_score":0.N,"token_ratio":0.N,"scope_fp_general":N,"ab_verdict":"significant|marginal|none"` ### Phase 5 — Propose instruction edits Determine target file path for curator proposals: When `LOCAL_MODE=true` and `TARGET_FILE` set: use `TARGET_FILE` directly. Otherwise resolve (first match wins): - Agent: `.claude/agents/<NAME>.md` → `~/.claude/plugins/cache/borda-ai-rig/<PLUGIN>/*/agents/<NAME>.md` (latest mtime) → `plugins/<PLUGIN>/agents/<NAME>.md` - Skill: `.claude/skills/<NAME>/SKILL.md` → `~/.claude/plugins/cache/borda-ai-rig/<PLUGIN>/*/skills/<NAME>/SKILL.md` (latest mtime) → `plugins/<PLUGIN>/skills/<NAME>/SKILL.md` (`<PLUGIN>` and `<NAME>` parsed from `<TARGET>` as in pre-flight: strip `/`, split on `:`) Spawn **foundry:curator** subagent using **Agent tool** — never via Bash or CLI. Pass only **file path** and **report path** — do NOT paste file contents into prompt; foundry:curator reads files itself: > Reviewing calibration benchmark result and proposing instruction improvements. > > **Files to read** (use Read tool on each): > > 1. Target file: `<AGENT_OR_SKILL_FILE_PATH>` > 2. Benchmark report: `.reports/calibrate/<TIMESTAMP>/<TARGET>/benchmark-report.md` — focus on **Systematic Gaps** and **Improvement Signals** sections > > Propose specific, minimal instruction edits that directly address each systematic gap (issues missed in ≥2/N problems) and each false-positive pattern. Conservative: one targeted change per gap. Don't refactor sections unrelated to findings. > > If no actionable systematic gaps (target calibrated with recall ≥ 0.70 and no repeated misses), write: `## Proposed Changes — <TARGET>\n\nNo changes needed — target is calibrated.` > > Otherwise format each change as: > > ``` > ## Proposed Changes — <TARGET> > > ### Change 1: <gap name> > **File**: `<file path>` > **Section**: `<antipatterns-to-flag>` / `<workflow>` / `<notes>` / etc. > **Current**: [exact verbatim text to replace; or "none" if inserting new content] > **Proposed**: [exact replacement text] > **Rationale**: one sentence — why this closes the gap > ``` Write foundry:curator response verbatim to `.reports/calibrate/<TIMESTAMP>/<TARGET>/proposal.md`. Ask foundry:curator to end proposed changes with `## Confidence` block per CLAUDE.md output standards. ### Return value **CRITICAL — context discipline**: return ONLY compact JSON line below. No prose, no report summary, no table, no Confidence block, no additional output. Every extra byte accumulates in orchestrator context, can cause synthesis hang. All report content already on disk from Phase 4. Return **only** this compact JSON (no prose before or after): `{"target":"<TARGET>","mean_recall":0.N,"extreme_recall":0.N_or_null,"mean_confidence":0.N,"calibration_bias":0.N,"mean_f1":0.N,"severity_accuracy":0.N,"format_score":0.N,"scope_fp":N,"verdict":"calibrated|borderline|overconfident|underconfident","gaps":["..."],"proposed_changes":N,"source_mode":"dual|claude-only","scoring":"dual|single","scorer_agreement":0.N_or_null,"generator_recall_delta":0.N_or_null}` If AB_MODE is true, also include: `"delta_recall":0.N,"delta_f1":0.N,"delta_severity_accuracy":0.N,"delta_format_score":0.N,"token_ratio":0.N,"scope_fp_general":N,"ab_verdict":"significant|marginal|none"` -
routing-pipeline-prompt.md 9.5 KB
You routing calibration pipeline runner. Complete all phases in sequence. <!-- Substitutions: TIMESTAMP=run timestamp (YYYY-MM-DDTHH-MM-SSZ), MODE=fast|full, N=problem count (fast=5, full=10) --> ```text Mode: `<MODE>` Run dir: `.reports/calibrate/<TIMESTAMP>/routing/` ``` <!-- All paths relative to project root. Pipeline runner must have project root as working dir. --> ### Phase 1 — Collect agent descriptions Enumerate roster file set. Source tree (`plugins/*/agents/*.md`) is authoritative; installed cache is fallback when source tree carries no agents; project-local `.claude/agents/*.md` is an override tier empty in most setups — `/foundry:setup` never creates that directory, purges stale entries from it, so it must never be the sole source: ```bash RUN_DIR=".reports/calibrate/<TIMESTAMP>/routing" mkdir -p "$RUN_DIR" find plugins -mindepth 3 -maxdepth 3 -path "*/agents/*.md" 2>/dev/null | sort > "$RUN_DIR/roster-files.txt" if [ ! -s "$RUN_DIR/roster-files.txt" ]; then # one version dir per plugin — the cache retains every prior version, so an unfiltered scan duplicates each agent for P in ~/.claude/plugins/cache/borda-ai-rig/*/; do V=$(find "$P" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | grep -v '\.orphaned_at' | sort -Vr | head -1) [ -n "$V" ] && find "$V/agents" -maxdepth 1 -name "*.md" 2>/dev/null done | sort > "$RUN_DIR/roster-files.txt" fi find .claude/agents -maxdepth 1 -name "*.md" 2>/dev/null >> "$RUN_DIR/roster-files.txt" grep -c . "$RUN_DIR/roster-files.txt" ``` **Empty-roster hard stop** — zero lines: do NOT generate problems, do NOT score, do NOT reconstruct a roster from memory. A fabricated roster yields a measured-looking `routing_accuracy` for a run that measured nothing, and that number lands in `calibrations.jsonl` history. Write this line to `.reports/calibrate/<TIMESTAMP>/routing/result.jsonl`, return it as compact JSON, skip Phases 2–4: `{"ts":"<TIMESTAMP>","target":"routing","mode":"<MODE>","routing_accuracy":null,"confusion_rate":null,"hard_accuracy":null,"auto_invoke_accuracy":null,"problems":0,"verdict":"incomplete","confused_pairs":[],"gaps":["no agent files found under plugins/*/agents/, the installed plugin cache, or .claude/agents/ — routing accuracy not measured"]}` Read each file listed in `roster-files.txt`. Per file, extract `name:` and `description:` from YAML frontmatter (between `---` delimiters). Roster entries must carry the **dispatch name**, not the bare frontmatter `name:` — that's what `expected_agent` and every selector answer are matched against: for `plugins/<dir>/agents/<n>.md` and cache `<plugin>/<ver>/agents/<n>.md`, use `<plugin>:<n>` (strip any leading `cc_` from `<dir>`); for `.claude/agents/<n>.md`, use bare `<n>`. Same dispatch name from more than one tier: keep `.claude/` entry, else source-tree entry. Build roster string, one line per agent: ```text <dispatch-name>: <description> ``` Write roster to `.reports/calibrate/<TIMESTAMP>/routing/roster.txt`. ### Phase 2 — Generate routing problems Generate `<N>` synthetic task prompts across all agents. Per problem, produce JSON with these fields: - `problem_id`: kebab-slug string - `task_prompt`: realistic user request to orchestrator (no hint at expected agent) - `expected_agent`: correct `subagent_type` from roster (or `"general-purpose"` if no specialist needed) - `difficulty`: `"easy"` (single-domain, obvious match), `"medium"` (2 domains, one primary), `"hard"` (ambiguous, requires NOT-for clauses or fine distinctions) - `confusion_pair`: most likely wrong agent for medium/hard; `null` for easy - `auto_invoke_test`: `true` if problem tests TRIGGER or SKIP-guard coverage; `false` otherwise Rules: - Cover every agent ≥1 in `expected_agent` (distribute evenly given N) - Include ≥2 hard problems testing high-overlap pairs: e.g., sw-engineer vs qa-specialist, doc-scribe vs oss:shepherd, linting-expert vs sw-engineer, solution-architect vs sw-engineer, web-explorer vs sw-engineer (look up docs to implement vs implement directly), challenger vs sw-engineer (critique plan vs implement), oss:analyse vs oss:review (analyze thread vs code review) - Include exactly 1 `expected_agent: "general-purpose"` problem (general question, no specialist) - Difficulty distribution: ~40% easy, ~40% medium, ~20% hard (adjust to cover all agents) - **Auto-invocation coverage**: include ≥3 problems where `task_prompt` uses exact TRIGGER phrasing for an agent with a TRIGGER block (e.g. "what does the requests docs say about retries", "write tests for the auth module", "add docstrings to utils.py") — these are easy/medium; the TRIGGER phrase is the signal - **SKIP-guard coverage**: include ≥2 problems where `task_prompt` superficially resembles a TRIGGER but a SKIP guard applies — `expected_agent` must be `"general-purpose"` or a different specialist, NOT the TRIGGER agent; add field `"skip_guard_test": true` to these problems - Add boolean field `"auto_invoke_test": true` to problems covering TRIGGER/SKIP scenarios - Return valid JSON array only (no prose) Write JSON array to `.reports/calibrate/<TIMESTAMP>/routing/problems.json`. ### Phase 3 — Run routing selection (parallel) Read roster from `.reports/calibrate/<TIMESTAMP>/routing/roster.txt`. Per problem in `problems.json`, spawn `general-purpose` selector subagent. Issue ALL spawns in **single response** — no waiting between spawns. Each selector gets this prompt (substitute `<ROSTER>`, `<TASK_PROMPT>`, `<PROBLEM_ID>`, `<RUN_DIR>`): > Select specialized agent for task. Available agents: > > ``` > <ROSTER> > ``` > > Task: `<TASK_PROMPT>` > > Select one agent. If no specialist fits, select `general-purpose`. > > Write response to `<RUN_DIR>/selection-<PROBLEM_ID>.md` via Write tool. File must contain ONLY valid JSON (no prose): > > `{"selected":"<agent-name>","reasoning":"<one sentence>"}` > > Then end reply with exactly one line: `Wrote: <PROBLEM_ID>` **Context discipline**: subagents write to disk, return single-line ack. Pipeline agent must NOT accumulate full analyses — scorers read from disk in Phase 3. `Wrote: <PROBLEM_ID>` per agent correct. **Completion handling** — spawns are blocking `Agent()` calls, so no poll loop is possible (`_FOUNDRY_SHARED/agent-spawn-protocol.md` §Synchronous spawns). Each subagent returns: check for `selection-<PROBLEM_ID>.md`; missing: mark that problem `{"selected":null,"timed_out":true}` with ⏱ in report. ### Phase 4 — Score <!-- Design note: N=5/10, selection files tiny (~100 bytes), under 2K inline threshold. Inline reading intentional. If N>~20, refactor Phase 4 to use consolidator subagent. --> Per problem, read `selection-<problem_id>.md` from `.reports/calibrate/<TIMESTAMP>/routing/`. Parse JSON, extract `selected` and `reasoning`. Compare vs `expected_agent` from `problems.json`: - `selected` == `expected_agent` → `correct: true`, `error_type: null` - `selected` == `confusion_pair` → `correct: false`, `error_type: "confusion"` - Other mismatch → `correct: false`, `error_type: "wrong"` - `timed_out: true` → `correct: false`, `error_type: "timeout"` Compute aggregates: - `routing_accuracy` = correct_count / total_count - `confusion_rate` = confusion_error_count / total_count - `hard_accuracy` = correct hard / total hard (omit if no hard problems) - `auto_invoke_accuracy` = correct on `auto_invoke_test: true` problems / total `auto_invoke_test: true` problems (omit if no such problems) - Confusion list: per incorrect selection, record `(expected → selected, task_prompt, reasoning)` Verdict: - `routing_accuracy ≥ 0.90` AND `hard_accuracy ≥ 0.80` → `calibrated` - `routing_accuracy ≥ 0.80` but below threshold OR `hard_accuracy < 0.80` → `borderline` - `routing_accuracy < 0.80` → `needs-improvement` The Write tool refuses any file whose exact basename is `report.md` from a subagent context — use `benchmark-report.md` instead. Write full report to `.reports/calibrate/<TIMESTAMP>/routing/benchmark-report.md`: ```markdown ## Routing Benchmark — <date> — <MODE> ### Per-Problem Results | Problem ID | Difficulty | Expected | Selected | Correct | |------------|------------|----------|----------|---------| | ... ### Aggregate | Metric | Value | Status | |------------------|-----------|--------| | Routing accuracy | X/N (XX%) | ≥90% ✓ / 80–90% ~ / <80% ⚠ | | Hard accuracy | X/N (XX%) | ≥80% ✓ / <80% ⚠ | | Confusion errors | N | 0 ✓ / >0 list pairs | | Auto-invoke accuracy | X/N (XX%) | ≥90% ✓ / <90% ⚠ (auto_invoke_test problems only) | ### Confused Pairs | Task Prompt | Expected → Selected | Reasoning | |-------------|---------------------|-----------| | ... (omit this section if no confusion errors) ### Proposals For each confused pair: suggest specific wording improvements to the relevant agent descriptions that would disambiguate the routing decision. Reference the NOT-for clause pattern when applicable — adding "NOT for X" to one agent in the pair is often the minimal effective fix. ``` Write result JSONL to `.reports/calibrate/<TIMESTAMP>/routing/result.jsonl`: `{"ts":"<TIMESTAMP>","target":"routing","mode":"<MODE>","routing_accuracy":0.N,"confusion_rate":0.N,"hard_accuracy":0.N,"auto_invoke_accuracy":0.N,"problems":<N>,"verdict":"calibrated|borderline|needs-improvement|incomplete","confused_pairs":["expected→selected",...]}` ### Return value Return **only** compact JSON (no prose): `{"target":"routing","routing_accuracy":0.N,"confusion_rate":0.N,"hard_accuracy":0.N,"auto_invoke_accuracy":0.N,"problems":<N>,"verdict":"calibrated|borderline|needs-improvement|incomplete","confused_pairs":["expected→selected",...]}` -
rules-pipeline-prompt.md 11.7 KB
Rules calibration pipeline runner for rule file `<RULE_BASENAME>`. Complete all phases in sequence. <!-- Substitutions before spawning: RULE_BASENAME=filename (e.g. commit-and-git.md), RULE_CONTENT=full rule file text verbatim, TIMESTAMP=YYYY-MM-DDTHH-MM-SSZ, MODE=fast|full, N=_tasks per directive (fast=3, full=5), IS_PATH_SCOPED=true|false (true if rule has a non-empty paths: frontmatter field) --> <!-- Derive RULE_DIR before spawning: RULE_DIR="${RULE_BASENAME%.md}" (strips .md extension — used as the run directory name to avoid permission-matcher conflicts with .md-suffixed paths) --> Mode: `<MODE>` Run dir: `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/` ```bash mkdir -p .reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/ ``` **Rule under test** (loaded as context for all Phase 2 agents): ```text <RULE_CONTENT> ``` ### Phase 1 — Extract directives and generate problems **Step 1a — Extract directives**: identify 2–3 key directives from rule content above. Key directive = specific, action-prescribing sentence in imperative mood with concrete, observable required behaviour (e.g. `"Never use git add -A"`, `"Always append a Legend block after any results table"`). Skip section headers, explanatory prose, context-setting sentences. Write to `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/directives.json`: ```json [ { "directive_id": "dir-1", "text": "<directive text verbatim>", "expected_behavior": "<observable property of a compliant response — what must be present or absent>" } ] ``` **Step 1b — Generate adherence problems** (`<N>` per directive): for each directive, create `<N>` tasks where correct response MUST apply directive, ignoring it produces detectably wrong result. Cover realistic user requests; vary surface form across `<N>` problems per directive. Problem format: ```json { "problem_id": "<rule-basename-without-extension>-dir-1-1", "type": "adherence", "directive_id": "dir-1", "task_prompt": "<realistic user request>", "context": "<additional context the agent needs, or empty string>", "expected_behavior": "<what a compliant response must show or avoid>" } ``` **Step 1c — Generate trigger problems** (only if `<IS_PATH_SCOPED>` is `true`): for each `paths:` glob pattern in rule frontmatter, generate 2 problems: - One with **matching** file context (`expected_trigger: true`) — rule should be active - One with **non-matching** file context (`expected_trigger: false`) — rule should stay silent ```json { "problem_id": "<rule-basename-without-extension>-trigger-1", "type": "trigger", "file_context": "<filename with extension, e.g. main.py>", "expected_trigger": true, "task_prompt": "Working on `<file_context>`: <generic task that the rule could apply to>" } ``` Write all problems to `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/problems.json` as JSON array. ### Phase 2 — Run tasks (parallel) Spawn one `general-purpose` subagent per problem. **Issue ALL spawns in single response — no waiting between spawns.** Each subagent receives this prompt (substitute `<PROBLEM_ID>`, `<TASK_PROMPT>`, `<CONTEXT>`, `<RUN_DIR>` before spawning): <!-- BEGIN SPAWN PROMPT --> General-purpose coding assistant. Following rule is in effect — apply it in your response: ```text <RULE_CONTENT> ``` Task: `<TASK_PROMPT>` `<CONTEXT>` Write complete response to `<RUN_DIR>/response-<PROBLEM_ID>.md` using Write tool. End reply with exactly one line: `Wrote: <PROBLEM_ID>` <!-- END SPAWN PROMPT --> **Context discipline**: subagents write to disk, return single-line acknowledgment. Pipeline agent must NOT accumulate their full analyses in context — scorers read from disk in Phase 3. Receiving only `Wrote: <PROBLEM_ID>` per agent is correct, expected. **Completion handling** — spawns are blocking `Agent()` calls, so no poll loop is possible (`_FOUNDRY_SHARED/agent-spawn-protocol.md` §Synchronous spawns). Each subagent returns: check for `response-<PROBLEM_ID>.md`; missing: mark that problem `{"timed_out": true}` in scores.json, proceed. ### Phase 3 — Score (parallel scorer subagents) Spawn one `general-purpose` scorer per problem. **Issue ALL spawns in single response.** Each scorer receives this prompt (substitute `<PROBLEM_ID>`, `<PROBLEM_TYPE>`, `<DIRECTIVE_TEXT>`, `<EXPECTED_BEHAVIOR>`, `<EXPECTED_TRIGGER>`, `<RUN_DIR>` before spawning): <!-- BEGIN SPAWN PROMPT --> Scoring rule compliance test. Read response from `<RUN_DIR>/response-<PROBLEM_ID>.md` using Read tool. **Problem type**: `<PROBLEM_TYPE>` **[For adherence problems]** Directive under test: `<DIRECTIVE_TEXT>` Expected behavior: `<EXPECTED_BEHAVIOR>` Score on two dimensions: 1. **Directive outcome** — assign exactly one of: - `correct` — directive applied; expected behavior present in response - `missed` — response otherwise reasonable but directive ignored - `misapplied` — wrong directive applied, or directive applied where it should not be 2. **Outcome correctness** — beyond whether directive was mentioned or acknowledged, check whether response's *actual content* (commands used, flags omitted, files listed, patterns followed) satisfies directive's intent: - `true` — behavioral output correct, not just stated intent - `false` — agent says it will follow rule but concrete output violates it (e.g. says "I'll stage specific files" then writes `git add -A`) Return ONLY this JSON (no prose): `{"problem_id":"<PROBLEM_ID>","type":"adherence","outcome":"correct|missed|misapplied","outcome_correct":true|false,"reasoning":"<one sentence>"}` **[For trigger problems]** Expected trigger: `<EXPECTED_TRIGGER>` Determine whether rule's directives visible in response: - `triggered: true` — rule clearly active (response applies or references rule's constraints) - `triggered: false` — response shows no sign of rule being active Return ONLY this JSON (no prose): `{"problem_id":"<PROBLEM_ID>","type":"trigger","triggered":true|false,"expected_trigger":<EXPECTED_TRIGGER>,"correct":true|false,"reasoning":"<one sentence>"}` <!-- END SPAWN PROMPT --> Collect all scorer compact JSONs. Write to `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/scores.json` as JSON array. ### Phase 4 — Aggregate and write report Compute aggregates from `scores.json`: **Adherence** (type == "adherence" problems only): - Per directive: `adherence_recall_dir_N` = correct_count / total tasks for that directive - `mean_adherence_recall` = mean across all directives - `outcome_correctness` = outcome_correct_count / correct_count (N/A if correct_count = 0) - `misapplied_rate` = misapplied_count / total adherence tasks **Trigger fidelity** (type == "trigger" problems, skip if none): - `trigger_recall` = (triggered=true AND expected=true) / total expected=true problems - `trigger_precision` = (triggered=false AND expected=false) / total expected=false problems **Verdict**: - `mean_adherence_recall ≥ 0.8` AND `outcome_correctness ≥ 0.8` → `calibrated` - `mean_adherence_recall ≥ 0.8` AND `outcome_correctness < 0.8` → `outcome-gap` (directive followed in word, not in effect) - `mean_adherence_recall < 0.8` → `under-enforced` The Write tool refuses any file whose exact basename is `report.md` from a subagent context — use `benchmark-report.md` instead. Write full report to `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/benchmark-report.md`: ```markdown ## Rules Benchmark — <RULE_BASENAME> — <date> Mode: <MODE> | Directives: D | Adherence tasks: D×N | Trigger tests: T (or 0 if global rule) ### Per-Directive Results | Directive (truncated) | Adherence Recall | Outcome Correct | Misapplied | Status | |-----------------------|-----------------|----------------|------------|-----------| | Never git add -A | 0.89 | 0.90 | 0 | ✓ | | Always append legend | 0.67 ⚠ | — | 1 | ⚠ | *Legend: Adherence Recall — directive followed / total tasks (0–1, higher is better, ≥0.8 target). Outcome Correct — fraction of "correct" scores where actual output also matched expected behavior, not just stated intent (0–1, higher is better, ≥0.8 target). Misapplied — tasks where wrong directive was applied (lower is better; ≥1 suggests ambiguous wording). Status: ✓ calibrated | ⚠ under-enforced.* ### Trigger Fidelity (path-scoped rules only — omit section if global) | Metric | Value | Status | |-------------------|-------|----------------------| | Trigger recall | 0.XX | ≥0.95 ✓ / <0.95 ⚠ | | Trigger precision | 0.XX | ≥0.95 ✓ / <0.95 ⚠ | *Legend: Trigger recall — rule fired on all matching-path contexts (0–1, higher is better, ≥0.95 target). Trigger precision — rule stayed silent on non-matching contexts (0–1, higher is better, ≥0.95 target).* ### Aggregate | Metric | Value | Status | |----------------------|-------|-----------------------| | Adherence recall | 0.XX | ≥0.80 ✓ / <0.80 ⚠ | | Outcome correctness | 0.XX | ≥0.80 ✓ / <0.80 ⚠ | | Misapplied rate | 0.XX | 0 ✓ / >0 ⚠ | | Verdict | | calibrated / outcome-gap / under-enforced | *Legend: Adherence recall — mean fraction of tasks where directive was applied across all directives (0–1, higher is better, ≥0.80 threshold). Outcome correctness — mean fraction of applied directives that also produced the correct behavioral output (0–1, higher is better, ≥0.80 target). Misapplied rate — fraction of tasks where wrong directive applied (0–1, lower is better, 0 = ideal).* ### Systematic Gaps <missed directives or outcome failures recurring in ≥2 problems> ### Wording Improvement Opportunities <for under-enforced directives: original text and suggested rewording> ``` Write result JSONL to `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/result.jsonl`: `{"ts":"<TIMESTAMP>","target":"rules/<RULE_BASENAME>","mode":"<MODE>","mean_adherence_recall":0.N,"outcome_correctness":0.N,"misapplied_rate":0.N,"trigger_recall":0.N,"trigger_precision":0.N,"problems":<N>,"verdict":"calibrated|outcome-gap|under-enforced","gaps":["..."]}` Use `null` for `trigger_recall`/`trigger_precision` when `IS_PATH_SCOPED` is `false`. ### Phase 5 — Propose wording improvements Spawn **foundry:curator** subagent using Agent tool. Pass only file paths — do NOT paste file contents into prompt: > Read these files using Read tool: > > 1. Rule file: `.claude/rules/<RULE_BASENAME>` > 2. Benchmark report: `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/benchmark-report.md` — focus on Systematic Gaps and Wording Improvement Opportunities sections > > For each under-enforced or outcome-gap directive, propose minimal rewording making directive more specific, action-prescribing, unambiguous. Keep surrounding context unchanged. If all directives calibrated, write: `## Proposed Changes — <RULE_BASENAME>\n\nNo changes needed — all directives calibrated.` > > Format each change as: > > ``` > ## Proposed Changes — <RULE_BASENAME> > > ### Change N: <directive summary> > **File**: `.claude/rules/<RULE_BASENAME>` > **Current**: [exact verbatim text] > **Proposed**: [exact replacement] > **Rationale**: one sentence — what failure mode this prevents > ``` > > Write to `.reports/calibrate/<TIMESTAMP>/rules/<RULE_DIR>/proposal.md`. End with `## Confidence` block per CLAUDE.md output standards. ### Return value Return **only** this compact JSON (no prose before or after): `{"rule":"<RULE_BASENAME>","mean_adherence_recall":0.N,"outcome_correctness":0.N,"misapplied_rate":0.N,"trigger_recall":0.N,"trigger_precision":0.N,"problems":<N>,"verdict":"calibrated|outcome-gap|under-enforced","gaps":["..."],"proposed_changes":N}` Use `null` for `trigger_recall`/`trigger_precision` when `IS_PATH_SCOPED` is `false`.
-
-
SKILL.md 45.2 KB
--- name: calibrate description: Calibration testing for agents and skills. Generates synthetic problems with known outcomes (quasi-ground-truth), runs targets against them, measures recall, precision, confidence calibration — reveals whether self-reported confidence scores track actual quality. argument-hint: '[<scope>...] [--fast | --full] [--ab-test | --apply] [--skip-gate] [--local] [--keep "<items>"]' effort: high disable-model-invocation: true allowed-tools: Read, Write, Bash, Agent, Glob, TaskCreate, TaskUpdate, TaskList, AskUserQuestion --- <objective> Validate agents and skills by measuring outputs against synthetic problems with defined ground truth. Primary signal: **calibration bias** — gap between self-reported confidence and actual recall. Well-calibrated agent reports 0.9 when it finds ~90% of issues. Miscalibrated: reports 0.9, finds 60%. Calibration data drives improvement loop: systematic gaps: instruction updates; persistent overconfidence: adjusted re-run thresholds in MEMORY.md. NOT for: static routing overlap analysis (use /foundry:audit); manually reviewing skill output quality (use /develop:review (requires `develop` plugin)). </objective> <inputs> - **$ARGUMENTS**: parse `--flags` first, then resolve remaining tokens as scope targets **Flags** (order independent): - `--fast` — 3 problems per target (default when neither pace flag passed) - `--full` — 10 problems per target; mutually exclusive with `--fast` - `--ab-test` — also run `general-purpose` baseline and report delta metrics; requires benchmark (default `--fast` if no pace flag); mutually exclusive with `--apply` - `--apply` — apply proposals: with `--fast`/`--full`: run benchmark then immediately apply; without pace flag: skip benchmark, apply proposals from most recent past run; mutually exclusive with `--ab-test` - `--skip-gate` — suppress follow-up gate; for programmatic callers - `--local` — resolve target agent/skill files from source tree (`plugins/*/`) instead of installed plugin cache; for plugin-dev workflows where local edits aren't yet installed; sets `LOCAL_MODE=true` in all pipeline spawns **Mutual exclusion validation** (check before any work): - `--ab-test` + `--apply` together: hard error: "`--ab-test` and `--apply` are mutually exclusive. Pass one or neither." - `--fast` + `--full` together: hard error: "Pass `--fast` or `--full`, not both." - `--ab-test` without pace flag: default `--fast` silently (no error) **Unsupported flag check** — after all supported flags extracted (`--fast`, `--full`, `--ab-test`, `--apply`, `--skip-gate`, `--local`, `--keep`), scan `$ARGUMENTS` for remaining `--<token>` tokens. Found: print `` ! Unknown flag(s): `--<token>`. Supported: `--fast`, `--full`, `--ab-test`, `--apply`, `--skip-gate`, `--local`, `--keep`. `` then invoke `AskUserQuestion` — (a) **Abort** (stop, re-invoke with correct flags) · (b) **Continue ignoring** (skip unknown flags, proceed). On Abort: stop. **Legacy positional tokens** (`ab`, `apply`, `fast`, `full`) — **hard error**: print migration hint, stop. Example: "`ab` removed — use `--ab-test` flag: `/calibrate curator --ab-test`." **Scope tokens** (positional, space-separated — defaults to `all`): - `all` — all agents + relevant skills + routing + communication + all rules - `agents` — all agents only (full agent list in `modes/agents.md`) - `skills` — calibratable skills only (`/audit` and others per `modes/skills.md`; `/oss:review` (requires `oss` plugin) excluded — requires live GitHub PR) - `routing` — routing accuracy test: measures how accurately `general-purpose` orchestrator selects correct `subagent_type` for synthetic task prompts (not per-agent quality benchmark; included in `all`) - `communication` — handover + team protocol compliance: runs `foundry:curator` against synthetic agent responses and team transcripts with injected protocol violations (missing JSON envelope, missing `summary`, AgentSpeak v2 breaches); included in `all` - `rules` — rule adherence test: for each global rule file (no `paths:`) and each path-scoped rule when matching file is in context, generates synthetic tasks that should trigger rule's key directives, measures whether `general-purpose` agent with rule loaded correctly applies them; reports rules that are ignored, misapplied, or redundant; included in `all` - `plugins` — all agents + calibratable skills from all `plugins/*/` directories (union of all plugin-namespaced agents and calibratable skills) - `<plugin-name>` — **tier 2**: bare plugin directory name (e.g. `oss`, `foundry`, `research`, `develop`) auto-resolved when token matches `plugins/<name>/` directory; calibrates all agents + calibratable skills in that plugin - `<agent-name>` — **tier 3**: single agent (e.g., `foundry:sw-engineer`); also accepts bare name (e.g. `sw-engineer`) and resolves via `plugins/*/agents/<name>.md` - `/foundry:audit` — single skill (pass any calibratable skill name; `/oss:review` (requires `oss` plugin) accepted but excluded per `modes/skills.md`) - Multiple scope tokens — space-separated; calibrates union of resolved targets: `oss research`, `agents skills`, `curator shepherd`; each token resolved through same tier hierarchy as `/audit` scope tokens (reserved keywords first, then plugin-dir lookup, then agent/skill file search) Every invocation surfaces report: benchmark runs print new results; `--apply` without pace flag prints saved report from last run before applying. </inputs> <constants> - FAST_N: 3 problems per target - FULL_N: 10 problems per target - RECALL_THRESHOLD: 0.70 (below → agent needs instruction improvement) - CALIBRATION_BORDERLINE: ±0.10 (|bias| within this → calibrated; between 0.10 and 0.15 → borderline) - CALIBRATION_WARN: ±0.15 (bias beyond this → confidence decoupled from quality) - CALIBRATE_LOG: `.notes/logs/calibrations.jsonl` (legacy `.claude/logs/calibrations.jsonl` read-only fallback for historical entries) - AB_ADVANTAGE_THRESHOLD: 0.10 (delta recall or F1 above this → meaningful advantage; below → marginal or none) - PHASE_TIMEOUT_MIN: 5 (per-phase budget — if spawned subagents haven't all returned, collect partial results and continue) - PIPELINE_TIMEOUT_MIN: 10 (hard cutoff — pipeline not notified within 10 min of launch is timed out; extendable if agent explains delay) # tighter than global 15-min cutoff from CLAUDE.md §6 — intentional for calibrate - PIPELINE_BATCH_SIZE: 5 when one mode category runs alone, 2 while two categories are in flight (max agent/skill pipeline subagents spawned concurrently within one mode — prevents agent count explosion on `all`; batch: spawn ≤ that many, wait for all results, then spawn next batch; halving keeps peak concurrency at 4 ≤ 5 when paired) - ROUTING_ACCURACY_THRESHOLD: 0.90 (below → agent descriptions need improvement) # keep in sync with modes/routing.md - ROUTING_HARD_THRESHOLD: 0.80 (below → high-overlap pair descriptions need disambiguation) - SPAWN_GATE_THRESHOLD: 50 (spawn estimate = target-count × N; above this, large-fan-out gate fires before Step 2 even when `--apply` is set — only `--skip-gate` bypasses) <!-- Problem-set version 1.0 — bump when calibration problem set is refreshed (CODEX_PROBLEM_RATIO, CODEX_SCORER_WEIGHT, threshold defaults). Canonical source: this constants block + the per-mode problem fixtures under modes/*.md. Update version line below whenever any constant or fixture changes so historical calibrations.jsonl entries can be filtered by version. --> - PROBLEM_SET_VERSION: 1.0 - CODEX_PROBLEM_RATIO: 0.6 (fraction of in-scope problems generated by Codex — agents/skills modes only) - CODEX_SCORER_WEIGHT: 0.49 (Codex scorer weight; Claude = 0.51 — Claude has last word on disagreements) - SCORER_AGREEMENT_WARN: 0.70 (scorer agreement below this → flag ambiguous ground truth ⚠) - CODEX_MODES: ["agents", "skills"] (modes where Codex is active; routing/communication/rules excluded — test Claude-specific internals) - PIPELINE_TIMEOUT_MIN_DUAL: 15 (hard cutoff when Codex active — replaces PIPELINE_TIMEOUT_MIN=10 for dual-source runs) Domain tables per mode: see `modes/agents.md`, `modes/skills.md`, `modes/routing.md`, `modes/communication.md`, `modes/rules.md`. </constants> <compaction> - Key boundary 1: after Step 2 pipeline fan-out (all mode pipelines spawned), before Step 3 collect+synthesize. - Preserve at boundary 1: TIMESTAMP, run-dir (.reports/calibrate/<TIMESTAMP>/), target list, LOCAL_MODE. - Terminal paths: end of Step 5 (no-apply path) and end of Step 6 (apply path). </compaction> <workflow> **Task hygiene**: load and follow the protocol below. ```bash # loads: compaction-contract.md # audit-skip: resilience-replication — duplicated; plugin cannot self-locate cat "$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_shared_path.py" foundry skills/_shared 2>/dev/null || echo "plugins/cc_foundry/skills/_shared")/task-hygiene.md" ``` **Task tracking**: create tasks at start of execution (Step 1) for each phase that will run: - "Calibrate agents" — Step 2 (benchmark mode, when target includes agents) - "Calibrate skills" — Step 2 (benchmark mode, when target includes skills) - "Calibrate routing" — Step 2 (benchmark mode, when target includes routing) - "Calibrate communication" — Step 2 (benchmark mode, when target includes communication) - "Calibrate rules" — Step 2 (benchmark mode, when target includes rules) - "Analyse and report" — Steps 3–5 (benchmark mode) - "Apply findings" — Step 6 (apply mode only) **Task marking discipline**: create ALL category tasks as `pending` at the start (before any pipeline spawns). Mark a task `in_progress` only immediately before spawning its pipeline. Mark it `completed` immediately after collecting its results. Never mark more than one category task `in_progress` simultaneously — misrepresents execution state. On loop retry or scope change, create new task. ## Step 1: Parse targets and create run directory From `$ARGUMENTS`, determine: - **Strip flags first**: extract `--fast`, `--full`, `--ab-test`, `--apply`, `--skip-gate`, `--local`, `--keep` before scope resolution; validate mutual exclusion (error and stop on conflict). Strip all flags from ARGUMENTS before scope token resolution: ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/extract-keep-flag.py" calibrate-state "$ARGUMENTS" --out-file "${TMPDIR:-/tmp}/calibrate-state-${CSID}/keep-items" # timeout: 5000 — parses --keep, clears stale contract, makes state dir eval "$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/parse-skill-flags.py" --flags fast,full,ab-test,apply,skip-gate,local "$ARGUMENTS")" # timeout: 5000 LOCAL_MODE="$FLAG_LOCAL" ARGUMENTS="$CLEAN_ARGS" mkdir -p "${TMPDIR:-/tmp}/calibrate-state-${CSID}" echo "$LOCAL_MODE" > "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" ``` - **Target list** — remaining tokens after flag-strip; union of resolved targets: - `all` or omitted → all agents + `/audit` + routing + communication + all rules - `agents` → all agents (full agent list in `modes/agents.md`) - `skills` → `/audit` only (and other non-live-PR skills in `modes/skills.md`; `/oss:review` (requires `oss` plugin) excluded) - `routing` → routing accuracy test only - `communication` → handover + team protocol compliance only - `rules` → rule adherence test (all rule files in `.claude/rules/`) only - `plugins` → all agents + calibratable skills from all `plugins/*/` directories - `<plugin-name>` matching `plugins/<name>/` directory → tier 2: all agents + calibratable skills in that plugin - Any other token → tier 3: single agent or skill name; search `plugins/*/agents/<name>.md`, `.claude/agents/<name>.md`, `plugins/*/skills/<name>/SKILL.md`, `.claude/skills/<name>/SKILL.md`; error if no match - Multiple tokens → union: e.g. `oss research`, `curator shepherd`; each resolved independently **Empty resolution guard**: after resolving all scope tokens to target list, list empty (e.g. plugin matched but contains no calibratable agents/skills, such as `/calibrate codemap`): stop with: ```text ! No calibratable agents/skills found for scope: <input-scope> Verify: (a) plugin name spelled correctly, (b) plugin has agents/*.md or calibratable skills (see modes/skills.md domain table) ``` Do not proceed to Step 2 — silent no-op produces no report and confuses callers. - **Pace**: `--full`: 10 problems; `--fast`: 3 problems; neither: default `--fast` - **A/B flag**: `--ab-test`: also spawn `general-purpose` baseline per problem - **Apply flag**: - `--apply` without pace flag: pure apply mode: skip Steps 2–5, go to Step 6 - `--apply` with `--fast`/`--full`: benchmark + auto-apply: run Steps 2–5 then continue to Step 6 Benchmark will run (i.e. `--fast` or `--full` present, with or without `--apply`): generate timestamp `YYYY-MM-DDTHH-MM-SSZ` (UTC, e.g. `2026-03-03T13-44-48Z`) explicitly via Bash tool, persist for downstream steps (fresh-shell state loss between Bash() calls): ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" TIMESTAMP=$(date -u +%Y-%m-%dT%H-%M-%SZ) echo "Calibration timestamp: $TIMESTAMP" mkdir -p "${TMPDIR:-/tmp}/calibrate-state-${CSID}" echo "$TIMESTAMP" > "${TMPDIR:-/tmp}/calibrate-state-${CSID}/timestamp" ``` Every subsequent Bash block in Steps 2–6 that uses `$TIMESTAMP` must re-read it at the top of the block: ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r TIMESTAMP < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/timestamp" 2>/dev/null || TIMESTAMP="" [ -z "$TIMESTAMP" ] && { echo "! TIMESTAMP state lost — re-invoke /foundry:calibrate"; exit 1; } # never fall back to $(date ...) — generates new timestamp → nonexistent run dir; surface state loss explicitly ``` All run dirs use this timestamp. **Large fan-out gate** — after target list resolves (and before any task creation or pipeline spawn), when `--skip-gate` not passed: - **Skip entirely** in pure-apply mode (`--apply` without a pace flag) — zero pipelines spawn in this mode (routes straight to Step 6), so no confirmation needed. - **Mode-category scopes** (`all`, `agents`, `skills`, `plugins`) — target list here is mode categories, not yet expanded to individual agent/skill files (expansion happens inside Step 2's mode files, per mode-file table below). An exact spawn count isn't knowable at this point — these scopes routinely expand to dozens of agent/skill pipelines. Gate **always fires** whenever a benchmark pace flag is set (`--fast` or `--full`), independent of any count. - **Tier-2 plugin scopes** (`<plugin-name>`) — one plugin's contents are countable here without entering Step 2, by the same globs the Step 2 dispatch table uses: `SPAWN_ESTIMATE = (files matching plugins/<name>/agents/*.md + files matching plugins/<name>/skills/*/SKILL.md) × (FULL_N if --full else FAST_N)`. The skill term is an upper bound — `modes/skills.md` excludes some — so the estimate over-counts, which fires the gate more often, never less; keep it that way rather than "correcting" it. Gate fires only when `SPAWN_ESTIMATE > SPAWN_GATE_THRESHOLD`. - **Tier-3 single-target scopes** (`<agent-name>`, `<skill-name>`) — target list is already a concrete file (or small union of files), so count is exact here: `SPAWN_ESTIMATE = <resolved-target-count> × (FULL_N if --full else FAST_N)`. Gate fires only when `SPAWN_ESTIMATE > SPAWN_GATE_THRESHOLD`. When gated (either branch), fire **even when `--apply` is set together with a pace flag** — `--apply` only skips Step 3 proposal-review gate, not this one. Call `AskUserQuestion`: - Mode-category scopes: question: "`<scope>` expands to dozens of agent/skill pipelines × `<N_PROBLEMS>` problems each — potentially 100+ spawns. Proceed?" - Counted scopes (tier-2 `<plugin-name>`, tier-3 `<agent-name>`/`<skill-name>`): question: "This run resolves to `<N>` targets × `<N_PROBLEMS>` problems ≈ `<SPAWN_ESTIMATE>` pipeline spawns. Proceed?" - (a) label: `Proceed` — description: run as specified - (b) label: `Switch to --fast` — description: re-run with `--fast` instead of `--full` (lowers spawn count ~3.3×) — **omit this option when pace is already `--fast`/default**; two-option menu (Proceed / Abort) in that case - (c) label: `Abort` — description: stop; narrow scope and re-invoke On Abort: stop immediately — no tasks created, no spawns. On Switch to --fast: replace pace flag with `--fast` (mode-category scopes still always-fire at `--fast`; tier-2 and tier-3 recompute `SPAWN_ESTIMATE`, and a recomputed estimate at or below `SPAWN_GATE_THRESHOLD` proceeds without re-asking), continue to task creation. Create tasks before proceeding: - Benchmark only (no `--apply`): TaskCreate "Calibrate agents" (if target includes agents), TaskCreate "Calibrate skills" (if target includes skills), TaskCreate "Calibrate routing" (if target includes routing), TaskCreate "Calibrate communication" (if target includes communication), TaskCreate "Calibrate rules" (if target includes rules), TaskCreate "Analyse and report" — all created as `pending`; do NOT mark any `in_progress` yet - Benchmark + auto-apply (`--fast`/`--full` + `--apply`): TaskCreate "Calibrate agents" (if target includes agents), TaskCreate "Calibrate skills" (if target includes skills), TaskCreate "Calibrate routing" (if target includes routing), TaskCreate "Calibrate communication" (if target includes communication), TaskCreate "Calibrate rules" (if target includes rules), TaskCreate "Analyse and report", TaskCreate "Apply findings" — all created as `pending`; do NOT mark any `in_progress` yet - Pure apply mode (only `--apply`, no pace flag): TaskCreate "Apply findings" only ## Step 2: Spawn pipeline subagents > **Pre-flight**: mode files at `<plugin-cache>/foundry/<v>/skills/calibrate/modes/` — resolve via plugin cache scan below. > > `/foundry:setup` does NOT symlink these (only `rules/*.md` and `TEAM_PROTOCOL.md`); if not found, re-install foundry plugin. > > ```bash > export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" > IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" > CALIB_MODES_DIR=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate modes $([ "$LOCAL_MODE" = "true" ] && echo --local)) # timeout: 5000 > ``` > > **Gate**: if the bash block above failed (non-zero exit or `$CALIB_MODES_DIR` empty) — stop immediately; do not proceed to pipeline spawns. Print: `! calibrate/modes/ directory not found — re-install foundry plugin then retry.` For each target mode in resolved target list, read corresponding mode file, execute spawn instructions. **At most 2 mode categories in flight at once**, and only with `$PIPELINE_BATCH_SIZE` halved to **2** (floor of 5÷2) for as long as two run concurrently. Rationale: the constraint being protected is peak agent count and context, not ordering — two categories at batch 2 peak at 4 concurrent pipelines, below the 5 a single category reaches on its own, so resource ceiling is unchanged while wall-clock on `all` drops. Everything else stays serial: never issue a third category's spawns while two are running, never restore batch size 5 until one of the two has fully returned its results. **Execution order for `all`**: agents → skills → routing → communication → rules, run as pairs in that order — (agents + skills), (routing + communication), then rules alone at batch 5. For each pair: 1. **Guard** — call `TaskList`; a category task (agents/skills/routing/communication/rules) is `in_progress` but its mode is **not** one of the categories currently in flight: call `TaskUpdate(that_task_id, completed)` before proceeding — corrects a missed completed call from a prior iteration. Never complete the task of a category still running: with two in flight, two category tasks are legitimately `in_progress`. 2. Mark both in-flight modes' tasks `in_progress` (all others stay `pending`) 3. Spawn pipelines for both modes with `$PIPELINE_BATCH_SIZE` = 2 (= 5 when a category runs alone — see constants) 4. Wait for all batch results from both modes before proceeding 5. Mark each mode's task `completed` as its own results arrive 6. Only then start the next pair | Target mode | Mode file | Task to mark in_progress | | -- | -- | -- | | agents | `$CALIB_MODES_DIR/agents.md` | "Calibrate agents" | | skills | `$CALIB_MODES_DIR/skills.md` | "Calibrate skills" | | routing | `$CALIB_MODES_DIR/routing.md` | "Calibrate routing" | | communication | `$CALIB_MODES_DIR/communication.md` | "Calibrate communication" | | rules | `$CALIB_MODES_DIR/rules.md` | "Calibrate rules" | | plugins or `<plugin-name>` (tier 2) | expand to per-agent + per-skill pipelines: glob `plugins/<name>/agents/*.md` and calibratable `plugins/<name>/skills/*/SKILL.md`; spawn one pipeline per resolved target using appropriate mode file (agents.md for agents, skills.md for calibratable skills); task name "Calibrate <plugin-name>" | "Calibrate <plugin-name>" | | `<agent-name>` / `<skill-name>` (tier 3) | single-file pipeline: use agents.md or skills.md mode file with `<TARGET>` = resolved name; task name "Calibrate <name>" | "Calibrate <name>" | For multiple tokens, merge resolved targets into per-mode groups before spawning — one pipeline per unique mode file needed, each carrying full target list. Before spawning **any** pipeline (target includes `agents`, `skills`, or `all`): check cross-plugin availability. `LOCAL_MODE=true`: check `plugins/` source tree (local edits not yet installed); otherwise check installed plugin cache: ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" if [ "$LOCAL_MODE" = "true" ]; then [ -d "plugins/cc_oss" ] && OSS_AVAILABLE="plugins/cc_oss" || OSS_AVAILABLE="" [ -d "plugins/cc_research" ] && RESEARCH_AVAILABLE="plugins/cc_research" || RESEARCH_AVAILABLE="" [ -d "plugins/codemap-py" ] && CODEMAP_AVAILABLE="plugins/codemap-py" || CODEMAP_AVAILABLE="" [ -d "plugins/cc_develop" ] && DEVELOP_AVAILABLE="plugins/cc_develop" || DEVELOP_AVAILABLE="" else OSS_AVAILABLE=$(find ~/.claude/plugins/cache -name "oss" -type d 2>/dev/null | head -1) # timeout: 5000 RESEARCH_AVAILABLE=$(find ~/.claude/plugins/cache -name "research" -type d 2>/dev/null | head -1) # timeout: 5000 CODEMAP_AVAILABLE=$(find ~/.claude/plugins/cache -name "codemap-py" -type d 2>/dev/null | head -1) # timeout: 5000 DEVELOP_AVAILABLE=$(find ~/.claude/plugins/cache -name "develop" -type d 2>/dev/null | head -1) # timeout: 5000 fi ``` - **`agents` pipeline**: exclude `oss:cicd-steward` and `oss:shepherd` (requires `oss` plugin) if `$OSS_AVAILABLE` empty; exclude `research:data-steward` and `research:scientist` (requires `research` plugin) if `$RESEARCH_AVAILABLE` empty. Log: "oss/research plugin not installed — skipping <agent> calibration" - **`skills` pipeline**: exclude `/oss:review` (requires `oss` plugin) always (requires live GitHub PR — not calibratable with synthetic input; see `modes/skills.md`); exclude `/codemap-py:*` skills (requires `codemap` plugin) if `$CODEMAP_AVAILABLE` empty; exclude `/research:plan`, `/research:judge`, `/research:verify` (requires `research` plugin) if `$RESEARCH_AVAILABLE` empty; exclude `/develop:review` (requires `develop` plugin) if `$DEVELOP_AVAILABLE` empty. Log skip message per excluded skill. Fallback role descriptions for cross-plugin agents (if ever substituted with `general-purpose`): run `cat "$_FS/agent-resolution.md"` (`$_FS` resolved via cache-resolution block at start of Step 2; `$_FS` empty: skip — role descriptions unavailable), apply matching fallback description. Each mode file defines `<TARGET>`, `<DOMAIN>`, any N overrides, extra instructions for pipeline subagent. Pipeline template lives at `$CALIB_MODES_DIR/../templates/pipeline-prompt.md`. **N override**: `communication` caps at fast=3 / full=5 (not global FULL_N=10) to prevent pipeline context overflow — run `cat "$CALIB_MODES_DIR/communication.md"` for details. **`rules` mode** spawns one `general-purpose` subagent per rule file (not standard pipeline template) — run `cat "$CALIB_MODES_DIR/rules.md"` for direct-spawn approach. ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r _TIMESTAMP < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/timestamp" 2>/dev/null || _TIMESTAMP="" IFS= read -r _KEEP < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/keep-items" 2>/dev/null || _KEEP="" _RUN_DIR=".reports/calibrate/$_TIMESTAMP" _PRESERVE="run-dir=$_RUN_DIR, timestamp=$_TIMESTAMP" [ -n "$_KEEP" ] && _PRESERVE="$_PRESERVE; user-keep: $_KEEP" python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/write_skill_contract.py" "foundry:calibrate" "collect+synthesize (after pipeline fan-out)" "$_RUN_DIR" "$_PRESERVE" "collect pipeline results → combined report → follow-up gate (Step 3) → log (Step 4) → signals (Step 5)" # timeout: 5000 ``` ## Step 3: Collect results and print combined report **Completion handling** — pipeline spawns run in the background: issue the batch, end turn, resume on completion notifications; never a poll loop, a filler call, or a "waiting" line (`_FOUNDRY_SHARED/agent-spawn-protocol.md`). Each returns: read that target's compact JSON; absent: read `.reports/calibrate/<TIMESTAMP>/<TARGET>/result.jsonl` (written on every exit path per pipeline's graceful-exit protocol). Neither present: record `{"verdict":"timed_out"}`, mark target `⏱` in report; never omit a stalled target. **On timeout**: read `tail -100 <output_file>` for partial JSON; none: use: `{"target":"<TARGET>","verdict":"timed_out","mean_recall":null,"gaps":["pipeline timed out — re-run individually with /calibrate <target> fast"]}`. Timed-out targets appear in report with ⏱ prefix and null metrics. After all pipeline subagents complete or time out: mark "Analyse and report" in_progress. Parse compact JSON summary from each. (Category tasks — "Calibrate agents", "Calibrate skills", etc. — already marked `completed` inline during Step 2's sequential loop; don't re-mark them here.) For any pipeline that returned without a compact JSON, use Glob (pattern `*/result.jsonl`, base `.reports/calibrate/<TIMESTAMP>/`) to check whether a result file was written. `result.jsonl` exists: parse it as compact JSON for that target. Neither compact JSON nor `result.jsonl` exists: synthesize: `{"target":"<TARGET>","verdict":"incomplete","mean_recall":null,"calibration_bias":null,"gaps":["pipeline returned no output — re-run: /calibrate <TARGET> --fast"]}`, mark that target with ⏱ in report table. Print combined benchmark report: ```markdown ## Calibrate — <date> — <MODE> | Target | Recall | SevAcc | Fmt | Confidence | Bias | F1 | Scope | Verdict | Top Gap | |------------------|--------|--------|------|------------|---------|------|-------|------------|----------------------| | sw-engineer | 0.83 | 0.91 | 0.87 | 0.85 | +0.02 ✓ | 0.81 | 0 ✓ | calibrated | async error paths | | ... | | | | | | | | | | *Recall: in-scope issues found / total. SevAcc: severity match rate for found issues (±1 tier) — high recall + low SevAcc = issues found but misprioritized. Fmt: fraction of found issues with location + severity + fix (actionability). Bias: confidence − recall (+ = overconfident). Scope: FP on out-of-scope input (0 ✓).* ``` **If AB mode**, add `ΔRecall`, `ΔSevAcc`, `ΔFmt`, `ΔTokens`, and `AB Verdict` columns after F1. ΔTokens = token_ratio − 1.0 (negative = specialist more concise). ```markdown | Target | Recall | SevAcc | Fmt | Bias | F1 | ΔRecall | ΔSevAcc | ΔFmt | ΔTokens | Scope | AB Verdict | |-------------|--------|--------|------|---------|------|---------|---------|-------|---------|-------|------------| | sw-engineer | 0.83 | 0.91 | 0.87 | +0.02 ✓ | 0.81 | +0.05 ~ | +0.12 ✓ | +0.15 ✓ | −0.18 ✓ | 0 ✓ | marginal ~ | *ΔRecall/ΔSevAcc/ΔFmt: specialist − general (positive = specialist better). ΔTokens: token_ratio − 1.0 (negative = more focused). AB Verdict covers ΔRecall and ΔF1 only; use ΔSevAcc and ΔFmt as supplementary evidence for agents where ΔRecall ≈ 0.* ``` **If target is `routing`**: ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" CALIB_MODES_DIR=$(python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_skill_subdir.py" calibrate modes $([ "$LOCAL_MODE" = "true" ] && echo --local)) # timeout: 5000 cat "$CALIB_MODES_DIR/routing.md" ``` Use "Report format" section loaded above instead of table above. Mark "Calibrate routing" completed. Flag targets where recall < 0.70 or |bias| > 0.15 with ⚠. After table, print full content of each `proposal.md` for targets where `proposed_changes > 0`. `--apply` **not** set: after printing proposals, print two genuine re-run commands as plain copy-pasteable text, then fire **Follow-up gate** (unless `--skip-gate` passed): ```text Re-run full depth /calibrate <targets> --full Re-run full + A/B /calibrate <targets> --full --ab-test ``` Call `AskUserQuestion` — do NOT write options as plain text. Map options directly: - question: "Proposals ready. What next?" (include summary, e.g. "3 targets with proposals, 1 calibrated.") - (a) label: `Apply proposals now` — description: apply in this session — proceed directly to Step 6 using the persisted TIMESTAMP, no re-invocation, no benchmark re-run - (b) label: `skip` — description: review proposal files manually at `.reports/calibrate/<TIMESTAMP>/<TARGET>/proposal.md` `--apply` **was** set (benchmark + auto-apply mode): print `→ Auto-applying proposals now…`, proceed to Step 6. Targets with verdict `calibrated` and no proposed changes get single line: `✓ <target> — no instruction changes needed`. ## Step 4: Concatenate JSONL logs Append each target's result line to `.notes/logs/calibrations.jsonl` using native tools (no Bash needed): 1. Use Glob (pattern `*/result.jsonl`, path `.reports/calibrate/<TIMESTAMP>/`) to find all result files 2. Read each result file with Read tool 3. Read `.claude/logs/calibrations.jsonl` (legacy, if exists; use empty string if missing) and `.notes/logs/calibrations.jsonl` (if exists; use empty string if missing); concat both for historical context 4. Append new lines and Write combined content back to `.notes/logs/calibrations.jsonl` only — never write to `.claude/logs/calibrations.jsonl` ## Step 5: Surface improvement signals For each flagged target (recall < 0.70 or |bias| > 0.15): - **Recall < 0.70**: `→ Update <target> <antipatterns-to-flag> for: <gaps from result>` <!-- `<antipatterns-to-flag>` (not structural XML) — inline prose reference to agent-file section name --> - **Bias > 0.15**: `→ Raise effective re-run threshold for <target> in MEMORY.md (default 0.70 → ~<mean_confidence>)` - **Bias < −0.15**: `→ <target> is conservative; threshold can stay at default` Proposals shown in Step 3 already surface actionable signals. Follow-up gate fires in Step 3 (unless `--skip-gate`). Mark "Analyse and report" completed. `--apply` was set: proceed to Step 6. ```bash rm -f .temp/state/skill-contract.md # clear contract — skill complete (compaction-contract.md §Lifecycle) # timeout: 5000 ``` ## Step 6: Apply proposals (apply mode) Mark "Apply findings" in_progress. **Determine run directory**: - Benchmark + auto-apply mode (`--fast`/`--full` + `--apply`): re-read TIMESTAMP from persisted state (fresh-shell state loss): ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r TIMESTAMP < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/timestamp" 2>/dev/null || TIMESTAMP="" [ -z "$TIMESTAMP" ] && { echo "! TIMESTAMP state lost — falling back to latest run dir"; TIMESTAMP=$(basename "$(find .reports/calibrate -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort -Vr | head -1)"); } # safe: uses existing dir from find, not new $(date) timestamp — won't create phantom run dir ``` - Pure apply mode (only `--apply`, no pace flag): find most recent run: ```bash LATEST=$(find .reports/calibrate -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort -Vr | head -1) TIMESTAMP=$(basename "$LATEST") [ -z "$TIMESTAMP" ] && { echo "! No prior calibration run found under .reports/calibrate/ — run /calibrate <targets> --fast first."; exit 1; } ``` For each target in target list, check whether `.reports/calibrate/<TIMESTAMP>/<target>/proposal.md` exists. Collect targets with proposal (`found`) and without (`missing`). **Partial-match behavior**: `--apply` with mixed found/missing targets continues with found targets — doesn't halt on missing. For each **missing** target: print warning, skip (don't stop entire run): `⚠ No prior run for <target> — skipping. Re-run with --fast --apply to benchmark+apply, or --fast to benchmark only. (If target was skipped because its plugin was unavailable, install the plugin first, then re-run.)` Continue to next target. Only if ALL targets missing: stop with `! No proposals found for any requested target` — nothing to apply. `--apply` without pace flag is intentional — see `<inputs>` definition; auto-triggering benchmark would contradict that contract. **Print run's report before applying**: for each found target, read and print `.reports/calibrate/<TIMESTAMP>/<target>/benchmark-report.md` verbatim so user sees benchmark basis before any file changes. **Spawn one `foundry:curator` subagent per found target (`.md` files — agents and skills). Issue ALL spawns in single response — no waiting between spawns.** **Deduplicate by resolved physical path before spawning** — two targets resolve to the same `<AGENT_FILE>` (e.g. bare name and plugin-prefixed name for the same logical agent): concurrent curator spawns race on identical Edit calls, second write may clobber the first. Build a `RESOLVED_PATHS` map after the per-target path-resolution loop above; for any group of targets sharing the same `<AGENT_FILE>` after resolution: - Spawn one curator at a time for that group (sequential, not parallel) - Log: `! Sequential apply for <target-a> and <target-b> — both resolve to <AGENT_FILE>` - Other independent path groups remain parallel **`<AGENT_FILE>` and `<PROPOSAL_PATH>` resolution**: before spawning, resolve file paths for each target from project source tree (`plugins/`) — same three-tier ladder whether or not `--local` was passed. `<AGENT_FILE>` is a write target (curator Edits it): must never resolve to `.claude/agents/` (never created by `/foundry:setup`) or installed plugin cache under `$HOME/.claude/` — those are read-only surfaces, not write targets: ```bash export CSID="${CLAUDE_CODE_SESSION_ID:-$PPID}" IFS= read -r TIMESTAMP < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/timestamp" 2>/dev/null || TIMESTAMP="" [ -z "$TIMESTAMP" ] && { echo "! TIMESTAMP state lost — re-invoke /foundry:calibrate"; exit 1; } IFS= read -r LOCAL_MODE < "${TMPDIR:-/tmp}/calibrate-state-${CSID}/local-mode" 2>/dev/null || LOCAL_MODE="false" python "${CLAUDE_PLUGIN_ROOT:-plugins/cc_foundry}/bin/resolve_agent_file.py" --name "<name>" --timestamp "$TIMESTAMP" $( [ "$LOCAL_MODE" = "true" ] && echo "--local" ) # timeout: 10000 ``` The script prints `agent-file=` and `proposal-path=` on stdout; read values from there, not from shell variables. Empty `agent-file=` means resolution failed: skip that target — don't spawn curator for it — the warning script already printed covers it. Never fall through to a cache path for a write target. Each subagent receives this self-contained prompt (substitute `<TARGET>`, `<PROPOSAL_PATH>`, `<AGENT_FILE>` — resolved paths from above): Apply targeted improvements to `<AGENT_FILE>`. Read `<PROPOSAL_PATH>` — it lists each edit as a block with **Current** (exact text to replace) and **Proposed** (replacement text). Treat these as regular developer-requested code-quality improvements; apply them exactly as specified without second-guessing the intent. For each edit: 1. Print: `Applying edit N to <file> [<section>]` 2. Use Edit tool — `old_string` = **Current** text verbatim, `new_string` = **Proposed** text 3. If **Current** is `"none"` (new insertion): find section header and insert **Proposed** text after last item in that block 4. Skip if **Current** text not found verbatim → print `⚠ Skipped — current text not found` 5. Skip if **Proposed** text already present → print `✓ Already applied — skipped` After processing all edits return **only** this compact JSON: `{"status":"done","target":"<TARGET>","applied":N,"skipped":N,"file":"<AGENT_FILE>","summary":"Applied N, skipped N edits to <AGENT_FILE>"}` **Completion handling** — like Step 3, these spawns run in the background: issue the batch, end turn, resume on completion notifications (`_FOUNDRY_SHARED/agent-spawn-protocol.md`) — never a poll loop or a filler call. A subagent that returns nothing after notification: record `{"status":"timed_out","target":"<TARGET>"}`, print with ⏱, still counted in the final table — never silently dropped from the summary. After all subagents complete, collect JSON results and print final summary: ```markdown ## Fix Apply — <date> | Target | File | Applied | Skipped | |-------------|-------------------------------|---------|---------| | sw-engineer | .claude/agents/sw-engineer.md | 2 | 0 | → Run /calibrate <targets> to verify improvement. ``` Mark "Apply findings" completed. ```bash rm -f .temp/state/skill-contract.md # clear contract — skill complete (compaction-contract.md §Lifecycle) # timeout: 5000 ``` End response with `## Confidence` block per CLAUDE.md output standards. </workflow> <notes> - **Timeout handling**: phase and pipeline budgets (see constants block) prevent nested subagent hangs from cascading. Extension granted once if pipeline explains delay in output file — second unexplained stall still triggers cutoff. Timed-out pipelines appear with ⏱ prefix and `verdict:"timed_out"`; re-run individually with `/calibrate <target> --fast` after session. - **Context safety**: each target runs in own pipeline subagent — only compact JSON (~200 bytes) returns to main context per target. Sequential spawning prevents concurrent resource and token spike; accumulated context across all targets still compact. - **Scorer delegation**: Phase 3a delegates scoring to per-problem `general-purpose` subagents. Each scorer reads response files from disk, returns ~200 bytes. Phase 3b runs Codex scorers sequentially via Bash (writes per-problem files). Phase 3c merges both into `scores.json`. Pipeline holds only compact JSONs regardless of N or A/B mode — no context budget concern. - **Nesting depth**: main → pipeline subagent → target/scorer agents (2 levels). Pipeline spawns target agents (Phase 2), Claude scorer agents (Phase 3a), Codex scoring Bash calls (Phase 3b) at same depth — no additional nesting. - `general-purpose` is built-in Claude Code agent type (no `.claude/agents/general-purpose.md` needed) — no custom system prompt, all tools available. - **Quasi-ground-truth limitation**: partially addressed by cross-model generation (Claude + Codex) — two model families produce independent ground truth, reducing same-family blind spots. Adversarial and ceiling-difficulty problems included in every run (see difficulty distribution rules in `templates/pipeline-prompt.md` Phase 1a) to test false-positive discipline, reveal upper-bound limits. Remaining gap: synthetically generated adversarial problems weaker than expert-authored ones; `generator_recall_delta` surfaces whether one generator's problems are systematically easier or harder. `ceiling_recall` (reported separately from `mean_recall`) is primary signal for upper-bound performance — partial recall (0.4–0.7) on ceiling problems expected, doesn't affect calibration verdict. - **Dual evaluation and scorer agreement**: Phase 3a (Claude) and Phase 3b (Codex) score each response independently. Phase 3c merges with Claude as 51% tiebreaker. `scorer_agreement` measures fraction of issues where both scorers agreed — low agreement (< SCORER_AGREEMENT_WARN=0.70) flags ambiguous ground truth or scorer blind spots. Severity disputes (scorers disagree >1 tier) excluded from SevAcc aggregate. - **File-based Codex handoff**: Codex writes all output (problem JSON, score JSON) directly to run dir. Avoids bash stdout corruption when capturing large JSON from shell subprocesses. Pipeline reads from disk, never from stdout capture. - **Historical comparability**: `result.jsonl` includes `"scoring":"dual|single"` and `"source_mode":"dual|claude-only"`. Analyzing trends in `calibrations.jsonl`: filter by these fields — dual-scored results not directly comparable to single-scored baselines. - **Calibration bias is key signal**: positive bias (overconfident): raise agent's effective re-run threshold in MEMORY.md. Negative bias (underconfident): confidence conservative, no action needed. Near-zero: confidence trustworthy. - **Do NOT use real project files**: benchmark only against synthetic inputs — no sensitive data and real files have no ground truth. - **Skill benchmarks** run skill as subagent against synthetic config or code; scored identically to agent benchmarks. - **Improvement loop**: systematic gaps → `<antipatterns-to-flag>` | consistent low recall: consider model tier upgrade (sonnet tier → opus tier) | large calibration bias: document adjusted threshold in MEMORY.md | re-calibrate after instruction changes to quantify improvement. - **Report always**: every invocation surfaces report — benchmark runs print new results table; `--apply` without pace flag prints saved report from last run before applying, so user always sees basis for changes before files touched. - **`--apply` semantics**: `--fast --apply` / `--full --apply` = run fresh benchmark then auto-apply new proposals. `--apply` alone = apply proposals from most recent past run without re-running benchmark. - **Stale proposals**: `--apply` uses verbatim text matching (`old_string` = **Current** from proposal). Agent file edited between benchmark run and `--apply`: any change whose **Current** text no longer matches is skipped with warning — no silent clobbering of intermediate edits. - **`routing` target vs `/audit` Check 20**: `/audit` Check 20 (sub-check 20a, `audit/templates/checks-agents.md`) performs static analysis of description overlap (finds potential confusion zones); `/calibrate routing` tests behavioral impact — generates real routing decisions, measures whether descriptions actually disambiguate. Run in sequence: `/audit` first (fast, structural), then `/calibrate routing` (behavioral, slower). Complementary, not redundant. - **`routing`, `communication`, `rules` in `all`**: see `all` entry in `<inputs>` for authoritative definition — use explicit targets only when running single mode in isolation. - Follow-up chains: - Recall < 0.70 or borderline: pick "Apply proposals" from gate → `/calibrate <agent>` to verify improvement — stop, escalate to user if recall still < 0.70 after this cycle (max 1 apply cycle per run) - Calibration bias > 0.15: add adjusted threshold to MEMORY.md, note in next audit - Routing accuracy < 0.90 or hard accuracy < 0.80: update descriptions for confused pairs → `/calibrate routing` to verify improvement - Recommended cadence: run before and after any significant agent instruction change; run `/calibrate routing` after any agent description change; run `/calibrate communication` after any protocol or handoff change - **Internal Quality Loop suppressed during benchmarking**: Phase 2 prompt explicitly tells target agents not to self-review before answering. Ensures calibration measures raw instruction quality — not `(agent + loop)` composite. Loop enabled: inflates recall and confidence by unknown ratio, masks real instruction gaps, makes improvement attribution impossible. - **Skill-creator complement**: trigger accuracy and A/B description testing not yet implemented — future skill-creator skill from Anthropic would own this domain; run `/calibrate` for quality and recall. - **A/B interpretation**: every specialized agent adds system-prompt tokens — `general-purpose` subagent matches recall and F1: specialization adds no value. `ab` mode quantifies gap per-target. `significant` (Δ>0.10) confirms agent's domain depth earns cost; `marginal` (0.05–0.10) suggests instruction improvements may help; `none` (\<0.05) signals agent's current instructions add no measurable lift over vanilla agent. Token cost informational (logged in scores.json) but not part of verdict — prioritize recall/F1 delta as primary signal. Role-specificity caveat: for agents whose domain is well-covered by general training data, `none` ΔRecall does NOT mean "retire agent" — specialization shows up in ΔSevAcc, ΔFmt, ΔTokens even when ΔRecall ≈ 0; positive ΔSevAcc/ΔFmt combined with negative ΔTokens still confirms specialist earns cost. - **AB mode nesting**: Phase 2b spawns `general-purpose` baseline agents inside pipeline subagent. Phase 3 spawns `general-purpose` scorer agents inside same pipeline subagent. All at 2 levels (main → pipeline → agents) — no additional depth. - **Mode files**: domain tables and mode-specific spawn instructions live in `modes/agents.md`, `modes/skills.md`, `modes/routing.md`, `modes/communication.md`, `modes/rules.md`. Add new target mode by creating new file in `modes/`, adding row to Step 2 dispatch table. </notes>
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.