From 392e12b82ba0ed2fabda9500d031b1467f20fef3 Mon Sep 17 00:00:00 2001 From: cskwork Date: Wed, 23 Sep 2026 05:57:11 +0900 Subject: [PATCH] feat: leaner contract, test-first bug fixes, generic intake (v0.14.0) - AGENTS.md keeps what an agent must decide (453 -> 324 lines): script-enforced mechanics are one line each, docs/automation.md content is a pointer; rule numbers and section names unchanged; "rule 3a" now resolves - heartbeat (rule 9) and memory reading (rule 4) defined once; stage skills, SKILL.md, and roles/researcher.md reference instead of restating - bug fixes: the reproduction is a regression test by default - fails on the pre-fix code for the reported reason, passes after, stays in the suite - stage 6 intake and symptom classes fit UI, API, job, and CLI; probe 2 is no longer MyBatis-specific - optional researcher:/verifier:/adversary: keys in config.md name the project's own helpers per kit role --- AGENTS.md | 529 ++++++++++++++---------------------- README.ko.md | 4 +- README.md | 4 +- SKILL.md | 33 +-- VERSION | 2 +- init.sh | 6 + log/changelog-v0.14.0.md | 64 +++++ roles/researcher.md | 15 +- roles/verifier.md | 16 +- skills/1-intent/SKILL.md | 47 ++-- skills/2-spec/SKILL.md | 18 +- skills/3-plan/SKILL.md | 17 +- skills/4-build/SKILL.md | 19 +- skills/5-ship/SKILL.md | 15 +- skills/6-maintain/SKILL.md | 73 +++-- skills/6-maintain/probes.md | 12 +- templates/evidence.md | 3 +- templates/intent.md | 2 +- 18 files changed, 387 insertions(+), 492 deletions(-) create mode 100644 log/changelog-v0.14.0.md diff --git a/AGENTS.md b/AGENTS.md index 5c6248e..140977c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,9 @@ # sdlc-kit agent routing contract Anthropic's AI-Native SDLC playbook as plain Markdown and shell scripts. No -runtime hooks, no vendor-specific features. +runtime hooks, no vendor-specific features. The scripts enforce the mechanics +and, when they refuse, print the reason and the fix; this file states only +what an agent must decide or do. ## The loop @@ -22,41 +24,31 @@ the loop. Stage names double as gate names: `gates/check-gate.sh spec .sdlc/work//spec.md`. -**Two routes, one contract.** Every feature runs the FULL route unless it is -small and well understood, in which case it runs the COMPACT route. There is -no third shape: what skills/6-maintain used to call the "compressed loop" is -this same compact route. +**Two routes, one contract.** There is no third shape. -- **Compact** — `intent.md` is the single work artifact and carries the files - to change, the proof, the risk, and the delivery target (templates/intent.md). - Flow: intent (gate) → build → ship (evidence + delivery) → close. No spec, - no plan, and none is ever demanded of it. Ship keeps its full adversary - review — the only review that diff gets. Criteria: skills/1-intent. +- **Compact** — small and well understood. `intent.md` is the single work + artifact and carries the files to change, the proof, the risk, and the + delivery target (templates/intent.md). Flow: intent (gate) → build → ship + → close. No spec, no plan, and none is ever demanded of it. Ship keeps its + full adversary review — the only review that diff gets. Criteria: + skills/1-intent. - **Full** — all six stages, for anything ambiguous, broad, or risky. Any doubt means full. -Stage 1 records the verdict as `- Track: compact` or `- Track: full` -(`micro` is the older spelling of `compact` and still parses everywhere). -The intent approval freezes it: `approve.sh` records the track, `status.sh` -flags a post-approval rewrite, and `approve.sh spec|plan` refuses a -compact-track slug outright. **A track upgrade revalidates the approvals it -changes**: rewrite the Track line to `full — upgraded from compact ()` -and re-approve intent before any spec or plan gate. Work started under the -older compressed loop (a `plan.md` with no `intent.md`) is not stranded and -its gates are not waived — status.sh prints the continuation path -(skills/6-maintain "Continuing older compressed work"). +intent.md's `- Track:` line records the route (`micro` is the older spelling +of compact) and the intent approval freezes it. **A track upgrade +revalidates the approvals it changes**: rewrite the line to `full — upgraded +from compact ()` and re-approve intent before any spec or plan gate. +Older compressed work (a `plan.md` with no `intent.md`) keeps its gates; +`status.sh` prints its continuation path (skills/6-maintain). **Every feature ends in a terminal state**: `gates/close.sh "reason"` after the human decides -(`--delegated` under rule 3). **`shipped` means delivered** — see rule 6: -close.sh re-checks the ship approval and reads `delivery.md`. close.sh then archives the feature: the dir and -its approval records move to `.sdlc/archive//`, so `gates/status.sh` -stays scoped to open work (`--all` lists the newest 20 archived). -Abandoned or dead-end requires a lesson first: -what was tried, why it failed, what would unblock it (lazymode ≥3 waives the -separate lesson file — the close reason is the record). Handed-off requires the -external ticket/PR key or URL in the reason. Add durable facts to DOMAIN.md -when closing. +(`--delegated` under rule 3). `shipped` needs a confirmed delivery (rule 6). +Abandoned or dead-end needs a lesson first — what was tried, why it failed, +what would unblock it (lazymode ≥3: the close reason is the record). +Handed-off needs the external ticket/PR key or URL in the reason. close.sh +archives the feature to `.sdlc/archive//`. ## Hard rules (every stage, every harness) @@ -64,41 +56,28 @@ when closing. relative to this kit's directory. On Windows run `gates/*.sh` and `tools/*.sh` through Git Bash or WSL; `.sdlc/config.md` records a native path as `kit_windows:` when one is needed. -2. **Check the gate first** for stages 2-4 (stages 1, 5, and 6 have none): - `gates/check-gate.sh ` from the project root. - Compact-route features have no spec or plan: build checks the `intent` gate. - Anything but a printed `GATE OPEN` — including errors and silence — is - closed: STOP and tell the human exactly what to approve. At a gate - lazymode waives (rule 3), run that stage's review of the affected code and - behavior, then `approve.sh … --lazy --review ""`, not a human ask. - **What a gate binds**: the approval record names the canonical - `.sdlc/work//` path, the artifact's sha256, and the - digests of the upstream artifacts it was granted on top of — `origin.md`, - the snapshot of the ticket or 기획서 the request came from, included - whenever it exists (templates/origin.md). Editing the - approved artifact, or materially editing an upstream one, closes the gate - with the exact re-approval command — a downstream gate never outlives the - text it was granted for. The digest is CHANGE DETECTION, not - authentication: it proves the bytes are the ones approved, never who - approved them. Records written by an older kit carry no digest and fail - closed, saying so. -3. **Intent, spec, and ship approvals are human decisions** (unless the - project's lazymode waives one — see the lazymode levels below). On the - compact route there is no spec approval at all: the human authorized that - by approving the intent.md that carries the `Track: compact` verdict. Run - `gates/approve.sh --delegated` only after the human - explicitly approves that artifact in chat ("approve", "looks right", or - equivalent). Never approve on silence, a general "continue", or your own - judgment. Never write to `.sdlc/approvals/` directly. - Approval records are gitignored (init.sh): they live in the working copy, - not in git history, so `.sdlc/approvals/` and its `.approval.history` - files ARE the audit trail — a fresh clone mid-feature has none and must - re-gate. Approvals bind a path and content (rule 2): a rewritten artifact - needs a new approval (build-time procedure: skills/4-build deviations). - Re-gates are capped: - two per stage, per feature, at any point in the loop — a third means - intent got the facts wrong (escalation: skills/4-build "Re-gate cap"). +2. **Check the gate first** for stages 2-4: `gates/check-gate.sh + ` from the project root (compact route: build + checks the `intent` gate). Anything but a printed `GATE OPEN` — including + errors and silence — is closed: STOP and tell the human exactly what to + approve. Where lazymode waives that gate, run the stage's review instead + and approve with `--lazy` (rule 3). + **What a gate binds**: the artifact's content and the upstream artifacts + it was granted on — `origin.md`, the snapshot of the ticket or 기획서, + included (templates/origin.md). Editing any of them closes the gate and + the script prints the re-approval command; a downstream gate never + outlives the text it was granted for. The digest is CHANGE DETECTION, not + authentication. +3. **Intent, spec, and ship approvals are human decisions** unless the + project's lazymode waives one (compact route: no spec approval — the + human approved the intent that chose compact). Run `gates/approve.sh + --delegated` only after the human explicitly approves + that artifact in chat ("approve", "looks right", or equivalent). Never + approve on silence, a general "continue", or your own judgment. Never + write to `.sdlc/approvals/` directly. Those records are the audit trail; + they are gitignored, so a fresh clone mid-feature must re-gate. Re-gates + are capped at two per stage, per feature — a third means intent got the + facts wrong (skills/4-build "Re-gate cap"). **Autonomy is not authority.** Two separate questions, never merged: - *Who decides?* — lazymode. It moves human checkpoints to the agent. @@ -107,150 +86,113 @@ when closing. backfill, public API or contract change, security-sensitive paths (auth, secrets, permissions), schema or data migration, and external delivery (push to a shared branch, deploy, anything leaving this repo). - Inside a scope the human already authorized, do not ask again — that is - the point of the authorization. A red flag OUTSIDE that scope stops the - loop and goes to the human as a decision, at every lazymode level. - `approve.sh --lazy` records both: `--review ""` - is mandatory, and `--risk-authorized ""` is required - when the artifact shows risky work. **`tools/tripwire.sh` is supplemental**: - it scans English keywords in one file, so a hit can ADD the authorization - requirement, but a clean scan clears nothing and authorizes nothing. The - review that matters is a read of the affected code and behavior. + Inside a scope the human already authorized, do not ask again. A red flag + OUTSIDE that scope stops the loop and goes to the human as a decision, at + every lazymode level. `approve.sh --lazy` records both: `--review ""` is mandatory, and `--risk-authorized ""` is required when the artifact shows risky work. + `tools/tripwire.sh` scans English keywords in one file: a hit ADDS the + authorization requirement and a fresh-context adversary review; a clean + scan clears nothing. The review that matters is a read of the affected + code and behavior. **The plan gate is tiered.** Trip-wires: schema or data migration, data deletion or destructive backfill, public API or contract change, - security-sensitive paths (auth, secrets, permissions), infra or config - change, beyond-spec scope — anything build would execute irreversibly. - plan.md records the verdict in its **Gate tier** section; the adversary - re-checks every trip-wire, and an understated tier is a blocking finding. - - No trip-wires and no blockers: run `gates/approve.sh plan - --agent-adversary` (recorded as `mode: agent-adversary`), post the - plan's Human summary as FYI, and continue to build. - - Any trip-wire: a human gate, exactly like the others. + security-sensitive paths, infra or config change, beyond-spec scope — + anything build would execute irreversibly. plan.md records the verdict + in its **Gate tier** section; the adversary re-checks every trip-wire, + and an understated tier is a blocking finding. No trip-wires and no + blockers → `approve.sh plan --agent-adversary`, post the + plan's Human summary as FYI, continue. Any trip-wire → a human gate. **lazymode moves the human/auto line.** `lazymode: 0-4` in - `.sdlc/config.md` names which gates stay HUMAN; init.sh seeds 1 and the - agent asks the human which level they want at init. Each level keeps - these gates human and auto-approves the rest with `gates/approve.sh - --lazy --review ""`: + `.sdlc/config.md` names which gates stay HUMAN (init.sh seeds 1; ask the + human at init); the rest auto-approve with `approve.sh + --lazy --review ""`: - 0 — intent, spec, ship human; plan tiered (exactly the rules above) - - 1 (default) — intent, spec, ship human; plan always auto, - trip-wires included + - 1 (default) — intent, spec, ship human; plan always auto, trip-wires included - 2 — intent and ship human; spec and plan auto - 3 — intent human; spec, plan, and ship auto - 4 — no human gates; the whole loop runs autonomously - The `lazymode:` line itself is a human decision: edit it only on - explicit instruction, and commit config.md so the level is audit-trailed. - lazymode waives the human decision, nothing else. **Every `--lazy` - approval still carries a real review of the affected code and behavior**, - recorded in `--review`: plan authorizes what build executes irreversibly, - ship's diff review is the last look before delivery, and intent/spec are - reviewed for what the change actually does, not for which words it uses. - Run `tools/tripwire.sh` as one input among others; a hit means the - stage's adversary review runs and the risk authorization must exist - (intent defines no adversary — a hit on intent.md gets a fresh-context - adversary). - **A waived gate is not a stop.** A stage skill's "tell the human, then - STOP" applies to the gates the project's lazymode keeps HUMAN. Where the - level waives one, the agent runs that stage's review, records the approval - with `--lazy --review`, posts the summary as FYI, and CONTINUES — it does - not ask, and it does not wait. Exactly four things still stop a waived - loop, at every level including 4: work outside the authorized scope, an + The `lazymode:` line is itself a human decision: edit it only on explicit + instruction. lazymode waives the decision, never the review: every + `--lazy` approval carries a real review of the affected code and + behavior. `approve.sh --lazy` refuses a stage the level keeps human, and + any value outside 0-4 counts as 0. + + **A waived gate is not a stop.** "Tell the human, then STOP" applies to + the gates the level keeps HUMAN. At a waived one the agent reviews, + approves with `--lazy --review`, posts the summary (and any trip-wire + list) as FYI, and CONTINUES. Exactly four things stop a waived loop, at + every level including 4: work outside the authorized scope, an unresolved MATERIAL question in intent.md, a blocker surviving its round - cap, and external delivery beyond a review branch (merge, deploy). Ask each - of them ONCE, as one concrete decision; a question already answered for + cap, and external delivery beyond a review branch (merge, deploy). Ask + each ONCE, as one concrete decision; a question already answered for this scope is not asked again. - **The full-auto intent contract.** An unattended run may act on an - `intent.md` only when it states an actionable outcome, its scope and - non-goals, acceptance criteria, labelled evidence, a `Scope authorization` - line (the human's words), and a `## Material questions` section with - nothing unresolved in it. Known facts from the ticket, the code, and - DOMAIN.md come first; what remains are the questions. A question is - MATERIAL when a wrong answer would change what gets built, break something, - or exceed the authorized scope — it goes to the human, and is never guessed - away to make progress. Optional uncertainty is decided from evidence or - carried as `[assumed: why]` under `## Open questions`, and blocks nothing. - Missing required evidence or an unauthorized risk blocks the same way. - `tools/auto.sh intent-check ` reports the verdict. - - **A blocker surviving its round cap blocks `--lazy` at every stage**: - the gate reverts to a human ask; at lazymode 4 the loop stops. - Approvals are still recorded, and every auto-approved gate still posts its - Human summary (and any trip-wire list) to the human as FYI. `approve.sh - --lazy` refuses a stage the configured level keeps human, and any - `lazymode:` value outside 0-4 counts as 0. + **3a. The full-auto intent contract.** An unattended run may act on an + `intent.md` only when it states an actionable outcome, scope and + non-goals, acceptance criteria, labelled evidence, a `Scope + authorization` line (the human's words), and no unresolved MATERIAL + question — one whose wrong answer would change what gets built, break + something, or exceed the authorized scope. Those go to the human and are + never guessed away; optional uncertainty is carried as `[assumed: why]` + and blocks nothing. `tools/auto.sh intent-check ` reports the + verdict (section rules: templates/intent.md; full text: docs/automation.md §3). 4. **Keep memory bounded.** At each stage start read `.sdlc/memory/POLICY.md` (human-declared hard rules), `.sdlc/memory/INDEX.md` (lessons; 50 lines max), `.sdlc/memory/DOMAIN.md` (terms, verified facts, constraints; 100 lines max), and the feature's own `harvest.md` if present, then open lesson files whose tags match the - task. DOMAIN over its limit: split by subdomain, leave pointer lines. - INDEX over its limit: merge near-duplicates, drop superseded entries, - remove entries already promoted (skills/6-maintain). + task. Stage skills do not repeat this. DOMAIN over its limit: split by + subdomain, leave pointer lines. INDEX over its limit: merge + near-duplicates, drop superseded entries, replace promoted ones + (skills/6-maintain). **INDEX.md, DOMAIN.md, and lessons/ have one writer: the close step.** - Mid-loop, stages and researchers append candidates to - `.sdlc/work//harvest.md` (templates/harvest.md), never to the - shared files. At close, merge harvest into lessons/INDEX/DOMAIN and - delete it; `close.sh` blocks while harvest.md exists. - **A loop that never closes must not hide its knowledge.** An unmerged - harvest is readable before close — `tools/kb.sh show ` and the - contents page print its candidates, `tools/kb.sh harvest` lists every - open feature that holds one with its idle time — and a feature idle 30 - days or more (`--stale ` changes the threshold) may have its - harvest merged WITHOUT closing: the same procedure, the same one merge - at a time in the owning checkout, harvest.md deleted afterwards, the - feature stays open. Reporting is not merging: nothing in `kb.sh` writes - `memory/`. The feature's `summary.md` (templates/summary.md) is the one - record meant to be rewritten as the work moves — it is bound by no - approval — and is what `kb.sh show` prints first. + Mid-loop, stages and researchers append candidates — one line each — to + `.sdlc/work//harvest.md` (templates/harvest.md). At close, merge + harvest into lessons/INDEX/DOMAIN and delete it; `close.sh` blocks while + it exists. A feature idle 30 days or more may have its harvest merged the + same way WITHOUT closing — one merge at a time, in the owning checkout + (`tools/kb.sh harvest` lists them); nothing in `kb.sh` writes `memory/`. **Recency wins on merge, three guards.** A contradicting candidate - replaces the old entry with a fresh `[verified: how — YYYY-MM-DD]`; - date every fact. Guards: weaker evidence never supersedes stronger (a - code-read vs a production capture goes to the human); both-true-in- - different-scopes gets qualified, not replaced; a `supersedes:` target - already rewritten by a parallel close is reconciled by evidence, not - appended. Human-stated lines are never deleted on recency alone — ask. - **POLICY.md is written only on the human's word** (the one shared-memory - file outside the close-writer rule). When the human states a hard rule in - chat, transcribe it with the date and their words; never add, soften, or - remove a rule on your own judgment. A mid-loop transcription commits - with the next close. The adversary treats a violation as blocking. - The archive is bounded the same way: `status.sh --all` and `stats.sh` - default to the newest 20 closed features. Never read the whole - `.sdlc/archive/` into a working context — answer archive questions with - `tools/kb.sh search ""` or `tools/kb.sh show ` (rule 7), a - targeted `ls`/`grep`, or a single slug lookup. + replaces the old entry with a fresh `[verified: how — YYYY-MM-DD]`; date + every fact. Weaker evidence never supersedes stronger (a code-read vs a + production capture goes to the human); both-true-in-different-scopes gets + qualified, not replaced; a `supersedes:` target already rewritten by a + parallel close is reconciled by evidence. Human-stated lines are never + deleted on recency alone — ask. + **POLICY.md is written only on the human's word**: transcribe a hard rule + they state in chat with the date and their words; never add, soften, or + remove one on your own judgment. The adversary treats a violation as + blocking. + Never read the whole `.sdlc/archive/` into context: use `tools/kb.sh + search ""` / `show ` (rule 7), a targeted `ls`/`grep`, or a + single slug lookup. 5. **Fresh context for helpers.** Verification and adversarial review run in a fresh context — a subagent (pi: subagent tool; Claude Code: Task; Codex: spawn), else a new session given only the `roles/*.md` file and artifact paths — never in the context that authored the artifact. Give - the verifier and adversary the strongest model available. - - **One delegate is the default.** A single implementer carries the loop. - Do NOT dispatch a subagent per stage as a matter of course — the handoffs - cost more than they save on ordinary work. Scope a dispatch when it - genuinely helps: a large read-only exploration whose raw output should not - enter the main context, independent probes that can run in parallel, or a - sub-task with a crisp contract. Verification and adversarial review are - the exception that always stands: they run in a fresh context, because - the author cannot review their own work. If the harness cannot give them - one, say so in the artifact as an explicit gap ("no independent - verification available: ") instead of self-reviewing quietly. + them the strongest model available. A harness that cannot provide one + gets an explicit gap line in the artifact ("no independent verification + available: "), never a quiet self-review. + + **One delegate is the default.** A single implementer carries the loop; + do not dispatch a subagent per stage as a matter of course. Dispatch when + it buys something concrete: a large read-only exploration, independent + probes that can run in parallel, or a sub-task with a crisp contract. **Caps survive dispatch.** Write each count the moment it increments: - deviations, re-gates, fix-loop rounds → deviations.md (template); ship - adversary rounds → evidence.md; map sessions → map.md's Session log; - evidence requests → one intent.md line each; re-approvals → - `.approval.history` (approve.sh). Counters live on disk, not in context; - grill and fan-out caps are per-session and do not persist. + deviations, re-gates, fix-loop rounds → deviations.md; ship adversary + rounds → evidence.md; map sessions → map.md's Session log; evidence + requests → one intent.md line each; re-approvals → `.approval.history` + (approve.sh). Grill and fan-out caps are per-session and do not persist. **Roles are contracts, not headcount.** Independent probes (git history, live UI, API, DB) may run in parallel under one role: fewest read-only - workers, one writer per checkout. The dispatcher resolves contradictions - with primary evidence; a contradiction between probes is a finding. At - most two fan-out rounds per question — after that the contradiction goes - to the human, not to more probes. + workers, one writer per checkout. A contradiction between probes is a + finding, resolved with primary evidence; at most two fan-out rounds per + question, then it goes to the human. **Dispatch contract.** Every dispatch names: goal, exact input paths, write authority, verification commands from `.sdlc/config.md`, success @@ -258,134 +200,70 @@ when closing. instead of improvising). **Bulk rule.** Screenshots, probe logs, traces, and large command dumps - go to the gitignored `.sdlc/work//scratch/`; quote the deciding - lines in the stage artifact and keep the file. A bare `scratch/…` citation - does not survive a fresh clone — cite it only beside the quoted lines, or - point at a durable home (the PR body, an artifact URL). Scratch survives the push: - it is pruned once, at close, and anything evidence.md, delivery.md, or a - lesson cites is KEPT and named as load-bearing there. Nothing is deleted - mid-loop, and nothing referenced is deleted at all. + go to `.sdlc/work//scratch/`; quote the deciding lines in the + stage artifact beside the citation (a bare `scratch/…` path does not + survive a fresh clone; a PR body or artifact URL does). Nothing is + deleted mid-loop; close prunes scratch and keeps what a record cites. 6. **Proof over claims.** Every "done" claim carries command output, using the real commands in `.sdlc/config.md`. - **Verification runs the real thing, through three lenses.** Before a - feature ships, a fresh-context verifier (roles/verifier.md) checks it three - ways, in parallel. **E2E**: the changed behavior exercised through the - interface a user or caller actually meets, with the project's own commands - (`.sdlc/config.md`: `e2e:`, `qa:`, `run:`), scoped to the change — never - the whole product suite as a ritual. **Side effects**: what else changed - between AS-IS and TO-BE — the baseline, the untouched items, and the - consistency of every data shape the change writes or reads across its other - producers and consumers. **Intent match**: the build read back against the - origin of the request — `origin.md`, the snapshot the intent gate bound, - plus the live ticket or 기획서 when reachable — per intent.md O-item, - naming what is covered, missing, and beyond. Each check records command or tool, - environment, scenario, and the observed result. **No environment to run it - in = NOT VERIFIED**: say what is missing, in evidence.md. A passing unit - suite is never a silent substitute, and a delivery over a known gap is - allowed only when the human accepts that gap explicitly. A finding from any - lens enters the build fix loop (skills/4-build): three rounds, then the - human — `tools/auto.sh` reads the round lines in deviations.md and reports - an exhausted loop as `fixloop.exhausted`, needs-human at every lazymode. - - **A receipt makes a missing proof detectable** (optional, and the loop - works without it). A project that fills `.sdlc/verify.md` - (templates/verify.md) maps each requirement to its own real command, plus - the launch, doctor, and cleanup commands around them; `tools/verify.sh run - ` executes EVERY one of them, bounded and isolated, and records a - receipt bound to the source snapshot before and after the run, the recipe, - and each command's and output's digest. Editing the code, the commands, or - the recipe makes the receipt `stale`; a cited log that is missing or was - edited, or checks that do not add up, make it `invalid`. Under - `profile: strict` a feature is not review-ready without a passing `runtime` - or `e2e` check against a runtime that run actually launched, and a doctor - that never comes up is NOT VERIFIED — never "the unit suite is green". - A receipt is CHANGE DETECTION, not authentication: it makes "this never - ran" and "this was edited afterwards" visible, and says nothing about who - produced it. It does not replace the independent fresh-context verifier - (rule 5). + **Verification runs the real thing, through three lenses** — E2E, Side + effects, Intent match — each in its own fresh context, in parallel + (roles/verifier.md defines them). **No environment to run it in = NOT + VERIFIED**: say what is missing, in evidence.md. A passing unit suite is + never a silent substitute, and a delivery over a known gap is allowed + only when the human accepts that gap explicitly. A finding from any lens + enters the build fix loop (skills/4-build): three rounds, then the human + at every lazymode (`tools/auto.sh` reports `fixloop.exhausted`). + A project that fills `.sdlc/verify.md` (templates/verify.md) gets a + receipt from `tools/verify.sh run ` that makes "this never ran" and + "this was edited afterwards" detectable (docs/automation.md §4). It does + not replace the fresh-context verifier. + + **A bug fix carries its own proof chain**: the failure observed before + the fix, the causal mechanism, the SAME reproduction passing after, and + the adjacent flows that share the changed code. **The reproduction is a + test by default**: an automated test at the lowest level that reaches the + defect — unit, integration, API, or browser — that FAILS on the pre-fix + code for the reported reason, passes after, and stays in the suite as the + regression guard. Manual steps, logs, or traces stand in only when no + test can reach the defect: say why. An intermittent defect may use logs, + traces, or an isolated deterministic reproduction, with its limitation + stated. Without the chain the work is a diagnosis or an instrumentation + change — say so; never call it a confirmed fix. **"Shipped" means delivered.** The ship approval is a decision to - deliver; it is not a delivery. A feature closes as `shipped` only when - the agreed target — local implementation, PR, or deploy — is proven to - have happened, in `.sdlc/work//delivery.md` (templates/delivery.md): - target, the source identity that was reviewed, the command or project - tool actually run, and its verbatim deciding output. Remote facts (PR - state, deploy result) are established with the project's own tools, never - by asserting them in prose; a `pr` or `deploy` delivery must name the - delivered commit, and that commit must CONTAIN the reviewed source — - close.sh compares its tree against the reviewed snapshot, so a commit that - merely exists is refused. Local work needs no production step — `local` is - a first-class target. close.sh re-checks the ship approval (evidence - unchanged, source unchanged since the review) and refuses an absent, - mismatching, or unconfirmed delivery. - **What the ship approval binds is the project's whole source snapshot** as - the review saw it: every tracked file plus every untracked file git does - not ignore, minus `.sdlc/`, by path, content, and executable bit. Staging - or committing those exact bytes keeps the binding valid — work committed - BEFORE the review is bound too. An edit, a new file, a deletion, a chmod, - or a symlink swap afterwards breaks it, including in a file the review did - not name: a source change nobody reviewed never closes silently. check-gate, - status, and close say the same thing in the same words, and name the files - that changed. Approvals written by an older kit bound only the uncommitted - diff and fail closed, saying so. (Submodule contents are not bound.) A - path name git C-quotes — tab, newline, double quote, or backslash in the - name — cannot be bound: approve.sh refuses it by name, and one that - appears after the review closes the gate as an invalid source. - + deliver, not a delivery. A feature closes as `shipped` only when the + agreed target — `local`, `pr`, or `deploy` — is proven in + `.sdlc/work//delivery.md` (templates/delivery.md): target, the + delivered source, the command or project tool actually run, and its + verbatim deciding output. Remote facts (PR state, deploy result) come + from the project's own tools, never from prose. The ship approval binds + the project's whole source snapshot as the review saw it; any change + afterwards closes the gate, and check-gate/status/close name the files. **Review-ready is not merged, and not deployed.** A loop's own exit is a - FEATURE BRANCH pushed for a human to review: `tools/handoff.sh push - --authorized ""` refuses without that authorization, - refuses protected or shared branches, never force-pushes, refuses a commit - whose tree does not CONTAIN the reviewed source, and repeats no push that - already happened. `tools/handoff.sh check ` establishes the remote - branch's SHA with git, never in prose. Merging that branch or deploying it - is a separate human approval, recorded as `Authorized-by:` in delivery.md at - every lazymode level. delivery.md's `Remote`, `Branch`, `Handoff` and - `Authorized-by` lines are optional and backward-compatible: an older record - closes exactly as it did. - - **A bug fix carries its own proof chain** (skills/6-maintain): the - failure observed before the fix, the causal mechanism, the SAME - reproduction passing after, and the adjacent flows that share the changed - code. An intermittent defect may substitute logs, traces, or an isolated - deterministic reproduction, with its limitation stated. Without that - chain the work is a diagnosis or an instrumentation change — say so; do - not call it a confirmed fix. -7. **Artifacts live in the record store** under `.sdlc/work//` while - open and `.sdlc/archive//` after close. **The store is - gitignored in full** (`/.sdlc`, written by init.sh): the records are the - project's knowledge, not its source, so they never enter the - application's history and a clone of the application does not carry - them. They stay where they are written — in the project's working copy, - or, when `init.sh --area ` was used, in the folder the - human chose, one store per checkout (`/-/`, - `.sdlc` linked to it, ownership recorded in `PROJECT`). Nothing is ever - relocated automatically, and a store another checkout owns is refused, - never shared — at init AND before every gate verdict or state write, so a - copied working copy (the symlink survives `cp -R`) cannot open another - checkout's gate or close its features. Reading is not bound that way: - `tools/kb.sh` retrieval stays available, including `--area`. - **Backing the store up is the human's, not git's.** - The durable record is the same as before — `origin.md`, `intent.md`, - `spec.md`, `plan.md`, `map.md`, `evidence.md`, `delivery.md`, `CLOSED`, - `memory/`, `config.md`: the decisions and the final proof, readable a - year later. Working residue (`approvals/`, `baseline.txt`, - `deviations.md`, `harvest.md`, `progress.md`, `scratch/`) sits beside it - and is never quoted into an artifact. Bulk evidence lives in `scratch/`; - evidence.md quotes the deciding lines and cites the file, so the record - stays small. A PR body that carries the same evidence is an acceptable - durable home — link it from evidence.md. The kit directory stays - framework-only. - **Records are read back, not just written.** `tools/kb.sh` is the way in: - `index` regenerates the store's contents page (init.sh and close.sh run - it), `show ` prints one feature's goal, documents, delivery and - lessons, and `search ""` is a bounded literal search across open - and closed features and durable memory. `--area ` covers every - owned store in that folder, including features whose checkout is gone. - Exit codes: 0 found, 1 nothing found, 2 usage error or refusal. Never - read a whole archive into context to answer a question `search` or - `show` answers. + feature branch pushed for review (`tools/handoff.sh push + --authorized ""`); merging or deploying it is a + separate human approval, recorded as `Authorized-by:` in delivery.md at + every lazymode (skills/5-ship). +7. **Artifacts live in the record store** under `.sdlc/work//` + while open and `.sdlc/archive//` after close. The store is + gitignored in full (`/.sdlc`): the records are the project's knowledge, + not its source, and a clone does not carry them. They stay where they + are written — the working copy, or the folder the human chose with + `init.sh --area `. A store another checkout owns is + refused, never shared. **Backing the store up is the human's, not + git's.** The durable record is `origin.md`, `intent.md`, `spec.md`, + `plan.md`, `map.md`, `evidence.md`, `delivery.md`, `CLOSED`, `memory/`, + and `config.md`; working residue (`approvals/`, `baseline.txt`, + `deviations.md`, `harvest.md`, `progress.md`, `scratch/`) is never quoted + into an artifact. The kit directory stays framework-only. + **Records are read back, not just written**, through `tools/kb.sh`: + `search ""` (bounded, literal, open and closed features plus + memory), `show ` (summary.md first, then goal, delivery, lessons, + paths), `harvest` (unmerged candidates), `index` (contents page). + `--area ` covers every store in that folder, including features + whose checkout is gone. Exit 0 found · 1 nothing · 2 usage/refusal. 8. **Speak plainly.** Every report, gate request, and question starts with one short context paragraph (which stage, what happened before, what this message is for), uses short active sentences and the project's own @@ -393,32 +271,23 @@ when closing. take. 9. **Heartbeat.** `.sdlc/work//progress.md` holds exactly one line — `[ n/m] · · ` — - overwritten (never appended) on stage entry and whenever the sub-task - changes; before a dispatch, the orchestrator writes the dispatch as the - line. A sub-task that runs long refreshes the line at each natural - checkpoint (a command finished, a file edited) even when the text does - not change, so a stale heartbeat means a dead loop, not a slow step. - It is a live signal for the human, not a record: gitignored - (init.sh), never quoted into artifacts, and `status.sh` shows it with - its age so silence and a dead loop look different. History stays where - it already lives (deviations.md, evidence.md, harvest.md). + overwritten, never appended: as soon as the slug dir exists, on stage + entry, at every sub-task change, and before every dispatch. `` is + the stage name (`intent`, `spec`, `plan`, `build`, `ship`, `maintain`); + build adds `n/m` over plan.md's Order of work. A long sub-task refreshes + the line at each natural checkpoint even when the text does not change, + so a stale heartbeat means a dead loop, not a slow step. It is a live + signal (`status.sh` shows its age), never quoted into artifacts. Stage + skills do not repeat this rule. ## Driving the loop from a host (no daemon, no scheduler) -`gates/status.sh --json` (= `tools/auto.sh status --json`, schema -`sdlc-kit/auto-status@1`) is the machine view: per feature the stage, a -`status` of `ready | needs-human | blocked | complete`, the next action, the -blockers, the source identity, the verification and delivery state, and the -`exit_condition` (`review-ready` ≠ `deployed`). `tools/auto.sh next ` -prints one line and exits 0 / 10 / 20 / 30 for those four states. Every verdict -comes from `gates/_common.sh`, so the machine view is never more permissive -than the gates. - -These scripts REPORT and RECORD. They run no model and perform no stage: a -`ready` status means the next action is one the project's lazymode lets an -agent take, and the agent still takes it under the stage skill. The drive / -resume procedure, the verification recipe, the handoff boundary, the checkpoint -and its retry classes are documented in `docs/automation.md`. +`gates/status.sh --json` (= `tools/auto.sh status --json`) is the machine +view and `tools/auto.sh next ` exits 0 ready · 10 needs-human · 20 +blocked · 30 complete. Every verdict comes from `gates/_common.sh`, so the +machine view is never more permissive than the gates. These scripts REPORT +and RECORD; they run no model and perform no stage. Drive/resume procedure, +verification recipe, and handoff boundary: `docs/automation.md`. ## Greenfield vs brownfield @@ -437,10 +306,12 @@ baseline captured before changes, and a "what stays untouched" spec section. 2. **Existing knowledge wins.** DOMAIN.md points at existing glossaries, CONTEXT.md, ADRs, and domain docs (`- see docs/glossary.md [verified: exists]`) and holds only facts that exist nowhere else. -3. **Existing agents win.** Dispatch a matching local specialist (QA agent, - code reviewer, DB reader) with the kit's role file as its task contract; - spawn a generic worker only when no specialist fits. Fresh context and - the dispatch contract still apply. +3. **Existing agents win.** When `.sdlc/config.md` names a project agent or + skill for a role (`researcher:`, `verifier:`, `adversary:`), dispatch + that one with the kit's role file as its task contract; otherwise pick a + matching local specialist (QA agent, debugger, code reviewer, DB reader) + and spawn a generic worker only when none fits. Fresh context and the + dispatch contract still apply. 4. **Monorepos.** One `.sdlc/` per shipping unit — usually the service or package, not the repo root; a root `.sdlc/` only for cross-unit changes. intent.md names the owning unit. diff --git a/README.ko.md b/README.ko.md index c5b5310..21e8732 100644 --- a/README.ko.md +++ b/README.ko.md @@ -212,7 +212,7 @@ abandoned나 dead-end는 교훈이 없으면 닫히지 않습니다(lazymode 3 ### 장애 진단은 싼 프로브부터 -6단계는 에이전트를 대량으로 풀지 않습니다. 배포된 소스를 먼저 확인합니다. `refcheck.sh`는 작업 트리의 내용을 스테이징·비스테이징·미추적까지 모두 대상 리비전과 비교하고, 릴리스 시스템이 알려주는 실제 배포 SHA가 있으면 `--deployed-sha`로 받고, ref나 fetch가 실패하면 추측 대신 UNKNOWN을 보고합니다. 그다음 어떤 통제가 뚫렸는지 묻고, 요청한 재현 증거를 추적하고, `skills/6-maintain/probes.md`의 짧은 프로브를 돌립니다. +6단계는 에이전트를 대량으로 풀지 않습니다. 배포된 소스를 먼저 확인합니다. `refcheck.sh`는 작업 트리의 내용을 스테이징·비스테이징·미추적까지 모두 대상 리비전과 비교하고, 릴리스 시스템이 알려주는 실제 배포 SHA가 있으면 `--deployed-sha`로 받고, ref나 fetch가 실패하면 추측 대신 UNKNOWN을 보고합니다. 그다음 무엇을 어떤 입력으로 했는지, 대신 무슨 일이 일어났는지, 어디서, 누구로, 어떤 흔적이 남았는지 묻고(UI·API·배치 작업·CLI 모두 같은 다섯 질문), 요청한 재현 증거를 추적하고, `skills/6-maintain/probes.md`의 짧은 프로브를 돌립니다. 프로브는 수정 계획에 도달하기 전에 흔한 진단 실수 네 가지를 잡습니다. @@ -221,6 +221,8 @@ abandoned나 dead-end는 교훈이 없으면 닫히지 않습니다(lazymode 3 - 아래 계층이 이미 삼키는 에러에 `try/catch`를 덧대는 실수 - 데이터 없는 정상 상태를 확인하지 않고 "리스크 제로"라고 말하는 실수 +버그 수정은 수정 전 코드에서 보고된 이유로 실패하는 회귀 테스트부터 만듭니다. 같은 테스트가 수정 후 통과하고 테스트 스위트에 남습니다. 테스트로 결함에 닿을 수 없을 때만 수동 절차나 로그로 대신하고, 그 이유를 증거에 적습니다. + 재현이 안 되는 장애는 새 컨텍스트 adversary들이 범위를 다시 세고, 주장된 에러 전파를 증명하고, 모든 "절대 안 그래" 주장을 공격하고, 경쟁 원인을 제시합니다. 받지 못한 콘솔, 네트워크, 스크린샷 증거는 사람이 받거나 면제할 때까지 `status.sh`에 계속 보입니다. ## 조종석 diff --git a/README.md b/README.md index 87d5cab..7dc6a54 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ An abandoned or dead-end run cannot close until a lesson exists (at lazymode ≥ ### Incident diagnosis starts with cheap probes -Stage 6 does not begin with a broad agent fan-out. It first checks the deployed source — `refcheck.sh` compares the working tree's content (staged, unstaged, and untracked alike) against the target revision, takes the real deployment SHA with `--deployed-sha` when the release system reports one, and reports UNKNOWN rather than guessing when a ref or fetch fails — asks which control failed, tracks requested reproduction evidence, and runs the short probes in `skills/6-maintain/probes.md`. +Stage 6 does not begin with a broad agent fan-out. It first checks the deployed source — `refcheck.sh` compares the working tree's content (staged, unstaged, and untracked alike) against the target revision, takes the real deployment SHA with `--deployed-sha` when the release system reports one, and reports UNKNOWN rather than guessing when a ref or fetch fails — asks what was done with what input, what happened instead, where, as whom, and what trace exists (the same five questions for a UI, an API, a job, or a CLI), tracks requested reproduction evidence, and runs the short probes in `skills/6-maintain/probes.md`. The probes catch four common diagnosis mistakes before they reach a fix plan: @@ -221,6 +221,8 @@ The probes catch four common diagnosis mistakes before they reach a fix plan: - adding a `try/catch` where the lower layer already swallows the error; - calling a change "zero risk" without checking normal missing-data states. +A bug fix starts with a regression test that fails on the pre-fix code for the reported reason; the same test passes after and stays in the suite. Manual steps or logs stand in only when no test can reach the defect, and the evidence says why. + When the incident cannot be reproduced, fresh-context adversaries recount the scope, prove the claimed error propagation, attack every "never" claim, and propose a rival cause. Outstanding console, network, or screenshot evidence stays visible in `status.sh` until it is received or the human waives it. ## Cockpit diff --git a/SKILL.md b/SKILL.md index 70f20b0..e3b92c5 100644 --- a/SKILL.md +++ b/SKILL.md @@ -8,8 +8,9 @@ description: "Gated SDLC loop with human approvals, for building features and fi One loop, six stages, one artifact per stage, and a gate between stages: human at intent, spec, and ship; tiered at plan; `lazymode:` in `.sdlc/config.md` can waive human gates (AGENTS.md rule 3). -This file routes requests. `AGENTS.md` in this directory is the full contract. -Read it completely on first contact with a project, then return here. +This file routes requests. `AGENTS.md` in this directory is the full contract +— gates, authority, memory, fresh-context review, proof. Read it completely +before the first stage of a session, then return here. ## When this skill runs @@ -35,30 +36,10 @@ they do it under this contract (gates, artifacts, memory), not beside it. | ticket too big or foggy for one intent pass | `map.md` in the same slug dir first (skills/1-intent "Chart a map first"); one Unknown per session, six sessions max. | | "continue " / "what's next" | Run `gates/status.sh ` from the project root. Its `next →` line names the stage skill or gate command. | | "where are we" / "sdlc status" | `gates/status.sh` (open features; `--all` adds the newest 20 archived) + `gates/stats.sh` (open + recent closed). Full-archive sweeps: `ls`/`grep .sdlc/archive/`, never the whole listing into context. | -| "has this been done before" / "why is X like this" / debugging an old area | `tools/kb.sh search ""` then `tools/kb.sh show ` — a digest (goal, summary.md, delivery, unmerged harvest candidates, lesson titles, then the paths) over open and closed features plus durable memory, bounded output (`--area ` covers every store, even one whose checkout is gone). Exit 0 found · 1 nothing · 2 usage/refusal. | -| "what did we learn that is not in memory yet" / many open features, few closes | `tools/kb.sh harvest [--stale ]` — open features whose harvest.md no close has merged, with idle time; a STALE one may be merged without closing (AGENTS.md rule 4). The contents page (`tools/kb.sh index`; `index_style: obsidian` in config.md for a vault) shows the same candidates and an overview table by state, date and tags. | -| a host/scheduler drives the loop, or you need machine state | `gates/status.sh --json` (= `tools/auto.sh status --json`) and `tools/auto.sh next ` (exit 0 ready · 10 needs-human · 20 blocked · 30 complete). Verification receipts: `tools/verify.sh`; review handoff: `tools/handoff.sh`. Contract: `docs/automation.md`. These report and record — they run no stage. | +| "has this been done before" / "why is X like this" / debugging an old area | `tools/kb.sh search ""` then `tools/kb.sh show ` (AGENTS.md rule 7). | +| "what did we learn that is not in memory yet" / many open features, few closes | `tools/kb.sh harvest [--stale ]`; a stale one may be merged without closing (AGENTS.md rule 4). Contents page: `tools/kb.sh index` (`index_style: obsidian` in config.md for a vault). | +| a host/scheduler drives the loop, or you need machine state | `gates/status.sh --json`, `tools/auto.sh next `; contract: `docs/automation.md`. | | gate request answered "approve" in chat | `gates/approve.sh --delegated` per AGENTS.md rule 3. | | incident / bug / alert on a shipped feature | Read `skills/6-maintain/SKILL.md`. | -| "we're done / drop this / dead end" for a feature | `gates/close.sh "reason"`. `shipped` needs a confirmed `delivery.md` (templates/delivery.md) and an unchanged ship approval; dead-end/abandoned need a lesson (lazymode ≥3: the reason line suffices); handed-off needs an external ticket/PR reference. close.sh archives the feature to `.sdlc/archive//`. | +| "we're done / drop this / dead end" for a feature | `gates/close.sh "reason"` — what each needs: AGENTS.md "Every feature ends in a terminal state". | | project has no `.sdlc/` yet | Run `/init.sh` from the project root (records are gitignored; `--area ` keeps them in a folder the human names instead); ask the human which lazymode level they want (0–4, default 1; AGENTS.md rule 3) and set it in `.sdlc/config.md`; fill the config commands; then stage 1. | - -## Coexistence (full text in AGENTS.md) - -Project rules control implementation details such as commands, branches, and -style. The kit controls stages, gates, and memory. Quote conflicts to the human -instead of resolving them silently. DOMAIN.md points at existing -glossaries/ADRs instead of copying. Kit roles dispatch onto existing specialist agents when one fits. -Monorepos: one `.sdlc/` per shipping unit. - -## Invariants (full text in AGENTS.md) - -Before stages 2–4, check the gate. One delegate carries the loop; verification -and adversarial review always run in a fresh context, and a harness that cannot -provide one gets an explicit gap line in the artifact (AGENTS.md rule 5). -Read `.sdlc/memory/POLICY.md`, -`.sdlc/memory/INDEX.md`, and `.sdlc/memory/DOMAIN.md` at every stage start; -mid-loop memory candidates go to the feature's `harvest.md`, merged only at -close (rule 4). Speak plainly to the human. Keep artifacts in the record -store, which is gitignored in full and is the human's to back up (rule 7). -Store large evidence in scratch/ and cite only the deciding lines. diff --git a/VERSION b/VERSION index b561134..4a29f93 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.13.1 +v0.14.0 diff --git a/init.sh b/init.sh index 71dea00..53cc3f4 100755 --- a/init.sh +++ b/init.sh @@ -354,6 +354,12 @@ qa: # then finds the project's own e2e entry point, and records NOT VERIFIED when # there is no runnable environment (roles/verifier.md). Never a new dependency. e2e: +# Optional: the project's own agent or skill to dispatch for each kit role +# (AGENTS.md "Running beside…" rule 3) — e.g. a debugging skill as researcher, +# a QA agent as verifier. Empty = the best local fit, else a generic worker. +researcher: +verifier: +adversary: EOF # projects seeded before lazymode existed keep their config; append the block diff --git a/log/changelog-v0.14.0.md b/log/changelog-v0.14.0.md new file mode 100644 index 0000000..473c4a5 --- /dev/null +++ b/log/changelog-v0.14.0.md @@ -0,0 +1,64 @@ +# v0.14.0 — a leaner contract, test-first bug fixes, generic intake + +Real stores showed where the kit's words went. The agent-facing prose had +grown to about 128 KB. `AGENTS.md` restated what the scripts already enforce, +each stage skill repeated the heartbeat and memory paragraphs, and bug fixes +could "prove" themselves with reproduction steps that nothing re-runs. The +kit is used for any software (web, API, batch, CLI), but stage 6 intake still +asked only UI questions. This release cuts the duplication and makes the bug +proof durable. Gates, scripts, the `--json` schema, and lazymode are +unchanged; `init.sh` gains three optional config lines. + +## Changes + +- **`AGENTS.md` keeps what an agent must decide** (453 → 324 lines, −31%). + Mechanics a script enforces and prints a reason for (digest binding, + ship-snapshot rules, C-quoted paths, handoff refusals, store ownership) are + now one line each. Text that `docs/automation.md` already holds (full-auto + intent contract §3, verify receipt §4) is now a pointer. Rule numbers and + section names are unchanged. The stale "rule 3a" citations in + `gates/_auto.sh` and `gates/status.sh` now resolve: 3a labels the full-auto + intent contract. +- **Defined once.** Heartbeat (rule 9, now listing the stage names and + build's n/m) and memory reading (rule 4) are no longer repeated in six stage + skills; each skill carries a one-line pointer. The harvest/close-writer + rule, the `kb.sh` digest description, and tripwire caveats are referenced, + not restated. `SKILL.md` drops its Coexistence and Invariants summaries, + which repeated `AGENTS.md`. `roles/researcher.md` points at `probes.md` + instead of copying three probes. +- **Bug fixes start with a failing test** (AGENTS.md rule 6). By default the + reproduction is an automated test at the lowest level that reaches the + defect. It fails on the pre-fix code for the reported reason, passes after, + and stays in the suite. Manual steps or logs stand in only when no test can + reach the defect, and the evidence says why. Stage 6 drafts the test outside + the source tree, build adds it before the fix, and the verifier runs it + against the pre-fix commit and must see it fail. `templates/evidence.md` + gains a `Regression test:` line, and the plan's Proof and the compact + route's Proof line name it. +- **Generic stage 6 intake.** The five questions now fit a UI, an API, a job, + or a CLI: what was done with what input, what happened versus what was + expected, where and when, as whom, and what trace exists (request or trace + id, log line, affected record keys). A symptom class (nothing happened / + wrong result / looks wrong / intermittent) replaces the UI-only + "does not react vs looks disabled" split. Probe 2 is no longer a MyBatis + `awk` over `mapper.xml`: it diffs the filters of every query on one entity + (SQL, ORM, API params, cache keys). +- **Projects name their own helpers.** New optional `researcher:`, + `verifier:`, `adversary:` keys in `.sdlc/config.md`: the named agent or + skill is dispatched with the kit's role file as its contract ("Running + beside…" rule 3). Empty or absent means the old behavior. Existing configs + are not rewritten. + +Agent-facing prose (SKILL.md, AGENTS.md, stage skills, roles): 104,136 → +~89,700 bytes. + +## Validation + +- `bash gates/knowledge-test.sh` → `KNOWLEDGE-TEST PASS`, 144 +- `bash gates/selftest.sh` → `SELFTEST PASS` +- `bash gates/e2e.sh` → `E2E PASS`, 152 · `bash gates/autotest.sh` → `AUTOTEST PASS`, 195 +- Three fresh-context verifier lenses over the diff: E2E (init.sh in a + disposable repo, plus a backend-bug compact walk and a UI full-route walk), + Side effects (removed instructions and cross-references), and Intent match + (against the approved recommendation). Their minor findings in the changed + text were fixed before release. diff --git a/roles/researcher.md b/roles/researcher.md index 5cc9f25..343a802 100644 --- a/roles/researcher.md +++ b/roles/researcher.md @@ -18,14 +18,10 @@ Do: suspicious duplication, version constraints, and feature flags. 3. Verify claims you were given ("the bug is in module Y", "the API does X"): confirm or refute with file:line evidence. -4. Class sweep: if you find a defect that is an instance of a pattern - (missing filter/guard/timeout/lock), grep the same file or module for the - whole class and report a count table, not just the one instance. -5. Shared-symbol audit: before reporting that a shared query/function should - change, list every call site and whether each guards the result - (null/empty check). The call-site × guard table goes in your report. -6. Gate check: when verifying a constant or flag ("logging is on"), read the - condition AROUND it. A true constant inside a dead branch is false. +4. Run the probes in `skills/6-maintain/probes.md` (kit-relative) that fit + the question — above all the class sweep (5), the call-site × guard table + before calling a shared symbol wrong (4), and the gate check on + "impossible" claims (6). Their tables go in your report. Report format (target: 60 lines or fewer): @@ -42,8 +38,7 @@ Report format (target: 60 lines or fewer): ``` The dispatcher appends Domain candidates to the feature's -`.sdlc/work//harvest.md`; INDEX.md, DOMAIN.md, and lessons/ are -written only at close (AGENTS.md rule 4). A candidate that contradicts an +`.sdlc/work//harvest.md` (AGENTS.md rule 4). A candidate that contradicts an existing DOMAIN.md entry supersedes it — mark it `supersedes: ` so the close merge replaces the old line instead of keeping both. diff --git a/roles/verifier.md b/roles/verifier.md index 023f2b4..b6c4314 100644 --- a/roles/verifier.md +++ b/roles/verifier.md @@ -16,16 +16,20 @@ spec.md and plan.md (compact route: intent.md only), the changed-file list, `tools/verify.sh run `: the receipt records what ran, your report is still the judgement. 2. Exercise the change for real, scoped to it — the flows it touches, not the - product's whole suite; the project's own commands and fixtures, never a - parallel harness: + product's whole suite; the project's own commands and fixtures (config.md + `e2e:` when set), never a parallel harness: - **UI** → drive the actual screen (`qa:` tool, else any browser tool in the harness): load it, do the user's steps, read the rendered result. - **API / CLI / job** → the real request or command against a running instance (`run:`); read the response, exit status, and resulting state. - - **Bug fix** → the proof chain (AGENTS.md rule 6): reproduce the ORIGINAL - failure against the pre-fix state (`git show :` into scratch - or a disposable checkout — never `git stash` or anything that mutates the - human's tree), confirm the mechanism, run the SAME reproduction after. + - **Bug fix** → the proof chain (AGENTS.md rule 6): run the regression + test (or, where none can reach the defect, the recorded reproduction) + against the pre-fix code — a disposable worktree of the commit before + the fix (HEAD while the fix is uncommitted) with only the new test + copied in; never `git stash` or anything that mutates the human's + tree — and + confirm it FAILS for the reported reason; confirm the mechanism; run the + SAME test after. A test that passes on the pre-fix code proves nothing. A chain you cannot complete is a FAIL, or a stated limitation for an intermittent defect — never a pass by assumption. 3. Check each plan.md **Proof** item (compact route: intent.md's Proof line). diff --git a/skills/1-intent/SKILL.md b/skills/1-intent/SKILL.md index c80e670..cb46ace 100644 --- a/skills/1-intent/SKILL.md +++ b/skills/1-intent/SKILL.md @@ -9,23 +9,18 @@ Goal: create an `intent.md` precise enough to plan without guessing. Verify the problem, cause, and requested outcome before moving on. Stage 1 is the least costly place to correct a wrong assumption. -Heartbeat: as soon as `.sdlc/work//` exists, and at every sub-task -change, overwrite `.sdlc/work//progress.md` with one line — -`intent · · ` (AGENTS.md rule 9). +Heartbeat throughout: AGENTS.md rule 9. ## Before you start -1. Read `.sdlc/memory/POLICY.md`, `.sdlc/memory/INDEX.md`, and - `.sdlc/memory/DOMAIN.md`; open lessons whose tags match this request. - Then **retrieve what past features already decided about this area**: +1. Read memory (AGENTS.md rule 4), then **retrieve what past features + already decided about this area**: `tools/kb.sh search ""` over the request's main nouns (the module, the endpoint, the error text), and - `tools/kb.sh show ` for any feature the hits name — a digest - (goal, summary.md, delivery, unmerged harvest candidates, lesson titles) - that answers most questions before a single record file is opened. - Closed features are included, so a decision made a year ago surfaces - with its evidence and delivery. Two or three targeted searches, not a scan of the archive: - what you find goes into the Evidence section with its source path. + `tools/kb.sh show ` for any feature the hits name (closed ones + included — AGENTS.md rule 7). Two or three targeted searches, not a scan + of the archive: what you find goes into the Evidence section with its + source path. 2. Pick a kebab-case feature slug; create `.sdlc/work//`. Prefix with the tracker key when one exists (`a20-1234-fix-login`), else the date (`260830-fix-login`) — at thousands of tickets, bare names collide. Slugs @@ -126,10 +121,9 @@ finding about the Destination, never progress. If an Unknown turns out to be an independent shippable change, open a new feature slug for it and record the reference under Decided. When resolving an Unknown surfaces a durable fact about the system, add it to the feature's -`.sdlc/work//harvest.md` as a domain candidate (merged into DOMAIN.md -at close, or without closing once the feature is stale — AGENTS.md rule 4; -readable before either through `tools/kb.sh show`) — Decided records the -decision, the harvest carries the fact to every later feature. +`.sdlc/work//harvest.md` as a domain candidate (AGENTS.md rule 4) — +Decided records the decision, the harvest carries the fact to every later +feature. ## Write the artifact @@ -213,11 +207,10 @@ refuses a spec or plan approval until intent is re-approved as full. ## Gate At lazymode 4 (AGENTS.md rule 3): review the change itself — the code the -intent points at and the behavior it would alter. `tools/tripwire.sh` over -intent.md is one supplemental input: any hit means a fresh-context adversary -(`roles/adversary.md`) reviews intent.md — this stage has no other adversary -pass — and the risky work needs recorded authorization. A clean scan clears -nothing on its own. Max 2 adversary rounds: blockers surviving round 2 mean +intent points at and the behavior it would alter. A `tools/tripwire.sh` hit +over intent.md means a fresh-context adversary (`roles/adversary.md`) +reviews it — this stage has no other adversary pass. Max 2 adversary +rounds: blockers surviving round 2 mean the intent is unclearable — `close.sh dead-end "intent blockers: "` with a lesson, and report them. When your review finds no blocking objection, run: @@ -227,10 +220,9 @@ objection, run: --review "" [--risk-authorized ""] ``` -Post the intent summary and any objections to the human as FYI, then continue -to the next stage in the same run — a waived gate is not a stop (AGENTS.md -rule 3). An unresolved MATERIAL question is the exception: it stops the loop -here, at every level. +Post the intent summary and any objections as FYI and continue (AGENTS.md +rule 3 "A waived gate is not a stop"); an unresolved MATERIAL question +stops the loop here, at every level. Below lazymode 4 the intent gate is the human's. Tell the user: @@ -239,6 +231,5 @@ Below lazymode 4 the intent gate is the human's. Tell the user: and STOP there. After approval, continue to stage 2 (`skills/2-spec/SKILL.md`) — or, on the compact route, straight to build (`skills/4-build/SKILL.md`) with the -intent gate as its gate. Dispatch that work to a subagent only when it buys -something concrete (AGENTS.md rule 5); the approved artifact, not the -conversation, is the input either way. +intent gate as its gate. The approved artifact, not the conversation, is +the input. diff --git a/skills/2-spec/SKILL.md b/skills/2-spec/SKILL.md index 64636e3..6044aee 100644 --- a/skills/2-spec/SKILL.md +++ b/skills/2-spec/SKILL.md @@ -9,17 +9,13 @@ Goal: create `spec.md` from `intent.md` so engineering work has a clear contract. The agent writes the spec, and the human reviews it. Automate checks where possible. Keep human attention on gate decisions. -Heartbeat: on entry and at every sub-task change, overwrite -`.sdlc/work//progress.md` with one line — -`spec · · ` (AGENTS.md rule 9). +Heartbeat throughout: AGENTS.md rule 9. ## Before you start 1. Run `gates/check-gate.sh intent .sdlc/work//intent.md`. STOP if closed. -2. Read intent.md fully. Read `.sdlc/memory/POLICY.md`, - `.sdlc/memory/INDEX.md`, `.sdlc/memory/DOMAIN.md`, and the feature's - `harvest.md` if present; open lesson files whose tags match the current - task. Use DOMAIN.md terms so the spec uses the project's established +2. Read intent.md (and origin.md) fully, and memory (AGENTS.md rule 4). + Use DOMAIN.md terms so the spec uses the project's established vocabulary. 3. Brownfield: read the researcher report from stage 1 (or dispatch one now). @@ -61,11 +57,9 @@ Fill `templates/spec.md`. Rules: ## Adversarial verification (automated, before the human) -At lazymode ≥2 (AGENTS.md rule 3) this review is still the reviewer — what -changes is who decides at the gate. `tools/tripwire.sh` over the draft is a -supplemental input: a hit means the review runs in full AND the risky work -needs recorded authorization. A clean scan shortens nothing on its own; judge -by what the spec actually changes, in any language it is written in. +This review runs at every lazymode — lazymode changes who decides at the +gate, not whether the spec is reviewed (AGENTS.md rule 3). Include +`tools/tripwire.sh` output over the draft as evidence. Dispatch a fresh-context adversary (`roles/adversary.md`) with ONLY: intent.md, draft spec.md, `.sdlc/memory/POLICY.md` if present, and the diff --git a/skills/3-plan/SKILL.md b/skills/3-plan/SKILL.md index d7b0f56..358cc89 100644 --- a/skills/3-plan/SKILL.md +++ b/skills/3-plan/SKILL.md @@ -8,20 +8,16 @@ description: "Read-only planning with a tiered gate: files, order, risks, proof. Goal: create `plan.md` before changing code. Name the files, work order, risks, and proof. During this stage, read and run non-mutating commands only. -Heartbeat: on entry and at every sub-task change, overwrite -`.sdlc/work//progress.md` with one line — -`plan · · ` (AGENTS.md rule 9; writing inside -`.sdlc/work//` is allowed here, like the plan artifact itself). +Heartbeat throughout: AGENTS.md rule 9. ## Before you start 1. Run `gates/check-gate.sh spec .sdlc/work//spec.md`. STOP if closed. -2. Read spec.md fully. Read `.sdlc/memory/POLICY.md`, - `.sdlc/memory/INDEX.md`, `.sdlc/memory/DOMAIN.md`, and the feature's - `harvest.md` if present; open lesson files whose tags match the current - task. Treat DOMAIN.md constraints and POLICY.md rules as plan risks. +2. Read spec.md fully, and memory (AGENTS.md rule 4). Treat DOMAIN.md + constraints and POLICY.md rules as plan risks. 3. **Read-only rule: in this stage you may read code and run non-mutating - commands only. No edits, no writes outside `.sdlc/work//`.** + commands only. No edits, no writes outside `.sdlc/work//`** (the heartbeat and + the plan artifact live there). ## Plan @@ -36,7 +32,8 @@ exploration stays out of the main context. Then fill `templates/plan.md`: - **Order of work.** Make each step keep the configured checks passing. Add tests with the code they test. - **Risks.** Record rate limits, migrations, shared state, and important quirks. -- **Proof.** For each spec requirement, name the test or command that proves it. +- **Proof.** For each spec requirement, name the test or command that proves it + (bug fix: the regression test — AGENTS.md rule 6). Use commands from `.sdlc/config.md`. - Brownfield additions: - **Regression baseline.** Give the exact commands to run before changes and diff --git a/skills/4-build/SKILL.md b/skills/4-build/SKILL.md index 693063e..69450ad 100644 --- a/skills/4-build/SKILL.md +++ b/skills/4-build/SKILL.md @@ -8,10 +8,7 @@ description: "Plan execution with fresh-context verification and triaged fix loo Goal: execute the plan and verify each step. Run checks during implementation, not only at the end. -Heartbeat: on entry, at every plan step, and at every fix-loop round, -overwrite `.sdlc/work//progress.md` with one line — -`build / · · `, n/m counting plan.md's -Order of work — and update it before each dispatch (AGENTS.md rule 9). +Heartbeat throughout: AGENTS.md rule 9. ## Before you start @@ -21,10 +18,8 @@ Order of work — and update it before each dispatch (AGENTS.md rule 9). `gates/check-gate.sh intent .sdlc/work//intent.md` instead, and treat intent.md's Compact route section (Files · Proof · Risk · Delivery target) plus its success criteria as the plan. -2. Read plan.md and spec.md (compact route: intent.md). Read - `.sdlc/memory/POLICY.md`, `.sdlc/memory/INDEX.md`, - `.sdlc/memory/DOMAIN.md`, and the feature's `harvest.md` if present; - open lesson files whose tags match the current task. +2. Read plan.md and spec.md (compact route: intent.md), and memory + (AGENTS.md rule 4). 3. **Brownfield: capture the regression baseline before editing.** Run the baseline commands from plan.md and save output to `.sdlc/work//baseline.txt`. Without a baseline, you cannot prove that @@ -59,6 +54,11 @@ Order of work — and update it before each dispatch (AGENTS.md rule 9). deviations.md the moment it happens — counters live on disk, not in context (AGENTS.md rule 5 "Caps survive dispatch"). Endless spec↔plan churn is a finding about intent, never progress. +- **Bug fix: the failing test comes first.** Before touching the fix, add + the regression test (AGENTS.md rule 6; the one stage 6 drafted, if any) + and watch it fail on the current code for the reported reason. Save that + output under `scratch/`; ship quotes its deciding lines in evidence.md's + Bug proof. A test you never saw fail is not proof. - A check that must fail the build must fail it synchronously (direct throw, sync IO, or top-level await). An unawaited promise is not a gate. It depends on environment behavior and may finish too late. @@ -80,8 +80,7 @@ Order of work — and update it before each dispatch (AGENTS.md rule 9). expectation is the correct one. What is forbidden is preserving a wrong expectation, and equally, editing a test to make a real failure quiet. - **Record each mistake immediately** in the feature's - `.sdlc/work//harvest.md` (INDEX.md, DOMAIN.md, and lessons/ are - written only at close — AGENTS.md rule 4). This includes your mistakes, + `.sdlc/work//harvest.md` (AGENTS.md rule 4). This includes your mistakes, plan mistakes, and surprises in the codebase. Use the skill 6 lesson format so a future run can avoid it. - Independent parallel work: use worktrees/subagents if your harness supports diff --git a/skills/5-ship/SKILL.md b/skills/5-ship/SKILL.md index a101e24..0808927 100644 --- a/skills/5-ship/SKILL.md +++ b/skills/5-ship/SKILL.md @@ -9,9 +9,7 @@ Goal: create `evidence.md` so a human can decide whether to release, then deliver and record what was delivered in `delivery.md`. Run agent reviews first. The human reviews findings about intent and risk. -Heartbeat: on entry and at every sub-task change, overwrite -`.sdlc/work//progress.md` with one line — -`ship · · ` (AGENTS.md rule 9). +Heartbeat throughout: AGENTS.md rule 9. ## Before you start @@ -20,10 +18,7 @@ rule 5); assembling the evidence itself may stay with the implementer. Read plan present), and the diff (`git diff` against the base branch). Compact-route features have no spec or plan: intent.md replaces both as the upstream source, and its Compact route section and success criteria are the -requirements. Read -`.sdlc/memory/POLICY.md`, `.sdlc/memory/INDEX.md`, `.sdlc/memory/DOMAIN.md`, -and the feature's `harvest.md`; open lesson files whose tags match the -current task. +requirements. Read memory (AGENTS.md rule 4). ## Adversarial code review (fresh context) @@ -69,10 +64,8 @@ what would help the next agent — but only what a future run could REUSE (skills/6-maintain "Record the lesson"); a clean feature legitimately leaves no lesson. Write what there is into the feature's `.sdlc/work//harvest.md` (lesson candidates in the skill 6 format; -durable terms, verified facts, and constraints as domain candidates). -INDEX.md, DOMAIN.md, and lessons/ are written only at close, by the closer -(AGENTS.md rule 4) — or, for a feature that stays open and idle, by the -stale-harvest merge the same rule allows. Then bring the feature's +durable terms, verified facts, and constraints as domain candidates; +AGENTS.md rule 4). Then bring the feature's `summary.md` up to date: `Result` says what delivery.md confirms (a pushed review branch is not a deployment), `Lesson` is the one line worth remembering, `Cause`/`Change` match what was actually found and built. diff --git a/skills/6-maintain/SKILL.md b/skills/6-maintain/SKILL.md index 0aa9c5c..cddf52d 100644 --- a/skills/6-maintain/SKILL.md +++ b/skills/6-maintain/SKILL.md @@ -9,9 +9,7 @@ Goal: turn each bug report, incident, alert, or ticket into a diagnosed `intent.md`. Restart the process with evidence, not a vague complaint. People triage and review the work. They do not create the initial diagnosis. -Heartbeat: as soon as `.sdlc/work//` exists, and at every sub-task -change, overwrite `.sdlc/work//progress.md` with one line — -`maintain · · ` (AGENTS.md rule 9). +Heartbeat throughout: AGENTS.md rule 9. ## Running headless? Sandbox first @@ -38,15 +36,17 @@ change what gets built or exceed the authorized scope: those go to the human as `## Material questions` and the loop stops for them (AGENTS.md rule 3). Everything else is an `[assumed]` line and the diagnosis continues. -1. Which exact control did you use? (button label / menu item / gesture) -2. What did you see immediately after? (nothing at all, a popup, an error, - a partial change) — "nothing at all" and "something wrong appeared" are - different bug classes. -3. Which environment and when? (prod/stg/dev, URL, approximate time — this - picks the deploy ref and the log window) -4. What account/role? (permissions often hide or disable the control) -5. Do you have a console log, network capture, or screenshot? If not, can - you reproduce once with DevTools open? +1. What exactly was done, with what input? (the control clicked, the + request sent, the command run, the job or schedule that fired) +2. What happened, and what was expected instead? (nothing at all, an error, + a wrong result, a partial change, slow) — each is a different bug class. +3. Where and when? (environment, URL or host, version, time window — this + picks the deployed ref and the log window) +4. As whom? (account, role, tenant, client — permissions and data scope + change behavior) +5. What trace exists? (screenshot, console or network capture, request or + trace id, log line, the affected record keys) If none, can it be + reproduced once with capture on? Record the answers in `intent.md` under Evidence. Track question 5 explicitly (see Evidence tracking below). @@ -67,30 +67,29 @@ explicitly (see Evidence tracking below). 2. Before forming a hypothesis or offering options, run fresh-context history and feasibility research under skill 1. Check whether this failure was fixed or reverted before, why, and whether it can be reproduced here. -3. Reproduce the issue first. **A fix needs the proof chain of AGENTS.md - rule 6**: the failure before, the mechanism, the same reproduction passing - after, the adjacent flows. If it cannot be reproduced, the honest outputs +3. Reproduce the issue first, as a failing test wherever one can reach the + defect (AGENTS.md rule 6). Draft it in `scratch/` or a disposable + worktree — the source tree stays untouched until the intent gate — and + cite its failing output in intent.md's Evidence; build adds it to the + suite first. If it cannot be reproduced, the honest outputs are a diagnosis, instrumentation, or a defensive change labelled as - unconfirmed — never "fixed". An intermittent defect may stand on logs, - traces, or an isolated deterministic reproduction, with the limitation - stated. -4. Trace the cause. Read `.sdlc/memory/POLICY.md`, `.sdlc/memory/INDEX.md`, - and `.sdlc/memory/DOMAIN.md`, then open lesson files whose tags match - the task. Then ask the store directly whether this has been seen before: + unconfirmed — never "fixed". +4. Trace the cause. After memory (AGENTS.md rule 4), ask the store directly + whether this has been seen before: `tools/kb.sh search ""`, `tools/kb.sh search ""`, and `tools/kb.sh show ` for the features the hits name — the search covers closed features, so a fix from two years ago comes back with its evidence and delivery record. Cite what you find by path in the diagnosis. Records of a checkout that no longer exists are reachable the same way with `--area `. -5. Separate the claim before hunting: "it does not react" is a state/handler - problem; "it looks wrong/disabled" is a RENDERING problem until proven - otherwise. They have different checklists. -6. **Class sweep.** When a found defect is an instance of a pattern (missing - filter, guard, timeout, lock), grep the same file/module for the whole - class and report a count table. Before changing any shared symbol, - produce the call-site × guard table. One instance is a bug; the table is - the scope, and it decides fix ordering. +5. Name the symptom class before hunting; each has its own checklist: + *nothing happened* (handler not reached, swallowed error, missing + timeout — probes 7, 8), *wrong result* (logic or data: which query, + which record, which version — probes 2, 3), *looks wrong* (rendering + until proven otherwise), *intermittent* (concurrency, caching, + environment, data-dependent). +6. **Class sweep and caller audit** (probes 4, 5): one instance is a bug; + the count table is the scope, and it decides fix ordering. 7. Check the feature's `evidence.md` — a shipped feature is archived, so it sits at `.sdlc/archive//evidence.md` (`tools/kb.sh show ` names the path): was this covered by proof, or was it a verification gap? A gap is itself a lesson (`promote: skills/5-ship`). @@ -113,8 +112,8 @@ with the reporter's ticket key. Never re-request a third time. reporter", not "this is reproduced". Work that continues under a waiver is unconfirmed by definition: it may ship as instrumentation, a defensive change, or a documented hypothesis, and it says so in evidence.md's Bug -proof section. If it is later reproduced, the chain of AGENTS.md rule 6 -applies in full before anything is called fixed. +proof section. If it is later reproduced, the full chain (AGENTS.md rule 6) +applies before anything is called fixed. If `.sdlc/config.md` has empty `test:`/`lint:` commands, record one line of verification debt in the artifact: what could not be run, and what manual check replaced it. @@ -167,10 +166,8 @@ spec.md and run the full route instead; the intent gate still comes first. **Recurrence cap: three fix loops for one symptom.** Before opening a fix-slug, grep the symptom's tags in INDEX.md AND open features' harvests -(`tools/kb.sh harvest` names every open feature still holding one; -`tools/kb.sh search ""` reads through them) — in-flight lessons are -not merged yet, and a harvest idle 30 days or more may be merged now -without closing its feature (AGENTS.md rule 4). On the third match, stop fixing and start investigating: the repetition is +(`tools/kb.sh harvest`, `tools/kb.sh search ""`) — in-flight lessons +are not merged yet. On the third match, stop fixing and start investigating: the repetition is evidence that the cause found so far is not the cause. Widen the investigation — what the three incidents share, which invariant keeps breaking, what the earlier fixes actually changed — and take the finding to @@ -189,10 +186,8 @@ is a valid, complete answer — INDEX.md is a 50-line budget, and filler crowds out the entries that matter. Durable facts about the system are domain candidates, not lessons. -When there is one, draft it in the fix feature's `.sdlc/work//harvest.md` -(INDEX.md, DOMAIN.md, and lessons/ are written only at close — AGENTS.md -rule 4). The -close merge materializes it as `.sdlc/memory/lessons/YYYY-MM-DD-.md` +When there is one, draft it in the fix feature's +`.sdlc/work//harvest.md` (AGENTS.md rule 4). The close merge materializes it as `.sdlc/memory/lessons/YYYY-MM-DD-.md` via `templates/lesson.md` plus ONE line in `.sdlc/memory/INDEX.md`: ``` diff --git a/skills/6-maintain/probes.md b/skills/6-maintain/probes.md index 41598ce..3610a41 100644 --- a/skills/6-maintain/probes.md +++ b/skills/6-maintain/probes.md @@ -16,13 +16,13 @@ at all. Pass `--deployed-sha` whenever the release system or the running app reports one; a branch ref is a pointer in this clone, not deployment evidence. -## 2. Sibling-query filter diff (when one method issues 2+ queries on one entity) +## 2. Sibling-query filter diff (when one flow reads or writes one entity 2+ ways) - awk '/id="queryA"/,/<\/select>/' mapper.xml | grep -E 'WHERE|AND' - awk '/id="queryB"/,/<\/select>/' mapper.xml | grep -E 'WHERE|AND' - -Any predicate present in one and absent in the other is a candidate defect. -Watch for filters written in JOIN ON clauses, not only WHERE. +List the filter of every query on that entity along the flow — SQL WHERE and +JOIN ON, ORM criteria, API query params, cache keys — side by side. A +predicate present in one and absent in another (soft delete, tenant, status, +version) is a candidate defect; so is a read key that differs from the +write's unique key. ## 3. Blame the failing lines (who, when, and was it ever revisited) diff --git a/templates/evidence.md b/templates/evidence.md index bef35d0..f06ab59 100644 --- a/templates/evidence.md +++ b/templates/evidence.md @@ -18,7 +18,8 @@ ``` ## Bug proof -- Before: `` → +- Regression test: +- Before: `` on the pre-fix code → - Mechanism: - After: `` → - Adjacent flows: → diff --git a/templates/intent.md b/templates/intent.md index 6bd2213..537147c 100644 --- a/templates/intent.md +++ b/templates/intent.md @@ -40,7 +40,7 @@ else the human's. Name a command or test where possible.> - Files: -- Proof: +- Proof: - Risk: - Delivery target: local | pr | deploy