@afokapu/atdd-bun 0.7.2 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +45 -4
  2. package/conventions/delivery/delivery.approved-sha-resolves.convention.yaml +33 -0
  3. package/conventions/delivery/delivery.config-schema.convention.yaml +43 -0
  4. package/conventions/delivery/delivery.evidence-schema.convention.yaml +34 -0
  5. package/conventions/delivery/delivery.findings-resolved.convention.yaml +42 -0
  6. package/conventions/delivery/delivery.merge-gate.convention.yaml +42 -0
  7. package/conventions/delivery/delivery.model-allowed.convention.yaml +36 -0
  8. package/conventions/delivery/delivery.reviewer-independent.convention.yaml +34 -0
  9. package/conventions/delivery/delivery.stages-complete.convention.yaml +31 -0
  10. package/detectors/delivery_evidence/atdd.implementation.yaml +33 -0
  11. package/detectors/delivery_evidence/detect.mjs +9 -0
  12. package/detectors/delivery_evidence/fixtures/clean/atdd-bun.yaml +8 -0
  13. package/detectors/delivery_evidence/fixtures/clean/delivery/api/evidence.yaml +54 -0
  14. package/detectors/delivery_evidence/fixtures/dirty/atdd-bun.yaml +3 -0
  15. package/detectors/delivery_evidence/fixtures/dirty/delivery/api/evidence.yaml +37 -0
  16. package/detectors/delivery_evidence/fixtures/dirty/delivery/data/evidence.yaml +8 -0
  17. package/detectors/delivery_evidence/fixtures/dirty/delivery/orphan/README.md +1 -0
  18. package/detectors/delivery_evidence/fixtures/dirty/delivery/ui/evidence.yaml +5 -0
  19. package/integrity.json +33 -11
  20. package/package.json +1 -1
  21. package/planner-schemas/delivery-config.schema.json +80 -0
  22. package/planner-schemas/delivery-evidence.schema.json +84 -0
  23. package/relationships.yaml +98 -0
  24. package/src/agent.ts +16 -2
  25. package/src/ci.ts +8 -1
  26. package/src/delivery.ts +415 -0
  27. package/src/enforce.ts +2 -1
  28. package/src/index.ts +2 -0
  29. package/src/integrity.ts +38 -11
  30. package/src/setup.ts +5 -2
  31. package/templates/agents/AGENTS.block.md +4 -2
  32. package/templates/agents/delivery/SKILL.md +77 -0
  33. package/templates/agents/delivery/review.md +45 -0
  34. package/templates/github/atdd-bun.yml +6 -1
