Commit Graph

134 Commits

Author SHA1 Message Date
claude 4996f2d919 Revert "feat(models): move the implementer to opus/high"
This reverts commit cdbc2d0. The bump was a judgment call without
evidence, and the planner design intent argues the other way: the plan
Iron Law is "EVERY STEP THAT CHANGES CODE INCLUDES THE CODE" and tasks
are sized so a subagent executes one "without judgement calls outside
its remit" (planner/SKILL.md) — the planner exists precisely to remove
design latitude from the implementer, which points at sonnet, not opus.
opus is only justified to the degree real plans leave slack (RED-step
invention, tree reconciliation, review repair), and that slack is
measurable, not felt. Restore sonnet/high; a future bump should be
grounded in the loop metrics (spec re-loop count, quality
changes_requested rate, end-verify BLOCKED rate) via postmortem, not a
gut call. The four fable gates (b591e75) are untouched.
2026-07-20 16:03:12 +02:00
claude cdbc2d03ae feat(models): move the implementer to opus/high
Owner-ratified 2026-07-20: authored code is the pipeline's primary
output, so plan execution takes the judgment model — but keeps the
in-loop effort tier (high, not xhigh): the implementer is the
most-dispatched per-task role and volume x wall-clock still governs
its thinking budget. Applies to the frontmatter pin and the three
implement-loop dispatches (impl, impl-fix-spec, impl-fix-qual).

The compiler-driven-edit arm deliberately keeps its implementer
dispatch at sonnet/high: compiler-enumerated propagation is
mechanical, and the arm's policy header pins its own tier.
2026-07-20 14:50:31 +02:00
claude b591e753cd feat(models): add fable tier for the four singleton judgment gates
Owner-ratified 2026-07-20: architect, grounding-check, tdd-author and
debugger pin fable/xhigh — cycle-reach singleton gates whose miss
silently ratifies or poisons an entire cycle (drift verdict, autonomous
sign-off signature, RED executable-spec, root-cause). The set is
closed: extending it requires fresh owner ratification, no fable agent
ever runs per-task in a loop or in a parallel fan-out, and workflow
scripts stay fable-free (the implement-loop quality gate caps at opus).

Policy home: docs/agent-template.md $ model rule 1 (effort: fable
gates stay xhigh, not max); the workflow policy headers now point at
the exception instead of the former blanket ban.
2026-07-20 14:49:24 +02:00
claude c68b2303a0 Add explore skill: interactive pseudocode browser
Serves a localhost page in the pseudo-skill register with the
reference markers as clickable buttons: clicks land in
<workdir>/events.jsonl, a persistent Monitor tail wakes the session,
the session rewrites page.html, and the browser live-reloads over SSE.
Actions per marker: expand / show real code / explain / ask, plus a
page-level ask box; anchors become forge deep-links when the project
has a reachable remote; incidental findings are surfaced on the page
as anchored notes.

The port is configured in one place (the PORT constant atop
scripts/server.py; --port overrides per run). Mechanics proven live
against the aura repo before extraction into this skill.
2026-07-20 12:11:57 +02:00
claude fe39658d67 feat(workflows): tier the standing reading for schema-bound stages
The anonymous script stages received the full standing-reading
instruction (project CLAUDE.md + git log -10 --format=full) although
a tree-footprint or text-extraction stage consumes none of it and a
verify stage needs only the build/test commands — re-executed on
every dispatch including tight repair rounds, at ~40k+ real tokens
per freshly-primed context.

Two slim variants in both workflow scripts: STANDING_FACTS
(verify-type stages — mini-verify, standard end-verify,
compiler-driven build/suite verify: project-facts build/test commands
only) and STANDING_NONE (tree/extraction stages — preflight,
plan-index, plan-extract[-all], snapshot: nothing beyond their own
instructions). Judgment roles (implementer, spec/quality reviewers,
tester/e2e, compiler-driven edit stage) keep the full read.
conventions.md § Standing reading and agent-template.md § Standing
reading list carry the tiering sentence; the precedent is the
narrowed per-role reading the named agents already practise
(tester -3, plan-recon/grounding-check -5, fieldtester -8,
docwriter --oneline).

closes #31
2026-07-17 15:39:06 +02:00
claude 44f45d16a9 feat(implement-loop): tier the quality review by independently-measured diff size
qual+repairs are the pipeline's largest cost pool (51M of 164.5M real
tokens, 31%, in the 206-run corpus), with opus weighing ~5x on the
quota side. The opus pin's own rationale (consequence-of-a-miss,
agent-template § model) scales with diff size — so the tier now does
too: the spec-reviewer, which runs before quality, reads the diff
itself and is independent of the implementer, reports diff_magnitude
(git diff HEAD --shortstat) and touches_contract; <=25 changed lines
and no contract-referenced path -> sonnet/high, anything larger,
contract-touching, or unmeasured -> opus/xhigh (fail conservative).
The independent end-verify/mini-verify suite gate is the
deterministic backstop that makes the lower tier defensible; the
chosen tier is logged per task (qual_tier) in the end-report.

Sampling phase per the issue's acceptance: the first ~10 real
small-diff iterations get a one-off opus second review; important+
divergences are recorded on the issue before the threshold counts as
proven.

closes #30
2026-07-17 15:37:28 +02:00
claude 1cb52fb821 fix(implement-loop): stamp a repo-root anchor into every stage prompt
In worktree sessions a dispatched agent's cwd can resolve to the
primary checkout instead of the loop's working tree — observed as a
per-dispatch race: 6/9 quality dispatches returning infra_blocked with
the sha256-of-empty fingerprint over a real diff, and a tree-check
counting the primary checkout's clean tree into a false no-op BLOCKED
on a genuinely-DONE iteration.

