@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.
- package/README.md +45 -4
- package/conventions/delivery/delivery.approved-sha-resolves.convention.yaml +33 -0
- package/conventions/delivery/delivery.config-schema.convention.yaml +43 -0
- package/conventions/delivery/delivery.evidence-schema.convention.yaml +34 -0
- package/conventions/delivery/delivery.findings-resolved.convention.yaml +42 -0
- package/conventions/delivery/delivery.merge-gate.convention.yaml +42 -0
- package/conventions/delivery/delivery.model-allowed.convention.yaml +36 -0
- package/conventions/delivery/delivery.reviewer-independent.convention.yaml +34 -0
- package/conventions/delivery/delivery.stages-complete.convention.yaml +31 -0
- package/detectors/delivery_evidence/atdd.implementation.yaml +33 -0
- package/detectors/delivery_evidence/detect.mjs +9 -0
- package/detectors/delivery_evidence/fixtures/clean/atdd-bun.yaml +8 -0
- package/detectors/delivery_evidence/fixtures/clean/delivery/api/evidence.yaml +54 -0
- package/detectors/delivery_evidence/fixtures/dirty/atdd-bun.yaml +3 -0
- package/detectors/delivery_evidence/fixtures/dirty/delivery/api/evidence.yaml +37 -0
- package/detectors/delivery_evidence/fixtures/dirty/delivery/data/evidence.yaml +8 -0
- package/detectors/delivery_evidence/fixtures/dirty/delivery/orphan/README.md +1 -0
- package/detectors/delivery_evidence/fixtures/dirty/delivery/ui/evidence.yaml +5 -0
- package/integrity.json +33 -11
- package/package.json +1 -1
- package/planner-schemas/delivery-config.schema.json +80 -0
- package/planner-schemas/delivery-evidence.schema.json +84 -0
- package/relationships.yaml +98 -0
- package/src/agent.ts +16 -2
- package/src/ci.ts +8 -1
- package/src/delivery.ts +415 -0
- package/src/enforce.ts +2 -1
- package/src/index.ts +2 -0
- package/src/integrity.ts +38 -11
- package/src/setup.ts +5 -2
- package/templates/agents/AGENTS.block.md +4 -2
- package/templates/agents/delivery/SKILL.md +77 -0
- package/templates/agents/delivery/review.md +45 -0
- package/templates/github/atdd-bun.yml +6 -1
package/integrity.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.8.1",
|
|
3
3
|
"files": {
|
|
4
4
|
"HOOK_AUDIT.md": "5329d840db37671b1918f688ead26865473b87db73dbc75f7c8b2a8bbe8d6d43",
|
|
5
5
|
"PLANNER_PORT.md": "fb5935bac8b7ac18994de21e43ace3a5ef8cd55f85b0e3349fca261280054f11",
|
|
6
|
-
"README.md": "
|
|
6
|
+
"README.md": "e39b94cf795cd3b50b9ee88283beaef1e4d73568a5da2cf2959ea02a98d97afb",
|
|
7
7
|
"bunfig.toml": "b9fc65eca9014c5179380259d70e76385a6a80788fa9a2df5fb3eaa5554fd2fe",
|
|
8
8
|
"conventions/atdd-bun.planner/atdd-bun.planner.acceptance-identity.convention.yaml": "81c5c773d5ee15e8d99a2c237aa9846b110b2533df45ebf407d0e3ec6ed3dd03",
|
|
9
9
|
"conventions/atdd-bun.planner/atdd-bun.planner.identity-required.convention.yaml": "e96d7c1455d0c221072d82e7f2b55da1c4f9ceb17718eb6ed96affdeef37675b",
|
|
@@ -91,6 +91,14 @@
|
|
|
91
91
|
"conventions/coder.htmx/coder.htmx.verb-endpoint-is-routed.convention.yaml": "d6aa58d35df4b7ebbcf675ca79f0177d64e56f095802b9a3eaae3e4befb5c270",
|
|
92
92
|
"conventions/coder.htmx/coder.htmx.verb-endpoint-same-origin.convention.yaml": "2128d26153e2d1f19c65a1e1665d4f82c78395daedb336d6ef1256e82b74aedb",
|
|
93
93
|
"conventions/coder.htmx/coder.htmx.verb-mutation-signals-progress.convention.yaml": "ae85c5ea01a09a3c41b939988088a8e5da91848d2710a1f0a1e0c86308638ac9",
|
|
94
|
+
"conventions/delivery/delivery.approved-sha-resolves.convention.yaml": "8bad8a0fdb28c4dc5f22b8949c8113eec4cc7b18b18af8c12ead5e3e320384ac",
|
|
95
|
+
"conventions/delivery/delivery.config-schema.convention.yaml": "da60ccaed20fb8c77eb8adeb2999158ac3790c6bd28f2e2b2f69e75badbc34fa",
|
|
96
|
+
"conventions/delivery/delivery.evidence-schema.convention.yaml": "ecd838a69c53a84018bfc937dce5a80877f5251172b498e418e7d1d3db46ea43",
|
|
97
|
+
"conventions/delivery/delivery.findings-resolved.convention.yaml": "f6574e93a9a2d4bdd6d6f5645720b1a647fc0048d95f7675fe783d2ddb62c05b",
|
|
98
|
+
"conventions/delivery/delivery.merge-gate.convention.yaml": "dab8c893999d13798d99a9b3ecd350f47de651365bc9d05b9be57a87aecf84ce",
|
|
99
|
+
"conventions/delivery/delivery.model-allowed.convention.yaml": "0476fb4a00dfdfbc16ac3c5843d7796d03e9d7c3ebd2c898eddb47160ac2fcdb",
|
|
100
|
+
"conventions/delivery/delivery.reviewer-independent.convention.yaml": "f3388fe27a0b50549c913ab56a3afda7b70e54f8d0c32146ff59bd9da76afcfc",
|
|
101
|
+
"conventions/delivery/delivery.stages-complete.convention.yaml": "1fd8c0a57e8ee2f91104088c25ee2000fb83e15b58a0cc5c432b37fa0457d056",
|
|
94
102
|
"conventions/planner.docs/planner.docs.adr-registry-derived.convention.yaml": "0ea4232beba90280c664f93d097cafa44c67c2919c1468d4823fdc9e686aa5d2",
|
|
95
103
|
"conventions/planner.docs/planner.docs.area-index-required.convention.yaml": "fd931e9f225bfbb5e78436d0d8a2a89cc0f5114493579962c72dd971301becce",
|
|
96
104
|
"conventions/planner.docs/planner.docs.artifact-path-shape.convention.yaml": "a9f6178d29abe9385342a46a2c57470a3631aaf5e26f01e3660b7088b042418e",
|
|
@@ -654,6 +662,15 @@
|
|
|
654
662
|
"detectors/bun_ts_metrics_detector/fixtures/dirty/orphan.ts": "0f7acd0dffe90902a0a43cc45771b8a473d079efc9693112b3b85645c191c23d",
|
|
655
663
|
"detectors/bun_ts_metrics_detector/fixtures/dirty/typed.ts": "7c27ee1a674af7d5b2cce3a65bfec2111602d84a75817fd60f737c7d63fc9c83",
|
|
656
664
|
"detectors/bun_ts_metrics_detector/ts_metrics.mjs": "6fe397d634e05a0c9605dcefcec53a5736eab4bcc5c45adec55fb8a3de9b3c6d",
|
|
665
|
+
"detectors/delivery_evidence/atdd.implementation.yaml": "2f6fc30dc353bef97bcb32ea54e4317d3c87cbd7ae1443fcef2aefc46280dc09",
|
|
666
|
+
"detectors/delivery_evidence/detect.mjs": "e98664dee8090a0b280cd285a54e9a6fb9ba3572af2666b4e3656ca5b0555509",
|
|
667
|
+
"detectors/delivery_evidence/fixtures/clean/atdd-bun.yaml": "f701861e3530bb5a25a70d73e248549fb96642f48db1ff4d3e8e4546aaa825ee",
|
|
668
|
+
"detectors/delivery_evidence/fixtures/clean/delivery/api/evidence.yaml": "2cdbc4f628cf2d56627e6692b1f4e1a9b72316a3b7d09b47fffcd54c696a0fcb",
|
|
669
|
+
"detectors/delivery_evidence/fixtures/dirty/atdd-bun.yaml": "85c572d65f27b11b7ff8f115883913b2d2f1978097c416d3341b9c9d0de373d4",
|
|
670
|
+
"detectors/delivery_evidence/fixtures/dirty/delivery/api/evidence.yaml": "2b848f160a401a217f56d53d87ce8e0a0efc0ed6d3781f6cc746e384c93eb8cc",
|
|
671
|
+
"detectors/delivery_evidence/fixtures/dirty/delivery/data/evidence.yaml": "165dd67ff64f14c30268de5b18bf0c9c6634fb9ca48439c660c1962cebe3e0cb",
|
|
672
|
+
"detectors/delivery_evidence/fixtures/dirty/delivery/orphan/README.md": "7d480b1fff6546615e55d866784bc2267d06d0221dfde8d0ba0353fa1ea0db9a",
|
|
673
|
+
"detectors/delivery_evidence/fixtures/dirty/delivery/ui/evidence.yaml": "777b4f7921e302dfce79cd764bba8b44091ac9c7ee04a00f5dbb663342ec68a0",
|
|
657
674
|
"detectors/htmx_e2e_detector/atdd.implementation.yaml": "454bb123039d57c992d27d9274e20fa3452ac41a237eb55471be62a4bcfebf06",
|
|
658
675
|
"detectors/htmx_e2e_detector/checks/_e2e.mjs": "4e3605500ac232603083790c3984de5c828028c60eef366b26aba18d38fce30b",
|
|
659
676
|
"detectors/htmx_e2e_detector/checks/_map.json": "94dec08ff4764cd6a3dba139f12a7c984292e95a9354b0cdaa0ce9d4180e2c89",
|
|
@@ -1155,6 +1172,8 @@
|
|
|
1155
1172
|
"planner-schemas/binding-lock.schema.json": "f2455606702f45fafa194549126d4a66e6c286ba1c4ba9e6bdcf932286a6d34d",
|
|
1156
1173
|
"planner-schemas/component.schema.json": "d20d3502c155627a120cb10d5e9bdec4ba2c73af9c3e9a9d10e3c351f167c72a",
|
|
1157
1174
|
"planner-schemas/contract-registry.schema.json": "b9dbaf6c87d4f4d676e3b4251344b9eada523b1c5e739c0423cabe267012c12e",
|
|
1175
|
+
"planner-schemas/delivery-config.schema.json": "34e46c305b85340844086e60b2f5cbc1105ecc03ca63e5f9e494eff62353d30d",
|
|
1176
|
+
"planner-schemas/delivery-evidence.schema.json": "9b084eb73752d5637ba1d429f3709f8795cc2860c21c0b9bd58751b9887b001c",
|
|
1158
1177
|
"planner-schemas/feature.schema.json": "eb4aa40d89067ae5c86a079bb3d8e4f45c8727f9e15db2b86c08dacf8e4ae56a",
|
|
1159
1178
|
"planner-schemas/journey.schema.json": "1ff705bcf89a2823cf60c9e1597e254f97844e7a74dc58299d53192ad2c9f8c3",
|
|
1160
1179
|
"planner-schemas/registry-index.schema.json": "ffd5643da662ced4052707eeb270eb02908f2e48365103ff0638ec7ba146f430",
|
|
@@ -1167,28 +1186,31 @@
|
|
|
1167
1186
|
"planner-schemas/train.schema.json": "d6fbac9067c1bffeb84eb79a71228441055af6e6e7ba141dd4e0bcb079345ec0",
|
|
1168
1187
|
"planner-schemas/wagon.schema.json": "57b98f1ade998d745538eb3d72fb3014a50042006870f90bce47028eea336eb4",
|
|
1169
1188
|
"planner-schemas/wmbt.schema.json": "7a3a5693bfcf01340667c2be4a3c48e74f34b1af7e8dc13372c0de06b7f4fe12",
|
|
1170
|
-
"relationships.yaml": "
|
|
1171
|
-
"src/agent.ts": "
|
|
1172
|
-
"src/ci.ts": "
|
|
1189
|
+
"relationships.yaml": "a996da48da310c2fb2503e75470cdec77c850387b7e441b011acff56550b695b",
|
|
1190
|
+
"src/agent.ts": "b2015873940ca83bb8fdc683dbb85c2d53fe6f8c3e2b6b0b71bda895f0c1eb2f",
|
|
1191
|
+
"src/ci.ts": "67e54d2cbfc44a9e42837d5e750af526d6255c539d3c452a4d5fca3226c0d9ac",
|
|
1173
1192
|
"src/cli.ts": "bb2047cee60f48bfe3eaee4c1b3dcd3538a0e1edc170cf58e87686117bea07a7",
|
|
1193
|
+
"src/delivery.ts": "7962144972ae1f853a25cd88cf0cb7d4bca247b1193cd5eb33acc1ef272072cb",
|
|
1174
1194
|
"src/docs-capability.ts": "0feae94b7697dd53d8a457b24765e81fcf804c774f0cc4b6035cb3da822e486a",
|
|
1175
|
-
"src/enforce.ts": "
|
|
1195
|
+
"src/enforce.ts": "58ad0593895912bdc1effe97430b07acf8cda066052397957558cbb331c16778",
|
|
1176
1196
|
"src/hooks.ts": "adbb72f7a83f53d596fd217f01f4ce32c5a59a23ab81993fed226fb96fd1cbd1",
|
|
1177
|
-
"src/index.ts": "
|
|
1178
|
-
"src/integrity.ts": "
|
|
1197
|
+
"src/index.ts": "8ee4d7716794f6990ae8580e471b98256a0d0223dad063cd3b4542e598b6e744",
|
|
1198
|
+
"src/integrity.ts": "7cbb1ad4991079a4852d2d131c0769f66e13dc8b5fa0e637780a1b70a75eaf78",
|
|
1179
1199
|
"src/journey-docs.ts": "994d229376244c84212cff951032823068a76565dd2fd427b9d44e341bd14853",
|
|
1180
1200
|
"src/planner-kernel.ts": "5d3f5305fb59becb2cc97d8a03aca6b104f385805d91cc0410856e289dd6fbb1",
|
|
1181
1201
|
"src/planner-schema-validator.ts": "ce529c0936171075e93c7539b3655fe895a98dd2973ebda5775958e6ebc316d9",
|
|
1182
1202
|
"src/planner-validators.ts": "99adeb65f579af923c11f21a8f55cfb9993b007fd8df59c5f764696b55379cfc",
|
|
1183
1203
|
"src/register.ts": "6a2f1c6b8df0dc9c8f45df8ec9fac2be29044e048b08c8ffe423410e94dadedd",
|
|
1184
1204
|
"src/release.ts": "7b0fe444ee81f476f53b9c21b6c347ef588ee616c60211419cf984132be768ba",
|
|
1185
|
-
"src/setup.ts": "
|
|
1205
|
+
"src/setup.ts": "04fe6dc4618c14b93580f36d9775b7deca2082b8cc4efab7668795053b7d8dd0",
|
|
1186
1206
|
"src/telemetry-plan.ts": "cdb1e8bfff414f3ea81977388973da2cf6d89567d9e060dc9d5989a33600f153",
|
|
1187
1207
|
"src/topology.ts": "9779ee48e1c453abb76363163d4ab363463fa14e359571139f6d1f1fcc51ae2c",
|
|
1188
|
-
"templates/agents/AGENTS.block.md": "
|
|
1208
|
+
"templates/agents/AGENTS.block.md": "7e9687b1eff245b66da4127b336a9e20af2f5fa273e08895188c0a0dffebd77d",
|
|
1189
1209
|
"templates/agents/atdd-bun.integrity.test.ts": "dec6f6e5f65a08d9512fc703b367c163f8c9da1f6aa7fd466835c1ec30348a41",
|
|
1190
1210
|
"templates/agents/atdd/SKILL.md": "b621abe22851a75b30fc0e6c339a2c0a3ed6bbf78b8c17000a4ce301e05df96d",
|
|
1211
|
+
"templates/agents/delivery/SKILL.md": "72c279fba45c867d0a5b5e02f34dcba89efe06dfc9230c7aad501d2ae3629c35",
|
|
1212
|
+
"templates/agents/delivery/review.md": "289ee5d55ba0f321e5703a6fd8d5417d55bf0d9c6dc3103ea0f79af11c159d9c",
|
|
1191
1213
|
"templates/github/atdd-bun-release.yml": "d9547e9e6ef3ae010d53d55314f6a54567f88bd900f7e50d994cd308601d2684",
|
|
1192
|
-
"templates/github/atdd-bun.yml": "
|
|
1214
|
+
"templates/github/atdd-bun.yml": "bb42414f72f4b9a2fb1eb69530695e193f105a984542f4ca124c898a5f1489be"
|
|
1193
1215
|
}
|
|
1194
1216
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Delivery Profile Configuration",
|
|
4
|
+
"description": "The `delivery:` block of atdd-bun.yaml: which models may author and review each lifecycle stage, in preference order, how independent a reviewer must be, and when a model counts as unavailable. Every key is optional; an omitted key takes the package default (src/delivery.ts). `stages`, when given, replaces the default stage set: a stage it omits is not required.",
|
|
5
|
+
"$comment": "Shipped by the delivery profile (delivery_evidence). Cross-field checks (a reviewer listed twice, a stage override naming an unknown mode) are schema-level; loosening against the base branch is judged by the integrity check.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"root": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^[a-z0-9_][a-z0-9_.-]*(?:/[a-z0-9_][a-z0-9_.-]*)*$",
|
|
12
|
+
"description": "Repository-relative folder holding one <tranche>/evidence.yaml per tranche, in canonical form: no leading, trailing or doubled slash, no dot segments. Default: delivery. Changing it after adoption is a loosening the integrity check reports."
|
|
13
|
+
},
|
|
14
|
+
"require_record": {
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"description": "At the gate, a change outside the delivery root needs a tranche record in the same change. Default: true; turning it off is a loosening."
|
|
17
|
+
},
|
|
18
|
+
"multiplexer": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
21
|
+
"description": "The terminal multiplexer the coordinator drives agents through, named by its command. Default: herdr. Any other name is accepted; the agent learns its commands from the multiplexer's own help."
|
|
22
|
+
},
|
|
23
|
+
"independence": { "$ref": "#/definitions/independence" },
|
|
24
|
+
"stages": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"minProperties": 1,
|
|
28
|
+
"properties": {
|
|
29
|
+
"plan_review": { "$ref": "#/definitions/stage" },
|
|
30
|
+
"test_review": { "$ref": "#/definitions/stage" },
|
|
31
|
+
"code_review": { "$ref": "#/definitions/stage" },
|
|
32
|
+
"final_review": { "$ref": "#/definitions/stage" }
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"fallback": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"additionalProperties": false,
|
|
38
|
+
"properties": {
|
|
39
|
+
"after_failures": { "type": "integer", "minimum": 1, "description": "Failures (outage, rate limit, no auditable report) before a model counts as unavailable. A REQUEST CHANGES verdict is never a failure." },
|
|
40
|
+
"within_minutes": { "type": "integer", "minimum": 1 },
|
|
41
|
+
"when_exhausted": { "enum": ["block", "wait"], "description": "block: the tranche emits BLOCKED provider-unavailable and the coordinator reassigns the slot. wait: the driver keeps retrying the last model in the list." }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"commands": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"description": "Headless invocation per model, overriding the skill's built-in defaults. {prompt} and {worktree} are substituted by the driver. Adding or changing an entry after adoption is a loosening the integrity check reports; removing one returns to the default.",
|
|
47
|
+
"additionalProperties": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"properties": {
|
|
51
|
+
"author": { "type": "string", "minLength": 1 },
|
|
52
|
+
"review": { "type": "string", "minLength": 1 }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"definitions": {
|
|
58
|
+
"independence": {
|
|
59
|
+
"enum": ["fresh-process", "different-model"],
|
|
60
|
+
"description": "fresh-process: the reviewer is a new process that authored nothing in the tranche. different-model: additionally, the reviewer's model differs from the stage author's."
|
|
61
|
+
},
|
|
62
|
+
"models": {
|
|
63
|
+
"type": "array",
|
|
64
|
+
"minItems": 1,
|
|
65
|
+
"uniqueItems": true,
|
|
66
|
+
"items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
|
|
67
|
+
"description": "Models in preference order: the first is used normally, each later one only as a recorded fallback."
|
|
68
|
+
},
|
|
69
|
+
"stage": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"required": ["reviewers"],
|
|
73
|
+
"properties": {
|
|
74
|
+
"authors": { "$ref": "#/definitions/models" },
|
|
75
|
+
"reviewers": { "$ref": "#/definitions/models" },
|
|
76
|
+
"independence": { "$ref": "#/definitions/independence" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Delivery Evidence Schema",
|
|
4
|
+
"description": "Validates one <delivery root>/<tranche>/evidence.yaml: the record a tranche leaves of its reviews. Local shape only: stage completeness, allowed models and fallbacks, reviewer independence, finding outcomes and SHA resolution are cross-field validator concerns (src/delivery.ts).",
|
|
5
|
+
"$comment": "Shipped by the delivery profile (delivery_evidence). `reviews` is chronological: a repair loop appends a new entry for the same stage rather than editing the earlier one.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["tranche", "status", "reviews"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"tranche": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Must equal the tranche folder name." },
|
|
11
|
+
"status": { "enum": ["open", "ready"], "description": "open: the lifecycle is in progress. ready: every configured stage is approved and approved_sha is the commit to merge." },
|
|
12
|
+
"base_sha": { "$ref": "#/definitions/sha", "$comment": "Informational: the commit the tranche started from. Not checked; the gate derives its range from Git." },
|
|
13
|
+
"approved_sha": { "$ref": "#/definitions/sha" },
|
|
14
|
+
"pr": { "type": "string", "minLength": 1, "$comment": "Informational: the pull request URL. Not checked." },
|
|
15
|
+
"reviews": { "type": "array", "items": { "$ref": "#/definitions/review" } }
|
|
16
|
+
},
|
|
17
|
+
"if": { "required": ["status"], "properties": { "status": { "const": "ready" } } },
|
|
18
|
+
"then": { "required": ["approved_sha"] },
|
|
19
|
+
"definitions": {
|
|
20
|
+
"sha": { "type": "string", "pattern": "^[0-9a-f]{7,40}$" },
|
|
21
|
+
"actor": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"required": ["model", "run"],
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"properties": {
|
|
26
|
+
"model": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
|
|
27
|
+
"run": { "type": "string", "minLength": 1, "description": "Identifies the process: a session id, a pane id plus start time, or the report file. Two entries with the same run are the same process." }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"fallback": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"required": ["from", "kind", "failures", "window", "reason"],
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"properties": {
|
|
35
|
+
"role": { "enum": ["author", "reviewer"], "description": "Which actor fell back. Default: reviewer." },
|
|
36
|
+
"from": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
|
|
37
|
+
"kind": { "enum": ["outage", "rate_limit", "no_report", "timeout"], "description": "Why the model counts as unavailable. A verdict is never one of these." },
|
|
38
|
+
"failures": { "type": "integer", "minimum": 1, "description": "Failures observed before falling back; at least delivery.fallback.after_failures." },
|
|
39
|
+
"window": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"required": ["from", "to"],
|
|
42
|
+
"additionalProperties": false,
|
|
43
|
+
"description": "When the first and last counted failures happened; the span is at most delivery.fallback.within_minutes.",
|
|
44
|
+
"properties": { "from": { "type": "string", "format": "date-time" }, "to": { "type": "string", "format": "date-time" } }
|
|
45
|
+
},
|
|
46
|
+
"reason": { "type": "string", "minLength": 10, "description": "Why the preferred model was unavailable: outage, rate limit, or no auditable report. Never a verdict." }
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"finding": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"required": ["id", "severity", "evidence", "invariant", "proposed_fix"],
|
|
52
|
+
"additionalProperties": false,
|
|
53
|
+
"properties": {
|
|
54
|
+
"id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$", "description": "Stable across re-reviews, so an upheld finding keeps its id." },
|
|
55
|
+
"severity": { "enum": ["critical", "high", "medium", "low"] },
|
|
56
|
+
"evidence": { "type": "string", "minLength": 5, "description": "Concrete: file:line, a failing command, a counter-example." },
|
|
57
|
+
"invariant": { "type": "string", "minLength": 5 },
|
|
58
|
+
"affects": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
59
|
+
"proposed_fix": { "type": "string", "minLength": 5, "description": "A precise correction for the author to apply; the reviewer never applies it." },
|
|
60
|
+
"rebuttal": { "type": "string", "minLength": 20, "description": "The author's written dispute, with evidence. One round only." },
|
|
61
|
+
"outcome": { "enum": ["fixed", "withdrawn", "human"] },
|
|
62
|
+
"decision": { "type": "string", "minLength": 5, "description": "The human's ruling when outcome is human." }
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"review": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"required": ["stage", "sha", "reviewer", "verdict", "checked"],
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"properties": {
|
|
70
|
+
"stage": { "enum": ["plan_review", "test_review", "code_review", "final_review"] },
|
|
71
|
+
"sha": { "$ref": "#/definitions/sha" },
|
|
72
|
+
"author": { "$ref": "#/definitions/actor" },
|
|
73
|
+
"reviewer": { "$ref": "#/definitions/actor" },
|
|
74
|
+
"fallback": { "type": "array", "items": { "$ref": "#/definitions/fallback" } },
|
|
75
|
+
"verdict": { "enum": ["approve", "request_changes"] },
|
|
76
|
+
"checked": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 }, "description": "Everything the reviewer went through, not only what failed." },
|
|
77
|
+
"findings": { "type": "array", "items": { "$ref": "#/definitions/finding" } },
|
|
78
|
+
"report": { "type": "string", "minLength": 1, "description": "Path of the retained raw reviewer output, inside the tranche's folder." }
|
|
79
|
+
},
|
|
80
|
+
"if": { "required": ["verdict"], "properties": { "verdict": { "const": "request_changes" } } },
|
|
81
|
+
"then": { "required": ["findings"], "properties": { "findings": { "minItems": 1 } } }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
package/relationships.yaml
CHANGED
|
@@ -94,6 +94,14 @@ nodes:
|
|
|
94
94
|
- coder.htmx.verb-endpoint-is-routed
|
|
95
95
|
- coder.htmx.verb-endpoint-same-origin
|
|
96
96
|
- coder.htmx.verb-mutation-signals-progress
|
|
97
|
+
- delivery.approved-sha-resolves
|
|
98
|
+
- delivery.config-schema
|
|
99
|
+
- delivery.evidence-schema
|
|
100
|
+
- delivery.findings-resolved
|
|
101
|
+
- delivery.merge-gate
|
|
102
|
+
- delivery.model-allowed
|
|
103
|
+
- delivery.reviewer-independent
|
|
104
|
+
- delivery.stages-complete
|
|
97
105
|
- planner.acceptance.abstract-fields-required
|
|
98
106
|
- planner.acceptance.authoring-guidelines
|
|
99
107
|
- planner.acceptance.boundary-kind-vocabulary
|
|
@@ -5186,3 +5194,93 @@ edges:
|
|
|
5186
5194
|
target_ref: planner.telemetry.tracking-plan-schema
|
|
5187
5195
|
type: requires
|
|
5188
5196
|
origin: "@afokapu/atdd-bun"
|
|
5197
|
+
- confidence: 1
|
|
5198
|
+
constraint: mandatory
|
|
5199
|
+
control: internal
|
|
5200
|
+
foundation: finish_to_start
|
|
5201
|
+
reason: evidence is judged against the stages the policy configures
|
|
5202
|
+
source_ref: delivery.evidence-schema
|
|
5203
|
+
strength: important
|
|
5204
|
+
target_ref: delivery.config-schema
|
|
5205
|
+
type: requires
|
|
5206
|
+
origin: "@afokapu/atdd-bun"
|
|
5207
|
+
- confidence: 1
|
|
5208
|
+
constraint: mandatory
|
|
5209
|
+
control: internal
|
|
5210
|
+
foundation: finish_to_start
|
|
5211
|
+
reason: allowed models and their preference order come from the policy
|
|
5212
|
+
source_ref: delivery.model-allowed
|
|
5213
|
+
strength: important
|
|
5214
|
+
target_ref: delivery.config-schema
|
|
5215
|
+
type: requires
|
|
5216
|
+
origin: "@afokapu/atdd-bun"
|
|
5217
|
+
- confidence: 1
|
|
5218
|
+
constraint: mandatory
|
|
5219
|
+
control: internal
|
|
5220
|
+
foundation: finish_to_start
|
|
5221
|
+
reason: models are read from a well-formed review entry
|
|
5222
|
+
source_ref: delivery.model-allowed
|
|
5223
|
+
strength: important
|
|
5224
|
+
target_ref: delivery.evidence-schema
|
|
5225
|
+
type: requires
|
|
5226
|
+
origin: "@afokapu/atdd-bun"
|
|
5227
|
+
- confidence: 1
|
|
5228
|
+
constraint: mandatory
|
|
5229
|
+
control: internal
|
|
5230
|
+
foundation: finish_to_start
|
|
5231
|
+
reason: independence is judged over the author and reviewer runs the record names
|
|
5232
|
+
source_ref: delivery.reviewer-independent
|
|
5233
|
+
strength: important
|
|
5234
|
+
target_ref: delivery.evidence-schema
|
|
5235
|
+
type: requires
|
|
5236
|
+
origin: "@afokapu/atdd-bun"
|
|
5237
|
+
- confidence: 1
|
|
5238
|
+
constraint: mandatory
|
|
5239
|
+
control: internal
|
|
5240
|
+
foundation: finish_to_start
|
|
5241
|
+
reason: outcomes are read from well-formed findings
|
|
5242
|
+
source_ref: delivery.findings-resolved
|
|
5243
|
+
strength: important
|
|
5244
|
+
target_ref: delivery.evidence-schema
|
|
5245
|
+
type: requires
|
|
5246
|
+
origin: "@afokapu/atdd-bun"
|
|
5247
|
+
- confidence: 1
|
|
5248
|
+
constraint: mandatory
|
|
5249
|
+
control: internal
|
|
5250
|
+
foundation: finish_to_start
|
|
5251
|
+
reason: a stage is approved only once its earlier findings are settled
|
|
5252
|
+
source_ref: delivery.stages-complete
|
|
5253
|
+
strength: important
|
|
5254
|
+
target_ref: delivery.findings-resolved
|
|
5255
|
+
type: requires
|
|
5256
|
+
origin: "@afokapu/atdd-bun"
|
|
5257
|
+
- confidence: 1
|
|
5258
|
+
constraint: mandatory
|
|
5259
|
+
control: internal
|
|
5260
|
+
foundation: finish_to_start
|
|
5261
|
+
reason: the approved SHA is the one the closing review approved
|
|
5262
|
+
source_ref: delivery.approved-sha-resolves
|
|
5263
|
+
strength: important
|
|
5264
|
+
target_ref: delivery.stages-complete
|
|
5265
|
+
type: requires
|
|
5266
|
+
origin: "@afokapu/atdd-bun"
|
|
5267
|
+
- confidence: 1
|
|
5268
|
+
constraint: mandatory
|
|
5269
|
+
control: internal
|
|
5270
|
+
foundation: finish_to_start
|
|
5271
|
+
reason: the gate compares the branch head with an approved SHA that exists
|
|
5272
|
+
source_ref: delivery.merge-gate
|
|
5273
|
+
strength: important
|
|
5274
|
+
target_ref: delivery.approved-sha-resolves
|
|
5275
|
+
type: requires
|
|
5276
|
+
origin: "@afokapu/atdd-bun"
|
|
5277
|
+
- confidence: 1
|
|
5278
|
+
constraint: mandatory
|
|
5279
|
+
control: internal
|
|
5280
|
+
foundation: start_to_start
|
|
5281
|
+
reason: the gate merges a tranche whose lifecycle closed its acceptances
|
|
5282
|
+
source_ref: delivery.merge-gate
|
|
5283
|
+
strength: important
|
|
5284
|
+
target_ref: traceability.plan.executable-acceptance-has-test
|
|
5285
|
+
type: requires
|
|
5286
|
+
origin: "@afokapu/atdd-bun"
|
package/src/agent.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { deliveryAdopted } from "./delivery";
|
|
4
5
|
|
|
5
6
|
const root = resolve(import.meta.dir, "..");
|
|
6
7
|
const version = (await Bun.file(join(root, "package.json")).json() as { version: string }).version;
|
|
7
8
|
const render = async (path: string) => (await readFile(join(root, "templates/agents", path), "utf8")).replace("{{VERSION}}", version);
|
|
8
9
|
// .agents/skills is the vendor-neutral Agent Skills path (Codex, Copilot, Cursor, Gemini CLI, …); .claude/skills is Claude Code's.
|
|
9
10
|
const skillPaths = [".agents/skills/atdd/SKILL.md", ".claude/skills/atdd/SKILL.md"];
|
|
11
|
+
/** The delivery skill and its review contract, installed only where the delivery profile is adopted: generated path → template. */
|
|
12
|
+
export const deliverySkillFiles = [".agents/skills", ".claude/skills"].flatMap(base => ["SKILL.md", "review.md"].map(name => [`${base}/delivery/${name}`, `delivery/${name}`] as const));
|
|
13
|
+
/** Whether the repository's atdd-bun.yaml adopts the delivery profile. */
|
|
14
|
+
export async function deliveryInstalled(repo: string): Promise<boolean> {
|
|
15
|
+
const file = join(repo, "atdd-bun.yaml");
|
|
16
|
+
try { return existsSync(file) && deliveryAdopted(Bun.YAML.parse(await readFile(file, "utf8"))); } catch { return false; }
|
|
17
|
+
}
|
|
10
18
|
// AGENTS.md is read by Codex, Cursor and most agents; CLAUDE.md by Claude Code. Both carry the same block.
|
|
11
19
|
export const instructionPaths = ["AGENTS.md", "CLAUDE.md"];
|
|
12
20
|
const block = /<!-- atdd-bun:start[\s\S]*?<!-- atdd-bun:end -->\n?/;
|
|
@@ -22,6 +30,11 @@ export async function agentInit(repo = process.cwd(), replace = false) {
|
|
|
22
30
|
if (existsSync(output) && !replace) { kept.push(output); continue; }
|
|
23
31
|
await mkdir(dirname(output), { recursive: true }); await writeFile(output, await render("atdd/SKILL.md")); written.push(output);
|
|
24
32
|
}
|
|
33
|
+
if (await deliveryInstalled(repo)) for (const [path, template] of deliverySkillFiles) {
|
|
34
|
+
const output = join(repo, path);
|
|
35
|
+
if (existsSync(output) && !replace) { kept.push(output); continue; }
|
|
36
|
+
await mkdir(dirname(output), { recursive: true }); await writeFile(output, await render(template)); written.push(output);
|
|
37
|
+
}
|
|
25
38
|
const managed = await render("AGENTS.block.md");
|
|
26
39
|
for (const path of instructionPaths) {
|
|
27
40
|
const file = join(repo, path), current = existsSync(file) ? await readFile(file, "utf8") : "";
|
|
@@ -32,7 +45,8 @@ export async function agentInit(repo = process.cwd(), replace = false) {
|
|
|
32
45
|
return { ok: true, message: written.join("\n") };
|
|
33
46
|
}
|
|
34
47
|
export async function agentStatus(repo = process.cwd()) {
|
|
35
|
-
const
|
|
48
|
+
const expected = [...skillPaths, ...(await deliveryInstalled(repo) ? deliverySkillFiles.map(([path]) => path) : [])];
|
|
49
|
+
const missing = expected.map(path => join(repo, path)).filter(path => !existsSync(path));
|
|
36
50
|
for (const path of instructionPaths) { const agents = join(repo, path); if (!existsSync(agents) || !block.test(await readFile(agents, "utf8"))) missing.push(`${agents} (atdd-bun block)`); }
|
|
37
|
-
return { ok: !missing.length, message: missing.length ? `missing: ${missing.join(", ")}` : [...
|
|
51
|
+
return { ok: !missing.length, message: missing.length ? `missing: ${missing.join(", ")}` : [...expected, ...instructionPaths].map(path => join(repo, path)).join("\n") };
|
|
38
52
|
}
|
package/src/ci.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
+
import { policy } from "./hooks";
|
|
4
5
|
|
|
5
6
|
const root = resolve(import.meta.dir, "..");
|
|
6
7
|
const template = join(root, "templates/github/atdd-bun.yml");
|
|
7
8
|
const version = (await Bun.file(join(root, "package.json")).json() as { version: string }).version;
|
|
8
|
-
|
|
9
|
+
/** The workflow for this repository: pushes to its protected branches run the post-merge checks, so a repository
|
|
10
|
+
* whose base branch is not main or master is covered too. The integrity check compares against this same rendering.
|
|
11
|
+
* Each branch is written as a JSON string, a YAML scalar a branch name can never break out of. */
|
|
12
|
+
export async function renderWorkflow(repo = process.cwd()) {
|
|
13
|
+
return (await readFile(template, "utf8")).replace("{{VERSION}}", version).replace("{{PROTECTED_BRANCHES}}", (await policy(repo)).protected_branches.map(branch => JSON.stringify(branch)).join(", "));
|
|
14
|
+
}
|
|
15
|
+
export async function ciInit(repo = process.cwd(), replace = false) { const output = join(repo, ".github/workflows/atdd-bun.yml"); if (existsSync(output) && !replace) return { ok: false, message: `${output} exists; use --replace` }; let rendered: string; try { rendered = await renderWorkflow(repo); } catch (error) { return { ok: false, message: `atdd-bun.yaml could not be parsed, so the workflow's push branches are unknown; fix the file first: ${String(error)}` }; } await mkdir(join(repo, ".github/workflows"), { recursive: true }); await writeFile(output, rendered); return { ok: true, message: output }; }
|
|
9
16
|
export async function ciStatus(repo = process.cwd()) { const output = join(repo, ".github/workflows/atdd-bun.yml"); return { ok: existsSync(output), message: output }; }
|