@dzhechkov/harness-core 0.5.1 → 0.5.3
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/.dz-manifest.json +68 -28
- package/README.md +8 -2
- package/dist/feature-adr-checkpoints.d.ts +93 -1
- package/dist/feature-adr-checkpoints.d.ts.map +1 -1
- package/dist/feature-adr-checkpoints.js +105 -1
- package/dist/feature-adr-checkpoints.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/loop-blobs.generated.js +5 -5
- package/dist/loop-blobs.generated.js.map +1 -1
- package/dist/loop-render.js +1 -1
- package/dist/loop-render.js.map +1 -1
- package/dist/loop-trace.d.ts +75 -3
- package/dist/loop-trace.d.ts.map +1 -1
- package/dist/loop-trace.js +62 -6
- package/dist/loop-trace.js.map +1 -1
- package/dist/trace-corroborate.d.ts +48 -0
- package/dist/trace-corroborate.d.ts.map +1 -0
- package/dist/trace-corroborate.js +172 -0
- package/dist/trace-corroborate.js.map +1 -0
- package/dist/workflow-run.d.ts +15 -0
- package/dist/workflow-run.d.ts.map +1 -1
- package/dist/workflow-run.js +19 -1
- package/dist/workflow-run.js.map +1 -1
- package/package.json +18 -18
- package/sbom.json +127 -27
- package/src/feature-adr-checkpoints.ts +140 -1
- package/src/index.ts +1 -0
- package/src/loop-blobs.generated.ts +5 -5
- package/src/loop-render.ts +1 -1
- package/src/loop-trace.ts +123 -6
- package/src/trace-corroborate.ts +205 -0
- package/src/workflow-run.ts +31 -1
- package/LICENSE +0 -21
package/.dz-manifest.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
7
|
"path": "CHANGELOG.md",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "1790811c8031105b1f281ecaff8a2e5b66a33ac9a323cbe63fb0caae67835b0d"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "README.md",
|
|
@@ -609,19 +609,19 @@
|
|
|
609
609
|
},
|
|
610
610
|
{
|
|
611
611
|
"path": "dist/index.d.ts",
|
|
612
|
-
"sha256": "
|
|
612
|
+
"sha256": "837b65bceef392d58a8b85257443e796c8da7219e2c7d5749df952ff4ba9a7d9"
|
|
613
613
|
},
|
|
614
614
|
{
|
|
615
615
|
"path": "dist/index.d.ts.map",
|
|
616
|
-
"sha256": "
|
|
616
|
+
"sha256": "2c88a22a96119c8ed14d67c1830bd85857e0c43f8a730951c1279ec9442decd6"
|
|
617
617
|
},
|
|
618
618
|
{
|
|
619
619
|
"path": "dist/index.js",
|
|
620
|
-
"sha256": "
|
|
620
|
+
"sha256": "5c208320312a34f0e4d09b2cea3d50a057253771a67b60a0ee0d0907a382546c"
|
|
621
621
|
},
|
|
622
622
|
{
|
|
623
623
|
"path": "dist/index.js.map",
|
|
624
|
-
"sha256": "
|
|
624
|
+
"sha256": "262dd0fca9a734cc81ba33c215adb9ef88b343ee56091c017abda45c68bc2508"
|
|
625
625
|
},
|
|
626
626
|
{
|
|
627
627
|
"path": "dist/learning-backend.d.ts",
|
|
@@ -649,11 +649,11 @@
|
|
|
649
649
|
},
|
|
650
650
|
{
|
|
651
651
|
"path": "dist/loop-blobs.generated.js",
|
|
652
|
-
"sha256": "
|
|
652
|
+
"sha256": "115740b3c04b6e906e135eb9d1e462ae4197cdba558d4eb620e29e541b4de288"
|
|
653
653
|
},
|
|
654
654
|
{
|
|
655
655
|
"path": "dist/loop-blobs.generated.js.map",
|
|
656
|
-
"sha256": "
|
|
656
|
+
"sha256": "2cbadd2514704ccf6cfbf7e44fc50cad3d3701bc91b98651015896ebe209449a"
|
|
657
657
|
},
|
|
658
658
|
{
|
|
659
659
|
"path": "dist/loop-lint.d.ts",
|
|
@@ -713,11 +713,11 @@
|
|
|
713
713
|
},
|
|
714
714
|
{
|
|
715
715
|
"path": "dist/loop-render.js",
|
|
716
|
-
"sha256": "
|
|
716
|
+
"sha256": "49b8fc106dee22095dc02c43e224de52b9026dbf77d2f2e2654219a776017a09"
|
|
717
717
|
},
|
|
718
718
|
{
|
|
719
719
|
"path": "dist/loop-render.js.map",
|
|
720
|
-
"sha256": "
|
|
720
|
+
"sha256": "170a7cdafb569ce8d9d1bd7c63ab83d4689cd3b1ed8a1f02536f5affd9dd6d5f"
|
|
721
721
|
},
|
|
722
722
|
{
|
|
723
723
|
"path": "dist/loop-run-semantics.d.ts",
|
|
@@ -737,19 +737,19 @@
|
|
|
737
737
|
},
|
|
738
738
|
{
|
|
739
739
|
"path": "dist/loop-trace.d.ts",
|
|
740
|
-
"sha256": "
|
|
740
|
+
"sha256": "bd228e00e217a99ee7f192c9e87d4e1c794c8ffb52323b77b87ee93f601f013a"
|
|
741
741
|
},
|
|
742
742
|
{
|
|
743
743
|
"path": "dist/loop-trace.d.ts.map",
|
|
744
|
-
"sha256": "
|
|
744
|
+
"sha256": "4c37b21c750133def0498c6d1b0fddfb2525500ced4dc58634ae1234425337d3"
|
|
745
745
|
},
|
|
746
746
|
{
|
|
747
747
|
"path": "dist/loop-trace.js",
|
|
748
|
-
"sha256": "
|
|
748
|
+
"sha256": "83f2afea542e80bf09f9ccf9a56a9d352111a8a3cd7744bf8f2ccad84d796c6a"
|
|
749
749
|
},
|
|
750
750
|
{
|
|
751
751
|
"path": "dist/loop-trace.js.map",
|
|
752
|
-
"sha256": "
|
|
752
|
+
"sha256": "93a3007d6a7a906344f8f85272aef1928811997d331202171558763ab917b9d6"
|
|
753
753
|
},
|
|
754
754
|
{
|
|
755
755
|
"path": "dist/managed-hooks.d.ts",
|
|
@@ -1439,6 +1439,22 @@
|
|
|
1439
1439
|
"path": "dist/trace-bundle.js.map",
|
|
1440
1440
|
"sha256": "9aafc5fe1b5f3bc878b063b94c7d3a89e4459f999c357252928d7b5498a8a5f7"
|
|
1441
1441
|
},
|
|
1442
|
+
{
|
|
1443
|
+
"path": "dist/trace-corroborate.d.ts",
|
|
1444
|
+
"sha256": "ebc36a47e4f8359eb7359a1e1697e9a135b2a281ecb1f795e99da7f9476f7f4c"
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
"path": "dist/trace-corroborate.d.ts.map",
|
|
1448
|
+
"sha256": "7a2f343525b6585d0cd54644282bc49b741baffd066ebff0f023c036b622e6f8"
|
|
1449
|
+
},
|
|
1450
|
+
{
|
|
1451
|
+
"path": "dist/trace-corroborate.js",
|
|
1452
|
+
"sha256": "1b78df722776f6e253e3d0babb90c8557b5d733528125c793b7519ec724db96b"
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
"path": "dist/trace-corroborate.js.map",
|
|
1456
|
+
"sha256": "7c95e98228f86fda4f4503b04efaf149466f9bd78fbb549a8aad49c8a4f3b7ab"
|
|
1457
|
+
},
|
|
1442
1458
|
{
|
|
1443
1459
|
"path": "dist/upgrade.d.ts",
|
|
1444
1460
|
"sha256": "b256da4de28359110f1ff791d6e6ed1e91339c1cd32d6e222048066b1ee9e0d3"
|
|
@@ -1505,19 +1521,19 @@
|
|
|
1505
1521
|
},
|
|
1506
1522
|
{
|
|
1507
1523
|
"path": "dist/workflow-run.d.ts",
|
|
1508
|
-
"sha256": "
|
|
1524
|
+
"sha256": "94d154db3feb9676e515fc04129ac299f967ff46b8a7daedc51ec201f7eb5259"
|
|
1509
1525
|
},
|
|
1510
1526
|
{
|
|
1511
1527
|
"path": "dist/workflow-run.d.ts.map",
|
|
1512
|
-
"sha256": "
|
|
1528
|
+
"sha256": "0bda62d918a427203c946a0d6ec9fdb67a2223573939bc358fa9d48545e34361"
|
|
1513
1529
|
},
|
|
1514
1530
|
{
|
|
1515
1531
|
"path": "dist/workflow-run.js",
|
|
1516
|
-
"sha256": "
|
|
1532
|
+
"sha256": "c5d24bc9e5a8731ecd9e83e0fc3c3bac02421b76028906b20d2a113f04efbe59"
|
|
1517
1533
|
},
|
|
1518
1534
|
{
|
|
1519
1535
|
"path": "dist/workflow-run.js.map",
|
|
1520
|
-
"sha256": "
|
|
1536
|
+
"sha256": "f9a9a320dde4bae0d6f6b0b2e7c03c08127e452f7fa7e00d78ea9f9b816bc6e7"
|
|
1521
1537
|
},
|
|
1522
1538
|
{
|
|
1523
1539
|
"path": "dist/workflows.d.ts",
|
|
@@ -1537,7 +1553,7 @@
|
|
|
1537
1553
|
},
|
|
1538
1554
|
{
|
|
1539
1555
|
"path": "package.json",
|
|
1540
|
-
"sha256": "
|
|
1556
|
+
"sha256": "f44d3dd18b5332681d861707c5644b1cbb027b217b9fda07a0b8510b6346d1a8"
|
|
1541
1557
|
},
|
|
1542
1558
|
{
|
|
1543
1559
|
"path": "src/__tests__/golden-baseline.test.ts",
|
|
@@ -1689,7 +1705,7 @@
|
|
|
1689
1705
|
},
|
|
1690
1706
|
{
|
|
1691
1707
|
"path": "src/index.ts",
|
|
1692
|
-
"sha256": "
|
|
1708
|
+
"sha256": "b741c4477d04f5fdb88f88601b8528f56e9b1fdc6a849dece4af157a81c0fe57"
|
|
1693
1709
|
},
|
|
1694
1710
|
{
|
|
1695
1711
|
"path": "src/learning-backend.ts",
|
|
@@ -1697,7 +1713,7 @@
|
|
|
1697
1713
|
},
|
|
1698
1714
|
{
|
|
1699
1715
|
"path": "src/loop-blobs.generated.ts",
|
|
1700
|
-
"sha256": "
|
|
1716
|
+
"sha256": "929be36a3c9fd2cf3ba6e6b7328dd8d7928d9c031c38bb62880ba234c9553334"
|
|
1701
1717
|
},
|
|
1702
1718
|
{
|
|
1703
1719
|
"path": "src/loop-lint.ts",
|
|
@@ -1713,7 +1729,7 @@
|
|
|
1713
1729
|
},
|
|
1714
1730
|
{
|
|
1715
1731
|
"path": "src/loop-render.ts",
|
|
1716
|
-
"sha256": "
|
|
1732
|
+
"sha256": "69d0daac70fda89235352be2cc2e40bcfe62651aedab8056c1919ed062d4a75b"
|
|
1717
1733
|
},
|
|
1718
1734
|
{
|
|
1719
1735
|
"path": "src/loop-run-semantics.ts",
|
|
@@ -1721,7 +1737,7 @@
|
|
|
1721
1737
|
},
|
|
1722
1738
|
{
|
|
1723
1739
|
"path": "src/loop-trace.ts",
|
|
1724
|
-
"sha256": "
|
|
1740
|
+
"sha256": "ea7d5b64c7805fd4622e7a892e0e3f1f03e4fdbb883f5fe377fcd64330775330"
|
|
1725
1741
|
},
|
|
1726
1742
|
{
|
|
1727
1743
|
"path": "src/managed-hooks.ts",
|
|
@@ -1891,6 +1907,10 @@
|
|
|
1891
1907
|
"path": "src/trace-bundle.ts",
|
|
1892
1908
|
"sha256": "fec8d04a083f96f21d65a0dc1f131cb3cca6101c05f2cadcf540027c2a2a8774"
|
|
1893
1909
|
},
|
|
1910
|
+
{
|
|
1911
|
+
"path": "src/trace-corroborate.ts",
|
|
1912
|
+
"sha256": "28a872378dce68940237a99e8ffe57d3da049cccb0ffc315fbddf8ba65e80ee8"
|
|
1913
|
+
},
|
|
1894
1914
|
{
|
|
1895
1915
|
"path": "src/upgrade.ts",
|
|
1896
1916
|
"sha256": "8cc9e9e222149f711183980bfad317713aad0ecfa9fcff923dd3c93865b6966b"
|
|
@@ -1909,7 +1929,7 @@
|
|
|
1909
1929
|
},
|
|
1910
1930
|
{
|
|
1911
1931
|
"path": "src/workflow-run.ts",
|
|
1912
|
-
"sha256": "
|
|
1932
|
+
"sha256": "f1aaf39fcb5088afe3c63185c05a0d22f0507d29c342e3024836f46e3996d430"
|
|
1913
1933
|
},
|
|
1914
1934
|
{
|
|
1915
1935
|
"path": "src/workflows.ts",
|
|
@@ -2135,6 +2155,14 @@
|
|
|
2135
2155
|
"path": "test/feature-adr-workflow-twin-drift.test.ts",
|
|
2136
2156
|
"sha256": "2b43ee26290b1617fc8b4a5ae81d7958dac0761041e63cd4d544383db628fa80"
|
|
2137
2157
|
},
|
|
2158
|
+
{
|
|
2159
|
+
"path": "test/feature-adr-workflow-write-discipline.test.ts",
|
|
2160
|
+
"sha256": "f491c12d9bb0a361095e9ec7cab216b60ea51f1c839256b8b4476bf0f8d5f4ca"
|
|
2161
|
+
},
|
|
2162
|
+
{
|
|
2163
|
+
"path": "test/feature-adr-write-discipline.test.ts",
|
|
2164
|
+
"sha256": "e44795d46da74d4f21bf6817d3884f1428f8adfd814c5174490c9c372299932e"
|
|
2165
|
+
},
|
|
2138
2166
|
{
|
|
2139
2167
|
"path": "test/files-whitelist-guard.test.ts",
|
|
2140
2168
|
"sha256": "c6dbf3388dfb1129e5954aeca3ccf3c6a7fccfe33e4530efe76b8d364e11f906"
|
|
@@ -2173,11 +2201,11 @@
|
|
|
2173
2201
|
},
|
|
2174
2202
|
{
|
|
2175
2203
|
"path": "test/fixtures/workflow-run/discrimination.capture-obligation.json",
|
|
2176
|
-
"sha256": "
|
|
2204
|
+
"sha256": "f20a7850a3313d5bb2431d81e8717694f2edf4cda5c67133c0b80d7549e2cbab"
|
|
2177
2205
|
},
|
|
2178
2206
|
{
|
|
2179
2207
|
"path": "test/fixtures/workflow-run/discrimination.loop.js",
|
|
2180
|
-
"sha256": "
|
|
2208
|
+
"sha256": "2bc8d4bd9c2bf15a3522d00b01a18611ef973f4b9e71ef5c1894ea72628294a8"
|
|
2181
2209
|
},
|
|
2182
2210
|
{
|
|
2183
2211
|
"path": "test/fixtures/workflow-run/discrimination.loop.plan.json",
|
|
@@ -2261,7 +2289,7 @@
|
|
|
2261
2289
|
},
|
|
2262
2290
|
{
|
|
2263
2291
|
"path": "test/helpers/workflow-run-harness.ts",
|
|
2264
|
-
"sha256": "
|
|
2292
|
+
"sha256": "95d04dbdb46e7f1fac3f6cfd5ec7705579a436ea7118823e11cb752da7f9adea"
|
|
2265
2293
|
},
|
|
2266
2294
|
{
|
|
2267
2295
|
"path": "test/import-upsert.test.ts",
|
|
@@ -2341,7 +2369,7 @@
|
|
|
2341
2369
|
},
|
|
2342
2370
|
{
|
|
2343
2371
|
"path": "test/mutation-registry.json",
|
|
2344
|
-
"sha256": "
|
|
2372
|
+
"sha256": "e9ccae5e13df6370a8564326e5766aa1e03973c595bfdf73765d54191acf98c4"
|
|
2345
2373
|
},
|
|
2346
2374
|
{
|
|
2347
2375
|
"path": "test/named-lock.test.ts",
|
|
@@ -2483,10 +2511,22 @@
|
|
|
2483
2511
|
"path": "test/target-resolution.test.ts",
|
|
2484
2512
|
"sha256": "146881c6848a59663fbbd070631af0f3c93f5bfa668958144bac70e2d5c7f7d0"
|
|
2485
2513
|
},
|
|
2514
|
+
{
|
|
2515
|
+
"path": "test/trace-attestation.test.ts",
|
|
2516
|
+
"sha256": "f4888117c97180797e6437abc1ef0c6aa1f1e48ee7c2df33d60a65e8bf11b35c"
|
|
2517
|
+
},
|
|
2486
2518
|
{
|
|
2487
2519
|
"path": "test/trace-bundle.test.ts",
|
|
2488
2520
|
"sha256": "66e784bd3f1344350e55b0003f5558f6cea388481fd339515b49c4c761de0af7"
|
|
2489
2521
|
},
|
|
2522
|
+
{
|
|
2523
|
+
"path": "test/trace-corroborate.test.ts",
|
|
2524
|
+
"sha256": "9e845bb448c1300966e76a030b2b0d88c3aa3cf666d85b58ddd981e15d4dcd85"
|
|
2525
|
+
},
|
|
2526
|
+
{
|
|
2527
|
+
"path": "test/trace-qe-round1.test.ts",
|
|
2528
|
+
"sha256": "7790c41628d7223a45aa61977511d1ddd6cd2cd8dc2dfdcdd248bb25c2effeca"
|
|
2529
|
+
},
|
|
2490
2530
|
{
|
|
2491
2531
|
"path": "test/trusttier-schema.test.ts",
|
|
2492
2532
|
"sha256": "430a5bb7ee5e1caf671db98e1b1833c64fb9b2b5cb4eefb5acc3675bb3529aee"
|
|
@@ -2581,5 +2621,5 @@
|
|
|
2581
2621
|
}
|
|
2582
2622
|
]
|
|
2583
2623
|
},
|
|
2584
|
-
"signature": "
|
|
2624
|
+
"signature": "R3nVNMcmCTbA+LwIEgj7iHl0wRbP6sUhatIOb7LHm+vjOfMu8U1PnEpVr0k3dGIjiKdtr7Z5Io11Om9iknZPDw=="
|
|
2585
2625
|
}
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ and any other consumer.
|
|
|
20
20
|
| `cost-ledger` | `deriveCostLedger`, `buildCostLedger`, `verifyCostLedgerReport`, `stageCostAggregates`, `renderCostLedger`, `writeCostLedgerJsonl`, `COST_LEDGER_SCOPE` | Per-stage cost ledger behind `dz usage --by-stage`. A feature-adr run reports ONE number; this joins the workflow's own `stageLabel()` strings to the per-agent transcripts the harness already writes, so a run becomes an itemized receipt. POST-HOC DERIVER, not a writer — no workflow edit, and a KILLED run is still derivable. The invariant: `accounted + unaccounted === runTotal` and `accounted + doubleAttributed === Σ stages`, RAW integer equality (rounding happens exactly once, per sample, at extraction), re-derived from the emitted report by `verifyCostLedgerReport` — the writer clamps, the verifier enforces. A mismatch is a NAMED defect (`Unaccounted`, `DoubleAttributed`, `ForeignSample`, `MissingStageTranscript`, `MalformedRecord`), never a rounding remainder, so `epsilon` defaults to 0. The run total comes from the run's transcript DIRECTORY LISTING, NOT the record's own `totalTokens` — that field is exactly `Σ workflowProgress[].tokens` in 29 of 29 recorded runs (MEASURED), so an invariant against it can never fail. Both sides share ONE estimator with `dz usage` (`weightedTokensOf`). `stageCostAggregates` is a pure feed-forward reader for auto-cost routing that EXCLUDES non-reconciling runs; wiring it into routing is deliberately out of scope. HONEST SCOPE, printed by every surface: local transcript ESTIMATES, not billed amounts — it catches ATTRIBUTION errors, NOT pricing errors; `hasKnownPricing` marks rows priced by the sonnet-class fallback. `INSUFFICIENT_DATA` is a distinct verdict, never collapsed into `BALANCED` |
|
|
21
21
|
| `compounding` | `mulberry32`, `bootstrapDelta`, `decidePromotion`, `assembleCompoundingReport` | Pure learning-loop payoff engine behind `dz compounding`: seeded deterministic bootstrap (conservative nearest-rank lower-95), promotion that refuses non-finite/malformed input and anything under 5 samples per arm, and dz-native measurements (pool write-only ratio, guard trajectory by RATE, replay readiness over unique untruncated prompt events). A gate without data says INSUFFICIENT_DATA — never a verdict. Compaction keeps the newest query-bearing rows verbatim and aggregates ONLY the rest (read totals are invariant across compactions). Also reports EVENT-CHAIN health of the evidence logs it computed from (`evidenceLogs` in, `instrumentation.chains` out) — verified / defect kinds / uncovered pre-chain prefix, with no logs handed in producing no line at all rather than a vacuous "clean" |
|
|
22
22
|
| `event-chain` | `fnv1a32`, `nextChainFields`, `appendChainedLines`, `chainRewrite`, `guardedRewrite`, `verifyEventChain`, `EVENT_CHAIN_SCOPE` | Pure hash-chain over the two learning-evidence logs (`.dz/recall-usage.jsonl`, `.dz/guard-audit.jsonl`): each appended record carries `seq` + `prevHash` (FNV-1a over the previous line AS WRITTEN, so key order cannot make writer and verifier disagree), derived from the LAST LINE ONLY so a per-prompt hook stays O(1). `verifyEventChain` names eight classes — `BrokenLink`, `DuplicateSeq`, `NonMonotonicSeq`, `TornTail`, `DoubleCounted`, `LedgerImbalance`, `MalformedLedger`, `ClaimInterrupted`. The last four exist because a rewriter must not be able to certify itself: the compaction ledger's arithmetic (`Σ weight + dropped === source`, `dropped ∈ [0, source]`) is enforced with NO clamps in the verifier (the clamp belongs to the writer), a damaged ledger line is a defect rather than a silently-disabled check, and a claim that never reached its `throughSeq` — because the segment restarted or the file ended — is reported instead of escaping through the discontinuity. `guardedRewrite` is the concurrency guard for any whole-file rewrite: exclusive lock, plus a re-read of the live file after computing the new text and BEFORE the rename, so a concurrent append aborts the attempt and is folded into a bounded retry rather than overwritten (it narrows the read→rename window; it cannot close it, and says so). Records written before chaining existed stay LEGAL and are counted as an uncovered `preChainPrefix`; an unreadable tail never blocks a write (fresh MARKED segment — an unreadable tail WINDOW is distinguished from an empty file — and the appender starts on a new line so one torn write cannot eat the next record); an unmarked restart is reported once and then re-anchored, so one incident is one defect instead of a cascade. HONEST SCOPE, carried in every result and printed by every surface: corruption detection for our own bugs — FNV-1a is not cryptography, its collisions are constructible, the threat model has no adversary, and a regression test fails if the module regrows tamper-proofing vocabulary |
|
|
23
|
-
| `feature-adr-checkpoints` | `checkpointInputHash`, `decideCheckpointResume`, `parseCheckpointRead`, `serializeCheckpoint`, `fnv1a64`, `CKPT_SCHEMA_VERSION`, `STAGE_ARTIFACTS` | The PURE half of feature-adr's durable per-stage checkpoints (`features/<slug>/.fa-state/checkpoints.jsonl`): a dead L/XL run — or the standard stop-after-plan re-invoke — resumes completed stages instead of re-spending them. Resume = INPUT-identity (64-bit salted FNV over a schema-versioned JSON tuple incl. upstream stage results) + presence of EVERY tier-required artifact; a stale-input hash never resumes in ANY mode (`force` relaxes only the artifact probe — the tested load-bearing property). HONEST SCOPE: it does NOT fingerprint the working tree (a crash-resume legitimately sees the dead run's uncommitted writes) — after manual edits use `resume:'never'` and re-QE. Null results are never persisted or resumable; a stage-identifiable corrupt record ERASES its older entry (last-wins holds for corruption too); the code stage's persist predicate is now an ALLOWLIST (`codeCheckpointPersistAllowed` + `codeStageResultShapeValid`, ADR-003 Condition 3): ONLY `landed` on a barrier-required run and `synchronous` on a non-barrier run may be checkpointed — inconclusive, not-landed, garbage and a mislabeled `synchronous` are all refused, and the `landing-v2` hash token makes every pre-protocol code checkpoint stale. The workflow mirrors this inline (wiring-guarded); RU: чекпоинт после каждой дорогой стадии — упавший ран возобновляется, а не пере-тратит
|
|
23
|
+
| `feature-adr-checkpoints` | `checkpointInputHash`, `decideCheckpointResume`, `parseCheckpointRead`, `serializeCheckpoint`, `fnv1a64`, `CKPT_SCHEMA_VERSION`, `STAGE_ARTIFACTS`, `DESIGN_SUBSTAGES`, `designStageKey`, `decideDesignFanResume`, `parseArtifactProbe` | The PURE half of feature-adr's durable per-stage checkpoints (`features/<slug>/.fa-state/checkpoints.jsonl`): a dead L/XL run — or the standard stop-after-plan re-invoke — resumes completed stages instead of re-spending them. Resume = INPUT-identity (64-bit salted FNV over a schema-versioned JSON tuple incl. upstream stage results) + presence of EVERY tier-required artifact; a stale-input hash never resumes in ANY mode (`force` relaxes only the artifact probe — the tested load-bearing property). HONEST SCOPE: it does NOT fingerprint the working tree (a crash-resume legitimately sees the dead run's uncommitted writes) — after manual edits use `resume:'never'` and re-QE. Null results are never persisted or resumable; a stage-identifiable corrupt record ERASES its older entry (last-wins holds for corruption too); the code stage's persist predicate is now an ALLOWLIST (`codeCheckpointPersistAllowed` + `codeStageResultShapeValid`, ADR-003 Condition 3): ONLY `landed` on a barrier-required run and `synchronous` on a non-barrier run may be checkpointed — inconclusive, not-landed, garbage and a mislabeled `synchronous` are all refused, and the `landing-v2` hash token makes every pre-protocol code checkpoint stale. **Since 0.5.3 the design fan is checkpointed PER SIBLING** (`design:requirements` / `adr` / `qcsd` / `architecture` via `designStageKey`), so one dead agent no longer discards three finished siblings, and a fix to one step's instructions invalidates that step alone. What may be CONSUMED is judged separately from what may be WRITTEN: `decideDesignFanResume` returns a named reason (`substage-missing` / `artifact-missing` / `probe-not-established` / `ok`) and the workflow REFUSES at the Step-5/6 boundary rather than planning off a partial design. The artifact half is judged against a POST-RUN probe that never prints filenames (`[ -f <exact rel> ]` per required artifact) — a listing is a list of filenames, and a file whose NAME ends in a newline was measured satisfying the requirement for the real file. `parseArtifactProbe` then validates the WHOLE transcript, because the probe is relayed by a model: an agent that merely NARRATES the expected output emits the token byte-identically. Inconclusive is never a pass. The workflow mirrors this inline (wiring-guarded); RU: чекпоинт после каждой дорогой стадии — упавший ран возобновляется, а не пере-тратит завершённое; веер проектирования — по каждому участнику отдельно, а неполный веер получает отказ, а не запись в лог |
|
|
24
24
|
| `discrimination-gate` | `planDiscriminationCheck`, `classifyExecutionEvidence`, `classifyDiscrimination`, `DiscriminationVerdict`, `BaseOutcome`, `TipOutcome`, `ExecutionEvidence`, `CannotIsolateReason`, `DiscriminationFinding`, `MeasurementValid`, `PrimaryAction` | The PURE §42 test-discrimination engine behind `dz discrimination-check`: it plans the pre-feature worktree check and classifies the observations the executor feeds back. **Every trust verdict is gated on execution evidence** (ADR-001, feature wave1-instrument-repair): `classifyExecutionEvidence` turns one captured run into `{exitCode, runner, failureKind, testsExecuted, targetSeen}` off the MEASURED vitest / node --test output shapes (reusing `mutation-gate`'s single regex family), and a row whose outcome VALUE is not backed by that evidence degrades to `CANNOT_ISOLATE` with a typed reason instead of minting trust. **Seven verdicts** (was four): `DISCRIMINATES` (assertion-red at base, evidenced) · `DISCRIMINATES_VIA_ERROR` (evidenced load error at base + evidenced pass at TIP) · `NON_DISCRIMINATING` (evidenced pass at base — a proven false green) · `TEST_FILE_ABSENT` (the named check is not a regular file — stat+isFile, before any worktree) · `LOAD_ERROR_AT_BOTH_REVS` (could not execute at EITHER rev — zero signal) · `FAILS_AT_TIP` (the feature's own test is red WITH the feature) · `CANNOT_ISOLATE` (no established observation; reason ∈ no-execution-evidence | unrecognised-runner-output | no-tests-executed | inconsistent-evidence | tip-control-missing | tip-evidence-missing | timeout). The result carries `findings[]` (one per distinct non-clean verdict — the scalar `aggregate` can only name the worst), plus two ORTHOGONAL axes: `measurementValid` (did the instrument measure at all: `true | false | 'partial'`) and `primaryAction` (the single most urgent operator repair). PARSE-NEVER-SYNTHESIZE: an outcome contradicted by its own evidence is rejected as `inconsistent-evidence`, never reinterpreted. HONEST SCOPE: the bar is "a recognized runner demonstrably executed the named test", NOT resistance to an output-imitating runner; recognising vitest/node --test shapes is in scope, CHOOSING the runner is not. The singular `finding` remains as a DEPRECATED one-release alias for `findings[0] ?? null`. RU: вердикт доверия теперь требует доказательства исполнения — «упало» без доказательства больше не считается доказательством |
|
|
25
25
|
| `feature-adr-routing` (landed barrier) | `sourceExpectedCodeTargets`, `validateExpectedTargetsBlock`, `codeLandedBarrierPlan`, `decideCodeLanding`, `codeLandedBarrierHasLanded`, `codeLandingProbeCmd`, `parseLandingSignal`, `verifyPreCodeBaseline`, `preCodeBaselineCaptureCmd`, `posixCksum`, `LANDING_PROTOCOL_VERSION`, `LANDING_HASH_TOKEN` | The PURE half of feature-adr's Step-7.5 Codex landing barrier (ADR-003, feature wave1-instrument-repair). Expected targets are SOURCED with an explicit precedence — a non-empty `args` override REPLACES the plan's `EXPECTED_CODE_TARGETS:` block (and narrowing to an all-unpollable set returns EMPTY with reason `override-unpollable`, never a silent fall-through), while Codex's own self-declared paths land in `scrapeDiagnostic` and can NEVER establish or match — the agent under test does not declare its own success criteria. An enabled barrier with no established target is `mode:'inconclusive'`, not the deleted `any-code-change` fallback that read an unrelated dirty file as landed. Landing is a DELTA, not dirtiness: `preCodeBaselineCaptureCmd` records `git hash-object` per pre-existing dirty path with a `count=/cksum=` trailer, `verifyPreCodeBaseline` refuses any truncated or edited baseline as `baseline-unverified` (a truncated baseline makes everything look landed), and a path counts only when it is absent from the baseline or its hash CHANGED. `parseLandingSignal` is the single normalization point — empty stdout is `probe-failure`, unparseable text is `malformed-signal`, and neither is ever a landing. RU: «файл грязный» ≠ «кодер его написал»; барьер теперь умеет сказать «не знаю» |
|
|
26
26
|
| `feature-adr-training-pairs` (in `feature-adr-checkpoints`) | `buildTrainingPair`, `serializeTrainingPair`, `trainingPairPath`, `trainingPairAppendCmd`, `modelFamily`, `TRAINPAIR_SCHEMA_VERSION`, `TRAINPAIR_MAX_IO_CHARS`, `TRAINPAIR_PRIVACY_NOTE` | The PURE half of feature-adr TRAINING-PAIR capture (backlog 70e0f083): every checkpointed stage emits one SFT-ready JSONL record — STAGE INPUT (full prompt/context) → STAGE OUTPUT (artifact/result) → EVALUATION {QE grade, gradedBy, lessonsInjected} with provenance {model, FAMILY ∈ claude/codex, role} — to `.dz/fa-training/<slug>/<stage>.jsonl` (one file per stage), raw material for future local-model fine-tuning. FAMILY is load-bearing: the downstream dataset must honour the cross-model rule (QE pairs from a DIFFERENT family than the coder). Oversize guard: input+output over 48k chars is TRUNCATED with a named marker + full-text fnv1a64 — never silently dropped, never unbounded. A stage without a QE grade (router) records `grade:null` honestly. Deterministic: `ts` is passed in (the workflow fills it shell-side). Capture is default-ON in the workflow, opt-out `args.captureTrainingPairs:false`, non-blocking (a capture failure never fails the run). PRIVACY: pairs may contain target-repo code; the capture dir carries a README note; NOT gitignored by explicit owner decision. RU: тренировочные пары вход→выход→оценка с каждого прогона feature-adr — сырьё для будущей локальной модели |
|
|
@@ -206,7 +206,13 @@ pause or the file deliverable.
|
|
|
206
206
|
|
|
207
207
|
## Status
|
|
208
208
|
|
|
209
|
-
`0.5.
|
|
209
|
+
`0.5.3` — published. **BEHAVIORAL:** `decideDesignFanResume` takes the design fan's LIVE results, not
|
|
210
|
+
the start-of-run checkpoint snapshot, and gained `artifacts` + `postRunListing`; `CKPT_SCHEMA_VERSION`
|
|
211
|
+
is `fa-ckpt-3`, so every existing `.fa-state/checkpoints.jsonl` reads as no checkpoint and each
|
|
212
|
+
in-flight feature re-runs router+design+plan once. Adds the per-sibling design checkpoint above and
|
|
213
|
+
`parseArtifactProbe`. Full detail in [CHANGELOG.md](CHANGELOG.md).
|
|
214
|
+
|
|
215
|
+
**0.5.1.** **BEHAVIORAL:** `parseTrace` orders events by `seq`, not by file order (§42
|
|
210
216
|
`CANNOT_ISOLATE` semantics unchanged from 0.5.0) — a stored verdict computed over a non-sequential
|
|
211
217
|
trace is not comparable with one computed here. Adds the plan enactor above, `qe-bridge.ts`
|
|
212
218
|
(cross-family QE hand-off with reviewer isolation, 17-reason taxonomy) and `named-lock.ts`
|
|
@@ -49,7 +49,14 @@ export declare const CHECKPOINT_MAX_RESULT_CHARS = 12000;
|
|
|
49
49
|
/** Checkpoint format/logic version — SALTED into every input hash. Bump it whenever the workflow's
|
|
50
50
|
* stage semantics, prompts, or composite result shapes change: every pre-existing checkpoint then
|
|
51
51
|
* hashes stale and re-runs, instead of an old-format entry resuming into new logic (Codex QE #5). */
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Bumped 'fa-ckpt-2' → 'fa-ckpt-3' on 2026-08-20: the `design` entry changed meaning. It used to be
|
|
54
|
+
* the ONE record for the whole parallel design fan; it is now a completeness marker sitting above
|
|
55
|
+
* four per-sibling records. A stale-format entry must hash stale rather than resume into new logic,
|
|
56
|
+
* so every in-flight `.fa-state/` re-runs router+design+plan once. That is the intended one-time
|
|
57
|
+
* price of the change, not an accident.
|
|
58
|
+
*/
|
|
59
|
+
export declare const CKPT_SCHEMA_VERSION = "fa-ckpt-3";
|
|
53
60
|
/** FNV-1a 32-bit over UTF-16 code units, hex-encoded (one pass; building block for the 64-bit form). */
|
|
54
61
|
export declare function fnv1a(str: string): string;
|
|
55
62
|
/** 64 bits from two independent FNV-1a passes (plain + salted). A single 32-bit hash admits
|
|
@@ -77,6 +84,64 @@ export interface ResumeDecision {
|
|
|
77
84
|
* resumes in any mode — force skips only the artifact probe, never the input check (a checkpoint
|
|
78
85
|
* for different inputs is a different feature). A malformed/null recorded result is treated as
|
|
79
86
|
* no-checkpoint (Codex QE #8 — a null result must not resume as a real one). */
|
|
87
|
+
/** The tier-active design sub-stages, in fan order. Namespaced keys are plain strings, so the
|
|
88
|
+
* checkpoint parser's last-wins-per-stage rule and its malformed-line erase rule work unchanged. */
|
|
89
|
+
export declare const DESIGN_SUBSTAGES: readonly ["requirements", "adr", "qcsd", "architecture"];
|
|
90
|
+
export type DesignSubstage = (typeof DESIGN_SUBSTAGES)[number];
|
|
91
|
+
/** `design:requirements`, … — the checkpoint stage key for one sibling. */
|
|
92
|
+
export declare function designStageKey(sub: DesignSubstage | string): string;
|
|
93
|
+
export interface DesignFanVerdict {
|
|
94
|
+
complete: boolean;
|
|
95
|
+
missingSubstages: string[];
|
|
96
|
+
missingArtifacts: string[];
|
|
97
|
+
/** Why the fan is not complete — 'ok' when it is. Never collapse 'probe-not-established' into
|
|
98
|
+
* 'ok': a gate that could not read its inputs is INCONCLUSIVE, and inconclusive is not a pass. */
|
|
99
|
+
reason: 'ok' | 'substage-missing' | 'artifact-missing' | 'probe-not-established';
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* SP-1 (completeness). The `design` stage may hand a value to Step 6 ONLY when every tier-required
|
|
103
|
+
* sibling produced a result AND every tier-required design artifact is on disk.
|
|
104
|
+
*
|
|
105
|
+
* This is the property the old all-or-nothing WRITE gate was implementing by accident, and the
|
|
106
|
+
* reason it must survive the split: a one-file probe once accepted a design missing its ADR and
|
|
107
|
+
* architecture (Codex QE #2). Splitting the write gate without keeping this would reopen that hole,
|
|
108
|
+
* so the two are landed together and tested together.
|
|
109
|
+
*
|
|
110
|
+
* It is deliberately a READ-side predicate. What may be WRITTEN (one sibling's completed work) and
|
|
111
|
+
* what may be CONSUMED (a whole design) are different questions; the previous code answered the
|
|
112
|
+
* second by crippling the first, which is how one dead agent discarded three finished artifacts.
|
|
113
|
+
*/
|
|
114
|
+
export declare function decideDesignFanResume(opts: {
|
|
115
|
+
/**
|
|
116
|
+
* The LIVE result of each required sibling, in `required` order — what the fan just returned.
|
|
117
|
+
*
|
|
118
|
+
* Round 1 of cross-family review graded this D and was right: the first version read the
|
|
119
|
+
* START-OF-RUN checkpoint snapshot instead. That snapshot is wrong in both directions. A sibling
|
|
120
|
+
* that succeeded THIS run is absent from it, and — the dangerous half — a stale non-null entry
|
|
121
|
+
* from a PREVIOUS run stays in it even when this run's retry returned null, so an incomplete
|
|
122
|
+
* design could be declared complete. That is the exact hole the old all-or-nothing write gate
|
|
123
|
+
* existed to prevent, reopened by reading the wrong source.
|
|
124
|
+
*
|
|
125
|
+
* The live result is authoritative and free: a sibling that returns non-null wrote its artifact,
|
|
126
|
+
* and a sibling that died returns null. Nothing needs to be re-probed to know that.
|
|
127
|
+
*/
|
|
128
|
+
results: readonly unknown[];
|
|
129
|
+
required: readonly string[];
|
|
130
|
+
/** Every artifact the tier requires from this fan. Empty ⇒ the artifact half is not checked. */
|
|
131
|
+
artifacts: readonly string[];
|
|
132
|
+
/**
|
|
133
|
+
* A listing taken AFTER the fan ran — never the start-of-run one, which is why the parameter is
|
|
134
|
+
* named for that and not just `listing`. Rounds 2 and 3 pinned both halves of this:
|
|
135
|
+
* • round 2 — fed the START-OF-RUN listing, the probe called every fresh M+ fan incomplete,
|
|
136
|
+
* because a listing taken before the fan cannot contain what the fan is about to write;
|
|
137
|
+
* • round 3 — with the probe removed entirely, a sibling that returns non-null having written
|
|
138
|
+
* only its primary artifact (L-tier requirements writes 01_requirements.md and skips
|
|
139
|
+
* 02_research.md) was accepted, and Step 6 planned with no research behind it. A non-null
|
|
140
|
+
* result is the agent's own word; it is not evidence that a file exists.
|
|
141
|
+
* `null` means the probe could not be read. That is INCONCLUSIVE, not clean.
|
|
142
|
+
*/
|
|
143
|
+
postRunListing: ReadonlySet<string> | null;
|
|
144
|
+
}): DesignFanVerdict;
|
|
80
145
|
export declare function decideCheckpointResume(opts: {
|
|
81
146
|
mode: ResumeMode;
|
|
82
147
|
entry: CheckpointEntry | undefined;
|
|
@@ -259,4 +324,31 @@ export declare function codeCheckpointPersistAllowed(landingStatus: unknown, bar
|
|
|
259
324
|
* hash-token invalidation, in case a hash somehow matches.
|
|
260
325
|
*/
|
|
261
326
|
export declare function codeStageResultShapeValid(r: unknown): boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Parse the design artifact probe's stdout into "which required artifacts exist".
|
|
329
|
+
*
|
|
330
|
+
* The probe is relayed by a MODEL, not read from a pipe: the workflow sandbox cannot run a shell, so
|
|
331
|
+
* an agent runs the command and hands back what it saw. That makes the transcript forgeable in
|
|
332
|
+
* principle, and cross-family review round 7 showed it forgeable in PRACTICE by accident — an agent
|
|
333
|
+
* that narrates ("Expected output when present: HAVE:01_requirements.md … Actual stdout: …") emits a
|
|
334
|
+
* line identical to the real token, and a permissive parser took it for evidence. The gate then passed a
|
|
335
|
+
* design whose artifact did not exist, which is the one thing this gate exists to prevent.
|
|
336
|
+
*
|
|
337
|
+
* So the transcript is validated STRICTLY, not scanned: after trimming blank lines, the output must be
|
|
338
|
+
* exactly some subset of the known HAVE tokens followed by exactly one sentinel, and nothing else.
|
|
339
|
+
* Anything unexpected — narration, a second sentinel, a shell error, a code fence — makes the probe
|
|
340
|
+
* NOT ESTABLISHED (null), which is a refusal, never a pass.
|
|
341
|
+
*
|
|
342
|
+
* What this does NOT do, named plainly: it cannot stop an agent that deliberately emits precisely the
|
|
343
|
+
* expected transcript and nothing else. That residual is the same trust the whole pipeline places in
|
|
344
|
+
* a relaying agent (the checkpoint reader and the Step-7.5 landing barrier share it). What it does do
|
|
345
|
+
* is make ACCIDENTAL forgery — the kind that actually happened — impossible rather than likely.
|
|
346
|
+
*
|
|
347
|
+
* @returns a Set of the required artifacts that exist, or `null` when the transcript is not trustworthy.
|
|
348
|
+
*/
|
|
349
|
+
export declare function parseArtifactProbe(opts: {
|
|
350
|
+
stdout: string | null | undefined;
|
|
351
|
+
sentinel: string;
|
|
352
|
+
required: readonly string[];
|
|
353
|
+
}): Set<string> | null;
|
|
262
354
|
//# sourceMappingURL=feature-adr-checkpoints.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-adr-checkpoints.d.ts","sourceRoot":"","sources":["../src/feature-adr-checkpoints.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"feature-adr-checkpoints.d.ts","sourceRoot":"","sources":["../src/feature-adr-checkpoints.ts"],"names":[],"mappings":"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"}
|
|
@@ -49,7 +49,14 @@ export const CHECKPOINT_MAX_RESULT_CHARS = 12_000;
|
|
|
49
49
|
/** Checkpoint format/logic version — SALTED into every input hash. Bump it whenever the workflow's
|
|
50
50
|
* stage semantics, prompts, or composite result shapes change: every pre-existing checkpoint then
|
|
51
51
|
* hashes stale and re-runs, instead of an old-format entry resuming into new logic (Codex QE #5). */
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Bumped 'fa-ckpt-2' → 'fa-ckpt-3' on 2026-08-20: the `design` entry changed meaning. It used to be
|
|
54
|
+
* the ONE record for the whole parallel design fan; it is now a completeness marker sitting above
|
|
55
|
+
* four per-sibling records. A stale-format entry must hash stale rather than resume into new logic,
|
|
56
|
+
* so every in-flight `.fa-state/` re-runs router+design+plan once. That is the intended one-time
|
|
57
|
+
* price of the change, not an accident.
|
|
58
|
+
*/
|
|
59
|
+
export const CKPT_SCHEMA_VERSION = 'fa-ckpt-3';
|
|
53
60
|
/** FNV-1a 32-bit over UTF-16 code units, hex-encoded (one pass; building block for the 64-bit form). */
|
|
54
61
|
export function fnv1a(str) {
|
|
55
62
|
let h = 0x811c9dc5;
|
|
@@ -85,6 +92,51 @@ export function resumeMode(raw) {
|
|
|
85
92
|
* resumes in any mode — force skips only the artifact probe, never the input check (a checkpoint
|
|
86
93
|
* for different inputs is a different feature). A malformed/null recorded result is treated as
|
|
87
94
|
* no-checkpoint (Codex QE #8 — a null result must not resume as a real one). */
|
|
95
|
+
/** The tier-active design sub-stages, in fan order. Namespaced keys are plain strings, so the
|
|
96
|
+
* checkpoint parser's last-wins-per-stage rule and its malformed-line erase rule work unchanged. */
|
|
97
|
+
export const DESIGN_SUBSTAGES = ['requirements', 'adr', 'qcsd', 'architecture'];
|
|
98
|
+
/** `design:requirements`, … — the checkpoint stage key for one sibling. */
|
|
99
|
+
export function designStageKey(sub) {
|
|
100
|
+
return 'design:' + sub;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* SP-1 (completeness). The `design` stage may hand a value to Step 6 ONLY when every tier-required
|
|
104
|
+
* sibling produced a result AND every tier-required design artifact is on disk.
|
|
105
|
+
*
|
|
106
|
+
* This is the property the old all-or-nothing WRITE gate was implementing by accident, and the
|
|
107
|
+
* reason it must survive the split: a one-file probe once accepted a design missing its ADR and
|
|
108
|
+
* architecture (Codex QE #2). Splitting the write gate without keeping this would reopen that hole,
|
|
109
|
+
* so the two are landed together and tested together.
|
|
110
|
+
*
|
|
111
|
+
* It is deliberately a READ-side predicate. What may be WRITTEN (one sibling's completed work) and
|
|
112
|
+
* what may be CONSUMED (a whole design) are different questions; the previous code answered the
|
|
113
|
+
* second by crippling the first, which is how one dead agent discarded three finished artifacts.
|
|
114
|
+
*/
|
|
115
|
+
export function decideDesignFanResume(opts) {
|
|
116
|
+
const missingSubstages = [];
|
|
117
|
+
opts.required.forEach((sub, i) => {
|
|
118
|
+
const r = opts.results[i];
|
|
119
|
+
if (r === null || r === undefined)
|
|
120
|
+
missingSubstages.push(sub);
|
|
121
|
+
});
|
|
122
|
+
const missingArtifacts = [];
|
|
123
|
+
let probeMissing = false;
|
|
124
|
+
if (opts.artifacts.length > 0) {
|
|
125
|
+
if (opts.postRunListing === null)
|
|
126
|
+
probeMissing = true;
|
|
127
|
+
else
|
|
128
|
+
for (const rel of opts.artifacts)
|
|
129
|
+
if (!opts.postRunListing.has(rel))
|
|
130
|
+
missingArtifacts.push(rel);
|
|
131
|
+
}
|
|
132
|
+
// Substage first: a dead sibling explains its own missing artifacts, and naming the artifacts
|
|
133
|
+
// instead would send the operator looking for a file when the agent is what died.
|
|
134
|
+
const reason = missingSubstages.length > 0 ? 'substage-missing'
|
|
135
|
+
: probeMissing ? 'probe-not-established'
|
|
136
|
+
: missingArtifacts.length > 0 ? 'artifact-missing'
|
|
137
|
+
: 'ok';
|
|
138
|
+
return { complete: reason === 'ok', missingSubstages, missingArtifacts, reason };
|
|
139
|
+
}
|
|
88
140
|
export function decideCheckpointResume(opts) {
|
|
89
141
|
if (opts.mode === 'never')
|
|
90
142
|
return { resume: false, reason: 'mode-never' };
|
|
@@ -421,4 +473,56 @@ export function codeStageResultShapeValid(r) {
|
|
|
421
473
|
return false;
|
|
422
474
|
return v.landingStatus === 'landed' || v.landingStatus === 'genuinely-not-landed' || v.landingStatus === 'inconclusive' || v.landingStatus === 'synchronous';
|
|
423
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* Parse the design artifact probe's stdout into "which required artifacts exist".
|
|
478
|
+
*
|
|
479
|
+
* The probe is relayed by a MODEL, not read from a pipe: the workflow sandbox cannot run a shell, so
|
|
480
|
+
* an agent runs the command and hands back what it saw. That makes the transcript forgeable in
|
|
481
|
+
* principle, and cross-family review round 7 showed it forgeable in PRACTICE by accident — an agent
|
|
482
|
+
* that narrates ("Expected output when present: HAVE:01_requirements.md … Actual stdout: …") emits a
|
|
483
|
+
* line identical to the real token, and a permissive parser took it for evidence. The gate then passed a
|
|
484
|
+
* design whose artifact did not exist, which is the one thing this gate exists to prevent.
|
|
485
|
+
*
|
|
486
|
+
* So the transcript is validated STRICTLY, not scanned: after trimming blank lines, the output must be
|
|
487
|
+
* exactly some subset of the known HAVE tokens followed by exactly one sentinel, and nothing else.
|
|
488
|
+
* Anything unexpected — narration, a second sentinel, a shell error, a code fence — makes the probe
|
|
489
|
+
* NOT ESTABLISHED (null), which is a refusal, never a pass.
|
|
490
|
+
*
|
|
491
|
+
* What this does NOT do, named plainly: it cannot stop an agent that deliberately emits precisely the
|
|
492
|
+
* expected transcript and nothing else. That residual is the same trust the whole pipeline places in
|
|
493
|
+
* a relaying agent (the checkpoint reader and the Step-7.5 landing barrier share it). What it does do
|
|
494
|
+
* is make ACCIDENTAL forgery — the kind that actually happened — impossible rather than likely.
|
|
495
|
+
*
|
|
496
|
+
* @returns a Set of the required artifacts that exist, or `null` when the transcript is not trustworthy.
|
|
497
|
+
*/
|
|
498
|
+
export function parseArtifactProbe(opts) {
|
|
499
|
+
if (opts.stdout === null || opts.stdout === undefined)
|
|
500
|
+
return null;
|
|
501
|
+
const known = new Map();
|
|
502
|
+
for (const rel of opts.required)
|
|
503
|
+
known.set('HAVE:' + rel, rel);
|
|
504
|
+
const found = new Set();
|
|
505
|
+
let sentinels = 0;
|
|
506
|
+
for (const raw of String(opts.stdout).split('\n')) {
|
|
507
|
+
const line = raw.trim();
|
|
508
|
+
if (line === '')
|
|
509
|
+
continue;
|
|
510
|
+
if (line === opts.sentinel) {
|
|
511
|
+
sentinels++;
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
// A token AFTER the sentinel is as wrong as an unknown line: the command emits every check first.
|
|
515
|
+
if (sentinels > 0)
|
|
516
|
+
return null;
|
|
517
|
+
const rel = known.get(line);
|
|
518
|
+
if (rel === undefined)
|
|
519
|
+
return null;
|
|
520
|
+
found.add(rel);
|
|
521
|
+
}
|
|
522
|
+
// Exactly one. Zero means the command never completed (or never ran); two means something other
|
|
523
|
+
// than the command produced output, and there is no way to tell which half was real.
|
|
524
|
+
if (sentinels !== 1)
|
|
525
|
+
return null;
|
|
526
|
+
return found;
|
|
527
|
+
}
|
|
424
528
|
//# sourceMappingURL=feature-adr-checkpoints.js.map
|