Remedy (validated in the field on the reporting run): the carrier
gains repo_root, stamped into every stage prompt as an explicit
'git -C <root>' anchor with a wrong-directory tripwire (an empty diff
or unexpected HEAD sha = wrong cwd, re-run against the anchor). When
the carrier omits it, the first dispatched stage (mini preflight /
standard plan-index) probes 'git rev-parse --show-toplevel' as a
fallback — itself subject to the same race, so SKILL.md documents the
field as effectively required in worktree sessions.
compiler-driven-edit gets the same carrier field (same defect class,
carrier-only). agent-template stage list updated in passing
(plan-extract[-all], end-verify).

closes #25
2026-07-17 15:35:11 +02:00
claude f5ba8c3747 feat(implement-loop): standard end-verify gains an independent suite gate
Standard mode was the only execution path without an end-of-iteration
suite gate: tree-check only counted files, so suite-green rode on the
per-task implementers' self-reports while mini-verify and
compiler-driven-edit both re-run the suite as a hard gate
(pipeline-audit finding). The tree-check stage becomes end-verify with
two independently-gating legs: files_touched (untracked-aware no-op
gate, unchanged semantics) and suite_green (full independent suite
run; red -> BLOCKED, route back to debug RED-first). Costs ~+51k real
tokens per standard DONE iteration vs. the old count-only stage; the
deterministic backstop is what makes the quality-review tiering in #30
defensible.

Known trade-off, by design: a flaky or environment-red suite now
blocks a standard iteration — the same exposure mini-verify has.

closes #29
2026-07-17 15:32:24 +02:00
claude 092bca554a feat(implement-loop): adaptive plan extraction — batch small plans, guarded
The per-task plan-extract fan-out re-primes a fresh context per task
(~59k real tokens each; 244 dispatches / 14.4M in the 206-run corpus)
to re-read the same plan. Small plans now extract in ONE
plan-extract-all call, gated by per-task byte estimates the index
reports (ceiling 20k bytes — on BYTES, never task count: the #22
truncation is output-byte-driven).

The #22 protection is strengthened, not traded: the batched result
must carry EXACTLY the expected id set (count match, every id present,
no empty text) or it is discarded wholesale and the per-task fan-out
runs instead — a prefix-truncated batch drops trailing tasks and fails
the count-match closed. No single-shot retry; the fan-out is the
retry. Estimates are a routing heuristic only, never load-bearing for
correctness.

refs #29, refs #22
2026-07-17 15:30:50 +02:00
claude 76c090c848 fix(implement-loop): no-op-repair backstop is severity-aware
The fingerprint early-exit closed a task DONE-with-concerns on a
byte-identical repair diff regardless of severity — a real defect the
opus review flagged as important could ride a green commit as a mere
concern (pipeline-audit finding). The exit now checks the surviving
finding set: any important finding over an unchanged diff is BLOCKED
(reason names it, detail carries the findings); minor-only or
unreported sets keep the existing neutral hold for the orchestrator's
Step-3 adjudication.

refs #29
2026-07-17 15:29:40 +02:00
claude 615a76eb01 feat(implement-loop): retire the finalize dispatch; the end-report carries the artifacts
The finalize agent only templated the script's already-computed
aggregate into stats.json / BLOCKED.md — ~41k real tokens per run
(197 dispatches / 8.0M in the 206-run corpus) for pure formatting.
The templates now live in the script (single source): the end-report
carries artifacts.stats_json and artifacts.blocked_md (null on DONE
and clean no-ops), and the orchestrator writes them byte-identical,
filling exactly two runtime slots it owns anyway — {{DATE}} (date +%F)
and {{FILES_TOUCHED}} (git status --porcelain, its Step-3/4 inspection
duty). File paths, consumers (tdd decompose reads BLOCKED.md,
postmortem parses it), and content shape are unchanged; the
agent-authored 'suggested next step' line is dropped — blocked_detail
carries the diagnosis.

refs #29
2026-07-17 15:29:12 +02:00
claude 8272077e9b feat(implement-loop): fold the standard-mode preflight into plan-index
A standard iteration paid a dedicated ~37k-real-token dispatch for a
clean-tree check. The check itself stays deterministic in the script:
plan-index now carries clean/head_sha/branch/dirty_paths (run FIRST,
before reading the plan; a dirty tree returns an empty index), and the
script evaluates the folded verdict before any cardinality guard. Mini
mode keeps its dedicated preflight — it has no plan-index to fold into.

refs #29
2026-07-17 15:27:03 +02:00
claude 7a08259db7 feat(postmortem): aggregate Workflow run logs per stage
Sessions that ran Workflow-substrate pipelines read as near-zero
subagent spend: analyze_subagents() globs one level only, while
Workflow runs log under workflows/wf_*.json (per-agent summary) and
subagents/workflows/<runId>/agent-*.jsonl (raw usage). New
analyze_workflows() joins both — raw transcripts authoritative
(dedup by requestId, as everywhere), summary supplies stage labels
and models, label-prefix grouping (impl:3 -> impl), untracked
transcripts isolated under '?'. Report gains workflows[] and
workflow_totals; totals now include workflow spend.