package/README.md CHANGED
@@ -55,6 +55,7 @@ registerEnforcementTest({ root: import.meta.dir + "/..", profiles: ["traceabilit
55
55
  | `topology` | feature decomposition and the plan, source, test and E2E locations |
56
56
  | `planner` | schemas for every plan artifact, graph integrity, the scoped planner rules |
57
57
  | `telemetry` | the telemetry tracking plan: item shape, path-mirrored identity and versioning under `telemetry/`, wagon ownership of logical artifacts, the per-acceptance telemetry decision, metric label cardinality, source `Telemetry:` references, raw-string and forbidden-property emission, the vendor-SDK boundary around the TelemetryPort, and telemetry tests that bind the acceptance and item, assert the exact identity on a captured sink, cover every required item, and exercise declared timing semantics |
58
+ | `delivery` | the review record of each tranche under `delivery/`: allowed author and reviewer models with recorded fallbacks, reviewer independence, every finding fixed, withdrawn after one dispute or ruled on by a human, every configured stage approved, and, at the gate, no change without a record and a merged head that contains exactly the approved commit. Inert until adopted |
58
59
  | `docs` | the documentation capability, including the generated journey view |
59
60
  | `coder`, `tester`, `security`, `architecture`, `metrics`, `runtime` | Bun source and test conventions |
60
61
  | `interlocking` | train/interlocking binding, infrastructure and route coverage |
@@ -84,7 +85,7 @@ the adoption that establishes the governed set, so a brownfield repository can d
84
85
  `profiles: [docs]` in an ordinary pull request. From then on, the integrity check reports, against
85
86
  the base branch, removing a profile from the list and removing the list itself. The second closes
86
87
  the two-step bypass `[docs, security]` → no list → `[docs]`. `init` writes a new `atdd-bun.yaml`
87
- with every profile listed, so a greenfield repository is governed from its first commit; trim the
88
+ with every profile listed except the opt-in `delivery`, so a greenfield repository is governed from its first commit; trim the
88
89
  list before that commit to adopt gradually.
89
90
 
90
91
  ## Configuration
@@ -108,6 +109,45 @@ worktrees: { enabled: false }
108
109
  release: { enabled: false }
109
110
  ```
110
111
 
112
+ ### Delivery
113
+
114
+ For programs delivered as tranches by a coordinator and persistent drivers, with headless authors
115
+ and independent reviewers. Adopt it by naming `delivery` in `profiles:` (or, with no list, by adding
116
+ a `delivery:` block); `agent init` then installs the delivery skill and its review contract. The
117
+ adopting pull request is itself governed: it changes files outside the delivery root, so it carries
118
+ its own tranche record, reviewed and `ready` like any other. Every key is optional; these are the
119
+ defaults:
120
+
121
+ ```yaml
122
+ delivery:
123
+ root: delivery # one <tranche>/evidence.yaml per tranche, reports beside it
124
+ require_record: true # at the gate, a change outside the root needs a tranche record
125
+ multiplexer: herdr # the terminal multiplexer agents run in; any command name
126
+ independence: fresh-process # or different-model; overridable per stage
127
+ stages: # models in preference order: the first, then recorded fallbacks
128
+ plan_review: { authors: [codex], reviewers: [glm, claude] }
129
+ test_review: { authors: [glm, claude], reviewers: [codex, claude] }
130
+ code_review: { authors: [glm, claude], reviewers: [glm, claude] }
131
+ final_review: { authors: [codex], reviewers: [codex, claude] }
132
+ fallback: { after_failures: 3, within_minutes: 10, when_exhausted: block } # or wait
133
+ commands: {} # per model: { author: "...", review: "..." } overriding the skill's defaults
134
+ ```
135
+
136
+ The profile checks the record, never the running agents. The generated CI sets
137
+ `ATDD_DELIVERY_GATE`: `merge` on pull requests and the merge queue, where every record the branch
138
+ changes must be `ready`, the branch may differ from its approved SHA only under the delivery root,
139
+ and a change outside the root needs a record (`require_record`, default true); `post-merge` on a
140
+ push to a protected branch (the generated workflow's push branches follow `protected_branches`), where the pushed commit must contain every approved SHA it brings in. Merge tranches with a
141
+ merge commit: a squash or rebase merge writes a commit no reviewer saw, and the post-merge check
142
+ fails on it. Moving the root, dropping a stage, relaxing a stage from `different-model` to
143
+ `fresh-process`, adding an author or reviewer, moving a fallback model earlier in a list, turning off
144
+ `require_record`, making fallback easier, or adding or changing a model's `commands` loosens the policy and is reported by the integrity check.
145
+
146
+ The record's model and run identifiers are the driver's claims. The profile checks that they are
147
+ consistent and that a `ready` record retains every review's raw report (a record in progress may lag
148
+ behind); it does not verify them
149
+ cryptographically.
150
+
111
151
  The hooks enforce protected-branch blocking, micro-commit limits, mass-delete approval and
112
152
  validation of the affected area. Git can bypass them, so CI is the authority.
113
153
 
@@ -115,14 +155,15 @@ validation of the affected area. Git can bypass them, so CI is the authority.
115
155
 
116
156
  The skill gives every coding agent the lifecycle PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE and
117
157
  the profile that gates each stage. The block in `AGENTS.md` and `CLAUDE.md` adds the rules: never
118
- modify the toolkit itself, only the configuration it offers, and enable capabilities through
119
- `profiles`.
158
+ modify the toolkit itself, only the configuration it offers; turn profiles on or off in
159
+ `profiles:` only when the user asks; and, where `delivery` is active, deliver tranches through the
160
+ delivery skill.
120
161
 
121
162
  `atdd-bun integrity`, run by the generated test and first in CI on a clean install, fails when:
122
163
 
123
164
  - the installed package differs from its published hashes;
124
165
  - the dependency is not an npm registry version;
125
- - a generated file (workflow, skills, instruction block, integrity test) was edited;
166
+ - a generated file (workflow, skills, the delivery review contract, instruction block, integrity test) was edited;
126
167
  - `atdd-bun.yaml` is looser than on the base branch (after the first explicit `profiles:` list,
127
168
  dropping a profile or the list counts).
128
169
 
@@ -0,0 +1,33 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.approved-sha-resolves
3
+ kind: rule
4
+ status: active
5
+ name: The approved SHA is a commit in this repository
6
+ statement: >-
7
+ A ready record's approved_sha resolves to a commit in the repository's history, and every configured stage's last approval names a commit in approved_sha's history, each stage's containing the one before it in lifecycle order (REQUIRED).
8
+ terms:
9
+ - term_id: approved_sha
10
+ text: >-
11
+ the commit the closing review approved and the tranche asks to merge.
12
+ content:
13
+ summary: >-
14
+ An approval of a commit nobody can find proves nothing: it may be a typo, a rewritten history, or an invention.
15
+ normative_text: |
16
+ The validator asks Git whether the commit exists. A rebase after approval changes every SHA and therefore needs a fresh review; the record cannot be updated by hand to follow it.
17
+ fix_hint: |
18
+ Record the full or abbreviated SHA the final review named. After a rebase, run the final review again on the new head.
19
+ exceptions:
20
+ - >-
21
+ At the gate, a record the change does not touch is not judged again: it was judged when it merged, and its tranche branch may be gone. Outside the gate every ready record is judged.
22
+ - >-
23
+ A shallow clone may lack the commit: CI must fetch full history (the generated workflow uses fetch-depth 0).
24
+ metadata:
25
+ aliases:
26
+ - DELIVERY-APPROVED-SHA-RESOLVES-001
27
+ severity: 3
28
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
29
+ disposition: strict
30
+ introduced_in: 0.8.0
31
+ implementation:
32
+ type: validator
33
+ ref: delivery_evidence
@@ -0,0 +1,43 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.config-schema
3
+ kind: rule
4
+ status: active
5
+ name: The delivery policy in atdd-bun.yaml is well-formed
6
+ statement: >-
7
+ The `delivery:` block of atdd-bun.yaml validates against delivery-config.schema.json: known keys only, each stage listing at least one reviewer, models named in lowercase, independence one of fresh-process or different-model, the root in canonical form (no leading, trailing or doubled slash, no dot segment) and not overlapping the plan, source, test, e2e or telemetry root (REQUIRED).
8
+ terms:
9
+ - term_id: policy
10
+ text: >-
11
+ the `delivery:` block: root, independence, stages (per stage: authors, reviewers, optional independence), fallback and commands. Every key is optional; an omitted key takes the package default.
12
+ content:
13
+ summary: >-
14
+ The skill and the validators read the same policy. A misspelled key would be ignored by one and not the other, so a malformed block is a finding, and the rest of the run judges evidence against the package defaults.
15
+ normative_text: |
16
+ The policy decides which models may author and review each stage, in preference order, how independent a reviewer must be, and when a model counts as unavailable. It is read by the delivery skill when it dispatches work and by this profile when it judges the record, so both must see the same, valid document.
17
+ fix_hint: |
18
+ Correct the key the finding names. The defaults are:
19
+
20
+ delivery:
21
+ root: delivery
22
+ independence: fresh-process
23
+ stages:
24
+ plan_review: { authors: [codex], reviewers: [glm, claude] }
25
+ test_review: { authors: [glm, claude], reviewers: [codex, claude] }
26
+ code_review: { authors: [glm, claude], reviewers: [glm, claude] }
27
+ final_review: { authors: [codex], reviewers: [codex, claude] }
28
+ exceptions:
29
+ - >-
30
+ Adoption is not exempt from the gate: the pull request that adopts delivery changes files outside the delivery root,
31
+ so it carries its own ready tranche record like any other change.
32
+ - >-
33
+ Inert until adoption: with no `delivery:` block and `delivery` absent from `profiles:`, no delivery rule emits anything.
34
+ metadata:
35
+ aliases:
36
+ - DELIVERY-CONFIG-SCHEMA-001
37
+ severity: 3
38
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
39
+ disposition: strict
40
+ introduced_in: 0.8.0
41
+ implementation:
42
+ type: validator
43
+ ref: delivery_evidence
@@ -0,0 +1,34 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.evidence-schema
3
+ kind: rule
4
+ status: active
5
+ name: Every tranche folder holds a well-formed evidence record
6
+ statement: >-
7
+ Every folder under the delivery root holds an evidence.yaml that validates against delivery-evidence.schema.json, whose tranche matches the folder name, whose reviews each name an author and a configured stage, and whose reports are data files (json, jsonl, yaml, yml, txt, md, log) inside the tranche's own folder, one per review; a ready record names one for every review (delivery.stages-complete) (REQUIRED).
8
+ terms:
9
+ - term_id: tranche
10
+ text: >-
11
+ one independently mergeable piece of a program, delivered on its own branch by one persistent driver through PLAN, RED, GREEN, SMOKE, REFACTOR and TRACE, with its reviews.
12
+ - term_id: evidence
13
+ text: >-
14
+ the tranche's record of its reviews at `<root>/<tranche>/evidence.yaml`: status (open or ready), base and approved SHAs, and the chronological list of reviews, each with stage, reviewed SHA, author, reviewer, fallbacks, verdict, the checklist it went through and its findings.
15
+ content:
16
+ summary: >-
17
+ The record is what CI can check. A review that is not written down, or written down in a shape the validator cannot read, did not happen as far as the merge gate is concerned.
18
+ normative_text: |
19
+ The profile judges the record a tranche leaves, not the agents while they work. Each review is appended, never edited, so a repair loop shows as a request-changes entry followed by a fresh review of the same stage. A review must name its author: independence is judged against the author, and without one it cannot be judged.
20
+ fix_hint: |
21
+ Create or repair `<root>/<tranche>/evidence.yaml`; the finding names the schema path at fault. A request-changes review carries at least one finding; every review carries its `checked` list.
22
+ exceptions:
23
+ - >-
24
+ Files other than evidence.yaml inside a tranche folder (retained raw reviewer reports) are not judged.
25
+ metadata:
26
+ aliases:
27
+ - DELIVERY-EVIDENCE-SCHEMA-001
28
+ severity: 3
29
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
30
+ disposition: strict
31
+ introduced_in: 0.8.0
32
+ implementation:
33
+ type: validator
34
+ ref: delivery_evidence
@@ -0,0 +1,42 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.findings-resolved
3
+ kind: rule
4
+ status: active
5
+ name: Every finding is fixed, withdrawn after one dispute, or ruled on by a human
6
+ statement: >-
7
+ Once a stage has a later review, or the record is ready, every finding of a request-changes review records its outcome: fixed (confirmed by a later review of the stage), withdrawn (after a written rebuttal, by a later review that does not raise it again) or human (with the decision). A finding disputed more than once goes to a human. An approving review carries no critical or high finding (REQUIRED).
8
+ terms:
9
+ - term_id: rebuttal
10
+ text: >-
11
+ the author's written dispute of a finding, with evidence: a test result, a rule id, a file and line. The next fresh reviewer upholds or withdraws the finding.
12
+ - term_id: outcome
13
+ text: >-
14
+ fixed, withdrawn or human, recorded on the finding where it was raised.
15
+ content:
16
+ summary: >-
17
+ A reviewer can be wrong and an author can be wrong. One written round, judged by a fresh reviewer, settles most disagreements; the rest go to a human instead of looping.
18
+ normative_text: |
19
+ No conversation between author and reviewer: a reviewer is stateless, and a long exchange turns it into a co-author. The author fixes a finding or disputes it once in writing; the next fresh reviewer decides. If that reviewer upholds a disputed finding, the tranche emits BLOCKED disputed-finding and a human rules.
20
+ fix_hint: |
21
+ On each finding of the request-changes review, record the outcome:
22
+
23
+ outcome: fixed
24
+
25
+ rebuttal: "handler.test.ts:31 proves the loop stops on abort"
26
+ outcome: withdrawn
27
+
28
+ outcome: human
29
+ decision: "Keep the retry; the caller owns the bound."
30
+ exceptions:
31
+ - >-
32
+ While a stage has no later review and the record is open, a finding without an outcome is work in progress, not a finding.
33
+ metadata:
34
+ aliases:
35
+ - DELIVERY-FINDINGS-RESOLVED-001
36
+ severity: 2
37
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
38
+ disposition: strict
39
+ introduced_in: 0.8.0
40
+ implementation:
41
+ type: validator
42
+ ref: delivery_evidence
@@ -0,0 +1,42 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.merge-gate
3
+ kind: rule
4
+ status: active
5
+ name: A tranche merges only its approved SHA
6
+ statement: >-
7
+ At the gate (ATDD_DELIVERY_GATE, which the generated CI sets to merge on pull requests and the merge queue and to post-merge on pushes to the protected branches), every evidence record the change touches is ready and approves a commit the head contains; before the merge the head differs from that commit only by the record and the reports it names; no record is deleted, and no record or report already on the base branch is modified; under the delivery root only records and the reports a changed record names change; and, with require_record (the default), a change outside the delivery root comes with a tranche record (REQUIRED).
8
+ terms:
9
+ - term_id: merge_gate
10
+ text: >-
11
+ the CI run that decides whether a pull request may merge. It compares the branch against the base it merges into; for a merge checkout, the base is the first parent and the head the second.
12
+ content:
13
+ summary: >-
14
+ Any commit after approval, a code change, a regenerated file, a conflict resolution or a rebase, invalidates it. The evidence commit itself is the one change allowed, since it cannot be in the SHA it records. A change with no record at all was never reviewed.
15
+ normative_text: |
16
+ This is where the profile becomes a merge rule rather than an instruction. Records that the change does not touch, earlier tranches already on the base branch, are not judged again; their approved SHAs may no longer be the head of anything.
17
+ After the merge, a push is judged from its previous tip (the generated CI passes it as ATDD_BASE_REF; a first push falls back to the parent): every record it brings in must approve a commit it contains. A deleted record never counts as the record that covers a change. A squash or rebase merge writes a new commit no reviewer saw and fails here, visibly, on the base branch; merge tranches with a merge commit. Drift is judged after the merge too, at the tranche's side of a merge commit or at the head of a direct push, over the files the push brings in. Only <root>/<tranche>/evidence.yaml is a record; an evidence.yaml at any other depth covers nothing. A rename is a deletion. When several tranches land in one change, a file another changed ready record approved with exactly that content is not drift.
18
+ fix_hint: |
19
+ Run the final review on the current head and record its SHA as approved_sha, or remove the change made after approval. Locally, reproduce the gate with ATDD_DELIVERY_GATE=merge ATDD_BASE_REF=origin/main bun run atdd-bun delivery.
20
+ exceptions:
21
+ - >-
22
+ Outside the gate (hooks, local runs) this rule emits nothing, so a tranche can push work in progress.
23
+ - >-
24
+ Before the merge, a pull request is judged at its head (the second parent of the test merge GitHub computes), not at
25
+ that merge commit; content only a merge commit introduces is judged after the merge, where a push is judged whole.
26
+ Judging GitHub's merge result instead would report the base branch's own changes to the same files as drift.
27
+ - >-
28
+ The policy governs the tree it sits in. With atdd-bun.yaml in a subfolder (a monorepo package run with --root),
29
+ require_record covers that subfolder, not the rest of the repository, which another policy or none governs; the
30
+ generated workflow runs from the repository root, and drift from an approved commit is judged repository-wide.
31
+ - >-
32
+ require_record false exempts changes with no record; turning it off is a loosening the integrity check reports.
33
+ metadata:
34
+ aliases:
35
+ - DELIVERY-MERGE-GATE-001
36
+ severity: 3
37
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
38
+ disposition: strict
39
+ introduced_in: 0.8.0
40
+ implementation:
41
+ type: validator
42
+ ref: delivery_evidence
@@ -0,0 +1,36 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.model-allowed
3
+ kind: rule
4
+ status: active
5
+ name: Authors and reviewers are allowed models, and every fallback says why
6
+ statement: >-
7
+ Each review's author and reviewer model appears in that stage's authors and reviewers lists; a model after the first is used only with a recorded fallback from each model before it, stating the kind of unavailability (outage, rate_limit, no_report, timeout), the failures observed (at least delivery.fallback.after_failures) within a window no longer than delivery.fallback.within_minutes, and the reason (REQUIRED).
8
+ terms:
9
+ - term_id: fallback
10
+ text: >-
11
+ a recorded switch from a preferred model to the next one in the stage's list, with role (author or reviewer) and a reason: an outage, a rate limit, or no auditable report. A REQUEST CHANGES verdict is never a reason.
12
+ content:
13
+ summary: >-
14
+ The lists are the operator's choice of who may do the work. A silent switch to another model hides an outage and can hide a reviewer chosen for being lenient.
15
+ normative_text: |
16
+ The first model in a list is used normally. When it is unavailable, the driver falls back to the next one and records it. A fallback is never triggered by a verdict: shopping for a reviewer until one approves is exactly what this rule exists to expose.
17
+ fix_hint: |
18
+ Record the fallback on the review:
19
+
20
+ fallback:
21
+ - { role: reviewer, from: glm, kind: rate_limit, failures: 3, window: { from: "2026-09-25T09:00:00Z", to: "2026-09-25T09:08:00Z" }, reason: "429 on 3 attempts in 10 minutes" }
22
+
23
+ or use a model the stage lists.
24
+ exceptions:
25
+ - >-
26
+ When a stage lists one model, no fallback is possible: an unavailable model blocks the tranche.
27
+ metadata:
28
+ aliases:
29
+ - DELIVERY-MODEL-ALLOWED-001
30
+ severity: 2
31
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
32
+ disposition: strict
33
+ introduced_in: 0.8.0
34
+ implementation:
35
+ type: validator
36
+ ref: delivery_evidence
@@ -0,0 +1,34 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.reviewer-independent
3
+ kind: rule
4
+ status: active
5
+ name: Every reviewer is a fresh process independent of the authors
6
+ statement: >-
7
+ A reviewer's run never authored anything in the tranche and never reviewed another entry; where the stage requires different-model independence, the reviewer's model also differs from the stage author's (REQUIRED).
8
+ terms:
9
+ - term_id: run
10
+ text: >-
11
+ the identity of one process: a session id, a pane id with its start time, or the retained report. Two entries with the same run were produced by the same process.
12
+ - term_id: independence
13
+ text: >-
14
+ fresh-process: the reviewer is a new process that authored nothing. different-model: additionally, its model is not the author's.
15
+ content:
16
+ summary: >-
17
+ A reviewer that edits becomes an author, and a reviewer that already saw an earlier round is anchored to it. Independence is what makes an approval evidence.
18
+ normative_text: |
19
+ Every review is a new process. The run identifiers make that checkable: a reviewer run that appears as an author anywhere in the tranche, or on a second review, is not independent. The stricter mode is chosen per stage in the policy.
20
+ fix_hint: |
21
+ Re-run the review in a fresh process and record its own run; under different-model, use a reviewer model other than the author's.
22
+ exceptions:
23
+ - >-
24
+ The persistent driver authors the plan and opens the PR; its run may never review.
25
+ metadata:
26
+ aliases:
27
+ - DELIVERY-REVIEWER-INDEPENDENT-001
28
+ severity: 3
29
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
30
+ disposition: strict
31
+ introduced_in: 0.8.0
32
+ implementation:
33
+ type: validator
34
+ ref: delivery_evidence
@@ -0,0 +1,31 @@
1
+ schema_version: 1.1.0
2
+ rule_id: delivery.stages-complete
3
+ kind: rule
4
+ status: active
5
+ name: A ready record has every configured stage approved
6
+ statement: >-
7
+ A record with status ready has, for every stage the policy configures, a last review that approves; its approved_sha is the SHA the last review of the closing stage approved; every review names its retained raw report, which exists; and, when code_review is configured and is not the closing stage, nothing outside the delivery root changed between code_review's last approval and approved_sha, since a code change goes back through code_review (REQUIRED).
8
+ terms:
9
+ - term_id: closing_stage
10
+ text: >-
11
+ the last configured stage in lifecycle order (plan_review, test_review, code_review, final_review); by default final_review, the review of the PR head.
12
+ content:
13
+ summary: >-
14
+ Ready is the driver's claim that the tranche can merge. It is only true when no stage is missing and the approval covers the commit being merged.
15
+ normative_text: |
16
+ Each stage may take several rounds; only its last review counts. The closing stage's approval names the SHA the whole tranche stands on, and approved_sha must be that SHA: the merge gate compares the branch head against it.
17
+ fix_hint: |
18
+ Run the missing review, or set status back to open until it has run. Set approved_sha to the SHA the final review approved.
19
+ exceptions:
20
+ - >-
21
+ A stage the policy omits is not required. Omitting one loosens the policy and is reported by the integrity check until a human approves it.
22
+ metadata:
23
+ aliases:
24
+ - DELIVERY-STAGES-COMPLETE-001
25
+ severity: 3
26
+ # strict: atdd-bun fails on every finding; it has no advisory mode and no ratchet baseline.
27
+ disposition: strict
28
+ introduced_in: 0.8.0
29
+ implementation:
30
+ type: validator
31
+ ref: delivery_evidence
@@ -0,0 +1,33 @@
1
+ schema_version: "1.0.0"
2
+ kind: implementation
3
+ subtype: validator
4
+ implementation_id: delivery.evidence.impl
5
+ targets_workspace: atdd.workspace.bun
6
+ contract_version: "1.0.0"
7
+ # The delivery record: one <root>/<tranche>/evidence.yaml per tranche, judged against the `delivery:` policy
8
+ # in atdd-bun.yaml. Runs only under the delivery profile and is inert until the repository adopts it
9
+ # (a `delivery:` block, or `delivery` named in `profiles:`).
10
+ emits_rule_ids:
11
+ - delivery.config-schema
12
+ - delivery.evidence-schema
13
+ - delivery.model-allowed
14
+ - delivery.reviewer-independent
15
+ - delivery.findings-resolved
16
+ - delivery.stages-complete
17
+ - delivery.approved-sha-resolves
18
+ # Emitted only at the merge gate (ATDD_DELIVERY_GATE=merge, set by the generated CI on pull requests and the
19
+ # merge queue): it needs a change set against the base branch. tests/delivery.test.ts triggers it in a real
20
+ # repository.
21
+ api_emits_rule_ids:
22
+ - delivery.merge-gate
23
+ realizes_convention:
24
+ - delivery.config-schema
25
+ - delivery.evidence-schema
26
+ - delivery.model-allowed
27
+ - delivery.reviewer-independent
28
+ - delivery.findings-resolved
29
+ - delivery.stages-complete
30
+ - delivery.approved-sha-resolves
31
+ - delivery.merge-gate
32
+ entrypoint: detect.mjs
33
+ report: detect.mjs
@@ -0,0 +1,9 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { validateDelivery } from "../../src/delivery.ts";
4
+
5
+ const roots = JSON.parse(process.env.ATDD_SCAN_ROOTS ?? "[]"), report = process.env.ATDD_VIOLATIONS_REPORT;
6
+ if (!report) throw new Error("ATDD_VIOLATIONS_REPORT is required");
7
+ const violations = (await Promise.all(roots.map(root => validateDelivery(root)))).flat().map(item => ({ ...item, line: 1, col: 1, source_line: "" }));
8
+ await mkdir(dirname(report), { recursive: true });
9
+ await writeFile(report, JSON.stringify({ violations }, null, 2));
@@ -0,0 +1,8 @@
1
+ profiles: [delivery]
2
+ delivery:
3
+ independence: fresh-process
4
+ stages:
5
+ plan_review: { authors: [codex], reviewers: [glm, claude] }
6
+ test_review: { authors: [glm, claude], reviewers: [codex, claude] }
7
+ code_review: { authors: [glm, claude], reviewers: [glm, claude], independence: different-model }
8
+ final_review: { authors: [codex], reviewers: [codex, claude] }
@@ -0,0 +1,54 @@
1
+ # In progress: every stage reviewed, the code-review dispute settled, the PR not yet marked ready.
2
+ tranche: api
3
+ status: open
4
+ base_sha: 3f2a91c
5
+ reviews:
6
+ - stage: plan_review
7
+ sha: 8b10e44
8
+ author: { model: codex, run: driver-api }
9
+ reviewer: { model: glm, run: glm-plan-1 }
10
+ verdict: approve
11
+ checked: [ACC-API-001, ACC-API-002, planner.decomposition]
12
+ - stage: test_review
13
+ sha: 91aa0b2
14
+ author: { model: glm, run: glm-red-1 }
15
+ reviewer: { model: codex, run: codex-test-1 }
16
+ verdict: approve
17
+ checked: [ACC-API-001, ACC-API-002, tester.bun.red]
18
+ - stage: code_review
19
+ sha: a4c0f11
20
+ author: { model: glm, run: glm-green-1 }
21
+ reviewer: { model: claude, run: claude-code-1 }
22
+ fallback:
23
+ - { from: glm, kind: rate_limit, failures: 3, window: { from: "2026-09-25T09:00:00Z", to: "2026-09-25T09:08:00Z" }, reason: "rate limit: 3 failures in 10 minutes" }
24
+ verdict: request_changes
25
+ checked: [ACC-API-001, ACC-API-002, src/wagons/api, coder.bun.error-response]
26
+ findings:
27
+ - id: F1
28
+ severity: high
29
+ evidence: src/wagons/api/handler.ts:42 returns a bare string
30
+ invariant: every error response carries a coded body
31
+ affects: [ui]
32
+ proposed_fix: return { code "API_NOT_FOUND" } instead of the bare string
33
+ outcome: fixed
34
+ - id: F2
35
+ severity: medium
36
+ evidence: src/wagons/api/handler.ts:57 retries without a bound
37
+ invariant: outbound calls are bounded
38
+ proposed_fix: cap the retry loop at three attempts
39
+ rebuttal: "The loop is bounded by the caller's AbortSignal; see handler.test.ts:31 which proves it stops."
40
+ outcome: withdrawn
41
+ - stage: code_review
42
+ sha: c77d0a2
43
+ author: { model: glm, run: glm-green-2 }
44
+ reviewer: { model: claude, run: claude-code-2 }
45
+ fallback:
46
+ - { from: glm, kind: rate_limit, failures: 3, window: { from: "2026-09-25T09:00:00Z", to: "2026-09-25T09:08:00Z" }, reason: "rate limit: 3 failures in 10 minutes" }
47
+ verdict: approve
48
+ checked: [ACC-API-001, ACC-API-002, src/wagons/api, F1, F2]
49
+ - stage: final_review
50
+ sha: c77d0a2
51
+ author: { model: codex, run: driver-api }
52
+ reviewer: { model: codex, run: codex-final-1 }
53
+ verdict: approve
54
+ checked: [src/wagons/api, contracts, ui]
@@ -0,0 +1,3 @@
1
+ profiles: [delivery]
2
+ delivery:
3
+ independence: loose
@@ -0,0 +1,37 @@
1
+ # Ready, but final_review never ran, the approved SHA exists nowhere, a reviewer is off-list, and one
2
+ # reviewer also authored.
3
+ tranche: api
4
+ status: ready
5
+ base_sha: 3f2a91c
6
+ approved_sha: "0000000"
7
+ reviews:
8
+ - stage: plan_review
9
+ sha: 8b10e44
10
+ author: { model: codex, run: driver-api }
11
+ reviewer: { model: gpt, run: gpt-plan-1 }
12
+ verdict: approve
13
+ checked: [ACC-API-001]
14
+ - stage: test_review
15
+ sha: 91aa0b2
16
+ author: { model: glm, run: glm-red-1 }
17
+ reviewer: { model: codex, run: driver-api }
18
+ verdict: approve
19
+ checked: [ACC-API-001]
20
+ - stage: code_review
21
+ sha: a4c0f11
22
+ author: { model: glm, run: glm-green-1 }
23
+ reviewer: { model: glm, run: glm-code-1 }
24
+ verdict: request_changes
25
+ checked: [ACC-API-001]
26
+ findings:
27
+ - id: F1
28
+ severity: high
29
+ evidence: src/wagons/api/handler.ts:42 returns a bare string
30
+ invariant: every error response carries a coded body
31
+ proposed_fix: return a coded error body
32
+ - stage: code_review
33
+ sha: "0000000"
34
+ author: { model: glm, run: glm-green-2 }
35
+ reviewer: { model: glm, run: glm-code-2 }
36
+ verdict: approve
37
+ checked: [ACC-API-001, F1]
@@ -0,0 +1,8 @@
1
+ # A reviewer without a verdict or a checklist.
2
+ tranche: data
3
+ status: open
4
+ base_sha: 3f2a91c
5
+ reviews:
6
+ - stage: plan_review
7
+ sha: 8b10e44
8
+ reviewer: { model: glm, run: glm-plan-1 }
@@ -0,0 +1 @@
1
+ The orphan tranche has a folder and no evidence.yaml.
@@ -0,0 +1,5 @@
1
+ # The folder says ui, the record says web.
2
+ tranche: web
3
+ status: open
4
+ base_sha: 3f2a91c
5
+ reviews: []