Skip to content

Commit 7622a3b

Browse files
committed
P-022 Stage 3: COMPLETE — reconcile at the terminal candidate
Terminal candidate f1d3681, qualified by run 35312190310: 31/31 jobs green, 0 failures. Every Stage-3 predicate is confirmed on THAT commit rather than assembled from earlier ones -- both Stage-1 control legs, both packed-artifact legs, both dogfood legs, the Windows-native and Stage-2 Windows campaigns, own-check.ps1's exit-code tiers, both shadow-compare gates, the Rust-default code-scanning dogfood, rust fmt/clippy/tests, and the Python suite on 3.11/3.12/3.13. public default Rust on owen / own-check.sh / own-check.ps1 / Action rollback explicit --engine python, tested, four states distinct silent fallback none compare zero acceptance-unexplained Linux packed path PASS Windows packed path PASS Windows rollback PASS Windows cancellation PASS Stage-1 campaign 21/21 Stage-2 campaign 11/11 Windows campaign 9/9 checkpoint gate green decision packet zero OWED rows performance DEFERRED BY OWNER, #263 open Stage 4 NOT STARTED The three qualification findings are recorded as DEFECTS FOUND AND CLOSED, not as known differences. That distinction is the point: after the fixes they are not permitted Stage-3 behaviour. They also form one sequence worth seeing whole -- an invocation that could reach no engine, a capture that captured nothing, and an assertion that passed BECAUSE the capture was empty -- each of which looked perfectly respectable alone, and all three of which were invisible while Python was the default. PS1-NOTMATCH-ASSERTION is scoped precisely rather than loosely, because the loose version would be untrue: it is the WINDOWS STAGE-2 DOGFOOD'S OWN001 OUTPUT-OBSERVATION assertion that had never constituted evidence on the Rust path. The other Stage-2 controls and the actual Rust-default execution (exit code, no-fallback, candidate identity) remain separately evidenced. Stage 2 as a whole is not being called unproven. Governance hand-off, recorded on the decision surface: P-037 A1 PRODUCTION GATE: BLOCKED BY DESIGN -> UNBLOCKED A1 is NOT started here and not in this PR. It begins on a new branch from the Rust-default baseline, so that nobody has to work out later whether the first ConsumesParam change belonged to the Rust migration or to a new inference feature. Refs #262, #250 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01376o4syzCem5aQ6NssxwX2
1 parent f1d3681 commit 7622a3b

4 files changed

Lines changed: 118 additions & 7 deletions

File tree