Live check against a real 17-agent workflow run: raw 1.30M vs
reported 1.22M (the live counter's known ~7-11% under-tracking).

closes #28
2026-07-17 15:23:22 +02:00
claude 22abd37458 feat(issue): work-start signal is assignee, not label
Retire the in-progress label. Work-start on a tracker issue is now
signalled by assigning the issue to the dedicated tracker user
claude — one write, no removal; the assignee survives the close as
provenance. The live worktree branch (issue-N-<slug>, from the
worktree convention) is the matching git-side signal, and it
disappears with the ratified merge on its own.

Rationale (user decision 2026-07-14): a set-and-remove label is
administrative overhead with a lying-label failure mode when the
removal is forgotten; an assignee needs no removal and stays
meaningful after close.

issue/SKILL.md documents the mechanic (PATCH .../issues/<n> with
{"assignees": ["claude"]} — the call replaces the assignee set;
Gitea has no additive endpoint, verified against the live swagger).
boss/SKILL.md Step 2 assigns on a clean pick (chat-seeded runs
assign when the reference issue is created). conventions.md § Issue
tracker carries the cross-project statement. The label itself was
deleted from all Gitea repos that had it (AILang, Aura, Skills,
doctate); the label vocabulary in ~/dev/CLAUDE.md no longer lists
it.
2026-07-14 12:42:50 +02:00
claude a1d6409163 feat(conventions): substantive work isolates into git worktrees, merge user-ratified
Introduce the worktree convention the corpus previously lacked: any
substantive work stream targeting main — in every mode, autonomous
(/boss) and interactive alike — runs in a git worktree on its own
branch (issue-N-<slug>), and the branch reaches main only through a
user-ratified merge performed by the orchestrator (fast-forward
preferred, push covered by the ratification, no pull request).
Background sessions were already harness-isolated; this extends the
same isolation to the sessions the harness does not guard. The
convention depends on worktree.baseRef=head (the default 'fresh'
bases branches on origin's routinely-stale tip under the
no-autonomous-push discipline), now pinned in conventions.md.

boss/SKILL.md gains the run-level mechanics (§ The run worktree):
one worktree per run named after the reference issue, entered before
the first dispatch; the merge is a user-reserved run-close act; the
done-state notify names the branch as the review handle; closes #N
fires at merge-and-push time. Iron Law, rollback-sandbox framing,
user-reserved-act enumerations, rationalisations, and red flags
updated to match.

Corollary reconciliations after adversarial review: implement's
'there is no branch' narrowed to 'the loop creates no branch of its
own'; specify's auto-signed-commits-on-main heading reworded to
ratified-history framing; the sandbox bullets in conventions.md and
the CLAUDE.md fragment note the anchor is the run branch's base.

The skills meta-repo itself stays exempt (its CLAUDE.md: install
symlinks resolve to the primary clone) and direct-on-main.
2026-07-14 12:32:26 +02:00
claude bff2120f42 fix(implement): spec-reviewer routes reality-contradicted task text to unclear
A requirement whose scripted literal is contradicted by verified
reality (or by another requirement of the same task) is a plan defect,
not a missing requirement: the persona and the loop's dispatch prompt
now direct that case to status `unclear`, which the loop already maps
to an immediate spec-ambiguous BLOCKED for the orchestrator to
adjudicate.

Grounding (aura runs, 2026-07-12): two of the last three cycles' four
review-loop-exhausted BLOCKs were exactly this shape. wot-241-t34
(wf_2c988736) re-flagged the same empirically-false exit-code literal
(task text Some(1), binary provably exits 2) as non_compliant across
all three rounds; wot-241-t4 (wf_f8fe5359) did the same for an
internally contradictory task (step 1 binds every param the step-5
sweep needs free) while its reviewer's own ambiguity field conceded the
text was "technically infeasible". Both burned two repair rounds that
could not converge before BLOCKing; the unclear route ends the same
runs after round one with the contradiction named.

The persona gains a "Task text vs reality" section (verify the
implementer's documented deviation yourself; unforced deviation stays
non_compliant), the matching rationalisation-table row, and a red flag;
the status protocol states that unclear outranks non_compliant for
verified contradictions.
2026-07-13 11:46:35 +02:00
claude 5606ca0213 fix(implement-loop): minor-only quality rounds surface as concerns, not BLOCKED
A quality changes_requested verdict whose findings are all Minor,
arriving after at least one repair dispatch, now breaks the loop with
the findings surfaced as concerns instead of consuming the retry budget
toward a hard BLOCKED.

Grounding (aura runs, 2026-07-12/13): each quality round reads the diff
fresh, so late rounds keep surfacing NEW polish with severity trending
down (Important -> Minor -> comment-only Minor). Run sab-246-t56
(wf_643ee9fa) fixed its one Important finding in round 1, then hard-
BLOCKed an 85-minute green task in round 3 over two stale comment
cross-references; the sibling task was never attempted and the
re-dispatch cost another 32 minutes. Three of 14 runs across the last
three cycles ended review-loop-exhausted with no commit-blocking
residue.

Mechanically, the QUAL_SCHEMA issues array is now structured as
{severity: 'important'|'minor', text} so the valve keys on a declared
classification instead of parsing free-text prefixes; the fingerprint
backstop and the repair-brief prompt render the new shape, and the
quality-reviewer persona documents the honest-severity requirement.
Important findings still consume the full retry budget and BLOCK.
2026-07-13 11:45:47 +02:00
claude cf708632c2 docs(issue): route agent tracker writes through the dedicated claude account
Agent-driven tracker writes previously authenticated as the repository
owner, making agent actions indistinguishable from the owner's own in
tracker history. A dedicated Gitea user `claude` now exists with
collaborator access; the issue skill documents the actor-identity rule
and the credential location.

refs #26
2026-07-12 13:30:40 +02:00
claude 8c03348245 chore: disable background-session worktree isolation
Background sessions are harness-guarded to edit only inside a git
worktree, but this repository forbids worktree development outright
(CLAUDE.md: install.sh symlinks resolve to the primary clone, so
worktree edits are silently ineffective). Align the guard with the
repo rule via worktree.bgIsolation none.
2026-07-12 13:30:40 +02:00
Brummel 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
2026-07-09 11:27:51 +02:00
Brummel 22aafe892a fix(workflows): fail fast on a malformed args carrier instead of misreporting it
Both workflow scripts destructured object-form `args` behind `args || {}`
only. A named-workflow invocation can deliver `args` as a string; a
non-empty string is truthy, so every carrier field silently read
`undefined` and the failure surfaced far from the cause: implement-loop
dispatched its plan-index agent against "Read the plan at undefined" and
stopped only via a mislabelled NEEDS_CONTEXT after burning agent calls;
compiler-driven-edit briefed its edit agent with "EDIT: undefined" and
mapped the agent's refusal onto the straddle-rule BOUNCE to specify —
a mechanics failure dressed as a design finding.

Guards now run before any agent dispatch, mirroring the existing
malformed-input pattern (the task_range guard):

- A string carrier is first JSON-parsed: a JSON-serialized object
  carrier (a stringifying caller or substrate layer that still authored
  the documented object form) is accepted; free text does not parse to
  an object and is rejected.
- A carrier that is not an object (string, number, boolean, array) is a
  distinct infra BLOCKED naming the received type (compiler-driven-edit:
  kind bad-carrier) — never a bounce, never NEEDS_CONTEXT.
- Missing or blank required fields fail fast by name, per mode:
  standard iter_id+plan_path, mini iter_id+red_test_path+cause_summary,
  compiler-driven-edit edit_description+def_site. implement-loop also
  rejects an unknown mode, since the required-field set keys off it.

String-form args are NOT a documented interface — the only invocation
examples in the plugin are object-form (implement/SKILL.md); the issue's
free-text-passthrough fix part was dropped on that ground (triage
verification on the issue). implement/SKILL.md now also documents the
infra early-exit end-report shape (minimal {status, iter_id, reason},
no BLOCKED.md, no blocked_detail) in the Iron Law exceptions, Step 2,
and Step 4's no-file special case.

Verified: both scripts pass node --check (async-wrapped, as the Workflow
substrate runs them) and a 17-case stub-agent harness — malformed
carriers block with zero agent dispatches; valid and JSON-serialized
object carriers reach the first agent unchanged.

closes #24
2026-07-09 11:14:03 +02:00
Brummel f1b3af5f09 docs(boss,specify): propagate the intent-in-English provenance rule to decision-log writers
21a745d rewrote issue rule 4's self-containment carve-out: a chat
decision's provenance is its intention rendered in English, a verbatim
quote only where the exact wording is load-bearing, and then translated.
The three sites that instruct writing such provenance still prescribed
the old verbatim-quote form:

- boss/SKILL.md — the decision-log comment rules, the common-mistakes
  row, and the red-flags entry now demand the intent statement instead
  of quoting the user's words.
- specify/SKILL.md — the fork-resolution comment templates' Basis lines
  carry the intent form.
- specify/agents/spec-skeptic.md — the grounding lens accepts a
  provenance record in the intent form, not only a verbatim statement.
2026-07-09 10:56:40 +02:00
Brummel dacadba07f docs(fragment): stop re-seeding the spec/plan lifecycle restatement
The 'Spec/plan artefacts are ephemeral' section duplicated conventions.md (sections File layout + Lifecycle) and re-seeded that restatement into every new consumer CLAUDE.md - the drift vector that let projects diverge on git-tracked vs git-ignored. The rule now lives once, in conventions.md; the fragment's documented building-block list never included this section anyway.
2026-07-07 11:47:03 +02:00
Brummel 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
2026-07-06 14:14:36 +02:00
Brummel 21a745d090 docs(issue): prescribe stating chat-decision intent in English over verbatim quotes
Rule 4's self-containment carve-out endorsed pasting a dated verbatim
chat quote inline. In practice the chat is not English (chat language per
settings) while an issue is an English repo artefact, so the quote
imported a foreign language and the chat register into the artefact — and
usually only restated an intent already stated in English beside it.

The prescribed self-containment vehicle is now the decision's intention
rendered in English. A verbatim quote survives only where the exact
wording is itself load-bearing, and then translated — never a non-English
quote imported verbatim. Applied to the carve-out, its upstream pointer,
the common-mistakes table (new row), and the red-flags checklist.
2026-07-06 11:56:09 +02:00
Brummel 42e4bf5286 docs(issue): state that the writing rules bind comments too
The four-rules header read "on create and on edit", naming only the
issue-body operations, even though the skill's scope (description,
when-to-use table, tea mechanics) covers commenting and rule 4 is
written around the comment-anchor reader. Make the binding explicit and
carve out rule 3 (a comment has no title).
2026-07-06 11:42:12 +02:00
Brummel 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.
2026-07-02 15:43:36 +02:00
Brummel 52c87d19ce fix(boss): done-state is queue-empty-of-autonomously-doable, not primary-task-complete
A /boss run whose closing gate (audit / milestone fieldtest) surfaces new
follow-up work no longer stops at a manufactured done-state: the
follow-ups — routed inline or filed onto the tracker — re-enter the queue
and take the direction-freedom test, and the loop continues onto the
autonomously-doable subset. Being discovered after the primary task, or
falling outside the originally discussed scope, is not a stopping reason.

