@afokapu/atdd-bun 0.6.1 → 0.7.0
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.
- package/README.md +89 -484
- package/conventions/coder.bun/coder.bun.telemetry-forbidden-properties.convention.yaml +51 -0
- package/conventions/coder.bun/coder.bun.telemetry-implementation-binding.convention.yaml +45 -0
- package/conventions/coder.bun/coder.bun.telemetry-raw-string-emit.convention.yaml +53 -0
- package/conventions/coder.bun/coder.bun.telemetry-source-binding.convention.yaml +48 -0
- package/conventions/coder.bun/coder.bun.telemetry-vendor-sdk.convention.yaml +51 -0
- package/conventions/planner.telemetry/planner.telemetry.acceptance-decision.convention.yaml +58 -0
- package/conventions/planner.telemetry/planner.telemetry.logical-ownership.convention.yaml +50 -0
- package/conventions/planner.telemetry/planner.telemetry.metric-cardinality.convention.yaml +47 -0
- package/conventions/planner.telemetry/planner.telemetry.tracking-plan-schema.convention.yaml +75 -0
- package/conventions/tester.bun/tester.bun.telemetry-captured-sink.convention.yaml +47 -0
- package/conventions/tester.bun/tester.bun.telemetry-identity-assertion.convention.yaml +44 -0
- package/conventions/tester.bun/tester.bun.telemetry-required-item-coverage.convention.yaml +44 -0
- package/conventions/tester.bun/tester.bun.telemetry-test-binding.convention.yaml +52 -0
- package/conventions/tester.bun/tester.bun.telemetry-timing-semantics.convention.yaml +53 -0
- package/detectors/atdd_traceability_closure/detect.mjs +31 -16
- package/detectors/bun_telemetry_code/atdd.implementation.yaml +24 -0
- package/detectors/bun_telemetry_code/calls.mjs +104 -0
- package/detectors/bun_telemetry_code/checks/t_forbidden_properties.mjs +46 -0
- package/detectors/bun_telemetry_code/checks/t_implementation_binding.mjs +41 -0
- package/detectors/bun_telemetry_code/checks/t_raw_string_emit.mjs +34 -0
- package/detectors/bun_telemetry_code/checks/t_source_binding.mjs +48 -0
- package/detectors/bun_telemetry_code/checks/t_vendor_sdk.mjs +38 -0
- package/detectors/bun_telemetry_code/detect.mjs +50 -0
- package/detectors/bun_telemetry_code/fixtures/clean/plan/commons/E001.yaml +10 -0
- package/detectors/bun_telemetry_code/fixtures/clean/plan/commons/E002.yaml +7 -0
- package/detectors/bun_telemetry_code/fixtures/clean/plan/commons/_commons.yaml +6 -0
- package/detectors/bun_telemetry_code/fixtures/clean/src/wagons/commons/features/ingress/domain/accept-response.ts +8 -0
- package/detectors/bun_telemetry_code/fixtures/clean/src/wagons/commons/features/ingress/infrastructure/otel-adapter.ts +8 -0
- package/detectors/bun_telemetry_code/fixtures/clean/telemetry/commons/response-invocation-accepted/event.be.json +16 -0
- package/detectors/bun_telemetry_code/fixtures/clean/telemetry/commons/response-invocation-accepted/metric.be.duration.json +19 -0
- package/detectors/bun_telemetry_code/fixtures/clean/tests/wagons/commons/features/ingress/unit/accept-response.telemetry.test.ts +13 -0
- package/detectors/bun_telemetry_code/fixtures/clean/tests/wagons/commons/features/ingress/unit/accept-response.test.ts +9 -0
- package/detectors/bun_telemetry_code/fixtures/dirty/plan/commons/E001.yaml +8 -0
- package/detectors/bun_telemetry_code/fixtures/dirty/plan/commons/_commons.yaml +6 -0
- package/detectors/bun_telemetry_code/fixtures/dirty/src/wagons/commons/features/ingress/domain/accept-response.ts +13 -0
- package/detectors/bun_telemetry_code/fixtures/dirty/src/wagons/commons/features/ingress/domain/tracing.ts +3 -0
- package/detectors/bun_telemetry_code/fixtures/dirty/telemetry/commons/response-invocation-accepted/event.be.json +16 -0
- package/detectors/bun_telemetry_code/fixtures/dirty/tests/wagons/commons/features/ingress/unit/probe.test.ts +7 -0
- package/detectors/bun_telemetry_code/registry.mjs +34 -0
- package/detectors/bun_telemetry_test/_shared.mjs +92 -0
- package/detectors/bun_telemetry_test/atdd.implementation.yaml +24 -0
- package/detectors/bun_telemetry_test/checks/t_captured_sink.mjs +35 -0
- package/detectors/bun_telemetry_test/checks/t_identity_assertion.mjs +45 -0
- package/detectors/bun_telemetry_test/checks/t_required_item_coverage.mjs +37 -0
- package/detectors/bun_telemetry_test/checks/t_test_binding.mjs +56 -0
- package/detectors/bun_telemetry_test/checks/t_timing_semantics.mjs +51 -0
- package/detectors/bun_telemetry_test/detect.mjs +50 -0
- package/detectors/bun_telemetry_test/fixtures/clean/plan/commons/E001.yaml +10 -0
- package/detectors/bun_telemetry_test/fixtures/clean/plan/commons/E002.yaml +7 -0
- package/detectors/bun_telemetry_test/fixtures/clean/plan/commons/_commons.yaml +6 -0
- package/detectors/bun_telemetry_test/fixtures/clean/src/wagons/commons/features/ingress/domain/accept-response.ts +8 -0
- package/detectors/bun_telemetry_test/fixtures/clean/telemetry/commons/response-invocation-accepted/event.be.json +16 -0
- package/detectors/bun_telemetry_test/fixtures/clean/telemetry/commons/response-invocation-accepted/metric.be.duration.json +19 -0
- package/detectors/bun_telemetry_test/fixtures/clean/tests/wagons/commons/features/ingress/unit/accept-response.telemetry.test.ts +13 -0
- package/detectors/bun_telemetry_test/fixtures/clean/tests/wagons/commons/features/ingress/unit/accept-response.test.ts +7 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/plan/commons/E001.yaml +10 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/plan/commons/E002.yaml +7 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/plan/commons/_commons.yaml +6 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/src/wagons/commons/features/ingress/domain/accept-response.ts +8 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/telemetry/commons/response-invocation-accepted/event.be.json +16 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/telemetry/commons/response-invocation-accepted/metric.be.duration.json +19 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/tests/wagons/commons/features/ingress/unit/dangling.telemetry.test.ts +9 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/tests/wagons/commons/features/ingress/unit/loose.telemetry.test.ts +11 -0
- package/detectors/bun_telemetry_test/fixtures/dirty/tests/wagons/commons/features/ingress/unit/unbound.telemetry.test.ts +10 -0
- package/detectors/planner_telemetry_plan/atdd.implementation.yaml +22 -0
- package/detectors/planner_telemetry_plan/detect.mjs +9 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/plan/commons/E001.yaml +10 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/plan/commons/E002.yaml +7 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/plan/commons/_commons.yaml +6 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/src/wagons/commons/features/ingress/domain/accept-response.ts +8 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/telemetry/commons/response-invocation-accepted/event.be.json +16 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/telemetry/commons/response-invocation-accepted/metric.be.duration.json +19 -0
- package/detectors/planner_telemetry_plan/fixtures/clean/tests/wagons/commons/features/ingress/unit/accept-response.telemetry.test.ts +13 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/plan/commons/E001.yaml +9 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/plan/commons/E002.yaml +4 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/plan/commons/E003.yaml +7 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/plan/commons/_commons.yaml +6 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/telemetry/commons/extra.json +1 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/telemetry/commons/orphan-artifact/event.be.json +14 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/telemetry/commons/response-invocation-accepted/event.be.json +16 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/telemetry/commons/response-invocation-accepted/metric.be.duration.json +22 -0
- package/detectors/planner_telemetry_plan/fixtures/dirty/telemetry/commons/response-invocation-accepted/notes.json +1 -0
- package/integrity.json +96 -13
- package/lib/scan.mjs +37 -0
- package/package.json +1 -1
- package/planner-schemas/acceptance.schema.json +70 -1
- package/planner-schemas/telemetry-plan.schema.json +133 -0
- package/relationships.yaml +174 -0
- package/src/agent.ts +15 -8
- package/src/enforce.ts +28 -3
- package/src/hooks.ts +2 -2
- package/src/index.ts +2 -0
- package/src/integrity.ts +13 -5
- package/src/telemetry-plan.ts +223 -0
- package/src/topology.ts +3 -1
- package/templates/agents/AGENTS.block.md +5 -1
package/README.md
CHANGED
|
@@ -1,537 +1,142 @@
|
|
|
1
1
|
# `@afokapu/atdd-bun`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
same Git history. It gives developers and coding agents fast local feedback,
|
|
6
|
-
then runs the same checks in GitHub Actions.
|
|
7
|
-
|
|
8
|
-
It runs entirely on Bun from the repository's own `node_modules`: no global
|
|
9
|
-
installation and no network access while enforcing a repository.
|
|
10
|
-
|
|
11
|
-
## What it protects
|
|
12
|
-
|
|
13
|
-
The package is an enforcer, not a planner or deployment platform. It checks the
|
|
14
|
-
relationships that a plan makes explicit:
|
|
3
|
+
Bun-native ATDD enforcement for repositories that keep their plan, acceptances, tests and
|
|
4
|
+
implementation in one Git history. It checks the links a plan makes explicit:
|
|
15
5
|
|
|
16
6
|
```text
|
|
17
7
|
plan / WMBT → acceptance → Bun test → implementation
|
|
18
8
|
```
|
|
19
9
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
It deliberately does **not** claim that static links prove a test is
|
|
25
|
-
semantically adequate. Where the package can establish only a structural link,
|
|
26
|
-
its report says so. Deployment execution, cloud credentials, and release
|
|
27
|
-
publishing remain repository-owned.
|
|
28
|
-
|
|
29
|
-
## How a repository uses it
|
|
30
|
-
|
|
31
|
-
A repository normally uses the package in three places:
|
|
32
|
-
|
|
33
|
-
1. A local Bun test or command gives immediate feedback while work is underway.
|
|
34
|
-
2. Git hooks prevent clearly invalid commits and pushes; they are convenience,
|
|
35
|
-
not merge authority.
|
|
36
|
-
3. GitHub Actions runs the full policy. Protect the resulting required check in
|
|
37
|
-
the repository’s GitHub branch ruleset.
|
|
10
|
+
It runs on Bun from the repository's own `node_modules`, with no global install and no network
|
|
11
|
+
access. The same checks run as local tests, as Git hooks for fast feedback, and in GitHub Actions,
|
|
12
|
+
which is the merge gate. Every finding fails: there is no advisory mode and no ratchet baseline.
|
|
38
13
|
|
|
39
|
-
|
|
40
|
-
the plan/test links the repository has chosen to require, and a local hook is
|
|
41
|
-
not the only thing standing between an invalid branch and `main`.
|
|
42
|
-
|
|
43
|
-
## Install and first use
|
|
44
|
-
|
|
45
|
-
Add the package from npm as a development dependency, then bootstrap the
|
|
46
|
-
repository once:
|
|
14
|
+
## Install
|
|
47
15
|
|
|
48
16
|
```sh
|
|
49
17
|
bun add -d @afokapu/atdd-bun
|
|
50
18
|
bun run atdd-bun init
|
|
51
19
|
```
|
|
52
20
|
|
|
53
|
-
`init` installs the
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
[integrity test](#integrity-files-agents-must-not-change). Commit what it
|
|
58
|
-
generates (`.githooks/`, `.github/workflows/atdd-bun.yml`, `.agents/`, `.claude/`,
|
|
59
|
-
`AGENTS.md`, `atdd-bun.integrity.test.ts`) so every clone and every agent session
|
|
60
|
-
gets them. To keep the
|
|
61
|
-
package and the skill current automatically, see
|
|
62
|
-
[Staying up to date](#staying-up-to-date).
|
|
21
|
+
`init` installs the Git hooks (`.githooks/`), the CI workflow (`.github/workflows/atdd-bun.yml`),
|
|
22
|
+
the agent skill (`.agents/skills/atdd/`, `.claude/skills/atdd/`), a managed block in `AGENTS.md`
|
|
23
|
+
and `CLAUDE.md`, and `atdd-bun.integrity.test.ts`. Commit all of them. Nothing is overwritten
|
|
24
|
+
without `--replace`, and adding the dependency changes nothing until you run `init`.
|
|
63
25
|
|
|
64
|
-
|
|
26
|
+
Then require the workflow's job in the GitHub branch ruleset, so it gates merges.
|
|
65
27
|
|
|
66
|
-
|
|
67
|
-
bun run atdd-bun all
|
|
68
|
-
```
|
|
28
|
+
## Commands
|
|
69
29
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
30
|
+
| Command | What it does |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `atdd-bun [profile ...] [--root <path>]` | Enforce the named profiles; `all` (the default) runs every activated one |
|
|
33
|
+
| `atdd-bun init [--replace]` | Install hooks, CI, agent files and the integrity test |
|
|
34
|
+
| `atdd-bun hooks <install\|uninstall\|status>` | Manage only the Git hooks |
|
|
35
|
+
| `atdd-bun ci <init\|status>` | Manage only the CI workflow |
|
|
36
|
+
| `atdd-bun agent <init\|status>` | Manage only the skills and the `AGENTS.md`/`CLAUDE.md` block |
|
|
37
|
+
| `atdd-bun integrity [init\|status]` | Check that the toolkit and its generated files are unmodified |
|
|
38
|
+
| `atdd-bun docs journeys [--check]` | Generate (or verify) the journey, interlocking and train views |
|
|
39
|
+
| `atdd-bun worktree <start\|finish\|status>` | Optional linked-worktree policy for agent work |
|
|
40
|
+
| `atdd-bun release check` | Read-only SemVer and release-intent check |
|
|
41
|
+
| `atdd-bun help [--json]` | Every command and profile, human- or agent-readable |
|
|
42
|
+
|
|
43
|
+
Run them with `bun run atdd-bun …`. To make a single Bun test fail on broken closure:
|
|
76
44
|
|
|
77
45
|
```ts
|
|
78
46
|
import { registerEnforcementTest } from "@afokapu/atdd-bun/register";
|
|
79
|
-
|
|
80
|
-
registerEnforcementTest({
|
|
81
|
-
root: import.meta.dir + "/..",
|
|
82
|
-
profiles: ["traceability"],
|
|
83
|
-
});
|
|
47
|
+
registerEnforcementTest({ root: import.meta.dir + "/..", profiles: ["traceability"] });
|
|
84
48
|
```
|
|
85
49
|
|
|
86
|
-
|
|
87
|
-
closure is broken, without enabling unrelated code-quality profiles.
|
|
50
|
+
## Profiles
|
|
88
51
|
|
|
89
|
-
|
|
52
|
+
| Profile | Checks |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `traceability` | acceptance → Bun test → source closure: every acceptance tested, every binding and `Tested-By` resolving |
|
|
55
|
+
| `topology` | feature decomposition and the plan, source, test and E2E locations |
|
|
56
|
+
| `planner` | schemas for every plan artifact, graph integrity, the scoped planner rules |
|
|
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
|
+
| `docs` | the documentation capability, including the generated journey view |
|
|
59
|
+
| `coder`, `tester`, `security`, `architecture`, `metrics`, `runtime` | Bun source and test conventions |
|
|
60
|
+
| `interlocking` | train/interlocking binding, infrastructure and route coverage |
|
|
61
|
+
| `htmx` | htmx source/test conventions and Playwright browser specs (`*.e2e.ts`) |
|
|
62
|
+
| `design` | design-system layering, token-only styling and responsiveness |
|
|
63
|
+
| `all` | every activated profile; what the hooks and CI run |
|
|
90
64
|
|
|
91
|
-
|
|
92
|
-
`bun run atdd-bun help --json` for an agent-readable command/profile inventory.
|
|
65
|
+
`planner-nodes/ENFORCEMENT_SCOPE.yaml` says which canonical planner rules have a Bun realization.
|
|
93
66
|
|
|
94
|
-
|
|
95
|
-
name.
|
|
67
|
+
## Greenfield and brownfield
|
|
96
68
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| `topology` | feature decomposition and canonical plan, source, test, and E2E locations |
|
|
101
|
-
| `planner` | plan parsing/graph integrity plus the explicitly scoped planner rules |
|
|
102
|
-
| `docs` | the optional documentation capability and its declared artifacts, including the generated journey view |
|
|
103
|
-
| `coder`, `tester`, `security`, `architecture`, `metrics`, `runtime` | Bun source and test conventions for that concern |
|
|
104
|
-
| `interlocking` | declared train/interlocking binding, infrastructure, and coverage |
|
|
105
|
-
| `htmx` | htmx-specific source and test conventions, including browser specs |
|
|
106
|
-
| `design` | the design system (tokens ← primitives ← components ← templates, token-only colors, spacing, radii, motion) and responsiveness (also part of `coder`) |
|
|
107
|
-
| `all` | the complete package policy, normally used by CI |
|
|
108
|
-
|
|
109
|
-
The package ships the canonical planner-node corpus as planning reference, but
|
|
110
|
-
does not pretend that every node is executable. The
|
|
111
|
-
[planner enforcement scope](planner-nodes/ENFORCEMENT_SCOPE.yaml) identifies
|
|
112
|
-
which rules have a Bun realization, which predicates are only partial, and which
|
|
113
|
-
nodes are reference-only.
|
|
114
|
-
|
|
115
|
-
The planner profile first validates recognized plan artifacts against the
|
|
116
|
-
package-shipped JSON Schemas—wagon, feature, WMBT (including embedded
|
|
117
|
-
acceptances), train, train interlocking, and journey topology. It then runs
|
|
118
|
-
cross-artifact validators such as registry coherence, traceability, and
|
|
119
|
-
cross-interlocking continuation closure. A journey starts at one interlocking;
|
|
120
|
-
each reachable route must either terminate explicitly or continue, through an
|
|
121
|
-
artifact produced by that route's selected train, to another interlocking. Exposed journeys also
|
|
122
|
-
carry Station Master actions; the Bun interlocking family checks those actions resolve through
|
|
123
|
-
`JOURNEY_MAP` to `JourneyRunner`, while internal journeys carry no public reachability obligation.
|
|
124
|
-
Hooks, direct CLI use, and CI invoke this same profile and therefore share the
|
|
125
|
-
same schema source.
|
|
126
|
-
|
|
127
|
-
### Repository topology
|
|
128
|
-
|
|
129
|
-
The topology gate makes a feature a required plan artifact instead of an
|
|
130
|
-
optional label on a WMBT. Its default layout is:
|
|
69
|
+
A greenfield repository enforces every profile from the start: that is the default. A brownfield
|
|
70
|
+
(legacy) repository can adopt enforcement gradually. The operator lists the profiles it is ready
|
|
71
|
+
for, and adds more as the code catches up:
|
|
131
72
|
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
tests/wagons/<wagon>/features/<feature>/{unit,contract,integration}/
|
|
136
|
-
e2e/interlockings/<interlocking>/<route>.routes.test.ts
|
|
137
|
-
e2e/journeys/<journey>.journey.test.ts
|
|
73
|
+
```yaml
|
|
74
|
+
# atdd-bun.yaml
|
|
75
|
+
profiles: [traceability, planner]
|
|
138
76
|
```
|
|
139
77
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
78
|
+
`all`, the hooks and the generated CI then run only those profiles. Any profile can still be run
|
|
79
|
+
by name (`bun run atdd-bun coder`) to see what remains. An unknown name or an empty list is an
|
|
80
|
+
error, never a silent run of nothing. Removing a profile loosens `atdd-bun.yaml`, so the integrity
|
|
81
|
+
check reports it against the base branch until a human approves the change.
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
144
84
|
|
|
145
|
-
|
|
146
|
-
validation then follows the configured locations:
|
|
85
|
+
Everything is set in `atdd-bun.yaml`. The main keys:
|
|
147
86
|
|
|
148
87
|
```yaml
|
|
149
|
-
topology:
|
|
88
|
+
profiles: [traceability, planner, topology] # default: every profile
|
|
89
|
+
topology: # default layout; point it at existing roots
|
|
150
90
|
plan_root: plan
|
|
151
91
|
source_root: src/wagons
|
|
152
92
|
test_root: tests/wagons
|
|
153
93
|
e2e_root: e2e
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
### Design system
|
|
157
|
-
|
|
158
|
-
The `design` profile (also part of `coder`) is the Bun realization of the core
|
|
159
|
-
`coder.design.*` obligations. It recognizes a design system by its directory:
|
|
160
|
-
a folder named `design`, `design_system`, or `design-system`, whose first
|
|
161
|
-
subfolder names the layer:
|
|
162
|
-
|
|
163
|
-
```text
|
|
164
|
-
design/
|
|
165
|
-
tokens/ or foundations/ values only: palette, spacing, radii, motion
|
|
166
|
-
primitives/ Button, Text, Stack … built from tokens
|
|
167
|
-
components/ composed from primitives
|
|
168
|
-
templates/ page structure composed from components
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Imports flow downward only, and the design system never imports app code.
|
|
172
|
-
Outside the tokens layer, `.tsx`, `.html`, and `.css` files take colors,
|
|
173
|
-
spacing, radii, and durations from tokens (`var(--…)`); app components render
|
|
174
|
-
controls through primitives and import at least one design-system element; and
|
|
175
|
-
every exported component has a consumer. Defining a custom property
|
|
176
|
-
(`--accent: #0ea5e9`) is defining a token and is allowed anywhere. A repository
|
|
177
|
-
without a design directory is not judged by these rules.
|
|
178
|
-
|
|
179
|
-
### Journey documentation
|
|
180
|
-
|
|
181
|
-
A plan describes behaviour on three levels. A journey (`plan/_journeys/`) enters
|
|
182
|
-
at one interlocking and continues, through an artifact the selected train
|
|
183
|
-
produces, into the next one. An interlocking chooses one route by its guards.
|
|
184
|
-
A route runs one train, a linear sequence of handovers. Generate the view of all
|
|
185
|
-
three from `plan/`:
|
|
186
|
-
|
|
187
|
-
```sh
|
|
188
|
-
bun run atdd-bun docs journeys # writes docs/purpose/journeys/
|
|
189
|
-
bun run atdd-bun docs journeys --check # fails when the committed view differs from plan/
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
It writes `docs/purpose/journeys/index.adoc` and one SVG for each of:
|
|
193
|
-
|
|
194
|
-
- **journey map:** the entry action, each interlocking, the routes it chooses
|
|
195
|
-
and their guards, the trains they run, continuations (labelled with the
|
|
196
|
-
artifact that carries control) and terminal outcomes;
|
|
197
|
-
- **nominal path, end to end:** the journey's trains across all its
|
|
198
|
-
interlockings, joined into one sequence diagram;
|
|
199
|
-
- **train:** each routed train as its own sequence diagram, under its
|
|
200
|
-
interlocking's route table.
|
|
201
|
-
|
|
202
|
-
The page also tables every path with how it ends, and every **gap**: unreached
|
|
203
|
-
interlockings, routes with no continuation or outcome, unrouted trains,
|
|
204
|
-
unresolved guards. Participants are coloured by what they are (wagon, person,
|
|
205
|
-
outside system) and arrows by the boundary they cross. Diagrams are inlined
|
|
206
|
-
(`opts=inline`) and coloured with `var(--atdd-*, fallback)`, so a doc site can
|
|
207
|
-
theme them by defining `--atdd-ink`, `--atdd-paper`, `--atdd-wagon`,
|
|
208
|
-
`--atdd-person`, `--atdd-system`, `--atdd-nominal`, `--atdd-alternate`,
|
|
209
|
-
`--atdd-error`, `--atdd-exception`, and the like. The output carries no
|
|
210
|
-
timestamp and no package version, so it changes only when the plan does.
|
|
211
|
-
|
|
212
|
-
The planner requires the journey level itself: `planner.journey.interlocking-composed`
|
|
213
|
-
fails when a plan declares interlockings and no journey, or when an interlocking
|
|
214
|
-
is neither a journey's entrypoint nor reached by one of its continuations.
|
|
215
|
-
`planner.journey.continuation-closure` then checks each declared journey closes.
|
|
216
|
-
|
|
217
|
-
**Required.** In a repository with `docs/` whose plan has journeys or
|
|
218
|
-
interlockings, the `docs` profile's `planner.docs.journey-view-current` rule
|
|
219
|
-
fails when any generated file is missing, stale, hand-edited, or extra. The
|
|
220
|
-
generator refuses to overwrite a hand-written `index.adoc` unless you pass
|
|
221
|
-
`--force`; use `--out <dir>` to preview elsewhere.
|
|
222
|
-
|
|
223
|
-
### Every enforced rule is strict
|
|
224
|
-
|
|
225
|
-
atdd-bun fails on every finding: it has no advisory mode and no ratchet
|
|
226
|
-
baseline. Every convention with a validator is therefore `strict` (or `block`),
|
|
227
|
-
and `tests/dispositions.test.ts` fails on any that promises otherwise. For the
|
|
228
|
-
canonical planner nodes, which ship verbatim, the package states its own
|
|
229
|
-
`disposition: strict` in `planner-nodes/ENFORCEMENT_SCOPE.yaml`.
|
|
230
|
-
|
|
231
|
-
### Browser specs (Playwright)
|
|
232
|
-
|
|
233
|
-
The `tester` and `htmx` profiles judge browser specs against the plan. A browser
|
|
234
|
-
spec is a `*.e2e.ts` file run by Playwright, never `*.spec.ts`, which `bun test`
|
|
235
|
-
would try to run itself. It binds to one plan subject and declares its layer
|
|
236
|
-
and test URN:
|
|
237
|
-
|
|
238
|
-
```ts
|
|
239
|
-
import { expect, test } from "@playwright/test";
|
|
240
|
-
|
|
241
|
-
// Train: train:orders:place-order (or // Journey: journey:buy)
|
|
242
|
-
// Layer: assembly
|
|
243
|
-
// URN: test:train:orders:place-order:E2E-001-places-an-order
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
The harness code in the URN (`E2E`, `SMOKE`, `A11Y`, `VIS`, `RESP`) says what
|
|
247
|
-
the spec must do: an `A11Y` spec runs `@axe-core/playwright` and asserts on its
|
|
248
|
-
violations, a `VIS` spec compares a screenshot, a `RESP` spec renders at every
|
|
249
|
-
declared viewport and asserts on `scrollWidth`. Coverage is read from `plan/`:
|
|
250
|
-
every train has a spec, every covered train is routed by an interlocking, every
|
|
251
|
-
exposed journey has an E2E or SMOKE spec and a RESP spec, and every presentation
|
|
252
|
-
component has a SMOKE spec naming its wagon. Route and Station Master coverage
|
|
253
|
-
remain `tester.bun` rules; browser specs count toward them.
|
|
254
|
-
|
|
255
|
-
### Responsiveness
|
|
256
|
-
|
|
257
|
-
The `coder` and `design` profiles check the structural causes of screens that
|
|
258
|
-
break on small devices: every HTML document declares
|
|
259
|
-
`<meta name="viewport" content="width=device-width, initial-scale=1">` and
|
|
260
|
-
never blocks zoom; no `width`/`min-width` is wider than the smallest viewport;
|
|
261
|
-
and every `@media` width is a declared breakpoint (media queries cannot read
|
|
262
|
-
CSS variables, so breakpoints are declared once). The browser proof is the
|
|
263
|
-
`RESP` spec above. Both read the same settings:
|
|
264
|
-
|
|
265
|
-
```yaml
|
|
266
|
-
# atdd-bun.yaml
|
|
94
|
+
telemetry_root: telemetry # tracking-plan registry; inert until the tree or a decision exists
|
|
267
95
|
frontend:
|
|
268
|
-
viewports: [375, 768, 1280]
|
|
269
|
-
breakpoints: [480, 768, 1024, 1280]
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
Theme vocabulary belongs to the repository, not the package. When a plan uses
|
|
275
|
-
themes, declare them in `plan/_themes.yaml`; only index `0: commons` is
|
|
276
|
-
reserved. Every other index and kebab-case name is repository-defined.
|
|
277
|
-
|
|
278
|
-
```yaml
|
|
279
|
-
themes:
|
|
280
|
-
"0": commons
|
|
281
|
-
"1": orders
|
|
282
|
-
"2": inventory
|
|
96
|
+
viewports: [375, 768, 1280]
|
|
97
|
+
breakpoints: [480, 768, 1024, 1280]
|
|
98
|
+
registry_paths: ["plan/_*.yaml", "contracts/_*.yaml"] # exempt from micro-commit size caps only
|
|
99
|
+
max_registry_removed_lines: 350 # larger removals need [mass-delete-approved]
|
|
100
|
+
worktrees: { enabled: false }
|
|
101
|
+
release: { enabled: false }
|
|
283
102
|
```
|
|
284
103
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
references resolve, registry paths exist, a contract identity begins with its
|
|
288
|
-
declared theme, and cross-wagon artifacts have contract evidence.
|
|
289
|
-
|
|
290
|
-
## Hooks: fast feedback, not merge authority
|
|
291
|
-
|
|
292
|
-
Run the explicit repository bootstrap once in each worktree where you work:
|
|
293
|
-
|
|
294
|
-
```sh
|
|
295
|
-
bun run atdd-bun init
|
|
296
|
-
```
|
|
104
|
+
The hooks enforce protected-branch blocking, micro-commit limits, mass-delete approval and
|
|
105
|
+
validation of the affected area. Git can bypass them, so CI is the authority.
|
|
297
106
|
|
|
298
|
-
|
|
299
|
-
generates `.github/workflows/atdd-bun.yml`, and installs the coding-agent skill
|
|
300
|
-
when they are absent. It never overwrites another hook path, an existing
|
|
301
|
-
generated workflow, or an existing skill unless you explicitly pass `--replace`.
|
|
302
|
-
The package itself has no install script: adding the dependency never changes
|
|
303
|
-
the repository until you run `init`.
|
|
107
|
+
## Agents and integrity
|
|
304
108
|
|
|
305
|
-
|
|
109
|
+
The skill gives every coding agent the lifecycle PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE and
|
|
110
|
+
the profile that gates each stage. The block in `AGENTS.md` and `CLAUDE.md` adds the rules: never
|
|
111
|
+
modify the toolkit itself, only the configuration it offers, and enable capabilities through
|
|
112
|
+
`profiles`.
|
|
306
113
|
|
|
307
|
-
|
|
308
|
-
bun run atdd-bun hooks install
|
|
309
|
-
bun run atdd-bun ci init
|
|
310
|
-
bun run atdd-bun agent init
|
|
311
|
-
bun run atdd-bun integrity init
|
|
312
|
-
```
|
|
114
|
+
`atdd-bun integrity`, run by the generated test and first in CI on a clean install, fails when:
|
|
313
115
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
116
|
+
- the installed package differs from its published hashes;
|
|
117
|
+
- the dependency is not an npm registry version;
|
|
118
|
+
- a generated file (workflow, skills, instruction block, integrity test) was edited;
|
|
119
|
+
- `atdd-bun.yaml` is looser than on the base branch.
|
|
317
120
|
|
|
318
|
-
|
|
319
|
-
bun run atdd-bun hooks status
|
|
320
|
-
bun run atdd-bun hooks uninstall
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
Hooks can be bypassed by Git and therefore are never the merge gate. The CI
|
|
324
|
-
workflow and GitHub branch ruleset are the authority for merging.
|
|
325
|
-
|
|
326
|
-
### Declarative registries
|
|
327
|
-
|
|
328
|
-
Micro-commit limits (`max_staged_files`, `max_staged_changed_lines`, default
|
|
329
|
-
350) exist to keep imperative code changes small. They do not apply to
|
|
330
|
-
declarative registries, which can legitimately be hundreds or thousands of lines
|
|
331
|
-
and must not be split into invalid intermediate states. Registries are matched by
|
|
332
|
-
`registry_paths` (default `plan/_*.yaml`, `plan/_*.yml`, `contracts/_*.yaml`,
|
|
333
|
-
`contracts/_*.yml`).
|
|
334
|
-
|
|
335
|
-
A staged registry is exempt from the size caps only. It is still:
|
|
336
|
-
|
|
337
|
-
- validated by the `planner` and `traceability` profiles on every commit that
|
|
338
|
-
touches it, even when `require_traceability` is `false`;
|
|
339
|
-
- subject to removal approval: a net removal above `max_registry_removed_lines`
|
|
340
|
-
(default 350) needs `[mass-delete-approved]` in the commit message. Rewriting
|
|
341
|
-
or reordering entries in place is not a removal.
|
|
342
|
-
|
|
343
|
-
```yaml
|
|
344
|
-
# atdd-bun.yaml
|
|
345
|
-
registry_paths: ["plan/_*.yaml", "contracts/_*.yaml", "telemetry/_*.yaml"]
|
|
346
|
-
max_registry_removed_lines: 200
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
Duplicate, stale, and ownership checks come from the planner rules, and
|
|
350
|
-
independent review comes from the CI workflow and branch ruleset.
|
|
351
|
-
|
|
352
|
-
## Agent skill: the lifecycle in the agent's context
|
|
353
|
-
|
|
354
|
-
`agent init` gives every coding agent the same short ATDD skill:
|
|
355
|
-
|
|
356
|
-
- `.agents/skills/atdd/SKILL.md`: the vendor-neutral Agent Skills path (Codex,
|
|
357
|
-
GitHub Copilot, Cursor, Gemini CLI, and others);
|
|
358
|
-
- `.claude/skills/atdd/SKILL.md`: Claude Code;
|
|
359
|
-
- a managed `<!-- atdd-bun:start -->` block in `AGENTS.md` pointing at the skill,
|
|
360
|
-
for agents that read `AGENTS.md` but not skills. The rest of `AGENTS.md` is
|
|
361
|
-
never touched.
|
|
362
|
-
|
|
363
|
-
The skill names the lifecycle PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE, the
|
|
364
|
-
conventions each stage follows, and the `atdd-bun` profile that gates it. It
|
|
365
|
-
points at the conventions shipped in this package instead of restating them, so
|
|
366
|
-
it stays correct as they change; after upgrading, refresh it with
|
|
367
|
-
`bun run atdd-bun agent init --replace`, or let the repository's own
|
|
368
|
-
`postinstall` do it (see [Staying up to date](#staying-up-to-date)). The skill
|
|
369
|
-
steers the agent; the profiles, hooks, and CI remain the enforcement.
|
|
370
|
-
|
|
371
|
-
## Integrity: files agents must not change
|
|
372
|
-
|
|
373
|
-
Coding agents can edit anything on the machine they run on, including
|
|
374
|
-
`node_modules/@afokapu/atdd-bun`, the files this package generates, and
|
|
375
|
-
`atdd-bun.yaml`. `init` therefore writes `atdd-bun.integrity.test.ts` (into the
|
|
376
|
-
`[test] root` from `bunfig.toml`, if one is set), and the generated CI workflow
|
|
377
|
-
runs `bun run atdd-bun integrity` before enforcement. Both run the same check:
|
|
378
|
-
|
|
379
|
-
| Checked | Canonical source | Restore |
|
|
380
|
-
|---|---|---|
|
|
381
|
-
| Every file of the installed package | `integrity.json`, the hashes published with the package | `bun install --force` |
|
|
382
|
-
| The dependency is an npm version range, locked to the registry with an integrity hash | npm | `bun add -d @afokapu/atdd-bun` |
|
|
383
|
-
| The CI workflow, both skills, the `AGENTS.md` block, and the integrity test | what the installed version generates (its version stamp is ignored) | `bun run atdd-bun init --replace` |
|
|
384
|
-
| `atdd-bun.yaml` is not looser than on the branch being merged into | the merge base; for a push to the base branch, the previous commit | `git checkout <base> -- atdd-bun.yaml` |
|
|
385
|
-
|
|
386
|
-
A failure is addressed to the agent: it lists every changed file with its
|
|
387
|
-
restore command and tells it to stop and ask a human instead of working around
|
|
388
|
-
the check. Locally, this is a reminder an agent can still ignore, because
|
|
389
|
-
anything on its machine can be edited. In CI the check runs on a clean install,
|
|
390
|
-
so its verdict cannot be faked. Loosening the policy remains possible, as a
|
|
391
|
-
separate change a human approves.
|
|
392
|
-
|
|
393
|
-
After upgrading to a version that changes generated files, run
|
|
394
|
-
`bun run atdd-bun init --replace` and commit the result.
|
|
395
|
-
|
|
396
|
-
## CI: the merge gate
|
|
397
|
-
|
|
398
|
-
Generate the repository-owned workflow with:
|
|
399
|
-
|
|
400
|
-
```sh
|
|
401
|
-
bun run atdd-bun ci init
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
This writes `.github/workflows/atdd-bun.yml`. It refuses to overwrite an
|
|
405
|
-
existing workflow unless `--replace` is supplied. The generated workflow runs
|
|
406
|
-
on pull requests, merge-queue merge groups, and pushes to `main`/`master`; it
|
|
407
|
-
installs with `bun install --frozen-lockfile`, runs the locally installed package
|
|
408
|
-
without `bunx`, runs `bun test`, and uploads reports when present.
|
|
409
|
-
|
|
410
|
-
After generating it, configure the GitHub branch ruleset to require the workflow
|
|
411
|
-
job before merging. `merge_group` is included so the same protection works with
|
|
412
|
-
GitHub Merge Queue.
|
|
121
|
+
Each finding names its restore command.
|
|
413
122
|
|
|
414
123
|
## Staying up to date
|
|
415
124
|
|
|
416
|
-
Every
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
conventions, validators, and hook policy change as soon as a repository
|
|
421
|
-
upgrades the dependency; nothing needs reinstalling. The generated files are
|
|
422
|
-
copies: when an upgrade changes them, the integrity check reports them until you
|
|
423
|
-
run `bun run atdd-bun init --replace` and commit the result. The agent skill is
|
|
424
|
-
the one refreshed automatically. To refresh it on every install, add a script to the
|
|
425
|
-
repository's own `package.json` (Bun runs a project's own lifecycle scripts, not
|
|
426
|
-
a dependency's):
|
|
125
|
+
Every merge to this package's `main` is published to npm with provenance as the next patch and
|
|
126
|
+
tagged `vX.Y.Z`. Rules and hooks change as soon as a repository upgrades the dependency. To refresh
|
|
127
|
+
the skills and instruction blocks on every install, add this to the repository's own
|
|
128
|
+
`package.json`:
|
|
427
129
|
|
|
428
130
|
```json
|
|
429
|
-
"scripts": {
|
|
430
|
-
"postinstall": "atdd-bun agent init --replace"
|
|
431
|
-
}
|
|
131
|
+
"scripts": { "postinstall": "atdd-bun agent init --replace" }
|
|
432
132
|
```
|
|
433
133
|
|
|
434
|
-
|
|
435
|
-
|
|
134
|
+
Upgrade with `bun update @afokapu/atdd-bun`, or let Dependabot (`package-ecosystem: "bun"`) open a
|
|
135
|
+
pull request per release. For a new `0.x` minor, run `bun add -d @afokapu/atdd-bun@latest`. If an
|
|
136
|
+
upgrade changes the workflow or integrity test, run `bun run atdd-bun init --replace` and commit.
|
|
436
137
|
|
|
437
|
-
|
|
438
|
-
version: 2
|
|
439
|
-
updates:
|
|
440
|
-
- package-ecosystem: "bun"
|
|
441
|
-
directory: "/"
|
|
442
|
-
schedule:
|
|
443
|
-
interval: "daily"
|
|
444
|
-
allow:
|
|
445
|
-
- dependency-name: "@afokapu/atdd-bun"
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
Merging that pull request installs the new version and, through `postinstall`,
|
|
449
|
-
rewrites the skill. Without Dependabot, upgrade with
|
|
450
|
-
`bun update @afokapu/atdd-bun`. The lockfile pins the installed version, so
|
|
451
|
-
nothing changes until one of these runs. While the package is `0.x`, a `^0.1.x`
|
|
452
|
-
range accepts only `0.1.*`; move to a new minor with
|
|
453
|
-
`bun add -d @afokapu/atdd-bun@latest`.
|
|
454
|
-
|
|
455
|
-
## Linked worktrees for agent work
|
|
456
|
-
|
|
457
|
-
An optional policy reserves one primary checkout for `main` and requires feature
|
|
458
|
-
commits to happen in sibling linked worktrees:
|
|
459
|
-
|
|
460
|
-
```text
|
|
461
|
-
my-repo/
|
|
462
|
-
main/ # primary checkout, on branch main
|
|
463
|
-
worktrees/feature-x/ # linked checkout, on branch feature/x
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
Enable the policy in `main/atdd-bun.yaml`:
|
|
467
|
-
|
|
468
|
-
```yaml
|
|
469
|
-
worktrees:
|
|
470
|
-
enabled: true
|
|
471
|
-
root: ../worktrees
|
|
472
|
-
primary_directory: main
|
|
473
|
-
primary_branch: main
|
|
474
|
-
require_linked_worktree: true
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
An agent starts one worktree per work item—not per commit:
|
|
478
|
-
|
|
479
|
-
```sh
|
|
480
|
-
# Run from my-repo/main/ while it is on main.
|
|
481
|
-
bun run atdd-bun worktree start feature/x
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
That command creates `worktrees/feature-x`, creates the `feature/x` branch, and
|
|
485
|
-
installs the package hooks there. Subsequent commits happen normally from that
|
|
486
|
-
linked checkout. The hook rejects commits from the primary checkout, protected
|
|
487
|
-
branches, detached heads, and linked checkouts outside the configured root.
|
|
488
|
-
|
|
489
|
-
When the branch is merged into local `main`, inspect or safely retire it with:
|
|
490
|
-
|
|
491
|
-
```sh
|
|
492
|
-
bun run atdd-bun worktree status
|
|
493
|
-
bun run atdd-bun worktree finish --delete-branch
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
`finish` refuses a dirty or unmerged worktree. It never removes a worktree just
|
|
497
|
-
because a hook ran.
|
|
498
|
-
|
|
499
|
-
Git stores linked-worktree metadata in `main/.git/worktrees/`; the linked
|
|
500
|
-
checkouts themselves belong beside `main`, not inside `.git` or inside the
|
|
501
|
-
primary repository working tree.
|
|
502
|
-
|
|
503
|
-
## Release policy
|
|
504
|
-
|
|
505
|
-
If a repository enables `release` in `atdd-bun.yaml`, this read-only command
|
|
506
|
-
checks SemVer, a single release decision, release intent, and that the proposed
|
|
507
|
-
version is greater than the latest reachable matching local Git tag:
|
|
508
|
-
|
|
509
|
-
```sh
|
|
510
|
-
bun run atdd-bun release check
|
|
511
|
-
```
|
|
138
|
+
## Developing this package
|
|
512
139
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
## Convention relationships
|
|
518
|
-
|
|
519
|
-
`relationships.yaml` relates every convention the package ships (`planner-nodes/`
|
|
520
|
-
and `conventions/`) to at least one other, as
|
|
521
|
-
`planner.relationship.no-orphan-nodes` requires. Edges that touch a shipped
|
|
522
|
-
convention are imported from the upstream ATDD graphs with their `origin`; the
|
|
523
|
-
package adds its own for the conventions it introduces. A test fails when any
|
|
524
|
-
shipped convention has no edge, when the node list drifts from the shipped
|
|
525
|
-
conventions, or when an edge breaks `relationship.schema.json`, so a new
|
|
526
|
-
convention cannot land without its relationships.
|
|
527
|
-
|
|
528
|
-
## Verification of this package
|
|
529
|
-
|
|
530
|
-
`bun test` runs the package’s real-Git fixtures and detector clean/dirty corpora.
|
|
531
|
-
The suite proves that every declared convention output has a matching convention
|
|
532
|
-
and a deliberate failing case, and runs the frontend chain end to end: a Bun app
|
|
533
|
-
built from a plan, its browser specs accepted by the detectors and passing in
|
|
534
|
-
Chromium, and broken variants of the page failing both the static rules and the
|
|
535
|
-
browser (Chromium must be installed: `bunx playwright install chromium`); it also covers hook isolation, the declarative
|
|
536
|
-
registry policy, CI generation, agent-skill installation, planner scope, release
|
|
537
|
-
validation, and linked-worktree policy.
|
|
140
|
+
`bun test` runs the detectors' clean and dirty corpora, real-Git hook fixtures, and the frontend
|
|
141
|
+
chain in Chromium (`bunx playwright install chromium`). Guard tests require every emitted rule to
|
|
142
|
+
have a strict convention, a failing fixture and an edge in `relationships.yaml`.
|