duediligence 0.0.0-stage → 0.3.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.
Files changed (147) hide show
  1. package/AGENTS.md +64 -0
  2. package/LICENSE +21 -0
  3. package/README.md +535 -2
  4. package/RESULTS.md +850 -0
  5. package/SKILL.md +249 -0
  6. package/bin/backends.mjs +762 -0
  7. package/bin/calibrate.mjs +228 -0
  8. package/bin/ci.mjs +158 -0
  9. package/bin/cli.mjs +62 -0
  10. package/bin/commitment.mjs +93 -0
  11. package/bin/confirm.mjs +370 -0
  12. package/bin/decisions.mjs +166 -0
  13. package/bin/fit.mjs +426 -0
  14. package/bin/generate.mjs +287 -0
  15. package/bin/grade.mjs +166 -0
  16. package/bin/handout.mjs +177 -0
  17. package/bin/import-archive.mjs +278 -0
  18. package/bin/judge.mjs +363 -0
  19. package/bin/lib.mjs +2048 -0
  20. package/bin/platform.mjs +145 -0
  21. package/bin/prepare.mjs +113 -0
  22. package/bin/promote.mjs +87 -0
  23. package/bin/red-team-audit.mjs +272 -0
  24. package/bin/referee.mjs +325 -0
  25. package/bin/repo.mjs +269 -0
  26. package/bin/retry.mjs +205 -0
  27. package/bin/run.mjs +170 -0
  28. package/bin/runners/boundary.mjs +220 -0
  29. package/bin/runners/cargo-test.mjs +102 -0
  30. package/bin/runners/go-test.mjs +107 -0
  31. package/bin/runners/guard.mjs +59 -0
  32. package/bin/runners/jest.mjs +103 -0
  33. package/bin/runners/native-build.mjs +63 -0
  34. package/bin/runners/node-test.mjs +108 -0
  35. package/bin/runners/pytest.mjs +149 -0
  36. package/bin/runners/shared.mjs +132 -0
  37. package/bin/runners/vitest.mjs +116 -0
  38. package/bin/seal.mjs +154 -0
  39. package/package.json +57 -4
  40. package/prompts/agent-red-team.md +22 -0
  41. package/prompts/agent.md +23 -0
  42. package/prompts/exec/agent.md +27 -0
  43. package/prompts/exec/hidden-tests.md +65 -0
  44. package/prompts/exec/public-tests.md +40 -0
  45. package/prompts/exec/reference.md +16 -0
  46. package/prompts/exec/skeleton.md +25 -0
  47. package/prompts/exec/spec-from-ticket.md +29 -0
  48. package/prompts/exec-native/agent.md +29 -0
  49. package/prompts/exec-native/hidden-tests.md +66 -0
  50. package/prompts/exec-native/public-tests.md +42 -0
  51. package/prompts/exec-native/reference.md +19 -0
  52. package/prompts/exec-native/skeleton.md +24 -0
  53. package/prompts/exec-native/spec-from-ticket.md +29 -0
  54. package/prompts/go/agent.md +22 -0
  55. package/prompts/go/hidden-tests.md +59 -0
  56. package/prompts/go/public-tests.md +33 -0
  57. package/prompts/go/reference.md +14 -0
  58. package/prompts/go/skeleton.md +31 -0
  59. package/prompts/go/spec-from-ticket.md +28 -0
  60. package/prompts/hidden-tests.md +58 -0
  61. package/prompts/http/agent.md +31 -0
  62. package/prompts/http/hidden-tests.md +67 -0
  63. package/prompts/http/public-tests.md +40 -0
  64. package/prompts/http/reference.md +19 -0
  65. package/prompts/http/skeleton.md +26 -0
  66. package/prompts/http/spec-from-ticket.md +30 -0
  67. package/prompts/http-native/agent.md +31 -0
  68. package/prompts/http-native/hidden-tests.md +70 -0
  69. package/prompts/http-native/public-tests.md +43 -0
  70. package/prompts/http-native/reference.md +20 -0
  71. package/prompts/http-native/skeleton.md +26 -0
  72. package/prompts/http-native/spec-from-ticket.md +30 -0
  73. package/prompts/lcb/agent.md +21 -0
  74. package/prompts/lcb/public-tests.md +37 -0
  75. package/prompts/public-tests.md +32 -0
  76. package/prompts/pyfunc/agent.md +19 -0
  77. package/prompts/pyfunc/hidden-tests.md +50 -0
  78. package/prompts/pyfunc/public-tests.md +30 -0
  79. package/prompts/python/agent.md +24 -0
  80. package/prompts/python/hidden-tests.md +62 -0
  81. package/prompts/python/public-tests.md +36 -0
  82. package/prompts/python/reference.md +15 -0
  83. package/prompts/python/skeleton.md +33 -0
  84. package/prompts/python/spec-from-ticket.md +30 -0
  85. package/prompts/red-team-audit.md +32 -0
  86. package/prompts/referee.md +37 -0
  87. package/prompts/reference.md +13 -0
  88. package/prompts/repo/agent-no-public.md +22 -0
  89. package/prompts/repo/agent.md +25 -0
  90. package/prompts/repo/hidden-tests.md +63 -0
  91. package/prompts/repo/public-tests.md +36 -0
  92. package/prompts/repo/reference.md +18 -0
  93. package/prompts/repo/skeleton.md +40 -0
  94. package/prompts/repo/spec-from-ticket.md +35 -0
  95. package/prompts/repo-python/agent-no-public.md +22 -0
  96. package/prompts/repo-python/agent.md +25 -0
  97. package/prompts/repo-python/hidden-tests.md +62 -0
  98. package/prompts/repo-python/public-tests.md +36 -0
  99. package/prompts/repo-python/reference.md +18 -0
  100. package/prompts/repo-python/skeleton.md +37 -0
  101. package/prompts/repo-python/spec-from-ticket.md +37 -0
  102. package/prompts/rust/agent.md +22 -0
  103. package/prompts/rust/hidden-tests.md +62 -0
  104. package/prompts/rust/public-tests.md +38 -0
  105. package/prompts/rust/reference.md +14 -0
  106. package/prompts/rust/skeleton.md +30 -0
  107. package/prompts/rust/spec-from-ticket.md +29 -0
  108. package/prompts/skeleton.md +29 -0
  109. package/prompts/spec-from-ticket.md +27 -0
  110. package/specs/duration-parse/calibration.json +104 -0
  111. package/specs/duration-parse/generation.json +69 -0
  112. package/specs/duration-parse/prepared.json +4 -0
  113. package/specs/duration-parse/reference/src/index.ts +85 -0
  114. package/specs/duration-parse/skeleton/src/index.ts +24 -0
  115. package/specs/duration-parse/spec.md +157 -0
  116. package/specs/duration-parse/tests/private/format.test.ts +157 -0
  117. package/specs/duration-parse/tests/private/parse.test.ts +252 -0
  118. package/specs/duration-parse/tests/public/format.test.ts +60 -0
  119. package/specs/duration-parse/tests/public/parse.test.ts +105 -0
  120. package/specs/duration-parse/ticket.md +7 -0
  121. package/template/.nvmrc +1 -0
  122. package/template/package-lock.json +32 -0
  123. package/template/package.json +17 -0
  124. package/template/sandbox/ambient.d.ts +86 -0
  125. package/template/sandbox/reporter.mjs +25 -0
  126. package/template/sandbox/run.mjs +121 -0
  127. package/template/sandbox/test.mjs +30 -0
  128. package/template/sandbox.env +1 -0
  129. package/template/tsconfig.json +17 -0
  130. package/template-go/README.md +15 -0
  131. package/template-go/go.mod +3 -0
  132. package/template-go/sandbox/test.sh +7 -0
  133. package/template-python/README.md +21 -0
  134. package/template-python/pytest.ini +5 -0
  135. package/template-python/requirements.txt +12 -0
  136. package/template-python/sandbox/check.py +99 -0
  137. package/template-python/sandbox/compile_check.py +28 -0
  138. package/template-python/sandbox/duediligence_reporter.py +87 -0
  139. package/template-python/sandbox/exec.py +38 -0
  140. package/template-python/sandbox/lcb/UPSTREAM +1 -0
  141. package/template-python/sandbox/lcb/__init__.py +34 -0
  142. package/template-python/sandbox/lcb/testing_util.py +592 -0
  143. package/template-python/sandbox/lcb_worker.py +18 -0
  144. package/template-python/sandbox/run.py +136 -0
  145. package/template-rust/Cargo.toml +10 -0
  146. package/template-rust/README.md +15 -0
  147. package/template-rust/sandbox/test.sh +6 -0