The done-state check gains its two edges everywhere it is stated
(Overview, exit list, Iron Law, Step 1, Step 4, notify state 1):

- closing-gate follow-ups re-enter the queue; primary-task-complete is a
  sub-goal, never a done-state;
- a queue of only user-reserved leftovers (idea items, user-reserved
  acts) IS a legitimate done-state, named in the notify — while a
  remaining design fork stays a bounce-back (triggers 1/4, problem-state
  notify), never a done-state wrap-up; when both remain, the bounce
  governs.

Plus a rationalisation-table row and a red flag pinning the observed
failure shape (file the fieldtest findings, then declare done).

closes #21
2026-07-02 12:34:04 +02:00
Brummel 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
2026-07-02 12:14:36 +02:00
Brummel ea54be6535 refactor(pipeline): ignore specs/plans via project-local docs/.gitignore
Replace the global ~/.config/git/ignore mechanism with a committed,
per-project docs/.gitignore whose entries `specs/` and `plans/` are
relative to docs/. The ignore now travels with each repo instead of
living in the user's global excludes.

specify (Step 3) and planner (intro) create docs/.gitignore on demand
if a project has not set it up yet, so a spec/plan can never become
committable. conventions.md § File layout is the single source; the
onboarding fragment tells a new project to set it up.