‎docs/evidence/p022-stage3-cutover.json‎

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"schema": 1,
33
"comment": "GENERATED-BY-HAND ledger of the #262 Stage-3 cutover measurements, ENFORCED by tests/test_stage3_packet.py and rendered into docs/generated/p022-stage3-packet.md by scripts/stage3_packet.py. Every row names WHAT was asked, WHERE it was taken and WHAT it returned, and carries an evidence label. A row whose platform is 'windows' and whose result is 'OWED' is exactly that: not measured yet, never a prediction from the Linux row beside it. The packet is derived from this file and never typed.",
44
"stage": "P-022 Stage 3 — public Rust-default cutover",
5-
"candidate_sha": "2ecf5017a89242dd64c6f420eedac6452b130ce0",
5+
"candidate_sha": "f1d3681e96e31bba7a36dda09967d0af7c3e9b56",
66
"owner_ruling_performance": "Performance evidence is deferred by owner for the Stage-3 public-default decision. Stage 3 makes no performance claim. #263 remains required before any published/reproducible performance claim and remains the performance-baseline tracker.",
77
"deferred_fields": {
88
"startup_delta": "DEFERRED BY OWNER — NOT MEASURED",
@@ -144,6 +144,14 @@
144144
"label": "MEASURED OBSERVATION",
145145
"method": "CI job `owen --engine (#262 Stage 1 controls)` on windows-latest (run 35304488082, job 105473759377, at 2ecf501); https://github.com/PhysShell/Own.NET/actions/runs/35304488082",
146146
"result": "19 controls passed, 0 failed, 0 skipped, 1 not applicable (a non-executable candidate cannot be constructed for the shell surface under git-bash). Includes default-is-rust, unset-locator-is-d6, rust-failure-no-fallback and an unexpected child status mapped to public exit 5 with the raw WINDOWS-NATIVE status (-1073740791) retained. The job as a whole went red on a HARNESS defect in the Stage-3 rollback control that ran after these, not on any of them"
147+
},
148+
{
149+
"id": "terminal-ci",
150+
"question": "does the whole matrix pass on the terminal candidate?",
151+
"platform": "n/a",
152+
"label": "MEASURED OBSERVATION",
153+
"method": "CI run 35312190310 at f1d3681e96e3; https://github.com/PhysShell/Own.NET/actions/runs/35312190310",
154+
"result": "31/31 jobs green. Includes both Stage-1 control legs, both packed-artifact legs, both dogfood legs, the Windows-native and Stage-2 Windows campaigns, own-check.ps1's exit-code tiers, both shadow-compare gates, the Rust-default code-scanning dogfood, rust fmt/clippy/tests and the Python suite on 3.11/3.12/3.13"
147155
}
148156
],
149157
"known_differences": [
@@ -228,5 +236,38 @@
228236
"url": "https://github.com/PhysShell/Own.NET/actions/runs/35307467735",
229237
"result": "30/31 jobs green. The single failure was own-check.ps1's exit-code tiers, which caught the PS1-CAPTURE regression above -- a real defect in the product surface, not a harness fault. Reproduced locally on pwsh (it is not Windows-specific; the Windows job is simply the only place own-check.ps1 is exercised with output capture), fixed, and re-qualified."
230238
}
239+
},
240+
"stage_3_status": "COMPLETE",
241+
"terminal_run": {
242+
"sha": "f1d3681e96e31bba7a36dda09967d0af7c3e9b56",
243+
"run": "https://github.com/PhysShell/Own.NET/actions/runs/35312190310",
244+
"result": "31/31 jobs green, 0 failures, 0 non-success",
245+
"comment": "The terminal qualification run. Every Stage-3 predicate is confirmed on THIS commit rather than assembled from earlier ones."
246+
},
247+
"defects_found_and_closed_during_qualification": {
248+
"comment": "Recorded here and NOT under known_differences, which is the distinction that matters: after the fixes these are not permitted Stage-3 behaviour. Each was invisible while Python was the default, and each was found by the qualification round rather than by review.",
249+
"items": [
250+
{
251+
"id": "PS1-CAPTURE",
252+
"what": "own-check.ps1's Rust branch spawned a child that inherited the console handle, bypassing PowerShell's pipeline, so `$out = & ./scripts/own-check.ps1 ...` captured NOTHING while the text still appeared on screen. The Python branch uses the call operator and was unaffected.",
253+
"closed": "streams redirected and replayed -- stdout to the pipeline, stderr to the error stream, UTF-8 with no BOM, both pipes drained concurrently. Measured: both engines now capture the same single OWN001 line, identically; exit tiers unchanged; SARIF 1413 bytes, no BOM, one result from either engine."
254+
},
255+
{
256+
"id": "PS1-NOTMATCH-ASSERTION",
257+
"what": "the Windows Stage-2 dogfood step asserted `$out -notmatch 'OWN001'`. On an ARRAY PowerShell's -notmatch is a FILTER, not a boolean. SCOPE, stated precisely: it is the Windows Stage-2 dogfood's OWN001 OUTPUT-OBSERVATION assertion that had never constituted evidence on the Rust path -- before the capture repair it received $null, and filtering an empty collection is falsy, so it passed on an empty capture. The other Stage-2 controls and the actual Rust-default execution (exit code, no-fallback, candidate identity) remain separately evidenced; this is NOT a claim that Stage 2 as a whole was unproven.",
258+
"closed": "rewritten as `-not ($out -match 'OWN001')`, the idiom the rest of the file uses. Measured correct in both directions: no throw on the real 166-line capture (137 OWN001 lines), throw on an empty capture. Only instance in any workflow. Confirmed passing on windows-latest at the terminal run."
259+
},
260+
{
261+
"id": "CI-SURFACES-HOLLOW",
262+
"what": "five CI steps injected a broken or crashing Python and then invoked a launcher BARE; after the cutover a bare invocation never consults OWEN_PYTHON, so the injected fault could not happen and each step would have passed vacuously. Two further call sites lived inside scripts rather than workflow YAML.",
263+
"closed": "each step now names the engine it is actually about, and tests/test_stage3_surfaces.py asserts the property over every workflow AND script -- 63 invocations over 26 files -- with all of its own escape hatches mutation-proved shut."
264+
}
265+
]
266+
},
267+
"p037_a1_gate": {
268+
"before": "BLOCKED BY DESIGN — the P-022 freeze on verdict-changing inference held until the cutover completed",
269+
"after": "UNBLOCKED",
270+
"not_started": true,
271+
"comment": "Unblocked by this Stage-3 terminal commit and deliberately NOT started in it. A1 begins on a new branch from the Rust-default baseline, so the provenance line stays legible: the last P-022 semantic state, then the Stage-3 terminal commit, then A1. Nobody should have to work out later whether the first ConsumesParam change belonged to the migration or to a new inference feature."
231272
}
232273
}