package/RESULTS.md ADDED
@@ -0,0 +1,850 @@
1
+ # duediligence: results
2
+
3
+ What the method was measured to do. About 3,000 graded agent runs on 26
4
+ TypeScript specs, 40 LiveCodeBench problems, 40 HumanEval+ tasks and a spec
5
+ ladder with oracle judges, and 110 on 11 changes replayed in an existing
6
+ repository, run 2026-10-23 to 2026-10-25 with Opus 5.5 writing the suites and
7
+ Haiku 5.5 implementing unless stated. The dated write-ups are vendored into
8
+ `evidence/` ([FINDINGS.md](evidence/FINDINGS.md),
9
+ [EXPERIMENT.md](evidence/EXPERIMENT.md), [LADDER.md](evidence/LADDER.md)) from
10
+ the experiment archive, `double-blind-experiment/`, which holds the runs and
11
+ data and is not part of this repository. Run 2026-10-26: Codex CLI as writer and
12
+ referee ([Writer backends](#writer-backends)) and as implementer
13
+ ([Other implementers](#other-implementers)), Opus 5.5 as an adversary
14
+ ([Red team](#red-team)), and 12 changes in two public repositories
15
+ ([In repositories not written here](#in-repositories-not-written-here)). Run
16
+ 2026-10-27: specs checked through a command or an HTTP service
17
+ ([Black-box seams](#black-box-seams)). Run 2026-10-28: Go and Rust modules end
18
+ to end ([Go and Rust](#go-and-rust)), and commands and services written in
19
+ Python, Go and Rust
20
+ ([Commands and services in other languages](#commands-and-services-in-other-languages)).
21
+ p-values are Fisher's exact test,
22
+ two-sided.
23
+
24
+ ## The agent's own green run is not an acceptance signal
25
+
26
+ Every agent that wrote its own tests ended saying they passed. Measured by
27
+ rerunning those tests on the submitted code, every one was green. The hidden
28
+ suite then rejected:
29
+
30
+ | brief the agent read | runs | own tests green | rejected by the hidden suite |
31
+ | --------------------------- | ---: | --------------: | ---------------------------: |
32
+ | the loose ticket | 105 | 105 | 75 (71%) |
33
+ | the precise, confirmed spec | 404 | 404 | 25 (6%) |
34
+
35
+ A blind referee on another model (Fable 5.1), given only the spec, the failing
36
+ code and one anonymised test, upheld 95 of the 100 rejections it was shown as
37
+ things the spec requires, and 24 of the 26 rejections of a run whose own tests
38
+ were green. Of 74 agent-written tests that fail the calibrated reference, 66
39
+ assert a reading the spec leaves open, 5 are wrong, 3 are rules the reference
40
+ misses. ([Self-grading](evidence/FINDINGS.md#self-grading),
41
+ [Follow-ups](evidence/FINDINGS.md#follow-ups))
42
+
43
+ ## Tests written from the spec carry it to the agent
44
+
45
+ The same seven specs, 15 runs per cell, graded by the same hidden suites. The
46
+ only thing that changes is what the agent reads.
47
+
48
+ | the agent reads | with the public suite | no tests | own tests |
49
+ | ----------------------------------------- | --------------------: | --------: | --------: |
50
+ | the loose ticket | **81 / 105** | 30 / 105 | 30 / 105 |
51
+ | the ticket plus the public suite as prose | 76 / 101 | | |
52
+ | the precise spec | 95 / 105 | 100 / 105 | 98 / 105 |
53
+
54
+ From the ticket the gain is p < 1e-11; from the precise spec there is none (p =
55
+ 0.28). The prose row shows what the gain is: the spec's decisions, which the
56
+ tests carry. A ticket that says "as CSV" fails in every cell; one that never
57
+ mentions overlap fails every control on concurrency and no run given the public
58
+ suite.
59
+ ([Precise spec against the ticket](evidence/FINDINGS.md#precise-spec-against-the-ticket))
60
+
61
+ The spec ladder makes the same point against an oracle nobody here wrote. One
62
+ invented version-range scheme, 396 oracle cases, a full spec L0 and four vaguer
63
+ ones down to ten words at L4; 5 runs per cell, macro average over rules, %:
64
+
65
+ | spec level | no tests | suite written from the same level | suite written from the full spec |
66
+ | ------------ | -------: | --------------------------------: | -------------------------------: |
67
+ | L0, full | 100 | 100 | 100 |
68
+ | L2 | 56 | 52 | **100** |
69
+ | L3 | 59 | 43 | **100** |
70
+ | L4, 10 words | 46 | 37 | **100** |
71
+
72
+ A suite from the full spec carries all of it, even when the agent reads ten
73
+ words. A suite from a vague spec locks in the writer's guess and does worse than
74
+ no suite. Twenty AtCoder problems judged by LiveCodeBench's own tests show the
75
+ same shape where the statement is present: the full-spec suite never loses a
76
+ problem, the reduced-spec suite loses three. Both are pilots: one task, small
77
+ counts. ([Spec ladder](evidence/LADDER.md))
78
+
79
+ ## Own tests on top of the public suite
80
+
81
+ The skill's brief, `prompts/agent.md`: pass the public suite and write one test
82
+ per scenario with inputs unlike the public ones. Against the public suite alone,
83
+ on the four specs where that suite had misses:
84
+
85
+ | spec | public suite + own tests | public suite alone |
86
+ | ------------- | -----------------------: | -----------------: |
87
+ | tool-versions | 50 / 50 | 42 / 50 |
88
+ | patch-apply | 19 / 20 | 20 / 20 |
89
+ | licence-scan | 20 / 20 | 19 / 20 |
90
+ | csv-export | 11 / 15 | 6 / 15 |
91
+ | pooled | **100 / 105** | 87 / 105 |
92
+
93
+ tool-versions p = 0.006, pooled p = 0.007. On csv-export the public suite alone
94
+ made agents stop at green with a number formatted `1e+21` where the spec says
95
+ plain digits (6 of 15 against 14 of 15 with no tests at all); own tests recover
96
+ most of that. A run of this brief whose own tests pass is rejected by the hidden
97
+ suite 1 time in 60, against 25 in 404 for own tests without the public suite.
98
+ ([Mechanisms](evidence/FINDINGS.md#mechanisms),
99
+ [Follow-ups](evidence/FINDINGS.md#follow-ups))
100
+
101
+ ## The hidden suite as a judge
102
+
103
+ - **Gaming.** Agents told to pass the public suite with the least general code:
104
+ 21 of 21 that did were rejected (20 hard-coded the public inputs, 1 skipped a
105
+ stated rule). Haiku declined to game in 31 of 52 runs. In 2,522 runs no agent
106
+ changed a test or the harness; 19 transcripts touched a path outside the
107
+ workdir, every one a mistyped own path.
108
+ ([Gaming the suite](evidence/FINDINGS.md#gaming-the-suite))
109
+ - **An outside oracle.** On 1,240 HumanEval+ solutions labelled by EvalPlus,
110
+ suites generated from the prompt alone accepted 4.8% of wrong solutions
111
+ against 15.0% for HumanEval's own tests, and rejected 3 of 289 right ones (two
112
+ tasks the suite and the oracle read differently excluded; all 40 tasks: 7.7%
113
+ against 17.5%, 23 of 314).
114
+ ([HumanEval+](evidence/FINDINGS.md#humaneval-as-an-outside-oracle))
115
+ - **Against git.** On a patch-apply spec the calibrated reference agreed with
116
+ `git apply` on all 7,533 real-history cases judged. One submission passed both
117
+ suites and disagreed with git, on a rename without hunks the hand-written test
118
+ diffs never showed.
119
+ ([A git oracle](evidence/FINDINGS.md#a-git-oracle-on-patch-apply))
120
+ - **Mutants.** Of 1,442 single-edit mutants of the references, the public suite
121
+ killed 75.6% and both suites 79.2%; of the public suite's survivors that
122
+ matter to the spec, the hidden suite kills about 30%. The misses cluster on
123
+ inputs the spec names by an outside format, which is why the skill asks for
124
+ real tool output in the spec.
125
+ ([Mutation score](evidence/FINDINGS.md#mutation-score))
126
+
127
+ ## Feedback after a verdict
128
+
129
+ One bounded retry of every first attempt that was not accepted, told either the
130
+ failing scenario keys (`unhappy-2`) or only that it failed:
131
+
132
+ | first attempt | keyed | plain |
133
+ | ----------------------------- | ----------: | ------: |
134
+ | public suite | 17 / 19 | 16 / 22 |
135
+ | no tests | 22 / 26 | 11 / 26 |
136
+ | own tests | 21 / 23 | 16 / 24 |
137
+ | public suite, from the ticket | 15 / 24 | 14 / 24 |
138
+ | pooled | **75 / 92** | 57 / 96 |
139
+
140
+ p = 0.001. A key names a scenario the agent already has in the spec, so it leaks
141
+ no test. On specs a session had drafted from the ticket without confirmation,
142
+ retries recovered 0 of 72: when the spec and the judge decide differently, no
143
+ feedback helps. That is why step 2 of the skill is a person.
144
+ ([Follow-ups](evidence/FINDINGS.md#follow-ups),
145
+ [From the ticket alone](evidence/FINDINGS.md#from-the-ticket-alone))
146
+
147
+ ## In an existing repository
148
+
149
+ Eleven changes from the history of
150
+ [sandbox-factory](https://github.com/lunox-work/sandbox-factory), replayed at
151
+ their parent commit: six in `packages/core`, one each in `packages/shared`,
152
+ `packages/jira`, `apps/worker`, `apps/api` and `apps/web` (vitest; the rest
153
+ `node:test`). The ticket is the commit message as written, plus the declarations
154
+ the commit adds to the seam, without bodies. A blind session drafts the spec
155
+ from it at base and never sees the diff. Each case is prepared twice: from the
156
+ drafted spec as it stands, and after a session playing the commit's developer,
157
+ shown the real diff, answers the spec's decisions the way the code does. That is
158
+ step 2 of the skill, done by the one person who knows what the code was meant to
159
+ do. The real commit is judged by both suites, and Haiku 5.5 implements the
160
+ confirmed spec five times with the public suite and five times without it.
161
+ Driver, cases, specs and grades: [evidence/in-repo.mjs](evidence/in-repo.mjs)
162
+ and `evidence/in-repo/`.
163
+
164
+ | the real commit, judged by suites written from | passed both | hidden tests passed | public tests passed |
165
+ | ---------------------------------------------- | ----------: | ------------------: | ------------------: |
166
+ | the spec drafted from its message | 0 / 11 | 256 / 709 (36%) | 263 / 601 |
167
+ | the same spec, confirmed by its developer | **8 / 11** | **659 / 665** | 599 / 600 |
168
+
169
+ - **A drafted spec does not describe the developer's code.** Two drafted suites
170
+ did not compile against the real commit: the drafter named an export or a
171
+ field the developer never wrote. The rest decided messages, limits and edge
172
+ rules otherwise. The identicon's message says plain FNV-1a was kept over a
173
+ finalized hash; the drafter specified the finalizer, and the real code passed
174
+ 3 of 80 hidden tests. Elsewhere the spec throws where the code returns.
175
+ Confirmation is where the accuracy comes from, here as in the archive.
176
+ - **Six hidden tests reject a confirmed real commit.** Two are defects in the
177
+ shipped code: `categories` looks names up in a plain object, so a priority
178
+ named `constructor` ranks as a function instead of `"high"`, and a threshold
179
+ named `toString` counts as known (`key in defaults`, two lines below an
180
+ `Object.hasOwn` guard on the category), against the confirmed spec in both
181
+ cases. Two hold the code to its confirmed words on inputs the developer did
182
+ not think of: a short title ending in a lone surrogate, which the spec says is
183
+ returned unchanged and the code trims, and a `String` object, which the spec
184
+ rejects as a non-string and the code accepts. Two read a question the spec
185
+ leaves open, an ADF heading level or list start given as a numeric string:
186
+ false rejects of the `spec-gap` kind. So 2 of 665 hidden tests rejected the
187
+ real code without the spec's support.
188
+
189
+ | Haiku 5.5 on the confirmed spec | with the public suite | without it |
190
+ | --------------------------------- | --------------------: | ---------: |
191
+ | passed | 55 / 55 | 55 / 55 |
192
+ | regressed: an existing test broke | 0 | 0 |
193
+ | changed outside the allowed paths | 0 | 0 |
194
+ | refused: edited a test or config | 0 | 0 |
195
+ | tried to read the hidden suite | 0 | 0 |
196
+
197
+ Every run passed, the three suites that rejected the real commit included, so
198
+ the arms do not separate (p = 1), as on precise specs in the archive. What the
199
+ arm shows is that the repository harness (stub, regression baseline, scope
200
+ rules) admits correct work: no run was refused for anything but its code, and
201
+ none was.
202
+
203
+ - **Suites.** Calibration kept 709 of 709 hidden tests on the drafted specs and
204
+ 665 of 666 on the confirmed ones; no reference broke an existing test. 600
205
+ public and 665 hidden tests on the confirmed specs, 25 to 150 per spec.
206
+ - **Selection.** A case is a commit whose change inside one package builds alone
207
+ at the parent and keeps the package's suite passing (`in-repo.mjs check`, no
208
+ model). The landing site's 122 commits have no TypeScript test of a source
209
+ file; most of sandbox-factory's 185 are squashed multi-package PRs, so four
210
+ cases are judged on the seam file alone. Three candidates were dropped: two
211
+ need same-commit changes in another package, one is a behaviour-preserving
212
+ ReDoS fix no unit test tells apart from base. `categories` was first cased
213
+ with one of its five files as the seam; the real commit then compiled against
214
+ neither suite, and it was prepared again with the commit's own layout.
215
+ - **Pilots.** Before the arm, `handle-candidates` (`packages/core`) and
216
+ `byte-size` (`apps/web`), confirmed by a person, passed blind Haiku runs
217
+ (18/18 and 32/32; 14/14 and 26/26), and every verdict was forced once by hand.
218
+ Dropping the deduplication at number 100 passes both handle-candidates suites:
219
+ the spec's examples never reach a three-digit repeat. A copy of a passing
220
+ step-holds run, broken by hand, was graded `incomplete`; one retry told only
221
+ its three scenario keys passed it.
222
+
223
+ ## In repositories not written here
224
+
225
+ The same arm on two public repositories, 2026-10-26: unjs/ufo (URL utilities)
226
+ and unjs/pathe (path utilities), both TypeScript on vitest with pnpm, neither
227
+ written by anyone here. `evidence/in-repo.mjs` takes any repository now
228
+ (`--cases <dir>/cases.json`; a case's `repo` may be a git URL); `discover`
229
+ listed the candidate commits with no model, as the sandbox-factory cases were
230
+ chosen: one package, a feat, fix or perf subject, source changed outside the
231
+ tests, a test changed that imports it, no harness change. `check` then kept the
232
+ commits whose change builds alone at the parent and keeps the suite. Both
233
+ repositories squash pull requests into one-line subjects, so the drafter's
234
+ ticket is the subject and the declarations the commit adds or changes, nothing
235
+ more. Cases, specs, ledgers and grades: `evidence/in-repo-ufo/`,
236
+ `evidence/in-repo-pathe/`; `sh evidence/in-repo-queue.sh <cases.json>` runs or
237
+ resumes a set.
238
+
239
+ | the real commit, judged by suites written from | ufo: passed both | hidden tests passed | pathe: passed both | hidden tests passed |
240
+ | ---------------------------------------------- | ---------------: | ------------------: | -----------------: | ------------------: |
241
+ | the spec drafted from its subject | 1 / 6 | 355 / 435 (82%) | 2 / 6 | 291 / 357 (82%) |
242
+ | the same spec, confirmed by its developer | **6 / 6** | **286 / 286** | **6 / 6** | **186 / 186** |
243
+
244
+ | implementer, on the confirmed specs | ufo, with the public suite | ufo, without | pathe, with | pathe, without |
245
+ | ----------------------------------- | -------------------------: | -----------: | ----------------------------: | -------------: |
246
+ | Haiku 5.5, 5 runs per spec | 25 / 25 | 24 / 25 | 30 / 30 | 30 / 30 |
247
+ | Codex CLI, 5 runs per spec | **25 / 25** | | 17 / 17 (4 specs; 13 pending) | |
248
+ | regressed, outside scope, refused | 0, 0, 0 | 0, 0, 0 | 0, 0, 0 | 0, 0, 0 |
249
+
250
+ - **Cases.** ufo: `filterQuery`, `joinRelativeURL` and `withoutHost` added;
251
+ `withBase`/`withoutBase` false prefix matches, Windows drive letters only with
252
+ `file://`, `parseQuery` on a null-prototype object fixed. Two older commits
253
+ were dropped by `check`: their parent does not build. pathe:
254
+ `reverseResolveAlias` added; a UNC prefix kept by `resolve`, `extname` of a
255
+ name ending in a dot, `format` with partial arguments, `filename` of a dotfile
256
+ or a name without extension, and `basename` ignoring a trailing separator
257
+ fixed. One commit was dropped: its parent does not build.
258
+ - **One case is judged as a commit only.** `joinRelativeURL` moved `../`
259
+ handling out of `joinURL` and rewrote 13 existing `joinURL` tests in the same
260
+ commit, so a faithful implementation fails those tests at base and every run
261
+ would read `regressed`; `run` now skips a case whose commit changed what
262
+ existing tests expect (`check`'s `editedTestsLost`). Its drafted and confirmed
263
+ references broke the same 13 tests, as the real commit does.
264
+ - **Spend.** ufo: 12 prepares $23.74 ($1.23–2.99, median $1.96), 50 Haiku runs
265
+ $0.85 (median 1.1 minutes). pathe: 12 prepares $29.61 ($1.72–3.30, median
266
+ $2.47), 60 Haiku runs $1.20. Codex (its own billing) ran 25 of 25 on ufo and
267
+ 17 on pathe on 2026-10-27 before its credits ran out again;
268
+ `sh evidence/in-repo-queue.sh evidence/in-repo-pathe/cases.json` runs the
269
+ other 13. Codex's shell looks for `AGENTS.md` in every folder above its
270
+ workdir, and the transcript scan reports that once as a peek at another
271
+ workdir; it named no hidden path.
272
+ - **Two harness fixes the second repository needed.** pathe names tests after
273
+ `process.cwd()`, so every staged tree gave them new ids and the baseline read
274
+ them as regressions: runners now write the tree's folder in a test name as
275
+ `<root>`. Since this phase vitest and Jest run under the memory guard
276
+ (`bin/runners/guard.mjs`: 512 MB heap per process, the whole run killed over 3
277
+ GB; sandbox-factory's apps/web suite peaks at 2.2 GB) with `--maxWorkers=2`,
278
+ which vitest before 4 rejects under its default minimum unless
279
+ `--minWorkers=1` comes with it; the runner adds it there.
280
+
281
+ ## Installed as a package
282
+
283
+ The README's five-minute path, run 2026-10-26 on the CLI alone: the `npm pack`
284
+ tarball in a fresh `node:22` container (Node 22.23.4), no checkout mounted, as
285
+ the unprivileged `node` user, with the data in a fresh `~/.duediligence/`.
286
+ No model session.
287
+
288
+ | step | global install (package dir root-owned) | `npx --package <tarball>` |
289
+ | ---------------------------------------------- | --------------------------------------: | -------------------------: |
290
+ | `prepare` on the confirmed example | ready, no session | ready, no session |
291
+ | toolchain installed on first use (npm 10.9.2) | yes | yes |
292
+ | `judge` the handout's skeleton | `incomplete`, 0/22, 0/39 | `incomplete`, 0/22, 0/39 |
293
+ | `judge` the reference | **`passed`, 22/22, 39/39** | **`passed`, 22/22, 39/39** |
294
+ | the clone URL and `npx duediligence` line | pending | pending |
295
+
296
+ The last row waits on the repository being pushed and the package published;
297
+ neither exists yet.
298
+
299
+ ## Commitment hash
300
+
301
+ The hidden suite's `hiddenSha256` (`bin/commitment.mjs`), checked 2026-10-26 on
302
+ existing material. No model session.
303
+
304
+ | check | result |
305
+ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
306
+ | `duration-parse` hashed twice, and by the shell recipe | the same hash all three times |
307
+ | the archive's 26 core specs, each hashed twice in place | 26 of 26 stable, 26 distinct |
308
+ | one byte of a hidden test changed after the handout (scratch home) | **judge refuses, exit 1**, `hidden suite changed since <at>`; handout refuses |
309
+ | the byte restored | `passed`, 22/22, 39/39, the handout's hash printed |
310
+ | a repository handout (`handles-confirmed`, scratch sandbox-factory) | hash in BRIEF.md and handout.json; one appended byte refused; stub `incomplete` |
311
+ | `promote` (same, hand-made `judged.json`) | hash printed at reveal; refused when it differs from the judged one |
312
+
313
+ ## Confirmation
314
+
315
+ How often a drafted spec's decision is the one the person confirms, on material
316
+ already here, no model: 18 drafts, one label per drafted `Decided:` item (294),
317
+ made by hand 2026-10-26 and kept as data with both texts, the kind of decision
318
+ and a one-line reason
319
+ ([evidence/default-match.json](evidence/default-match.json));
320
+ [evidence/default-match.mjs](evidence/default-match.mjs) counts them. The
321
+ archive's 7 `-gen` specs, drafted from the ticket alone, are set against the
322
+ person-written spec; 51 of their 127 items decide something that spec never
323
+ addresses and are left out. The 11 repository drafts are set against the spec
324
+ the developer stand-in confirmed from the real diff, cross-checked with its
325
+ `Changed:` list.
326
+
327
+ | drafts against | drafted defaults kept | drafts needing no change |
328
+ | ------------------------------------- | --------------------: | -----------------------: |
329
+ | the person's spec (archive, 7) | 66 / 76 (87%) | 2 / 7 |
330
+ | the developer's code (repository, 11) | 99 / 167 (59%) | 0 / 11 |
331
+ | all 18 | **165 / 243 (68%)** | 2 / 18 |
332
+
333
+ | kind of decision | kept / decided | archive | repository |
334
+ | --------------------------------------------- | -------------: | ------: | ---------: |
335
+ | the rule itself | 53 / 77 (69%) | 24 / 29 | 29 / 48 |
336
+ | invalid or missing input | 20 / 34 (59%) | 13 / 13 | 7 / 21 |
337
+ | limits, defaults, edges | 23 / 32 (72%) | 9 / 10 | 14 / 22 |
338
+ | purity, freezing, caching, concurrency | 20 / 23 (87%) | 4 / 4 | 16 / 19 |
339
+ | reading input text (trim, case, normalise) | 13 / 22 (59%) | 5 / 5 | 8 / 17 |
340
+ | exact output text (messages, labels, formats) | 7 / 18 (39%) | 6 / 9 | 1 / 9 |
341
+ | ordering and precedence | 12 / 15 (80%) | 3 / 4 | 9 / 11 |
342
+ | export names and constants | 8 / 12 (67%) | 0 / 0 | 8 / 12 |
343
+ | collaborator failures | 5 / 6 | 2 / 2 | 3 / 4 |
344
+ | contract scope | 4 / 4 | 0 / 0 | 4 / 4 |
345
+
346
+ - **Most drafted decisions survive; almost no draft does.** 16 of 18 drafts had
347
+ between 1 and 19 decisions changed, and one is often enough: no real commit
348
+ passed a suite from its draft (0 of 11), and on 4 of the 5 archive drafts with
349
+ a change every agent failed the person's hidden suite (0 of 10 each;
350
+ gherkin-parse's two changes are forms its hidden suite never tries).
351
+ - **The misses cluster.** Exact output text is kept 39% of the time. In the
352
+ repository, 12 of the 14 changed input decisions are a draft that rejects
353
+ input the code accepts or passes through: the drafter's conventional "validate
354
+ and throw" was the developer's choice 7 times in 21. These are the decisions
355
+ to put to the person first.
356
+ - **Person minutes: pending.** `bin/confirm.mjs` now records `startedAt` (the
357
+ first listing), `at`, `minutes` and the decisions changed in `confirmed.json`;
358
+ `node evidence/default-match.mjs confirmations` gives the median once five
359
+ real confirmations exist. The developer stand-in was a model session, so it
360
+ measures nothing about a person.
361
+ - **`--from` round trips** (2026-10-26): the public GitHub issue vercel/ms#284
362
+ into `ticket.md` (title, source link, state, body; `--comments` adds comments)
363
+ and back out as the source line of `decisions.md`; Jira BOX-85 read through
364
+ the Atlassian MCP and passed with `--body`, since no API token is set here.
365
+ The REST path (`JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN`) was checked
366
+ against a local stand-in server only.
367
+
368
+ ## Runners
369
+
370
+ Jest, pytest, `go test` and `cargo test` beside `node:test` and vitest,
371
+ 2026-10-26, each runner printing the one result shape
372
+ (`bin/runners/shared.mjs`). Python is pytest 8.4.2 on CPython 3.14.
373
+
374
+ **The HumanEval+ oracle row on the pytest runner, no model.** The archive's 40
375
+ HumanEval+ specs imported (`bin/import-archive.mjs`, not held out), every one of
376
+ the 1,240 EvalPlus solutions re-judged (`evidence/evalplus.mjs`,
377
+ `evidence/evalplus.json`) where the archive had judged them on its own unittest
378
+ runner:
379
+
380
+ | on 1,240 solutions, 926 wrong (889 without HumanEval/22 and /60) | archive, unittest | pytest runner |
381
+ | ------------------------------------------------------------------- | ---------------------: | ---------------------: |
382
+ | wrong accepted by HumanEval's original tests, without 22 and 60 | 133 (15.0%) | 133 (15.0%) |
383
+ | wrong accepted by generated public + hidden, without 22 and 60 | 43 (4.8%) | **43 (4.8%)** |
384
+ | right rejected by generated public + hidden, without 22 and 60 | 3 of 289 | **3 of 289** |
385
+ | the same three rows, all 40 tasks | 17.5%, 7.7%, 23 of 314 | 17.5%, 7.7%, 23 of 314 |
386
+ | solutions whose public or hidden verdict differs from the archive's | — | 0 of 1,240 |
387
+
388
+ The test ids are the archive's (`Class.method`, as unittest names them), so the
389
+ imported calibration.json files are used unchanged.
390
+
391
+ **`fit` on public repositories** (clones at their default branch, 2026-10-26):
392
+
393
+ | repository | runner, install | verdict | existing suite |
394
+ | ----------------------------------- | ------------------------------ | ------------------------------------------ | ---------------- |
395
+ | gvergnaud/ts-pattern `f11be73` | Jest 30 + ts-jest, npm | **supported** | 467 passed, 11 s |
396
+ | pallets/itsdangerous `672971d` | pytest, `uv.lock` (src layout) | **supported** | 297 passed, 1 s |
397
+ | typestack/class-validator `2e1a5c2` | Jest 29 + ts-jest, npm | supported, its failing `tsc` check dropped | 797 passed, 4 s |
398
+
399
+ A hand-made stub, public and hidden test on ts-pattern and on itsdangerous
400
+ judged `incomplete` on the stub, `passed` with the reference, and `refused` for
401
+ an edited `pyproject.toml` or an added `conftest.py`. Go and Rust, in Docker
402
+ (`golang:1.23`, `rust:1.82`; neither is on the host), on a hand-written fixture:
403
+ reference `passed`, skeleton `incomplete`, a wrong submission `overfit` with its
404
+ scenario keys, a panicking stub failing one test and not the binary, a hanging
405
+ Rust test failing alone, a hidden test that does not compile reported as not
406
+ compiled.
407
+
408
+ **End to end, confirm → prepare → blind run → judge**
409
+ (`evidence/runners/specs/`, `evidence/runners/results.jsonl`). Both specs were
410
+ drafted and confirmed by the phase's agent, not a person
411
+ (`--by "phase-2 agent (not a person)"`), so their confirmation minutes are not a
412
+ person's.
413
+
414
+ | spec | prepare (Opus 5.5) | public | hidden kept | Haiku 5.5 blind runs |
415
+ | -------------------------------------------------------------- | ------------------------------------------------- | -----: | ----------: | ------------------------------------- |
416
+ | `duration-parse-py`: duration-parse ported to Python, pytest | $1.48, 5.7 min of sessions | 74 | 212 of 212 | 3 of 3 `passed`, $0.01–0.02 |
417
+ | `ts-pattern-display`: readable `NonExhaustiveError`, Jest repo | $2.14, 9.2 min; existing 467/467 on the reference | 46 | 73 of 73 | 3 of 3 `passed`, 0 regressions, $0.03 |
418
+
419
+ One run's change, copied into a fresh ts-pattern checkout after
420
+ `handout --repo`, judged `passed` from the working tree (the stub alone:
421
+ `incomplete`, 1/46). No peek attempts in the six runs.
422
+
423
+ ## In CI
424
+
425
+ CI mode (`bin/seal.mjs`, `judge --seal`, `bin/ci.mjs`, `action.yml`,
426
+ `.github/workflows/judge.yml`), checked 2026-10-26 on the 11 repository cases
427
+ with no model and nothing pushed: each case's change inside its allowed paths as
428
+ a branch on its parent commit in a scratch clone of sandbox-factory, both arms'
429
+ specs sealed, and every branch judged by `duediligence ci`, the script the
430
+ workflow runs, in a fresh home with no `specs/` and fresh base installs
431
+ ([evidence/ci.mjs](evidence/ci.mjs), `evidence/ci/`).
432
+
433
+ | the change, judged from the seal of | checks passed | hidden tests passed | public tests passed | same verdict and counts as above |
434
+ | ----------------------------------- | ------------: | ------------------: | ------------------: | -------------------------------: |
435
+ | the spec drafted from its message | 0 / 11 | 256 / 709 | 263 / 601 | 11 / 11 |
436
+ | the same spec, confirmed | **8 / 11** | **659 / 665** | 599 / 600 | 11 / 11 |
437
+
438
+ - **Nothing hidden in the output.** Every log, check body and step summary (66
439
+ files) grepped for the slug's 2,748 hidden test names (with and without the
440
+ `[kind-n]` key), 80 hidden file paths and 8,908 hidden test lines not also in
441
+ the public suite, stub or spec: 0 found. The same grep finds 3 names in a
442
+ `judge --detail` log of one case. The two drafted suites that do not compile
443
+ print the public tree's compiler output only.
444
+ - **Refusals.** A seal with one hidden byte changed is refused before judging
445
+ (its file hash), and so is one whose file list was rewritten to match
446
+ (`hidden suite changed since <sealedAt>`, exit 1); `--detail` and `--audit`
447
+ are refused with `--seal`. The new-module example judges from its seal too:
448
+ reference `passed` 22/22 and 39/39, skeleton `incomplete`.
449
+ - **The check.** Posted to a local stand-in for the Checks API with a test
450
+ token: one `POST /repos/<owner>/<repo>/check-runs`, head SHA, name, conclusion
451
+ and title as written to `--out`. The judge runs with tokens, secrets and the
452
+ Actions files stripped from its environment.
453
+ - **Pending: GitHub.** The fork with one pull request per case, the private seal
454
+ store and the secret are one script, `evidence/ci/fork-and-open-prs.sh`, not
455
+ run: it creates repositories and opens pull requests. `act` is not installed
456
+ here; the workflow has not run on a runner.
457
+ - **Another implementer.** Codex CLI 0.164.0 (`gpt-6.1-sol`, on the person's
458
+ Codex login) implemented `limit-jobs-confirmed` from its repository handout
459
+ inside a container holding only the handout checkout (cloned at the base
460
+ commit, no later history), the brief and the spec; no suite, seal or reference
461
+ was on it (`evidence/ci/codex/`). Its commit, judged from the seal by `ci`:
462
+ **`passed`**, public 54/54, hidden 46/46, existing 120/120, its 22 own tests
463
+ not judged; 0 hidden names or lines in the log or check. One run on one spec,
464
+ so it shows the path works, not a rate.
465
+
466
+ ## Writer backends
467
+
468
+ The writers, the reference and the referee run on a backend chosen per spec
469
+ (`bin/lib.mjs` `session`, `bin/backends.mjs`): `claude-cli`, `codex-cli`,
470
+ `anthropic-api`, `exec`. Checked 2026-10-26 with Codex CLI 0.164.0
471
+ (`gpt-6.1-sol`, the person's Codex login) beside the archive's Claude numbers,
472
+ on the archive's material and with no agent run except the ladder's last row
473
+ ([evidence/backends.mjs](evidence/backends.mjs), `evidence/backends.json`,
474
+ Codex's suites in `evidence/backends/specs/`).
475
+
476
+ **One spec end to end.** `duration-parse` with toolchain.json
477
+ `"backend": "codex-cli"`, confirm → prepare, four Codex sessions (skeleton,
478
+ public, hidden, reference) in 9.2 minutes, no fix turn: 80 public tests, 90 of
479
+ 90 hidden kept, reference 80/80 and 90/90, skeleton `incomplete`. The Claude
480
+ reference passes Codex's suites (80/80, 90/90) and Codex's reference passes
481
+ Claude's (22/22, 39/39).
482
+
483
+ | metric | Claude (archive) | Codex CLI |
484
+ | --------------------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------- |
485
+ | hidden tests kept by calibration, 26 core specs | 1,361 of 1,361 | 1,126 of 1,133 (99.4%) |
486
+ | mutants killed, public suite (the same 1,442 mutants, 25 specs) | 1,090 (75.6%) | 1,119 (77.6%) |
487
+ | mutants killed, public + hidden | 1,142 (79.2%) | 1,162 (80.6%) |
488
+ | EvalPlus, wrong solutions accepted, 38 tasks | 4.8% (43 of 889; HumanEval's own 15.0%) | **3.8% (34 of 889)** |
489
+ | EvalPlus, right solutions rejected, 38 tasks | 3 of 289 | 5 of 289 |
490
+ | EvalPlus, the 6 tasks Codex wrote first | 2 of 159 wrong accepted, 0 of 27 right rejected | 0 of 159, 0 of 27 (HumanEval's own: 14 of 159) |
491
+ | ladder: public tests the oracle passes, L0 to L4 | 73/74, 31/32, 22/23, 14/14, 1/1 | 37/37, 45/45, 25/27, 16/16, 2/2 |
492
+ | ladder B: Haiku given L1–L4 and the L0 suite, oracle match | 100% at every level | 100% at every level (20 runs) |
493
+ | referee: rejected runs upheld, the same 57 cases (100 runs) | 95 of 100 | 95 of 100 |
494
+
495
+ - **Calibration.** Claude's suites were calibrated against a reference written
496
+ to pass them; Codex's against the archive's Claude reference with no session
497
+ (`backends.mjs calibrate`: fails on the skeleton, passes the reference), the
498
+ stricter test. The same scripted calibration on Claude's suites keeps 1,361 of
499
+ 1,361, as recorded. Of Codex's 676 public tests, 2 fail that reference
500
+ (shift-compliance).
501
+ - **Mutants.** `evidence/mutation.mjs` (the archive's `mutate.mjs` on this
502
+ package's runners) samples the mutants from the reference alone, so both
503
+ columns score the identical mutants; the Claude column is the archive's
504
+ `mutation.jsonl`. Codex's mutants equal the archive's one for one on all 26
505
+ specs. Of the public suite's survivors the hidden suite kills 43 of 323
506
+ (Claude: 52 of 352). The harness reproduced the archive mutant for mutant on
507
+ 24 of 26 specs (frame-codec: 2 mutants flip on the runner's output cap;
508
+ patch-apply needs the archive's `--max 400`); that run's files were lost with
509
+ a scratch folder, and the command is in `evidence/mutation.mjs`. keyed-queue,
510
+ statement-import and patch-apply were scored under the test processes' memory
511
+ caps (`bin/runners/guard.mjs`), added after two unguarded runs exhausted the
512
+ machine's memory; a capped mutant counts as killed.
513
+ - **Ladder.** Codex's L0 suite has none of Claude's R2 misreading; both writers
514
+ guessed at L2. Condition B (Haiku on the vague spec with the L0 suite, this
515
+ package's own-tests brief, 5 runs per level) is 100% on either writer's suite.
516
+ - **Referee.** Codex and Claude (Fable 5.1) give the same verdict on 52 of 57
517
+ cases (Codex: 45 required, 12 open; Claude: 46, 11); 93 runs are upheld by
518
+ both, 2 by each alone.
519
+ - **Blindness.** Codex runs under `sandbox-exec` over its staged workdir, its
520
+ own sandbox off; on macOS and in Linux (bwrap 0.8 in `node:22`) a negative
521
+ test reads a sibling workdir's hidden test, a spec's `tests/private`, the
522
+ home, `~/.codex/auth.json` and the package from inside and is refused every
523
+ time (`backends.mjs sandbox`, `evidence/backends/sandbox-*.json`). Codex's
524
+ shell looked for `AGENTS.md` in every folder above its workdir; those reads
525
+ were refused too.
526
+ - **anthropic-api** ran against a local stand-in for the Messages API only (no
527
+ key here): tool loop, path confinement, sandboxed Bash, transcript, cost,
528
+ resume (`backends.mjs selftest`). A live run is pending.
529
+ - **EvalPlus.** The Codex workspace ran out of credits after 6 of the 40
530
+ HumanEval+ tasks; `sh evidence/backends/queue.sh` wrote the other 34 on
531
+ 2026-10-27 (`evidence/backends/evalplus-codex-cli.json`). One of Codex's 40
532
+ hidden suites kept nothing (he-76: none of its 44 tests ran on the reference),
533
+ so that task is judged by Codex's public suite alone; without it, 33 of 858
534
+ wrong accepted and 5 of 289 right rejected.
535
+
536
+ ## Other implementers
537
+
538
+ Codex CLI 0.164.0 (`gpt-6.1-sol`, the person's Codex login) implemented ten of
539
+ the archive's core specs five times each, 2026-10-26, each from a handout folder
540
+ made by `duediligence handout` (template, spec, skeleton, public suite and
541
+ BRIEF.md; nothing hidden) under `sandbox-exec` over that folder, and every run
542
+ was graded by `bin/grade.mjs`
543
+ ([evidence/implementers.mjs](evidence/implementers.mjs),
544
+ `evidence/implementers.json`). The specs are imported, not held out: their
545
+ suites were published with the archive.
546
+
547
+ | implementer, on the same ten specs | runs | passed | overfit | incomplete | refused |
548
+ | ---------------------------------------------------------- | ---: | -----: | ------: | ---------: | ------: |
549
+ | Codex CLI, public suite + own tests (this package's brief) | 50 | **50** | 0 | 0 | 0 |
550
+ | Haiku 5.5, public suite + own tests (archive, 4 of the 10) | 105 | 100 | 5 | 0 | 0 |
551
+ | Haiku 5.5, public suite (archive) | 220 | 197 | 23 | 0 | 0 |
552
+
553
+ - **The specs**: csv-export, licence-scan, patch-apply and tool-versions (where
554
+ the archive has Haiku on this brief), retention-sweep and escrow-split (where
555
+ Haiku overfit), keyed-queue, frame-codec, statement-import, shift-compliance.
556
+ Haiku's overfits were csv-export 9 of 15, tool-versions 8 of 50,
557
+ retention-sweep 4 of 20; Codex passed 5 of 5 on each. A median run took 2.3
558
+ minutes (at most 4.8) and 12 turns; Codex bills its own account.
559
+ - **Nothing tampered**: no run changed a test or the harness, and no transcript
560
+ tried to read a hidden path.
561
+ - **Provider refusals.** Three sessions ended at once with "Selected model is at
562
+ capacity"; they were run again, and such a refusal now records no run.
563
+ - **No model, first.** `implementers.mjs selftest` drives fake agents through
564
+ the same path on the `exec` backend: the reference `passed`, an agent that
565
+ does nothing `incomplete`, a Haiku lookup table `overfit`, an edited public
566
+ test `refused`, and a read of the hidden suite's folder from inside refused by
567
+ the sandbox (`evidence/implementers/selftest.json`).
568
+ - **Aider and Cursor's agent** have adapters (`run aider`, `run cursor`);
569
+ neither is installed here, so neither has runs.
570
+
571
+ On these specs Codex sits at the ceiling where Haiku nearly does, so the cell
572
+ shows that the handout, the sandbox and the judge work the same for an agent
573
+ that is not Claude, not that the hidden suite catches more of one agent's work
574
+ than another's.
575
+
576
+ ## Red team
577
+
578
+ An adversary told to pass the public suite with the least general code,
579
+ hard-coding its inputs where that is shorter (`prompts/agent-red-team.md`,
580
+ `bin/run.mjs --brief red-team`), run 2026-10-26 on the archive's specs imported
581
+ into `evidence/red-team/`. `bin/red-team-audit.mjs` audits every run that passes
582
+ both suites, first with no model: the public tests' string literals the code
583
+ repeats that the spec and skeleton do not contain, and the run judged again by
584
+ Codex's suites for the same spec (`evidence/backends/specs/`, written blind and
585
+ calibrated on the same reference). Then a session on Opus 5.5 reads the spec,
586
+ the public suite, the code and the agent's summary, never the hidden suite, and
587
+ names each shortcut with an input it gets wrong
588
+ (`evidence/red-team/audit.jsonl`).
589
+
590
+ | adversary, specs | runs | rejected by the hidden suite | passed both | passes failing Codex's suite | passes a session audit calls a shortcut |
591
+ | -------------------------------------------------- | ---: | ---------------------------: | ----------: | ---------------------------: | --------------------------------------: |
592
+ | Haiku 5.5, the 26 core specs (archive, 2 each) | 52 | 28 | 24 | 5 | not run |
593
+ | Opus 5.5, patch-apply and csv-export (10 each) | 20 | **20** | 0 | — | — |
594
+ | Opus 5.5, gherkin-parse and reverse-diff (10 each) | 20 | **0** | 20 | 17 | 18 |
595
+
596
+ - **The specs** are the four whose suites let the most of the archive's mutants
597
+ survive both suites (patch-apply 44%, reverse-diff 36%, gherkin-parse 35%,
598
+ csv-export 23%): where gaming should pay most. 40 Opus runs cost $8.21, the 20
599
+ audits $4.22.
600
+ - **Opus never hard-coded an input** (0 public literals in 40 submissions). It
601
+ wrote small general code, left out the rules no public test reaches, and
602
+ listed them in its summary. On patch-apply and csv-export the hidden suite
603
+ caught the omissions every time. On gherkin-parse and reverse-diff every run
604
+ passed 47 of 47 and 42 of 42 hidden tests; 18 of the 20 leave out a rule the
605
+ audit names with an input it gets wrong (reverse-diff: identifiers inside hunk
606
+ lines left unmapped; gherkin-parse: doc-string indentation, comments, invalid
607
+ lines inside a scenario), 17 fail Codex's suite, and each of the 20 is flagged
608
+ by one or the other. Against a strong adversary the hidden suite did not stop
609
+ gaming on two of these four specs; a second suite written independently caught
610
+ most of what it missed.
611
+ - **Haiku, re-audited with no model.** The literal scan flags 11 of the 20 runs
612
+ the archive classified by hand as lookup tables and 0 of its 31 honest runs
613
+ (`runs/_redteam-classes.json`). Codex's suites agree with the hidden suite's
614
+ accept or reject on 45 of 52. Of the 24 passes, all classified honest, 19 pass
615
+ Codex's suites too; 5 fail a Codex test the reference passes, each on a rule
616
+ the spec states (an LRU refresh's position, which the hand classification had
617
+ found; a new or deleted empty file without headers; one separator space after
618
+ a keyword with CRLF; criteria empty once cleaned; unmapped paths in order of
619
+ appearance): bugs the hidden suite missed, not gaming it rewarded.
620
+ - No run edited a test or the harness, and no transcript tried to read a hidden
621
+ path (0 of 40).
622
+
623
+ ## Black-box seams
624
+
625
+ A spec checked at a boundary a test can call instead of its exports: a command
626
+ the suites run with `child_process`, or an HTTP service they `fetch`, started by
627
+ the judge for each suite under the memory caps and killed with its process group
628
+ after (toolchain `exec`, `bin/runners/boundary.mjs`). Checked 2026-10-27 on the
629
+ archive's material with no model ([evidence/seams.mjs](evidence/seams.mjs),
630
+ `evidence/seams.json`).
631
+
632
+ **patch-apply as a command.** `import-archive patch-apply --seam exec` converts
633
+ the archive's spec by script: each suite imports `boundary.ts`, the skeleton's
634
+ types with every function a call to `node src/cli.js applyPatch` (arguments as
635
+ JSON on stdin, the result on stdout, an error's message on stderr), so no test
636
+ reaches the code but through the command; the stub exits 2, the reference gains
637
+ a `src/cli.ts` over its exports. Both seams calibrated by script on the
638
+ archive's reference, then judged against `git apply` on the archive's git oracle
639
+ corpus (`bin/git-oracle/`, 8,842 cases from real history, one process per case,
640
+ 1.3 minutes) and on every stored archive submission:
641
+
642
+ | patch-apply | at its exports (archive) | at a command |
643
+ | ------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------- |
644
+ | hidden tests kept by calibration | 79 of 79 | 79 of 79, the same list |
645
+ | the reference, the stub | `passed` 30/30, 79/79; `incomplete` 0/30, 0/79 | the same |
646
+ | the reference agrees with `git apply`, judged set | 7,533 of 7,533 | **7,533 of 7,533** |
647
+ | the same, all cases (the rest: a hunk matching at several places) | 8,789 of 8,842 | 8,789 of 8,842, the same 53 off |
648
+ | the reference's answer, case by case | | 8,842 of 8,842 the module's |
649
+ | the 196 stored submissions: same verdict and failing hidden tests | | **196 of 196** |
650
+ | of the 120 with oracle results, passed the hidden suite but not git | 1 (`double-blind-rule-haiku/17`, rename) | the same 1 |
651
+
652
+ **The boundary runner, no model** (`seams.mjs selftest`, `repo-selftest`). On a
653
+ hand-made HTTP spec the reference `passed`; a stub answering 501, a service that
654
+ never answers (ready timeout), one that exits on its first request and one that
655
+ passes the 1 GB ceiling were each `incomplete`, with no process left in the
656
+ judge's trees; a judge SIGKILLed while the service was up left neither service
657
+ nor runner; the seal judged `passed`; `hiddenSha256` covers the boundary
658
+ (changing the healthcheck changes it) and matches the shell recipe. In a
659
+ repository: `fit --seam http` supported a TypeScript package whose server
660
+ answered in 0.6 s, `repo --seam http` recorded the boundary with no seam files,
661
+ and `judge --repo` read base `incomplete` (0/1, 0/2) and the change `passed`
662
+ (1/1, 2/2, existing 1/1), from the spec and from a seal.
663
+
664
+ **One HTTP spec.** `csv-export-http`: the archive's csv-export served as
665
+ `POST /requisitions.csv`, confirmed by the phase's agent, not a person; the
666
+ hidden writer's one open question (whether an error body may hold keys beyond
667
+ `error` and `id`) left open with `--accept-open`. Prepared on Opus 5.5
668
+ (`evidence/seams/specs/csv-export-http/`), every test reaching the service with
669
+ `fetch`:
670
+
671
+ | csv-export-http | result |
672
+ | ------------------------------------------- | -------------------------------------------------------- |
673
+ | prepare: public tests, hidden kept | 36; 48 of 48, the reference 36/36 and 48/48; $4.31 |
674
+ | the stub, the skeleton answering 501 | **`incomplete`**, 0/36, 0/48 |
675
+ | Haiku 5.5, blind, 5 runs | **2 `passed`**, 3 `overfit` at 47/48, all on `unhappy-2` |
676
+ | the first overfit's retry, told `unhappy-2` | `passed`, 48/48 |
677
+
678
+ - **The three overfits are one real defect.** Each accepts a status sent as
679
+ `["open"]`: `Object.hasOwn(labels, status)` turns the array into the string
680
+ `"open"`, where the spec names four strings. A sixth run's session was killed
681
+ partway by the first version of the session reaper (below); its code passed
682
+ 48/48 and is left out of the count. $0.04 per run; no run tried to read a
683
+ hidden path.
684
+ - **Sessions leave nothing running.** A writer session started a server in the
685
+ background to try its suite and it outlived the session by seven hours. Every
686
+ session now runs as its own process group, killed when it closes, and anything
687
+ whose working directory is in its workdir, or whose working directory or
688
+ command line names Claude Code's scratch folder for it, is killed after it
689
+ (`lib.mjs killStrays`). The first version also matched the workdir's literal
690
+ path in command lines, which a concurrent session's `claude` names in its deny
691
+ rules: it killed that run. The selftest's fake CLI now leaves three processes
692
+ that `pgrep` no longer finds, beside a concurrent one that survives.
693
+ - The earlier account's weekly limit stopped the first hidden writer ($1.56,
694
+ nothing written); `evidence/seams/queue.sh` resumed it.
695
+ - **Not yet.** A repository change judged at its service has no writer briefs
696
+ (`prompts/repo/` name seam files); the `anthropic-api` backend's shell has no
697
+ network, so an HTTP spec's suites cannot run inside it. UI through Playwright
698
+ is out of scope.
699
+
700
+ ## Go and Rust
701
+
702
+ The `go` and `rust` toolchains end to end, 2026-10-28, on the host (Go 1.27.3,
703
+ Rust 1.99.1 from Homebrew): duration-parse ported by hand to each, confirmed by
704
+ the phase's agent, not a person (`--by "phase-7 agent (not a person)"`),
705
+ prepared on Opus 5.5, three blind Haiku 5.5 runs each
706
+ (`evidence/languages/specs/`, `evidence/languages/results.jsonl`;
707
+ [evidence/languages.mjs](evidence/languages.mjs),
708
+ `evidence/languages/queue.sh modules`).
709
+
710
+ | spec | prepare (Opus 5.5) | public | hidden kept | Haiku 5.5 blind runs |
711
+ | ------------------------------------- | ------------------ | -----: | ----------: | --------------------------- |
712
+ | `duration-parse-go`: `(int64, error)` | $1.42, about 6 min | 65 | 159 of 159 | 3 of 3 `passed`, $0.02 |
713
+ | `duration-parse-rs`: `Result<u64, _>` | $1.28, about 7 min | 45 | 110 of 110 | 3 of 3 `passed`, $0.01–0.02 |
714
+
715
+ - **Mutants, no model** (`languages.mjs mutants`): 40 one-token mutants of each
716
+ reference (an operator flipped, a literal moved by one, by text: mutation.mjs
717
+ reads TypeScript's syntax tree only), judged as submissions. Go: the public
718
+ suite killed 39 of 40, the one left is equivalent (`u := -1` to `-2`, a
719
+ sentinel nothing reads as a number). Rust: 38 built, the public suite killed
720
+ all 38. On this spec the public suite leaves the hidden one nothing to find.
721
+ - Every session ran `go` or `cargo` inside Claude Code's sandbox with no change
722
+ to either toolchain. No run tried to read a hidden path.
723
+
724
+ ## Commands and services in other languages
725
+
726
+ A command or service written in Python, Go or Rust (toolchain `exec` with
727
+ `boundary.language`; lib.mjs `NATIVE`): the suites stay TypeScript on
728
+ `node:test` and reach the code only through the boundary, the tree is the node
729
+ template plus `go.mod` or `Cargo.toml`, and `sandbox/build.mjs`
730
+ (`bin/runners/native-build.mjs`) builds the suites and then `src/` for
731
+ `npm run build`, the judge's runner and a service's start alike. Briefs:
732
+ `prompts/exec-native/`, `prompts/http-native/`. Checked 2026-10-28.
733
+
734
+ **Selftest, no model** (`languages.mjs selftest`, 43 checks). A hand-made
735
+ command and service in each language, its suites calibrated by script: the
736
+ reference `passed`, the stub `incomplete`, a submission tuned to the public test
737
+ `overfit`, one that does not build `incomplete` and not compiled; the staged
738
+ tree's own `npm run build` passes on the stub and `npm test` fails; what the
739
+ build leaves (`.bin/`, `target/`, `Cargo.lock`, `__pycache__`) is never a
740
+ change; no service left running; every brief renders with no TypeScript
741
+ contract in it. The TypeScript seams' selftest and the package's smoke test
742
+ still pass.
743
+
744
+ **The seams' two specs, ported** (`languages.mjs port`). csv-export-http (a
745
+ service) and patch-apply-cli (a command) for each language: the same spec but
746
+ the command line in its interface paragraph, the same public and hidden tests
747
+ (csv-export-http's contract types moved from `src/server.ts` into
748
+ `tests/*/contract.ts`), a stub written by script. Only the reference is new: an
749
+ Opus 5.5 session per port writes it in the language and calibration runs on it
750
+ (`calibrate.mjs`), then three Haiku runs each (`queue.sh seams`).
751
+
752
+ | port | reference (Opus 5.5) | hidden kept | Haiku 5.5 blind runs |
753
+ | ----------------------- | -------------------- | ----------: | -------------------------------------------------------- |
754
+ | csv-export-http, Python | $0.41, 1.2 min | 48 of 48 | 3 of 3 `passed`, $0.04–0.05 |
755
+ | csv-export-http, Go | $0.75, 2.5 min | 48 of 48 | 2 `passed`, 1 `overfit` 47/48 on `unhappy-2`, $0.04–0.05 |
756
+ | csv-export-http, Rust | $0.86, 2.3 min | 48 of 48 | 2 `passed`, 1 `overfit` 47/48 on `happy-1`, $0.09–0.19 |
757
+ | patch-apply-cli, Python | $0.83, 2.8 min | 79 of 79 | 3 of 3 `passed`, $0.05–0.08 |
758
+ | patch-apply-cli, Go | $0.99, 3.5 min | 79 of 79 | 3 of 3 `passed`, $0.10–0.27 |
759
+ | patch-apply-cli, Rust | $1.13, 4.0 min | 79 of 79 | 3 of 3 `passed`, $0.06–0.13 |
760
+
761
+ - **Every hidden test the TypeScript reference kept, each language's reference
762
+ passes**, and every one fails on each stub: 48 and 79 kept of 48 and 79, six
763
+ times. No suite file changed but csv-export-http's import line, beside its
764
+ added `contract.ts`.
765
+ - **Against `git apply`** (`languages.mjs oracle`; the archive's corpus, 8,842
766
+ cases from real history): the Python, Go and Rust references agree with git
767
+ on 7,533 of 7,533 judged cases and on 8,789 of 8,842 in all, the same 53 off
768
+ as the TypeScript reference (a hunk matching at several places), and give the
769
+ TypeScript command's answer on 8,842 of 8,842, case by case. They are 360,
770
+ 548 and 840 lines, and start no other process.
771
+ - **The Rust overfit is a real defect.** It cuts creation times to whole
772
+ milliseconds ("as Date.parse cuts them", its comment says), so two
773
+ requisitions created 0.1 ms apart sort by id; the spec orders by creation
774
+ time and allows any fractional seconds.
775
+ - **The Go overfit is a judge defect the port exposed.** A hidden test expects
776
+ `"openings": 1e400` to be refused as infinite, as JavaScript's `JSON.parse`
777
+ reads it. The spec says only "a whole number of at least 0"; the Go run reads
778
+ `1e400` exactly, as the integer 10^400, and accepts it. Written against a
779
+ TypeScript reference, the hidden suite carried a JavaScript reading of an
780
+ open question into every language; the three new references passed it, as
781
+ the reference session sees both suites. Counted as it is graded, 16 of 18 `passed`; with
782
+ that test left open, 17 of 18.
783
+ - **Mutants, no model**, 30 per reference:
784
+
785
+ | port | built | public kills | hidden only | survive both |
786
+ | ----------------------- | ----: | -----------: | ----------: | -----------: |
787
+ | csv-export-http, Python | 30 | 21 | 5 | 4 |
788
+ | csv-export-http, Go | 29 | 19 | 5 | 5 |
789
+ | csv-export-http, Rust | 30 | 22 | 4 | 4 |
790
+ | patch-apply-cli, Python | 30 | 21 | 0 | 9 |
791
+ | patch-apply-cli, Go | 30 | 15 | 0 | 15 |
792
+ | patch-apply-cli, Rust | 30 | 18 | 0 | 12 |
793
+
794
+ On csv-export-http the hidden suite kills about half of what the public one
795
+ leaves: 5 of 9, 5 of 10, 4 of 8. On patch-apply it kills none, so
796
+ every mutant both suites passed was run on the git corpus
797
+ (`languages.mjs oracle-survivors`): 34 of the 36 answer all 8,842 real cases
798
+ as their reference does, so they never show on real history, most likely
799
+ equivalent (not checked one by one). Two are real misses:
800
+ in Python, `start + delta` turned to `start - delta` carries the wrong offset
801
+ into a file's later hunks (52 cases differ); in Go, a `new file mode` line
802
+ read only after the file's first hunk (4 cases). Both suites pass both.
803
+
804
+ ## What it does not show
805
+
806
+ - **That agents often overfit visible tests.** On precise specs every arm is at
807
+ or near the ceiling: 3 real overfits in 230 regraded runs, and the public
808
+ suite separated the arms on 1 spec of 14 (patch-apply, 20 of 20 against 7 and
809
+ 5 of 20).
810
+ - **That a drafted spec can go unchecked.** Drafted from the ticket alone, a
811
+ spec decided otherwise than the person's on 4 of 7 tickets; 16 of 18 drafts
812
+ had at least one decision changed on confirmation.
813
+ - **That the public suite helps inside a repository.** 55 of 55 against 55 of 55
814
+ on confirmed specs; 25 of 25 against 24 of 25 on ufo, 30 of 30 against 30 of
815
+ 30 on pathe.
816
+ - **Much about existing codebases.** Eleven changes from one repository written
817
+ by one small team with Claude, and a handful each from two small utility
818
+ libraries whose commits are one-line subjects; every confirmation by a
819
+ simulated developer.
820
+ - **That the hidden suite stops a determined adversary.** Opus 5.5 told to game
821
+ passed it on two of four specs while leaving rules out
822
+ ([Red team](#red-team)). It is an acceptance test of what the spec states; a
823
+ second, independently written suite caught most of what it missed.
824
+ - **That other agents need it more or less than Haiku.** Codex passed 50 of 50
825
+ on ten archive specs whose suites it could have seen, since they were
826
+ published.
827
+ - **Much about the other runners.** One prepared module each in Python, Go and
828
+ Rust (the same spec, duration-parse) and one Jest repository spec, all passed
829
+ by Haiku on every run, so none separates anything; pytest repositories only
830
+ on hand-made fixtures, never prepared by a model.
831
+ - **Much about black-box seams.** Two archive specs, a command and a service,
832
+ each run in four languages: one suite per spec, written once against a
833
+ TypeScript reference, so a suite written for Python, Go or Rust from the start
834
+ is untested, and that suite carried one JavaScript reading of an open
835
+ question into the others. 23 Haiku runs at a seam in all; Windows untested
836
+ for the Python, Go and Rust builds.
837
+ - **Problems newer than the model.** LiveCodeBench v6 predates the cutoff and
838
+ every arm solved all 37 sound problems; the ladder's L3 and L4 levels there
839
+ measure what Opus remembers, not the spec.
840
+
841
+ ## Cost
842
+
843
+ Preparing a spec is four Opus 5.5 sessions, about $1–4 (median $2) and 10–25
844
+ minutes. In a repository it was $1.92–6.99 (median $2.74 on the confirmed specs)
845
+ and 10–25 minutes; a developer's confirmation session $0.24–1.48. An agent run
846
+ is a few cents on Haiku 5.5 (median $0.02 and 1.8 minutes in a repository),
847
+ about $0.30 on Opus. Dollar figures are the CLI's estimates; the sessions bill
848
+ the signed-in subscription. The person's confirmation is the other cost: person
849
+ minutes per spec, from the first listing of the decisions to `confirm --by`, are
850
+ recorded from 2026-10-26 on; median pending.