The global ~/.config/git/ignore block is removed separately (it is
outside this repo).
2026-07-02 11:53:59 +02:00
Brummel 2bc0cf025f fix(pipeline): complete the gitignored-specs refactor (review gaps)
An adversarial review of 08bc2aa found three gaps:

- templates/CLAUDE.md.fragment still described the OLD git-tracked /
  git-rm-at-close model verbatim — the worst place to miss it, since new
  projects import this fragment into their CLAUDE.md. Rewritten to the
  gitignored / shell-rm / ledger-only model.
- INSTALL.md still cited "4-digit naming" — now slug-only.
- The fieldtest cross-cycle deletion rule was self-defeating: it keyed
  the spare/delete decision on the permanent fieldtest- prefix, which
  cannot encode "spare once, then delete." Because fieldtest runs only
  AFTER audit closes, the fresh fieldtest spec never exists at the
  cycle-close sweep, so the rule is simply "audit discards every
  working-tree spec/plan"; the spent fieldtest spec present at N+1's
  close was already consumed and goes with the rest. The prefix is now
  only a working-tree label, not a delete discriminator. Reconciled
  across audit, conventions, pipeline, fieldtest, fieldtester.
2026-07-02 11:46:29 +02:00
Brummel 9ca2c8ab87 chore: remove this repo's own committed specs/plans
These four cycles' specs and plans (glossary integration + skill,
milestone-close gate, specify entry path) were self-development
artefacts committed before specs/plans became gitignored working files
(08bc2aa). They are all long shipped and nothing references them.
Remove them from HEAD to match the new convention — git history retains
them, and docs/specs/ + docs/plans/ are now globally gitignored.
2026-07-02 11:38:55 +02:00
Brummel 08bc2aa027 refactor(pipeline): specs/plans are gitignored working files, never committed
Per-cycle specs and plans stop being git-tracked commit-then-git-rm
artefacts and become git-ignored working files: created on disk for the
active cycle, read across sessions from the working tree, and shell-rm'd
at cycle close by audit. Nothing is committed, so there is no
git-history copy — the durable record of a cycle's intent is the design
ledger only, and no durable artefact (code, test, doc, ledger) may cite
a spec/plan by number or path.

- conventions/pipeline/design/README: invert the git-tracked -> git-rm
  -> git-history-recovery model to gitignored -> shell-rm -> ledger-only.
- naming: drop the NNNN file counter; files are slug.md (fieldtest specs
  keep a fieldtest- prefix as the cycle-close discriminator).
- cycle number: separated from the (now-gone) file number, sourced from
  the feat(NNNN)/audit(NNNN) commit subjects, which cycle commits carry.
- specify/planner/fieldtest/fieldtester: no commit step; fieldtest splits
  fixtures (committed as code) from its spec (gitignored), with the
  cross-cycle rule that a fieldtest- spec belongs to the next cycle.
- boss: auto-sign auditability moves from the (boss-signed) commit
  subject to the run's reference issue; rollback reverts only code.
- audit: new Step 5 shell-rm's the cycle spec+plan after the architect
  reads them, sparing fieldtest- specs.

Companion machine config (outside this repo): the global git excludes
(~/.config/git/ignore) gains docs/specs/ and docs/plans/ so the ignore
applies to every project at once.
2026-07-02 11:35:06 +02:00
Brummel 1a1077b7f7 feat(issue): add comprehension axis and host-free reference grammar
Rule 4 now tests two axes — reachability (the pointer resolves) and
comprehension (a linearly-reading human understands the entry without
absorbing the target). A reachable-but-opaque reference no longer passes.

References go host-free: absolute URLs with a server name or port are
banned; the canonical clickable forms are Gitea relative links —
src/commit/<sha>/path#user-content-<slug> for a file section/line and
issues/N#issuecomment-M for a comment. Verified against live Gitea 1.26.2.

