bff2120f42cc050bf032dee512241b9af95c66a4
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e7009bc304 |
fix(implement-loop): guard against a task discarding sibling tasks' uncommitted work
During a multi-task run nothing commits between tasks, so one task's file-level `git checkout -- <file>` / `git restore <file>` silently destroys an earlier task's uncommitted DONE work in a shared file. The loss was structurally invisible: spec- and quality-reviewers are scoped to the current task's footprint, diff_fingerprint only detects same-task repair cycles, and the end-of-iteration tree gate counts files (the surviving changes keep it nonzero). Observed in the wild as a PARTIAL run whose DONE reports did not match the tree. Two layers, both plugin-side (harness-level prevention is ruled out — decision log on the issue): Prose guard — implementer.md Step 8 no longer sanctions file checkout for scope curation: over-reach is undone by editing back, a broken intermediate state is repaired forward or reported BLOCKED (new fourth BLOCKED bucket in the status protocol). A matching Iron Law line in implement/SKILL.md covers all in-loop agents, whole-file and --patch; docs/conventions.md now marks the checkout discard idiom as the orchestrator's, between iterations. Mechanical guard — after every task of a multi-task run a snapshot agent records `git stash create` (a dangling commit; HEAD, index, and tree untouched — semantics verified empirically in a scratch repo) plus the `git diff HEAD --name-only --no-renames` path set. A path that was HEAD-modified at one boundary and gone at the next trips a hard BLOCKED naming the lost paths, the boundary, and the recovery snapshot sha (`git show <sha>:<path>`); the discard verdict outranks per-task outcomes in blocked_detail since the reports and the tree have diverged. Coarse by design, in both directions, and documented as such: a checkout-then-re-edit or a --patch hunk restore escapes the comparison (the snapshot keeps it diagnosable); a legitimate back-to-HEAD edit trips it (the verdict says adjudicate against the snapshot). --no-renames keeps a staged rename from reading as a loss; untracked files are outside the threat model (checkout cannot discard them). Cost: one sonnet/medium call per task, multi-task runs only; single-task and mini runs are unchanged. Verified: node --check on the async-wrapped script and a stub-agent harness — discard trips the hard BLOCKED and stops the loop; an accumulating happy path, a plan-intended deletion, a single-task run, and a dead snapshot agent all pass without a false positive. closes #23 |
||
|
|
a75a821a29 |
fix(implement-loop): guard plan-extract against silent truncation on big plans
The plan-extract step pulled every requested task's verbatim block through a single schema-bound agent() response. On a large plan that response self-limits and returns a well-formed PREFIX (commonly just task 1); the only guard rejected an empty list, so a truncated non-empty subset ran to a clean DONE with the missing tasks never attempted, yet the end-report read as a completion. Replace the single-shot dump with an enumerate pass + per-task extraction, guarded by cardinality checks (issue #22 suggested either direction; this does both, plus a backstop the issue did not scope): - plan-index enumerates ids + one-line titles only (bounded output, self-limits far later than a verbatim dump) and reports total_tasks, the whole-plan count computed from the fully-readable plan text independently of the emitted list. - plan-extract:<id> carries one task's verbatim block per agent() call, removing the across-all-tasks output ceiling. Calls fan out via parallel() (which honours the concurrency cap on a big plan); the requested id is bound inside each thunk and results are re-associated by it, never by array position, so the mapping holds regardless of the order parallel() resolves in. - Cardinality guards: (a) the whole-plan enumerate must list exactly total_tasks (the only backstop the no-range path can have without a caller range); (b) a task_range must be well-formed and covered exactly by the plan; (c) every expected id must extract non-empty text. Any breach is a hard BLOCKED with a precise "got N of M" reason, never a silent short run. Known residual (documented in-code): a single task whose own verbatim body overflows its dedicated response still returns an accepted prefix — bounded only by the planner's bite-sized-task invariant, far narrower than the closed vector. Verified by driving the real script through 11 extraction scenarios in a stubbed harness plus an order- and self-id-independence association test, and an adversarial three-lens review of the diff. closes #22 |
||
|
|
edbbb68f97 |
feat(agents): pin explicit reasoning effort on every agent and workflow call
Effort joins model as a mandatory pin: an omitted field inherits the session effort, coupling every dispatch's thinking budget to whatever the user happens to be chatting at (often xhigh) — the same session-state coupling the model pin removes. The assignment follows the model split: - xhigh on every opus agent (judgement roles are the pipeline's quality floor and must not degrade with the session); - high on every sonnet agent (tightly-scoped plan execution gains little from xhigh but pays its latency per dispatch, and these are the per-task in-loop roles — wall-clock is the efficiency metric; not lower than high, since re-loops cost more than saved thinking); - medium inline in the workflow scripts for schema-bound extraction/verification stages that author no code (preflight, plan-extract, mini-verify, tree-check, finalize, build/suite verify). Workflow agent() calls pass effort explicitly on every call — whether frontmatter effort propagates through an agentType dispatch is undocumented, so the scripts do not rely on it. Policy documented in docs/agent-template.md § effort, mirroring § model. |
||
|
|
6bfec9655c |
feat(agents): pin explicit model on every agent and workflow call
Agents and workflows previously carried no model field, so every dispatch inherited the session model — including fable, which is banned for all plugin agents and workflows by owner decree. Every dispatch now pins opus or sonnet explicitly. - opus (low-volume judgment gates whose misses silently poison downstream work): architect, bencher, debugger, fieldtester, grounding-check, plan-recon, quality-reviewer, spec-skeptic, tdd-author - sonnet (mechanical scope, in-loop or fanned out): docwriter, glossary-extractor, implementer, spec-reviewer, synthetic-user, tester - workflows: all 13 agent() call sites pin a model — sonnet everywhere except the quality-reviewer gate in implement-loop, the loop's last correctness check (spec-reviewer only gates task-text correspondence; real-bug finding is the documented opus strength) - docs/agent-template.md: model is now a mandatory frontmatter field, with the assignment rule and the fable ban recorded |
||
|
|
7a58a530b1 |
feat(pipeline): route to the lightest correct methodology; move execution loops onto the Workflow substrate
The selector forced every task through the heaviest methodology's
critical path: a behaviour-preserving, type-enumerable change paid the
same specify -> planner -> implement front-half as a novel feature,
because it was neither new behaviour (tdd) nor an observed bug (debug)
and so fell to specify by elimination. Two coupled defects — a selector
with no verification axis, and an all-or-nothing executor — kept the
existing lighter path unreachable and uneconomical. This fixes both.
Part A — verification-keyed selector (boss/SKILL.md):
- Replace the three-way "design line" with an ordered cascade that adds
a verification/enumeration axis ahead of the settled-vs-fork question.
Each lighter arm carries a positive trigger matched by signature, not
reached by elimination.
- New `compiler-driven` arm: a type/signature edit at a definition site
that propagates mechanically. Observe-then-bounce — make the edit,
build, run the suite; clean build AND suite green unchanged commits;
a hole bounces up (specify for a design choice, tdd for discovered
test-specifiable new behaviour); a regression bounces to debug.
- The observed-bug RED-first gate is first in the cascade, so a
mechanical-looking fix cannot bypass it.
- The straddle rule ("add an enum variant") is codified as a rule:
mechanical/forwarding -> compiler-driven; encodes new behaviour ->
tdd/spec; doubt routes up.
- The executor is the elevated inline carve-out plus a shipped workflow,
not a heavy new skill ("the largest concrete win is small").
Part B — Workflow substrate (implement/workflows/):
- implement-loop.js: the per-task loop as a deterministic script. Each
phase (implementer -> spec-compliance -> quality, + tester for E2E) is
a separate top-level agent() call, so a single phase is independently
invokable and inter-phase aggregation/re-loop is code. Retires the
implement-orchestrator agent's inline-role-switch workaround (the four
phase agents survive as the agent-types the script dispatches).
- compiler-driven-edit.js: the observe-then-bounce loop.
- install.sh / uninstall.sh symlink shipped workflows into
~/.claude/workflows/.
- specify and brainstorm stay prose + interactive (human-intent oracle);
only the autonomous/mechanical loops moved. try-and-error is deferred.
Docs (pipeline taxonomy, design, agent-template, migration, README) and
all selector<->executor cross-references updated; the arm and its
executor are co-located so a future re-route through the full loop is a
visible regression.
Verified by an adversarial multi-agent pass: PASS on all six acceptance
criteria; two coherence concerns fixed. The shipped scripts are
syntax-validated but exercised only in a downstream target project (the
skills repo is not itself a pipeline target).
closes #7
|
||
|
|
26e9630496 |
refactor: drop dev-cycle-profile.yml for conventions + CLAUDE.md facts
The profile was never parsed — it was prose the skill bodies told the model to read, so most slots were dead, constant across every project, or fiction (the whole pipeline block, including the "tdd is opt-in" claim, was enforced by nothing). Split it in two: constants become fixed conventions named directly by the skills (new docs/conventions.md), and the few genuinely per-project facts move to each project's CLAUDE.md under '## Skills plugin: project facts'. tdd/fieldtest/docwriter are now always available; the only behavioural toggle left is spec auto-sign. Delete docs/profile-schema.md and templates/project-profile.yml; add docs/conventions.md and a project-facts section to templates/CLAUDE.md.fragment; rewrite all SKILL/agent prose and the pipeline/design/migration/README/INSTALL docs accordingly. |
||
|
|
cbd460e242 |
feat(boss): opt-in spec auto-sign via adversarial spec-skeptic panel
Add `pipeline.boss.spec_auto_sign` (default off). With it on, a /boss run may sign a spec in the user's place — but only through a gate built to never rely on the orchestrator's own confidence: all objective gates green (precondition, parse, grounding-check PASS with no human override) AND a unanimous five-lens adversarial spec-skeptic panel (criterion, grounding, scope-fork, ambiguity, plan-readiness). Any single BLOCK falls back to the human sign-off pause. On a clean sign the orchestrator commits the spec ((boss-signed) in the subject), fires a mandatory informational-with-veto notify, and proceeds to planner without stopping. A later veto is a forward correction, never a history rewind. - new agent: specify/agents/spec-skeptic.md (read-only, one lens per dispatch) - specify Step 6 + Iron Law: approval may come from the auto-sign gate, never from model self-confidence - boss: third notify category, §"Spec auto-sign", rationalisations, red flags - profile-schema + template: the opt-in slot - pipeline.md, agent-template.md, README: the auto-sign path documented |
||
|
|
4806b83265 |
audit(glossary): close cycle — glossary skill drift-clean
Cycle-close tidy for the glossary-skill cycle (59c2f4b..4fd5408). Architect drift review (sole gate — repo ships no .claude/dev-cycle-profile.yml, so commands.regression is empty and the regression step is a documented no-op): - [medium] FIXED. docs/agent-template.md said the Iron Law is rendered 'as a numbered list' (the schematic placeholder at l.37 and the prose at the § Iron Law section), but all 13 existing agents render it as a code-fenced block of short imperative lines — and the cycle's new glossary-extractor.md correctly followed that universal convention. So the drift was the template wording, stale relative to every one of its instances, not the new file. Resolution: align the template to reality (both spots now say 'a code-fenced block of short imperative lines'). The new agent file was carry-on — 'fixing' it to a numbered list would have made it the lone deviant among 14 agents, i.e. introducing drift, not removing it. - [low] CARRY-ON. README now classes issue/glossary as 'utility skills' but that taxonomy is not mirrored in issue/SKILL.md's or glossary/SKILL.md's own frontmatter. Accepted as low-severity: the invocation-class label is a README-level descriptor; mandating every skill self-declare its class in frontmatter is gold-plating with no consumer. Revisit only if a tool starts keying off a per-skill class. What holds: single-sourcing preserved (the new skill cites glossary-convention.md and restates no rule; paths.glossary semantics defer to profile-schema.md); authority consistent across the boss sentence, the convention, and the skill's Authority section; the utility-vs-phase distinction held (no claim that glossary is a pipeline phase); glossary-extractor.md conforms to agent-template.md. Cycle is drift-clean. Not a milestone close (no milestone fieldtest run; see docs/pipeline.md § Milestone-close gate). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a6794d178a |
feat(glossary): add optional paths.glossary standing-reading slot
Pins canonical nomenclature per project so terminology does not drift and LLM-driven work reuses the established term instead of coining a synonym each session. The glossary rides the existing standing-reading mechanism — one optional path slot, no new delivery path. Single-sourcing, to avoid cross-doc drift: - `paths.glossary` row in profile-schema.md owns the "set => standing reading for every role; unset => no-op" semantics; agent-template.md and pipeline.md each carry one referencing sentence, not a restatement. - glossary-convention.md owns the format (flat per-term blocks: canonical heading + Avoid line + <=2-sentence definition) and the boss record-reality-never-invent write-rule; boss/SKILL.md only points to it. - glossary.md dogfoods the format on the plugin's own vocabulary (cycle, milestone, iteration, drift, hard-gate). Write authority: user any time; boss autonomously but only to record terms already in consistent use or to settle a drift it just resolved — never to coin. All other roles are read-only consumers. No executable surface; this repo has no test runner, so each task closed on a grep presence-assertion against the file it touched. All eight gates green (T1 3>=3, T2 5, T3 2, T4 1, T5 1, T6 1, T7 2, final sweep present). Implements docs/specs/2026-05-31-glossary-integration-design.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
253273b007 |
skeleton: plugin layout + docs, skill/agent migration deferred to iter 1
Establishes the repository structure for the skills plugin: - README + INSTALL describing the two-layer split (plugin mechanics vs per-project profile) - docs/design, profile-schema, pipeline, agent-template covering the universal discipline constants and the profile slot model - templates/project-profile.yml as a copy-and-fill starting point - templates/CLAUDE.md.fragment with the baseline orchestrator rules a project can import - install.sh / uninstall.sh wiring skills/ + agents/ into ~/.claude/ via idempotent symlinks - skills/ and agents/ directories empty except for migration READMEs; the actual SKILL bodies and agent files migrate from ~/dev/ailang/skills/ in the next iteration. No skill or agent runs yet — this commit only stands up the structure and documents the substitution model. |