‎docs/generated/p022-stage3-packet.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# P-022 Stage 3 — #262 cutover decision packet
33

44
```text
5-
Stage-3 candidate SHA: f69f0988a14e00c0925a68b9fddd101aff7b3ebe (DIRTY TREE — not evidence)
5+
Stage-3 candidate SHA: f1d3681e96e31bba7a36dda09967d0af7c3e9b56 (DIRTY TREE — not evidence)
66
Observation window: the repository's own CI on the candidate branch, plus the release workflow's packed-artifact smoke test; first run b590bf46e9f1: 7 job failures, every one a real consequence of the cutover, all diagnosed and fixed
77
Fast compare result: 104 documents, 104 agreed, 0 acceptance-unexplained | samples: 1 document, 1 agreed, 0 acceptance-unexplained
88
Five-repo compare result: 10/10 documents agreed over 6 targets; 0 acceptance-unexplained, 0 declared-boundary; at b590bf46e9f1; local run (no CI anchor)
@@ -67,3 +67,4 @@ CLI contract campaign: 24/24 mutants caught at b5d9272a0a85
6767
* `stage2-controls` [linux] **MEASURED OBSERVATION** — 9 controls passed, including public-default-is-rust
6868
* `ci-surfaces` [n/a] **MEASURED OBSERVATION** — 63 invocations over 26 files; 23 explicit, 40 bare and all resolvable; 0 hollow Python injections
6969
* `stage1-controls-windows` [windows] **MEASURED OBSERVATION** — 19 controls passed, 0 failed, 0 skipped, 1 not applicable (a non-executable candidate cannot be constructed for the shell surface under git-bash). Includes default-is-rust, unset-locator-is-d6, rust-failure-no-fallback and an unexpected child status mapped to public exit 5 with the raw WINDOWS-NATIVE status (-1073740791) retained. The job as a whole went red on a HARNESS defect in the Stage-3 rollback control that ran after these, not on any of them
70+
* `terminal-ci` [n/a] **MEASURED OBSERVATION** — 31/31 jobs green. Includes both Stage-1 control legs, both packed-artifact legs, both dogfood legs, the Windows-native and Stage-2 Windows campaigns, own-check.ps1's exit-code tiers, both shadow-compare gates, the Rust-default code-scanning dogfood, rust fmt/clippy/tests and the Python suite on 3.11/3.12/3.13

‎docs/notes/p022-stage3-cutover-decision.md‎

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,76 @@ performance: DEFERRED BY OWNER; no Stage-3 performance claim; #263 remains open
280280
P-022 is **not** complete: Stage 4 is open and #263 still owes the baselines
281281
this decision deferred.
282282

283-
With the cutover complete, the P-022 feature freeze on verdict-changing
284-
inference lifts and the **P-037 A1 production gate opens**. It was deliberately
285-
not started here: A1 is a semantic change and this was a cutover, and #262's
286-
guardrails say no semantic cleanup is mixed into one.
283+
## Terminal evidence
284+
285+
```text
286+
Stage-3 terminal candidate: f1d3681e96e31bba7a36dda09967d0af7c3e9b56
287+
Terminal qualification run: 31/31 jobs green
288+
https://github.com/PhysShell/Own.NET/actions/runs/35312190310
289+
```
290+
291+
Every predicate below is confirmed on **that** commit, not assembled from
292+
earlier ones: both Stage-1 control legs, both packed-artifact legs, both
293+
dogfood legs, the Windows-native and Stage-2 Windows campaigns,
294+
`own-check.ps1`'s exit-code tiers, both shadow-compare gates, the Rust-default
295+
code-scanning dogfood, rust fmt/clippy/tests, and the Python suite on
296+
3.11/3.12/3.13.
297+
298+
## Defects found and closed during qualification
299+
300+
Recorded as **closures**, deliberately not under *Known differences*: after the
301+
fixes these are not permitted Stage-3 behaviour. All three were invisible while
302+
Python was the default, and all three were found by running the thing rather
303+
than by reading it — which is the entire argument for the qualification round.
304+
305+
They also form one sequence, and it is worth seeing whole:
306+
307+
```text
308+
1. an invocation that could reach no engine at all
309+
2. a capture that captured nothing
310+
3. an assertion that passed BECAUSE the capture was empty
311+
```
312+
313+
Each looked perfectly respectable on its own.
314+
315+
* **PS1-CAPTURE.** `own-check.ps1`'s Rust branch spawned a child that inherited
316+
the console handle, bypassing PowerShell's pipeline, so
317+
`$out = & ./scripts/own-check.ps1 ...` captured nothing while the text still
318+
appeared on screen. Closed by redirecting and replaying the streams.
319+
* **PS1-NOTMATCH-ASSERTION**, and its scope stated precisely because the loose
320+
version would be untrue: it is the **Windows Stage-2 dogfood's OWN001
321+
output-observation assertion** that had never constituted evidence on the
322+
Rust path — before the capture repair it received `$null`, and PowerShell's
323+
array/filter semantics make an empty capture pass. The other Stage-2 controls
324+
and the actual Rust-default execution (exit code, no-fallback, candidate
325+
identity) remain separately evidenced. This is **not** a claim that Stage 2
326+
as a whole was unproven.
327+
* **CI-SURFACES-HOLLOW.** Five steps injected a broken Python and then invoked
328+
a launcher bare, so the injected fault could no longer happen and each would
329+
have passed vacuously; two more call sites lived inside scripts rather than
330+
workflow YAML.
331+
332+
## Hand-off
333+
334+
```text
335+
P-037 A1 PRODUCTION GATE: BLOCKED BY DESIGN -> UNBLOCKED
336+
```
337+
338+
The P-022 freeze on verdict-changing inference held until the cutover
339+
completed; this commit completes it. A1 is **not started here**, and not in
340+
this PR: it is a semantic change and this was a cutover, and #262's guardrails
341+
say the two are never mixed.
342+
343+
A1 begins on a new branch from the Rust-default baseline, which keeps the
344+
provenance line legible:
345+
346+
```text
347+
last P-022 semantic state
348+
|
349+
+-- Stage-3 terminal commit (f1d3681)
350+
|
351+
+-- P-037 A1 starts here
352+
```
353+
354+
Nobody should have to work out, later, whether the first `ConsumesParam` change
355+
belonged to the Rust migration or to a new inference feature.

0 commit comments

Comments
 (0)