Bind every author, not just an explicit invocation, and pull milestones
into scope (rules 1/2/4 on the description; the title names the
container). Propagate the comment-link form and the rule-4 rename to boss.
2026-07-01 13:51:40 +02:00
Brummel c39a817982 feat(brainstorm): swarm-simulated discovery replacing the serial interview
Replace brainstorm's ~10 serial user round-trips with a parallel
populate-then-triage: enumerate the load-bearing forks, populate them with a
grounded synthetic-user swarm (mandatory per-answer citation), and triage — a
fork the swarm settles on a cited shared ground is decided (user vetoes), a
split or ungrounded-consensus is a direction fork the user settles. A
cross-check surfaces any fork the orchestrator's own enumeration held open but
the swarm closed. A fire-check + grounding floor skip the swarm when it would
be ceremony.

Under /boss the swarm runs autonomously: convergent forks are decided and
recorded on the reference issue, only a divergent direction fork (or a
sub-floor greenfield design) bounces. Retires trigger-4's "fresh brainstorm is
too high-context to run autonomously" rationale — the swarm is the compaction.

- brainstorm/agents/synthetic-user.md: new read-only swarm agent
- brainstorm/SKILL.md: full rewrite to the swarm flow + new Iron Law
- boss/SKILL.md: autonomous swarm-brainstorm (Iron Law, trigger 4, asymmetry,
  notifications, rationalisations, red flag)
- docs/pipeline.md: brainstorm phase description
- specify/SKILL.md: brainstorm characterised as swarm discovery, not interview

closes #19
2026-06-30 22:59:25 +02:00
Brummel dfb53ad7ed docs(postmortem): note the worktree slug caveat for the default log dir
The default project log dir is derived from cwd, so a session run inside a
git worktree resolves to a different slug than the primary clone. Document
that, and point at --project-dir / --file to grade a worktree run.

closes #18
2026-06-30 14:16:44 +02:00
Brummel 69034747c6 feat(install): add --force to repoint symlinks; document worktree caveat
install.sh skipped a symlink pointing at another checkout, so there was
no scripted way to take the live set over. Add a --force flag that
repoints such divergent symlinks at the invoking clone (default run still
skips, stays idempotent). Document in INSTALL.md that the plugin must be
developed in the primary clone, not a worktree, and that --force repoints.

closes #17
2026-06-30 14:16:44 +02:00
Brummel eec4754c3c docs(boss): anchor the rollback sandbox on the captured start HEAD
Define the session anchor as the HEAD revision captured at run start (a
fixed sha), not the live `main` ref, and spell out the git-worktree case:
the run sits on its own branch, so a reset to the anchor only moves that
branch and cannot reach `main`. Keeps the wording correct when the run is
not on `main`. Also rephrase the veto case from "committed on `main`" to
"committed below the session anchor (ratified history)".

closes #16
2026-06-30 14:16:44 +02:00
Brummel a18c0974e8 docs: add repo CLAUDE.md forbidding worktree development
The plugin installs via symlinks pinned at the absolute path of the
primary clone, so skill/agent/workflow edits made in a git worktree of
this repo are not what the live session runs (silent no-op or, on
re-install, a split-brain). Record a no-worktree rule for this repo in a
repo-local CLAUDE.md, with the dominant symlink-pinning rationale plus
the secondary cwd-slug memory/transcript re-keying caveat.

closes #15
2026-06-30 13:35:05 +02:00
Brummel fe0ad9d739 fix(issue,boss): bar tracker entries from carrying the loop's own dispatch
An issue or decision-log entry must state the situation, not the
orchestration loop's next move. "Next step: enter `specify`" — and its
role-periphrasis "hand it off to the spec writer next", which names no
skill — is Claude-Code session control-flow, meaningless to a tracker
reader who is not the loop. A distinct defect class from rule 4
reachability, and not curable by declarative phrasing: the content is
harness-native.

issue rule 1 retitled "No direct address" -> "Impersonal and
tool-neutral". The discriminator is status vs. dispatch, name-independent
(describes the work's condition -> keep; directs who runs what next ->
cut), and rule 1 now also bars first-person loop narration. boss § The
reference issue gains "Record the decision, not the dispatch". Triple-
encoded in both skills (rule/mechanic + table/rationalisation + red-flag).

Future-only; existing entries are not edited.
2026-06-29 18:00:40 +02:00
Brummel 82bb8642b2 style(issue): close the verbatim-quote example before the date
The rule-4 carve-out example wrapped the date inside the quotation
marks; close the quote right after the words so the date reads as
metadata, not part of the verbatim quote.
2026-06-29 11:08:35 +02:00
Brummel 815b559ea6 fix(boss): require decision-log comments to be tracker-reachable
The reference-issue mechanic told the orchestrator to record a fork's
chosen option, rationale, and (for a user decision) "the provenance",
and to use the thread as cross-run memory -- but said nothing about
reachability. So decision-log comments were the main source of
tracker-unreachable references: chat pointers ("decided in-context")
and weak intra-thread pointers ("logged above").

Make the decision log defer to issue rule 4 (the reachability test) in
all three of boss's rule surfaces: the "The reference issue" mechanic
(quote a user decision's provenance inline; reproduce each fork's
options and rationale inline, no bare "Approach B" label; link a sibling
comment by its full URL, never "above"), one Common-Rationalisations
row, and one Red-Flags bullet. The "Skill-system feedback" provenance
block already wrote provenance inline -- it is named as the form to
follow.
2026-06-29 11:08:35 +02:00
Brummel 19db0a933a fix(issue): sharpen rule 4 into a tracker-reachability test
Rule 4 ("Self-contained") forbade dangling pointers by example only, so
a reference reachable only through the producing chat slipped past it --
e.g. a shipped comment "Approach B (the mechanism refinement decided +
logged above)", whose "logged above" names no resolvable entry and whose
"Approach B" indexes an A/B fork the entry never reproduces.

Reframe rule 4 around one test: a reference is valid iff a reader who
lands on the entry alone (e.g. via a direct comment-anchor link) can
follow it to its target. A survey of the live tracker (63 issues / 96
comments) found 56 violations in six classes, now each named as an
unreachable form: chat references, weak intra-thread pointers
("above" / "logged above"), artifacts named by role, out-of-repo paths,
bare un-glossed codes, and locator-shaped tokens that resolve to nothing.
Carve-outs keep inline quotations, #N / SHA / URL / repo-path locators,
glossed codes, and restated forks legitimate. The constructive escape
hatch (log a chat decision to the tracker first, then cite that comment)
cross-references boss "The reference issue".

Align the Common-mistakes table, the Red-flags STOP gate, and the boss
cross-reference. Prescribe a comment's full URL rather than a bare
#issuecomment-NNNN fragment, which is not auto-linked on Gitea and so
does not itself satisfy the test.

Existing tracker entries are left unedited; the rule governs future
writing only.
2026-06-29 10:53:04 +02:00
Brummel 5a9a2ae05c fix(pipeline,audit): gate-side floors for prose-only no-op guards
Two roll-ups were vacuously satisfiable by a no-op and guarded only in
agent prose, never re-verified at the consuming gate:

- The milestone-close functional leg trusted a fieldtest `clean` roll-up
  even from a run with zero examples. The gate now requires
  examples_added >= 2 for a `clean` to be honoured (the empty-report and
  internal-milestone escapes are preserved); a `clean` with fewer over
  user-visible surface is itself a `spec_gap`.
- The audit carry-on accepted an architect `clean` with no evidence of
  review. It now requires a non-empty "What holds" (added as an explicit
  handoff field); a bare `clean` with nothing held — worst when no
  regression scripts run, so the architect is the sole gate — reads as
  unreviewed and is re-dispatched.

Both are second-layer checks: the consumer verifies the field rather
than trusting the agent's discipline. Lower-severity defense-in-depth,
not code-level floors (milestone-close and audit carry-on are
orchestrator-judgment acts with no script to instrument).

closes #14
2026-06-27 14:27:18 +02:00
Brummel f3eba8ab95 fix(grounding-check): an empty extraction is not a vacuous PASS
Step 5 emitted PASS on "all assumptions ratified", which is vacuously
true when the extraction yielded nothing. Under /boss a grounding PASS
IS the autonomous spec signature, so an under-extraction on a real spec
(zero assumptions -> PASS) would auto-sign an unread spec.

An empty assumption list is now a PASS only on a demonstrably trivial
spec (pure rename / doc-only / cosmetic, with the kind named as positive
evidence). An empty extraction over a spec that adds or changes
behaviour is an under-extraction -> BLOCK, which routes the spec to the
human sign-off pause it should have hit. Tightened consistently across
Step 5, the Iron Law, the trivial-spec clause, the Status protocol
table, and the Common Rationalisations.

closes #13
2026-06-27 14:27:18 +02:00
Brummel d6c4faa3c0 fix(implement-loop): require positive edit evidence before DONE
The #11 vacuous-green shape on the main path: `outcome = DONE` was set
purely from the absence of a BLOCKED task, with no check that the
iteration actually wrote anything. `files_touched` was even computed by
the finalize agent but never asserted > 0, `e2e.status` was never read,
and in mini mode the handed-off RED test was never independently re-run
(GREEN was asserted from the implementer's self-report, never observed).

Add a positive-evidence precondition on DONE, taken from git ground
truth — never a self-report, which must not be able to fail a run that
actually did the work:

- Standard mode: a dedicated `tree-check` agent runs `git status
  --porcelain | wc -l` after the per-task loop but BEFORE E2E/finalize.
  Zero (or a non-returning agent) downgrades DONE to BLOCKED. `git
  status --porcelain` (not `git diff HEAD`) so a brand-new untracked
  file — the implementer leaves edits unstaged — still counts; running
  pre-E2E/finalize keeps fixtures and the stats/BLOCKED.md artefacts
  from inflating it.
- Mini mode: an independent `mini-verify` agent re-runs the RED test by
  name and the suite and checks the tree is dirty; a still-red test, a
  regression, or a clean tree is BLOCKED (route back to debug).
- Per-task `applied_changes` (OR-ed across the initial dispatch and
  every repair) feeds only a neutral concern, never the outcome.
- `e2e.status` is now read: a non-DONE status or a zero-fixture run
  surfaces as a concern.

A clean-tree no-op is BLOCKED with no BLOCKED.md (nothing to clean up);
the status + reason ride the end-report. SKILL.md documents the
precondition, the no-BLOCKED.md carve-out, and the Step-4 handling.

closes #12
2026-06-27 14:26:58 +02:00
Brummel 89cc4bb9a8 fix(compiler-driven-edit): require positive edit evidence before DONE
The done-signal `build_clean && suite_green_unchanged` was vacuously
true on a clean working tree, so a no-op edit (the edit agent touched
nothing and reported sites: 0) read as DONE. An orchestrator trusting
that verdict would "commit the unstaged changes" — committing nothing
under a DONE banner.

Add positive evidence that an edit actually landed, checked at two
independent points:

- Phase 1 (cheap, pre-suite): the edit agent reports `applied_changes`
  as ground truth from `git status --porcelain` / `git diff HEAD`. No
  hole + clean tree -> distinct BLOCKED (kind: no-op-edit), skipping a
  pointless suite run against an empty tree.
- Phase 3 (authoritative backstop): DONE now also requires the verify
  agent's independent `working_tree_dirty` observation. The verify
  agent never sees the edit agent's self-report, so a false
  applied_changes is still caught. A green build+suite over a clean
  tree routes to the same BLOCKED, not to debug (a clean tree is no
  regression — nothing to reproduce RED-first).

The precondition keys on tree-dirty, not sites > 0: a legitimate
behaviour-preserving edit can touch only the definition site (sites: 0)
and still dirty the tree. Also fix the DONE note to report a legitimate
sites: 0 as 0 rather than coercing it to null.

closes #11
2026-06-27 13:12:24 +02:00
Brummel 52db1abe10 fix(implement-loop): hold plan-contradicting quality findings instead of oscillating to a false BLOCKED
The per-task quality re-loop treated every `changes_requested` as
"deviate to satisfy", and the quality-repair dispatch was not even
given the task text. When a finding's only remedy contradicted a
plan-prescribed name/signature, the implementer renamed off-plan, the
next review flagged "diverges from plan", and the loop oscillated
name-misleads <-> diverges-from-plan until the retry cap, emitting a
false BLOCKED on code that was green the whole time.

Fix (issue's option 2 — the plan knowledge lives with the implementer,
which holds the task text; the quality-reviewer is deliberately blind
to it, so option 1 would have breached that separation):

- The quality-repair dispatch now receives the task text and a HOLD
  CLAUSE. A cosmetic finding (plan kept => build+tests green) is KEPT
  and recorded in a new `held` field; the loop surfaces it as a concern
  instead of chasing a deviation. A finding the implementer judges
  correctness-breaking escalates to BLOCKED, never a silent hold.
- The hold is keyed on two structural signals, never on a self-reported
  status enum (which the implementer contract overloads): the `held`
  array, and a no-op backstop over a required `diff_fingerprint` (a
  changes_requested verdict over an already-seen diff-state means the
  repair was a no-op or cycled back — re-running quality is futile).
  Fingerprints are tracked in a Set so A-B-A edit-then-revert is caught.
- A no-op-backstop concern is labelled neutrally (a byte-identical diff
  cannot tell a principled plan-hold from an ignored bug); implement
  SKILL.md Step 3 now routes a held/unresolved quality finding to
  orchestrator hand-verification before committing, even under /boss.

The held/no-op partition is the implementer's judgement, not enforced
in code — the residual fail-open is bounded to cosmetic-on-green
findings and disclosed, with the orchestrator's Step-3 inspection as
the backstop, the same trust placed in its other self-reports. Verified
across three rounds of adversarial review (held-the-plan paths, fail-
open laundering, schema/Set mechanics) — all closed.

closes #10
2026-06-22 20:11:06 +02:00
Brummel bbb217d9a8 feat(boss): file skill-system deficiencies to the plugin's own tracker
Under /boss only, when the orchestrator hits a durable deficiency in the
plugin itself (a skill, agent, convention, or pipeline/cascade gap)
mid-run, it files an issue against the plugin's own tracker and continues,
marking provenance with a body block — no new label, so the fixed work-type
vocabulary stays intact.

Adds the trigger and its evidence gate (a citable path:line inside the
plugin), dedupe-as-gate over open and recently-closed issues, and the
discipline that filing is neither a notify event nor a substitute for a due
bounce-back. Wires the new section into issue/SKILL.md (boss joins the
issue-filing callers) and docs/conventions.md (Issue-tracker pointer).

closes #9
2026-06-19 18:39:32 +02:00
Brummel eb74f99bd4 feat(boss): bolder autonomous /boss — grounding-PASS auto-sign, rollback sandbox, reference issue
Retire the obligatory five-lens spec-skeptic auto-sign panel (worst case
18 agent runs per spec under /boss). The autonomous signature is now the
Step-5 grounding-check PASS alone — an independent fresh-context agent's
verdict against currently-green tests; a no-override BLOCK/INFRA_ERROR
routes to the human sign-off pause.

The judgement the panel applied moves upstream into specify Step 1.5,
whose stance inverts: a load-bearing fork the orchestrator can DERIVE an
answer for (sources, code, consistency, risk) is decided boldly and
recorded on the run's reference issue; only a pure-preference fork
bounces. spec-skeptic survives as an optional ad-hoc bias-breaker the
orchestrator pulls when unsure whether its leaning is judgement or bias —
not a gate, not a veto.

Every /boss run carries a mandatory reference issue (created if the cycle
had none): the fork-decision log, the orchestrator's cross-run memory,
and the only surviving trace of a hard-dropped attempt.

Relax main-sacrosanct below the session anchor: within an autonomous run
the orchestrator may git reset --hard its OWN UNPUSHED commits above the
anchor on a dead end — never below the anchor, never a pushed commit
(forward-only/revert). Discarded attempts are hard-dropped, no parking.

Verified across the 9 edited files by a 4-lens adversarial review
(retired-panel residue, cross-file contracts, rollback-boundary safety,
stance coherence): unanimous SOUND. Baseline tagged pre-autosign-rework.

closes #8
2026-06-19 00:06:44 +02:00