From 2f9c10e96f21363c1dadeb09ae0a8486783ad3fe Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 00:55:43 +0500 Subject: [PATCH 01/11] docs(t0): the pretraining protocol freeze, unfrozen and honest about it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T0 fixes how numbers will be judged before any number exists. It binds the step-7 training collection, the step-8 fit and #263-B alike, because a rule chosen after a look at training data is a preference with a timestamp. Frozen here: the pairing unit is the cell (rung, workload, regime) and the statistic is the median paired log-ratio, with index pairing named and forbidden — the harness shuffles cells and runs a cell's N iterations back to back, so same-index iterations of the two engines have no temporal correspondence. The two-margin form of acceptance, the four-state decision automaton, invalidation and retry semantics, and host selection and replacement rules are frozen. Training may derive N and nothing else. Not frozen, and recorded as typed slots rather than filled in: M, A, their scope, the caps K and B, the null-primary-metric outcome, the uncertainty model and its parameters, the retry budget, and five host-predicate slots. A drafter who fills one of those has replaced the owner. One conflict is open and cannot be settled inside T0: only two of #262's seven gate phases yield a standalone gateable number, so any primary/diagnostic split changes #262's acceptance surface and needs ratification against it. NORMATIVE_RATIFICATION_REQUIRED_AGAINST_262. Hostile review leaves five "yes" answers, every one of them an empty slot or that conflict. T0_NOT_FREEZABLE, collection_authorized: false. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 406 ++++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 docs/notes/p022-263-t0-protocol-freeze.md diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md new file mode 100644 index 00000000..6ebeeca4 --- /dev/null +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -0,0 +1,406 @@ +# P-022 / #263 — T0, the pretraining protocol freeze + +```text +Status: + NOT_FROZEN. + collection_authorized: false + MANDATORY UNRESOLVED SLOTS: 9 (T0-completion). + OPEN NORMATIVE CONFLICT: 1, against #262 (T0-3). + NO CLOCK HAS RUN. NO OBSERVATION EXISTS. +``` + +**What this is.** The contract that fixes *how numbers will be judged*, before any +number exists. It binds the training collection (step 7), the fit (step 8) and +the decisive campaign (#263-B) alike, because a rule chosen after a look at +training data is not a preregistered rule — it is a preference with a timestamp. + +**What this is not.** It is not D7. T0 says how a verdict is computed; D7 later +records *which* exact numbers, candidate, digests and host instances the verdict +was computed from, and adds no analytical decision of its own. + +**Authority.** T0-0 revoked the automatic authorisation of the first step-7 +collection (`docs/notes/p022-263a-step7-environment-capture.md`). Until this +document is frozen, `collection_authorized` is `false` and no training, first or +decisive collection may run, however ready the hosts are. + +**Slot discipline.** Every value this document does not already hold appears as a +typed `UNRESOLVED_OWNER_DECISION` slot with its unit and its scope stated. A slot +is filled by an owner ruling recorded here, never by a plausible default and +never by a number suggested by data. A drafter who fills one has replaced the +owner. + +--- + +## T0-1 — Statistic and pairing unit + +**FROZEN.** + +The pairing unit is the **cell**, keyed + + (rung, workload, regime) + +Engine is not part of the key: it is the two sides of the pair. This is the +ratified four-part cell identity of §2.1 with `engine` projected out, so the pair +exists exactly where both engines have a timed cell. + +For each matched pair: + + d_c = log(median(Rust_c)) - log(median(Python_c)) + D = median_c(d_c) + R = exp(D) + +`R` is the reported Rust-vs-Python ratio: `R < 1` means Rust is faster. + +**Index pairing is forbidden.** `Rust_i / Python_i` for the i-th iteration is not +a paired observation here and may not be computed, reported or gated on. +`run_calibration` shuffles **cells** under a recorded seed and runs a cell's `N` +iterations back to back, so a Rust iteration and a Python iteration with the same +index are separated by an arbitrary stretch of the session. Pairing them would +assert a temporal correspondence the harness does not produce — the "we matched +the fifth Rust run with the third Python run" defect, in a formula. + +**The harness is not to be changed to iteration-level A/B interleaving under T0.** +Doing so edits `scripts/perf_baseline.py`, which is one of the two files in the +harness source set, so it moves `measurement_harness_digest 562a7f7232da…` — the +identity steps 4, 5 and 6 were accepted on. That is a new instrument and a +re-evaluation of accepted instrumentation evidence, not a T0 detail. + +**An unpaired cell cannot reach the statistic.** A cell whose invocation did not +do the rung's work is not timed at all and the collection is refused +(instrument §2). Therefore a missing side is an admissibility failure — see +T0-4 — and never a pair dropped quietly from `median_c`. + +**Recorded consequence.** Cell-level pairing cancels *condition* noise (same +rung, workload, regime, same session, interleaved order). It does not cancel +per-iteration noise, because the data cannot support that claim. No stronger +noise-cancellation property may be asserted for `R`. + +--- + +## T0-2 — Acceptance margins + +**FORM FROZEN. VALUES UNRESOLVED.** + +A gate FAILs only when both margins are exceeded: + + FAIL(gate) iff relative_regression(gate) > M AND absolute_regression(gate) > A + +Two margins, because neither alone is meaningful: a relative-only rule fails a +`0.20 ms -> 0.24 ms` change that no user can perceive, and an absolute-only rule +is blind to scale. + +Semantics, frozen: + +| term | definition | +|---|---| +| `relative_regression` | `R - 1` for the gate's cell set, `R` per T0-1 | +| `absolute_regression` | the median over matched pairs of `median(Rust_c) - median(Python_c)`, in the gate's own unit | +| unit, time gates | milliseconds | +| unit, memory gates | bytes of peak RSS | + +```yaml +M: UNRESOLVED_OWNER_DECISION # dimensionless ratio margin +A: UNRESOLVED_OWNER_DECISION # absolute margin, in the gate's unit +M_A_scope: UNRESOLVED_OWNER_DECISION # one pair for all gates, or per-gate pairs +``` + +`M` and `A` derive from the cutover/product budget — what a user may be made to +wait, and how much memory the migration may cost. They may not be derived from +observed Rust-vs-Python results, calibration variance, or training output. + +--- + +## T0-3 — Gate population and aggregation + +**BLOCKED. `NORMATIVE_RATIFICATION_REQUIRED_AGAINST_262`.** + +#263-A must not silently narrow #263's acceptance (instrument §1), so the gate +population is not T0's to settle. What T0 can do is state the conflict exactly. + +### The authoritative list, and what is actually observable + +#262's performance gates name seven phases. The instrument measures a ladder of +real production invocations and records each as the composed interval it is: + +| #262 gate phase | observable as | standalone number? | +|---|---|---| +| process startup | `core-usage`, composed over `process-startup-core` + `cli-argv-parse` + `cli-usage-refusal` | **no** — a *lower bound* on core startup; `process-startup-launcher` is separate and lives inside `launcher-e2e` | +| OwnIR parse | `core-parse-refused - core-usage` | **no** — a derived bound, valid only under an assumption the instrument never measures | +| bridge/lowering | member of `core-full-*` | **no** — not separately observable (§14.1) | +| analysis | member of `core-full-*` | **no** — not separately observable (§14.1) | +| CLI/SARIF rendering | `core-full-sarif - core-full-human` | **no** — a renderer *difference*, which is not rendering in isolation | +| end-to-end C# project/solution run | `launcher-e2e` | **yes** | +| peak RSS / allocations where practical | RSS by named mechanism per platform | **RSS yes**; allocations **not captured** (§14.2) | + +Two of #262's seven gate phases yield a standalone gateable number. One yields a +bound. Four exist only as derived views, which §2 forbids presenting as +measurements. + +### The proposed reshape, and the three conflicts it raises + +Proposed primary gates: process startup, cold E2E, warm E2E, peak RSS. +Proposed diagnostic-only: OwnIR parse, bridge/lowering, analysis, rendering, +frontend extraction. + +- **C1 — acceptance surface.** Moving parse, bridge/lowering, analysis and + rendering out of the gating set changes #262's acceptance surface. Sound + engineering — one user-visible effect should not be gated four times — but it + is a normative change, and instrument §1 exists precisely to stop it happening + by omission. **Requires ratification against #262.** +- **C2 — "process startup" is not one number.** As a primary gate it can mean + `core-usage` (a bound on the child's startup) or `process-startup-launcher` + (what a user waits for), and §2 keeps the two deliberately unmerged. Which one + gates is undefined. **Requires a ruling, then ratification.** +- **C3 — three of the five diagnostics do not exist.** bridge/lowering, analysis + and launcher-scoped extraction are not separately observable; parse and + rendering exist only as derived bound and difference. A diagnostic list must be + written against observables, or it manufactures several metrics out of one + interval — the defect §2 records as `launcher-extract` withdrawn. +- **C4 — allocations.** #262's phrasing is "peak RSS/allocations where + practical"; allocations are not captured. Whether "where practical" already + discharges this must be recorded explicitly, not assumed. + +### Catastrophic-regression caps + +A diagnostic metric does not veto the cutover, but a diagnostic surface that +collapses should not pass silently either. + +```yaml +K: UNRESOLVED_OWNER_DECISION # per-phase ratio cap, dimensionless +B: UNRESOLVED_OWNER_DECISION # per-phase absolute cap, in the phase's unit +caps_apply_to: UNRESOLVED_OWNER_DECISION # which observable surfaces carry a cap +``` + +A cap fires only when both are exceeded, on the same two-margin logic as T0-2. + +**Normative, independent of the ratification:** a derived view (`core-parse-refused +- core-usage`, `core-full-sarif - core-full-human`) may inform a reading and may +never serve as a gate or a cap, and no two metrics may be manufactured from one +observable interval. + +--- + +## T0-4 — Decision automaton + +**STRUCTURE FROZEN. ONE SLOT.** + +Terminal states are exactly four, and the reading is a function of evidence, not +prose: + +```text +admissibility (T0-6 invalidation predicates) + │ + ├─ violated ─────────────────────────────► INVALID + │ + └─ clean + │ + required primary metric missing or null + │ + ├─ yes ──────────────────────────────► INVALID or NO_DECISION (never PASS) + │ + └─ no + │ + primary gates, T0-2 margins under the T0-5 uncertainty rule + │ + ├─ regression proven ────────────► FAIL ─► NO_GO + ├─ neither proven ───────────────► NO_DECISION + └─ non-inferiority proven + │ + catastrophic caps (T0-3) + ├─ violated ────────────────► FAIL ─► NO_GO + └─ clean ───────────────────► PASS ─► GO +``` + +`INVALID` and `NO_DECISION` both map to `NO_DECISION` at the cutover level: no +evidence, no verdict. They are kept apart because they mean different things — +`INVALID` says the measurement did not happen properly, `NO_DECISION` says it +happened and did not resolve. + +**A missing primary metric may never read as "no regression found".** Peak RSS is +the live case: §9 emits `null` with a reason where no mechanism exists, so if RSS +is a primary gate, a Job Object that did not answer on Windows must not become a +silent pass. + +```yaml +null_primary_metric_outcome: UNRESOLVED_OWNER_DECISION +# INVALID — treat an unmeasurable primary gate as a broken measurement, retry-eligible +# NO_DECISION — treat it as measured-but-unresolved, not retry-eligible +``` + +--- + +## T0-5 — Uncertainty rule + +**OPTIONS STATED. MODEL UNRESOLVED.** + +Without an uncertainty rule, `1.0999 -> PASS` and `1.1001 -> FAIL` become +metaphysics on a machine whose own floor tolerates 0.35 relative IQR. + +Cell count bounds the choice: up to `5 rungs x 13 decisive workloads x 2 regimes` += 130 cell pairs per platform, less whatever `_rung_accepts` rejects, and less +again if the gate population shrinks to primary surfaces only. + +| | Option A — bootstrap over paired cells | Option B — deterministic gray zone | +|---|---|---| +| shape | resample cell pairs, preregistered confidence level; PASS if the upper bound ≤ margin, FAIL if the lower bound > margin, else NO_DECISION | fixed `PASS_LIMIT` / `FAIL_LIMIT`; between them, NO_DECISION | +| reproducibility | recomputable from retained raw, but only if resampling unit, resample count and RNG seed are frozen too — otherwise the interval is itself a degree of freedom | trivially recomputable, no RNG | +| few cells | interval widens honestly; a narrow gate population can make NO_DECISION the usual outcome | insensitive to sample size — a 3-cell result and a 100-cell result read identically | +| retry semantics | a wide interval is **not** an invalid run; if it were, retry-until-narrow is rerun-until-pass | same; the gray zone is an outcome, not a retry trigger | +| machine-checkable | yes, once every parameter is frozen | yes, the simplest possible predicate | +| post-hoc exposure | low if frozen; the live risk is choosing the confidence level after seeing the width | low; the limits must come from the budget, and they overlap T0-2 unless defined as a bracket around `M`/`A` | + +```yaml +uncertainty_model: UNRESOLVED_OWNER_DECISION # A or B +confidence_level: UNRESOLVED_OWNER_DECISION # if A +bootstrap_unit_resamples_seed: UNRESOLVED_OWNER_DECISION # if A; all three, frozen +gray_zone_limits: UNRESOLVED_OWNER_DECISION # if B; PASS_LIMIT and FAIL_LIMIT +``` + +--- + +## T0-6 — Invalidation and retry + +**SEMANTICS FROZEN. BUDGET UNRESOLVED.** + +The unit of invalidation is the **session** — the whole predefined measurement +unit, as the instrument already treats it. A phase, a cell or a workload is never +invalidated, rerun or replaced on its own. + +Invalidation fires only on machine-detectable predicates frozen in advance: + +- opening or closing noise probe relative IQR above `NOISE_PROBE_MAX_RELATIVE_IQR` + (0.35); +- drift between opening and closing probes above `NOISE_PROBE_MAX_DRIFT` (0.35); +- reproducibility median change above `REPRODUCIBILITY_MAX_MEDIAN_CHANGE` (0.35); +- a cell that did not do its rung's work, proved by its post-condition; +- identity-field drift in the step-7 environment manifest, fields compared whole; +- candidate byte drift within a stratum after collection started. + +**A performance result is never an invalidation condition.** Not a slow cell, not +a wide interval, not a disappointing `R`. + +One retry attempt is one full re-collection of the invalidated session on the +same qualified host. Retries are bounded; on exhaustion the outcome is +`NO_DECISION`, never "one more run". Every attempt, including invalidated ones, +is retained as evidence and none is deleted. + +```yaml +retry_budget: UNRESOLVED_OWNER_DECISION # attempts per stratum, integer +``` + +--- + +## T0-7 — Host eligibility predicate + +**PARTIALLY NORMATIVE. INCOMPLETE — a freeze blocker.** + +Already normative, from the existing contract: + +- `NOISE_PROBE_MAX_RELATIVE_IQR` 0.35, `NOISE_PROBE_MAX_DRIFT` 0.35, + `REPRODUCIBILITY_MAX_MEDIAN_CHANGE` 0.35, all chosen before the runs they judge + and not to be re-chosen to make a host pass; +- a GitHub-hosted runner is not measurement-grade — established on one commit, + where two Windows runs minutes apart disagreed about their own validity; +- the decisive Windows measurement needs a single-tenant machine, and D7 may not + preregister a Windows protocol that assumes a hosted runner; +- both strata are required: `U_linux` and `U_windows`, never pooled; +- a step-7 environment identity manifest per host, identity fields compared whole; +- `host_fingerprint` inside a container is the container's identity, so a + container is not a host; +- per-stratum untimed builds, with `candidate_sha256` and `candidate_bytes` + identical across every run of that stratum. + +Still unresolved, and each is machine-checkable only once ruled: + +```yaml +single_tenant_predicate: UNRESOLVED_OWNER_DECISION # what a checker asserts +power_policy_requirement: UNRESOLVED_OWNER_DECISION # per platform +permitted_background: UNRESOLVED_OWNER_DECISION # what may run during a session +quiesce_procedure: UNRESOLVED_OWNER_DECISION # and how it is evidenced +manifest_refresh_rule: UNRESOLVED_OWNER_DECISION # per session or per campaign +``` + +An incomplete predicate blocks the freeze. It is not an invitation to write down +one drafter's idea of a good benchmark host. Reconnaissance already performed on +a shared developer workstation is **exploratory only**: it may inform the shape of +the predicate and contributes no measurement, no manifest and no qualified host. + +--- + +## T0-8 — Selection and replacement + +**FROZEN.** + +1. Qualification runs no Rust-vs-Python benchmark. A host is qualified against the + predicate and the noise floor, never against how the comparison came out. +2. The first host that passes the predicate, in a predeclared order, becomes the + host of its stratum. +3. After any outcome-bearing data exists, a host may be replaced only for a + predeclared environmental failure condition. **A performance outcome is never a + replacement reason.** +4. Replacement begins with full requalification. +5. Every replacement records: reason, the rule invoked, old identity, new + identity, time and order. Evidence from the replaced host is retained. + +Workloads and inputs are already frozen — 13 decisive entries, pinned. Drift on a +pinned target is a **failed target**, never a newer measurement and never a +substitution. + +--- + +## T0-9 — Training degrees of freedom + +**FROZEN.** + +Training may derive **`N` and nothing else**, by the already-ratified rule: the +ladder `[5, 15, 45]`, `G = [1, 10]`, per-stratum admissible sets +`Q_p = { N : W_p(N) <= (1+G) * min_N W_p(N) }`, selection = the smallest rung in +`Q_linux ∩ Q_windows`, and `NO_COMMON_N` is a stop with no fallback rung. + +Training may not change, and seeing training output grants no licence to revisit: +the statistic, the pairing unit, `M`, `A`, the gate population, `K`, `B`, the +uncertainty model and its parameters, the decision automaton, retry semantics, +host eligibility semantics, or workload selection and replacement rules. + +--- + +## T0-completion + +T0 is not frozen while any mandatory slot is unresolved or any normative conflict +is open. Until then `collection_authorized: false`. + +| # | slot | section | +|---|---|---| +| 1 | `M` | T0-2 | +| 2 | `A` | T0-2 | +| 3 | `M_A_scope` | T0-2 | +| 4 | `K`, `B`, `caps_apply_to` | T0-3 | +| 5 | `null_primary_metric_outcome` | T0-4 | +| 6 | `uncertainty_model` + its parameters | T0-5 | +| 7 | `retry_budget` | T0-6 | +| 8 | host predicate slots (5) | T0-7 | +| 9 | ratification of the gate population against #262, incl. C2's "which startup" | T0-3 | + +--- + +## Hostile review of this skeleton + +| question | answer under T0 as drafted | +|---|---| +| see training data, then change the statistic? | **no** — T0-1 frozen, T0-9 forbids revisiting | +| change the pairing definition? | **no** — T0-1 frozen, index pairing named and forbidden | +| change `M`/`A`? | **no once ruled** — but **yes while unresolved**, which is why the freeze is blocked | +| change the primary gate population? | **yes today** — C1/C2 open; closes only by ratification against #262 | +| change `K`/`B`? | **yes while unresolved** | +| pick the uncertainty model after the data? | **yes while unresolved** — the single largest post-hoc exposure left | +| raise the retry budget after a failure? | **no once ruled** — bounded, exhaustion yields NO_DECISION | +| replace a host because the result is unpleasant? | **no** — T0-8 rules 3 and 5 | +| can a missing or null primary metric yield PASS? | **no** — T0-4, structurally | +| can anyone start collecting because hosts and binding are ready? | **no** — T0-0 revoked that; `collection_authorized: false` | +| can one evidence set yield both PASS and FAIL under two admissible readings? | **yes while T0-3 and T0-5 are open**; **no** once both are closed, since the automaton is then a function | + +Five "yes" answers remain. Every one of them is an empty slot or the open #262 +conflict — none can be closed by drafting, and none may be closed by looking at +data. + + T0_NOT_FREEZABLE — until the table above is all "no". From a3963febed0f687d902a7be604c88bfa87f8f768 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 08:48:49 +0500 Subject: [PATCH 02/11] =?UTF-8?q?docs(t0):=20apply=20the=20owner=20rulings?= =?UTF-8?q?=20=E2=80=94=20structure=20resolved,=20numbers=20still=20open?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R1 — the user-visible path is `launcher-e2e`, evaluated as two preregistered regimes, cold and warm, both primary strata of one surface and never collapsed into one number. `core-usage` stays a published startup/floor baseline and does not stand in for the gate. R2 — peak RSS remains a required resource gate where a mechanism exists. Allocation/heap profiling is diagnostic, published where practical; a missing allocation profile is neither INVALID nor FAIL, and no instrumentation is added to obtain one. R3 — the #262 ratification blocker is withdrawn as a misreading. #262 asks for published BASELINES and states its gate once — an explicit budget and no material regression of the user-visible path — while #263 requires separate measurement only "where possible" and demands unavailable stages be marked. A phase published as composed and marked unavailable is that method working. Every stage baseline now carries one of four honest classes, and a derived number may not be renamed into something stronger than it proves. R4 — Option 2. K, B and caps_apply_to are REMOVED from the contract rather than filled: per-phase caps are an acceptance policy #262 does not ask for, and they would turn profiling surfaces back into hidden vetoes. A guardrail, if a real profile ever justifies one, arrives as its own amendment. The null-primary-metric switch is replaced by three distinct states: no mechanism before collection makes the session ineligible so it never starts; a metric that goes null mid-attempt invalidates that attempt; exhausting the retry budget yields NO_DECISION. PASS remains structurally unreachable in all three. T0-5 chooses the deterministic gray zone over a bootstrap across cells: the cells are fixed preregistered acceptance strata, not an IID sample, and resampling them would lend a workload list statistical authority it has not earned. The limits themselves stay unresolved. Twelve slots remain, all of them budget numbers or host-predicate fields. Verdict: T0_SKELETON_READY_FOR_NUMERIC_RULINGS. Status stays NOT_FROZEN and collection_authorized: false. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 324 ++++++++++++---------- 1 file changed, 183 insertions(+), 141 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 6ebeeca4..b6f09524 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -4,8 +4,10 @@ Status: NOT_FROZEN. collection_authorized: false - MANDATORY UNRESOLVED SLOTS: 9 (T0-completion). - OPEN NORMATIVE CONFLICT: 1, against #262 (T0-3). + STRUCTURE RESOLVED. NUMERIC AND HOST SLOTS OPEN. + MANDATORY UNRESOLVED SLOTS: 12 (T0-completion). + OPEN NORMATIVE CONFLICTS: none. The #262 ratification blocker was withdrawn + as a misreading — see T0-3. NO CLOCK HAS RUN. NO OBSERVATION EXISTS. ``` @@ -27,13 +29,15 @@ decisive collection may run, however ready the hosts are. typed `UNRESOLVED_OWNER_DECISION` slot with its unit and its scope stated. A slot is filled by an owner ruling recorded here, never by a plausible default and never by a number suggested by data. A drafter who fills one has replaced the -owner. +owner. Equally, a slot is not kept alive because it was once drafted: a +requirement the acceptance contract does not make is removed, not filled with a +zero, an infinity or an "N/A". --- ## T0-1 — Statistic and pairing unit -**FROZEN.** +**RESOLVED.** The pairing unit is the **cell**, keyed @@ -79,7 +83,7 @@ noise-cancellation property may be asserted for `R`. ## T0-2 — Acceptance margins -**FORM FROZEN. VALUES UNRESOLVED.** +**FORM RESOLVED. VALUES OPEN.** A gate FAILs only when both margins are exceeded: @@ -106,161 +110,184 @@ M_A_scope: UNRESOLVED_OWNER_DECISION # one pair for all gates, or per-gate pair `M` and `A` derive from the cutover/product budget — what a user may be made to wait, and how much memory the migration may cost. They may not be derived from -observed Rust-vs-Python results, calibration variance, or training output. +observed Rust-vs-Python results, calibration variance, or training output. Their +relationship to the T0-5 decision limits is itself an open slot, recorded there. --- -## T0-3 — Gate population and aggregation +## T0-3 — Gate population -**BLOCKED. `NORMATIVE_RATIFICATION_REQUIRED_AGAINST_262`.** +**RESOLVED (owner rulings R1–R4). The #262 ratification blocker is withdrawn.** -#263-A must not silently narrow #263's acceptance (instrument §1), so the gate -population is not T0's to settle. What T0 can do is state the conflict exactly. +### Why the blocker was withdrawn -### The authoritative list, and what is actually observable +An earlier draft of this document carried +`NORMATIVE_RATIFICATION_REQUIRED_AGAINST_262`, on the reading that #262 names +seven phases and demands a gate on each. Reading the issues themselves rather +than a restatement of them dissolves it: -#262's performance gates name seven phases. The instrument measures a ladder of -real production invocations and records each as the composed interval it is: +- **#262** says *"Establish and publish **baselines** for"* the seven surfaces, + delegates their production to #263, and then states the gate separately and + once: *"Rust must meet an explicit budget and must not materially regress the + user-visible path."* It also says *"profile before optimizing; JSON and + rendering may dominate once analysis becomes cheap"* — the per-phase surfaces + are named there as profiling instruments, not as vetoes. +- **#263**, which produces those baselines, requires measuring separately + *"where possible"* and *"clearly mark unavailable stages"*. -| #262 gate phase | observable as | standalone number? | +A phase that cannot be isolated, published as composed and marked unavailable, is +therefore #263's method working as specified, not a contract violation. No +amendment to #262 is required and none is made here. + +### Baseline classification, honestly named + +Every published stage baseline carries one of exactly four classes, and a derived +number may never be renamed into something stronger than it proves: + +| surface | observable | class | |---|---|---| -| process startup | `core-usage`, composed over `process-startup-core` + `cli-argv-parse` + `cli-usage-refusal` | **no** — a *lower bound* on core startup; `process-startup-launcher` is separate and lives inside `launcher-e2e` | -| OwnIR parse | `core-parse-refused - core-usage` | **no** — a derived bound, valid only under an assumption the instrument never measures | -| bridge/lowering | member of `core-full-*` | **no** — not separately observable (§14.1) | -| analysis | member of `core-full-*` | **no** — not separately observable (§14.1) | -| CLI/SARIF rendering | `core-full-sarif - core-full-human` | **no** — a renderer *difference*, which is not rendering in isolation | -| end-to-end C# project/solution run | `launcher-e2e` | **yes** | -| peak RSS / allocations where practical | RSS by named mechanism per platform | **RSS yes**; allocations **not captured** (§14.2) | - -Two of #262's seven gate phases yield a standalone gateable number. One yields a -bound. Four exist only as derived views, which §2 forbids presenting as -measurements. - -### The proposed reshape, and the three conflicts it raises - -Proposed primary gates: process startup, cold E2E, warm E2E, peak RSS. -Proposed diagnostic-only: OwnIR parse, bridge/lowering, analysis, rendering, -frontend extraction. - -- **C1 — acceptance surface.** Moving parse, bridge/lowering, analysis and - rendering out of the gating set changes #262's acceptance surface. Sound - engineering — one user-visible effect should not be gated four times — but it - is a normative change, and instrument §1 exists precisely to stop it happening - by omission. **Requires ratification against #262.** -- **C2 — "process startup" is not one number.** As a primary gate it can mean - `core-usage` (a bound on the child's startup) or `process-startup-launcher` - (what a user waits for), and §2 keeps the two deliberately unmerged. Which one - gates is undefined. **Requires a ruling, then ratification.** -- **C3 — three of the five diagnostics do not exist.** bridge/lowering, analysis - and launcher-scoped extraction are not separately observable; parse and - rendering exist only as derived bound and difference. A diagnostic list must be - written against observables, or it manufactures several metrics out of one - interval — the defect §2 records as `launcher-extract` withdrawn. -- **C4 — allocations.** #262's phrasing is "peak RSS/allocations where - practical"; allocations are not captured. Whether "where practical" already - discharges this must be recorded explicitly, not assumed. - -### Catastrophic-regression caps - -A diagnostic metric does not veto the cutover, but a diagnostic surface that -collapses should not pass silently either. +| launcher end-to-end run | `launcher-e2e` | `DIRECT` | +| peak RSS | `os.wait4` `ru_maxrss` (POSIX) / job object `PeakProcessMemoryUsed` (Windows), `null` with a reason elsewhere | `DIRECT` where a mechanism exists | +| core startup floor | `core-usage`, composed over `process-startup-core` + `cli-argv-parse` + `cli-usage-refusal` | `DIRECT` as an interval; a **lower bound** on core startup, never relabelled "startup" | +| OwnIR parse | `core-parse-refused - core-usage` | `DERIVED_ASSUMPTION_DEPENDENT` — assumes both invocations pay comparable argv handling and refusal rendering | +| CLI/SARIF rendering | `core-full-sarif - core-full-human` | `DERIVED_EXACT` **for the renderer difference**; imputing "rendering in isolation" from it is not permitted | +| bridge/lowering | member of `core-full-*` | `UNOBSERVABLE_SEPARATELY` | +| analysis | member of `core-full-*` | `UNOBSERVABLE_SEPARATELY` | +| frontend extraction | member of `launcher-e2e` | `UNOBSERVABLE_SEPARATELY` | +| allocations / heap profile | not captured | diagnostic, published where practical (R2) | + +`bridge/lowering` and `analysis` share one interval with no boundary between +them. No arithmetic recovers a division the instrument never recorded, and none +is invented here. + +### The gates + +**R1 — the user-visible path is `launcher-e2e`**, evaluated as two preregistered +regimes, **cold** and **warm**. Both are primary strata of one user-visible +surface and are never collapsed into a single number; #263 requires cold and warm +kept distinct. `core-usage` remains a published startup/floor baseline and +profiling evidence, and does not stand in for the cutover gate. + +**R2 — peak RSS** remains a required resource gate wherever the contract provides +a mechanism. Allocation and heap profiling is diagnostic, published for selected +workloads where practical; **a missing allocation profile is neither `INVALID` +nor `FAIL`**, and no instrumentation is added under T0 to obtain one. + +**R4 — Option 2, the current observable surface, with no new diagnostic veto +gates.** Catastrophic per-phase caps were considered and rejected: they are an +acceptance policy #262 does not ask for, and they would turn profiling surfaces +back into hidden vetoes. `K`, `B` and `caps_apply_to` are therefore **removed** +from this contract rather than filled — they are not part of it. Should a real +profile later show the need for such a guardrail, it arrives as its own +owner-ratified amendment, not as a silent passenger inside a preregistration. + +The primary gate set is therefore exactly: -```yaml -K: UNRESOLVED_OWNER_DECISION # per-phase ratio cap, dimensionless -B: UNRESOLVED_OWNER_DECISION # per-phase absolute cap, in the phase's unit -caps_apply_to: UNRESOLVED_OWNER_DECISION # which observable surfaces carry a cap +```text +launcher-e2e, regime cold (time) +launcher-e2e, regime warm (time) +peak RSS on the same surface (bytes) ``` -A cap fires only when both are exceeded, on the same two-margin logic as T0-2. +**Structural consequences, applied rather than re-decided.** Each primary gate is +evaluated on its own by T0-4; nothing compensates anything else, because no +compensation was ever granted. A surface whose strata disagree takes the worst +outcome among them — `FAIL` over `NO_DECISION` over `PASS` — since both regimes +are primary and neither may be discarded. Peak RSS is gated on the primary +surface only: gating it on diagnostic rungs would reintroduce exactly the +per-phase veto R4 removed. -**Normative, independent of the ratification:** a derived view (`core-parse-refused -- core-usage`, `core-full-sarif - core-full-human`) may inform a reading and may -never serve as a gate or a cap, and no two metrics may be manufactured from one -observable interval. +Every other surface in the table is **published, never gating**. A derived view +may inform a reading and may never serve as a gate. --- ## T0-4 — Decision automaton -**STRUCTURE FROZEN. ONE SLOT.** +**RESOLVED.** Terminal states are exactly four, and the reading is a function of evidence, not prose: ```text -admissibility (T0-6 invalidation predicates) - │ - ├─ violated ─────────────────────────────► INVALID +eligibility (T0-7: host qualified, every required primary metric has a + working mechanism on it) │ - └─ clean - │ - required primary metric missing or null + ├─ not eligible ────────────────────────► collection does not start + │ (no attempt, no evidence, no verdict) + └─ eligible │ - ├─ yes ──────────────────────────────► INVALID or NO_DECISION (never PASS) + admissibility (T0-6 invalidation predicates, incl. a required primary + metric that returned null or went missing mid-attempt) │ - └─ no + ├─ violated ───────────────────────► INVALID attempt ─► retry (T0-6) + │ └─ budget exhausted ─► NO_DECISION + └─ clean │ - primary gates, T0-2 margins under the T0-5 uncertainty rule + primary gates, T0-2 margins read through the T0-5 limits │ - ├─ regression proven ────────────► FAIL ─► NO_GO - ├─ neither proven ───────────────► NO_DECISION - └─ non-inferiority proven - │ - catastrophic caps (T0-3) - ├─ violated ────────────────► FAIL ─► NO_GO - └─ clean ───────────────────► PASS ─► GO + ├─ any gate FAIL ─────────────► FAIL ─► NO_GO + ├─ any gate in the gray zone ─► NO_DECISION + └─ all gates PASS ────────────► PASS ─► GO ``` -`INVALID` and `NO_DECISION` both map to `NO_DECISION` at the cutover level: no -evidence, no verdict. They are kept apart because they mean different things — -`INVALID` says the measurement did not happen properly, `NO_DECISION` says it -happened and did not resolve. +The three null-metric situations are **different states**, and collapsing them +into one switch was the defect this section used to carry: -**A missing primary metric may never read as "no regression found".** Peak RSS is -the live case: §9 emits `null` with a reason where no mechanism exists, so if RSS -is a primary gate, a Job Object that did not answer on Windows must not become a -silent pass. +| situation | outcome | +|---|---| +| **A.** Before collection: a required primary metric has no mechanism on this host or session | the host/session is **not eligible**; collection does not start | +| **B.** Collection was eligible, but a required primary metric returned `null` or went missing during the attempt | the attempt is **`INVALID`** — evidence that should exist is damaged | +| **C.** Retry budget exhausted after `INVALID` attempts | **`NO_DECISION`** | -```yaml -null_primary_metric_outcome: UNRESOLVED_OWNER_DECISION -# INVALID — treat an unmeasurable primary gate as a broken measurement, retry-eligible -# NO_DECISION — treat it as measured-but-unresolved, not retry-eligible -``` +`null primary metric => PASS` is structurally unreachable, in every one of the +three. + +`INVALID` and `NO_DECISION` both surface as `NO_DECISION` at the cutover level, +and are kept apart because they mean different things: `INVALID` says the +measurement did not happen properly, `NO_DECISION` says it happened and did not +resolve. --- ## T0-5 — Uncertainty rule -**OPTIONS STATED. MODEL UNRESOLVED.** +**MODEL RESOLVED: deterministic gray zone. LIMITS OPEN.** -Without an uncertainty rule, `1.0999 -> PASS` and `1.1001 -> FAIL` become -metaphysics on a machine whose own floor tolerates 0.35 relative IQR. + value <= PASS_LIMIT => PASS + value >= FAIL_LIMIT => FAIL + PASS_LIMIT < value < FAIL_LIMIT => NO_DECISION -Cell count bounds the choice: up to `5 rungs x 13 decisive workloads x 2 regimes` -= 130 cell pairs per platform, less whatever `_rung_accepts` rejects, and less -again if the gate population shrinks to primary surfaces only. +**Why not a bootstrap over cells.** The cells are a fixed, preregistered set of +acceptance strata — an engineering choice of workloads, rungs and regimes — not +an IID sample drawn from a natural population. Resampling them produces an +interval that looks like statistical inference while describing the drafter's +workload list, and it would lend that list an authority it has not earned. The +gray zone is cruder and honest: it says where the contract refuses to call a +winner, and it says so in the same units as the margins. -| | Option A — bootstrap over paired cells | Option B — deterministic gray zone | -|---|---|---| -| shape | resample cell pairs, preregistered confidence level; PASS if the upper bound ≤ margin, FAIL if the lower bound > margin, else NO_DECISION | fixed `PASS_LIMIT` / `FAIL_LIMIT`; between them, NO_DECISION | -| reproducibility | recomputable from retained raw, but only if resampling unit, resample count and RNG seed are frozen too — otherwise the interval is itself a degree of freedom | trivially recomputable, no RNG | -| few cells | interval widens honestly; a narrow gate population can make NO_DECISION the usual outcome | insensitive to sample size — a 3-cell result and a 100-cell result read identically | -| retry semantics | a wide interval is **not** an invalid run; if it were, retry-until-narrow is rerun-until-pass | same; the gray zone is an outcome, not a retry trigger | -| machine-checkable | yes, once every parameter is frozen | yes, the simplest possible predicate | -| post-hoc exposure | low if frozen; the live risk is choosing the confidence level after seeing the width | low; the limits must come from the budget, and they overlap T0-2 unless defined as a bracket around `M`/`A` | +It also removes a post-hoc surface a bootstrap would have kept open — the +confidence level, the resampling unit, the resample count and the seed would each +have had to be frozen, and each would have been a place to negotiate with the +data afterwards. ```yaml -uncertainty_model: UNRESOLVED_OWNER_DECISION # A or B -confidence_level: UNRESOLVED_OWNER_DECISION # if A -bootstrap_unit_resamples_seed: UNRESOLVED_OWNER_DECISION # if A; all three, frozen -gray_zone_limits: UNRESOLVED_OWNER_DECISION # if B; PASS_LIMIT and FAIL_LIMIT +PASS_LIMIT: UNRESOLVED_OWNER_DECISION # per gate unit; the value at or below which a gate passes +FAIL_LIMIT: UNRESOLVED_OWNER_DECISION # per gate unit; the value at or above which a gate fails +gray_zone_margin_binding: UNRESOLVED_OWNER_DECISION +# how PASS_LIMIT/FAIL_LIMIT relate to the T0-2 predicate: whether the M/A pair +# IS the FAIL_LIMIT with PASS_LIMIT below it, or the two limits bracket M/A. +# Both readings are consistent with the form; they are not the same contract. ``` +The limits are budget quantities. They may not be derived from training results, +calibration variance or any observed comparison. + --- ## T0-6 — Invalidation and retry -**SEMANTICS FROZEN. BUDGET UNRESOLVED.** +**SEMANTICS RESOLVED. BUDGET OPEN.** The unit of invalidation is the **session** — the whole predefined measurement unit, as the instrument already treats it. A phase, a cell or a workload is never @@ -273,11 +300,13 @@ Invalidation fires only on machine-detectable predicates frozen in advance: - drift between opening and closing probes above `NOISE_PROBE_MAX_DRIFT` (0.35); - reproducibility median change above `REPRODUCIBILITY_MAX_MEDIAN_CHANGE` (0.35); - a cell that did not do its rung's work, proved by its post-condition; +- a required primary metric that returned `null` or went missing mid-attempt + (T0-4 case B); - identity-field drift in the step-7 environment manifest, fields compared whole; - candidate byte drift within a stratum after collection started. **A performance result is never an invalidation condition.** Not a slow cell, not -a wide interval, not a disappointing `R`. +a gray-zone outcome, not a disappointing `R`. One retry attempt is one full re-collection of the invalidated session on the same qualified host. Retries are bounded; on exhaustion the outcome is @@ -292,7 +321,7 @@ retry_budget: UNRESOLVED_OWNER_DECISION # attempts per stratum, integer ## T0-7 — Host eligibility predicate -**PARTIALLY NORMATIVE. INCOMPLETE — a freeze blocker.** +**PARTIALLY OPEN — a freeze blocker.** Already normative, from the existing contract: @@ -308,7 +337,10 @@ Already normative, from the existing contract: - `host_fingerprint` inside a container is the container's identity, so a container is not a host; - per-stratum untimed builds, with `candidate_sha256` and `candidate_bytes` - identical across every run of that stratum. + identical across every run of that stratum; +- **every required primary metric must have a working mechanism on the host** + before the session is eligible (T0-4 case A). On a host where peak RSS has no + mechanism, the session does not start; it does not start and then fail. Still unresolved, and each is machine-checkable only once ruled: @@ -329,7 +361,7 @@ the predicate and contributes no measurement, no manifest and no qualified host. ## T0-8 — Selection and replacement -**FROZEN.** +**RESOLVED.** 1. Qualification runs no Rust-vs-Python benchmark. A host is qualified against the predicate and the noise floor, never against how the comparison came out. @@ -350,7 +382,7 @@ substitution. ## T0-9 — Training degrees of freedom -**FROZEN.** +**RESOLVED.** Training may derive **`N` and nothing else**, by the already-ratified rule: the ladder `[5, 15, 45]`, `G = [1, 10]`, per-stratum admissible sets @@ -358,49 +390,59 @@ ladder `[5, 15, 45]`, `G = [1, 10]`, per-stratum admissible sets `Q_linux ∩ Q_windows`, and `NO_COMMON_N` is a stop with no fallback rung. Training may not change, and seeing training output grants no licence to revisit: -the statistic, the pairing unit, `M`, `A`, the gate population, `K`, `B`, the -uncertainty model and its parameters, the decision automaton, retry semantics, -host eligibility semantics, or workload selection and replacement rules. +the statistic, the pairing unit, `M`, `A`, the gate population, the decision +limits, the uncertainty model, the decision automaton, retry semantics, host +eligibility semantics, or workload selection and replacement rules. --- ## T0-completion -T0 is not frozen while any mandatory slot is unresolved or any normative conflict -is open. Until then `collection_authorized: false`. +T0 is not frozen while any mandatory slot is unresolved. Until then +`collection_authorized: false`. | # | slot | section | |---|---|---| | 1 | `M` | T0-2 | | 2 | `A` | T0-2 | | 3 | `M_A_scope` | T0-2 | -| 4 | `K`, `B`, `caps_apply_to` | T0-3 | -| 5 | `null_primary_metric_outcome` | T0-4 | -| 6 | `uncertainty_model` + its parameters | T0-5 | +| 4 | `PASS_LIMIT` | T0-5 | +| 5 | `FAIL_LIMIT` | T0-5 | +| 6 | `gray_zone_margin_binding` | T0-5 | | 7 | `retry_budget` | T0-6 | -| 8 | host predicate slots (5) | T0-7 | -| 9 | ratification of the gate population against #262, incl. C2's "which startup" | T0-3 | +| 8 | `single_tenant_predicate` | T0-7 | +| 9 | `power_policy_requirement` | T0-7 | +| 10 | `permitted_background` | T0-7 | +| 11 | `quiesce_procedure` | T0-7 | +| 12 | `manifest_refresh_rule` | T0-7 | + +Removed rather than filled, because the acceptance contract does not make the +requirement: `K`, `B`, `caps_apply_to` (R4), and `null_primary_metric_outcome` +(replaced by the three distinct states of T0-4). Closed as a misreading: +ratification of the gate population against #262 (R3). --- -## Hostile review of this skeleton +## Hostile review after the rulings -| question | answer under T0 as drafted | +| question | answer | |---|---| -| see training data, then change the statistic? | **no** — T0-1 frozen, T0-9 forbids revisiting | -| change the pairing definition? | **no** — T0-1 frozen, index pairing named and forbidden | -| change `M`/`A`? | **no once ruled** — but **yes while unresolved**, which is why the freeze is blocked | -| change the primary gate population? | **yes today** — C1/C2 open; closes only by ratification against #262 | -| change `K`/`B`? | **yes while unresolved** | -| pick the uncertainty model after the data? | **yes while unresolved** — the single largest post-hoc exposure left | -| raise the retry budget after a failure? | **no once ruled** — bounded, exhaustion yields NO_DECISION | +| see training data, then change the statistic? | **no** — T0-1 resolved, T0-9 forbids revisiting | +| change the pairing definition? | **no** — index pairing named and forbidden | +| change the primary gate population? | **no** — T0-3 resolved under R1/R4; a new gate is an amendment, not an adjustment | +| reintroduce per-phase vetoes quietly? | **no** — the caps were removed from the contract, and a derived view may never gate | +| pick the uncertainty model after the data? | **no** — deterministic gray zone chosen, with its rationale recorded in T0-5 | +| change `M`/`A` or the decision limits? | **yes while unresolved** — the remaining budget exposure, closed by the numeric packet | +| raise the retry budget after a failure? | **yes while unresolved**; once set, bounded, and exhaustion yields NO_DECISION | | replace a host because the result is unpleasant? | **no** — T0-8 rules 3 and 5 | -| can a missing or null primary metric yield PASS? | **no** — T0-4, structurally | +| can a missing or null primary metric yield PASS? | **no** — structurally, in all three T0-4 states | +| can a host with no mechanism for a required metric start a session? | **no** — T0-7 eligibility, T0-4 case A | | can anyone start collecting because hosts and binding are ready? | **no** — T0-0 revoked that; `collection_authorized: false` | -| can one evidence set yield both PASS and FAIL under two admissible readings? | **yes while T0-3 and T0-5 are open**; **no** once both are closed, since the automaton is then a function | +| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** once the limits are set — the automaton is a function of evidence; **yes while `PASS_LIMIT`/`FAIL_LIMIT` are empty** | -Five "yes" answers remain. Every one of them is an empty slot or the open #262 -conflict — none can be closed by drafting, and none may be closed by looking at +Three "yes" answers remain, all of them the same thing: the budget numbers are +not chosen yet. None is a structural hole, and none may be closed by looking at data. - T0_NOT_FREEZABLE — until the table above is all "no". + T0_SKELETON_READY_FOR_NUMERIC_RULINGS + status: NOT_FROZEN — collection_authorized: false From 85ff3c1d96ce86c7fb4d6236f7c7c7143003f7ac Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 08:54:52 +0500 Subject: [PATCH 03/11] docs(t0): name the regime exactly, and give peak RSS the same regime dimension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two structural clarifications before any number is chosen. No harness change, no value selected, no new slot. The regime identifier is the instrument's: `process-cold`, not a bare `cold`. `warm` is still a fresh process, after discarded warmup iterations, with the OS and filesystem caches warm. `machine-cold` is not claimed by the instrument, so it is not a regime, not a gate and not an alias here. Documentation that says `cold` while evidence arrives as `process-cold` buys a three-day argument later about whether one is an alias of the other. Peak RSS carries the regime dimension too. `peak_rss_bytes` is captured on every measured cell and a cell's key includes its regime, so memory exists separately for `process-cold` and for `warm` rather than as one number beside the surface. The primary set is therefore FOUR independent gates — elapsed time and peak RSS, each in each regime — with no compensation between regimes and none between time and memory. This does not restore per-phase vetoes: all four sit on the same user-visible surface, and memory on a diagnostic rung stays published and never gating. T0-2 gains the dimensional constraint that follows: `A` carries the gate's unit, the primary set now spans milliseconds and bytes, and one absolute value cannot serve both. "One pair for all gates" is not a budget waiting to be chosen for `A`; it is not a quantity. Recorded as a constraint on the coming numeric ruling — `M_A_scope` stays unresolved and no value is picked. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 73 +++++++++++++++++------ 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index b6f09524..2bd15e3f 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -104,10 +104,23 @@ Semantics, frozen: ```yaml M: UNRESOLVED_OWNER_DECISION # dimensionless ratio margin -A: UNRESOLVED_OWNER_DECISION # absolute margin, in the gate's unit -M_A_scope: UNRESOLVED_OWNER_DECISION # one pair for all gates, or per-gate pairs +A: UNRESOLVED_OWNER_DECISION # absolute margin, carries the gate's unit: + # milliseconds for the time gates, + # bytes for the peak RSS gates +M_A_scope: UNRESOLVED_OWNER_DECISION # see the dimensional constraint below ``` +**Dimensional constraint, recorded rather than decided.** `A` carries the gate's +own unit, and the primary set now spans two units — milliseconds and bytes. One +absolute value therefore cannot serve all four gates: a single `A` shared across +time and memory is not a budget the owner has yet to pick, it is not a quantity. +"One pair for all gates" is consequently unavailable for `A` as literally +phrased, and the numeric ruling should be asked in the terms the units allow: one +absolute budget for the time gates and one for the memory gates, with the open +questions being whether `M` — dimensionless, and so unconstrained by this — is +one budget or split, and whether the two gates inside a unit share one `A` or +take one each. No value, and no choice among those readings, is made here. + `M` and `A` derive from the cutover/product budget — what a user may be made to wait, and how much memory the migration may cost. They may not be derived from observed Rust-vs-Python results, calibration variance, or training output. Their @@ -162,14 +175,25 @@ is invented here. ### The gates -**R1 — the user-visible path is `launcher-e2e`**, evaluated as two preregistered -regimes, **cold** and **warm**. Both are primary strata of one user-visible -surface and are never collapsed into a single number; #263 requires cold and warm -kept distinct. `core-usage` remains a published startup/floor baseline and -profiling evidence, and does not stand in for the cutover gate. +**R1 — the user-visible path is `launcher-e2e`**, evaluated in two preregistered +regimes, **`process-cold`** and **`warm`**. Both are primary strata of one +user-visible surface and are never collapsed into a single number; #263 requires +cold and warm runs kept distinct. `core-usage` remains a published startup/floor +baseline and profiling evidence, and does not stand in for the cutover gate. + +The identifiers are the instrument's own, and this document uses no others: +`process-cold` is a fresh process every iteration with no in-process warmup; +`warm` is still a fresh process, after a stated number of discarded warmup +iterations, with the OS and filesystem caches warm. `machine-cold` is **not +claimed** by the instrument and is therefore not a gate, not a regime and not an +alias for anything here. A bare `cold` is not an identifier in this contract. **R2 — peak RSS** remains a required resource gate wherever the contract provides -a mechanism. Allocation and heap profiling is diagnostic, published for selected +a mechanism, and it carries the same regime dimension as time. `peak_rss_bytes` +is captured on every measured cell, and a cell's key includes its regime, so +memory exists separately for `process-cold` and for `warm` rather than as one +number beside the surface. `warm` memory may not hide inside `process-cold` +memory, or the reverse. Allocation and heap profiling is diagnostic, published for selected workloads where practical; **a missing allocation profile is neither `INVALID` nor `FAIL`**, and no instrumentation is added under T0 to obtain one. @@ -181,21 +205,32 @@ from this contract rather than filled — they are not part of it. Should a real profile later show the need for such a guardrail, it arrives as its own owner-ratified amendment, not as a silent passenger inside a preregistration. -The primary gate set is therefore exactly: +The primary gate set is therefore exactly **four** independent gates: + +```text +launcher-e2e / process-cold / elapsed time (milliseconds) +launcher-e2e / warm / elapsed time (milliseconds) +launcher-e2e / process-cold / peak RSS (bytes) +launcher-e2e / warm / peak RSS (bytes) +``` + +**No compensation, in either direction**: not between `process-cold` and `warm`, +and not between time and memory. Four gates, each read on its own. + +The roll-up over them is the automaton of T0-4, applied without addition: ```text -launcher-e2e, regime cold (time) -launcher-e2e, regime warm (time) -peak RSS on the same surface (bytes) +any gate FAIL => FAIL +else any NO_DECISION => NO_DECISION +else => PASS ``` -**Structural consequences, applied rather than re-decided.** Each primary gate is -evaluated on its own by T0-4; nothing compensates anything else, because no -compensation was ever granted. A surface whose strata disagree takes the worst -outcome among them — `FAIL` over `NO_DECISION` over `PASS` — since both regimes -are primary and neither may be discarded. Peak RSS is gated on the primary -surface only: gating it on diagnostic rungs would reintroduce exactly the -per-phase veto R4 removed. +**Peak RSS is gated on `launcher-e2e` only.** The instrument captures +`peak_rss_bytes` on every measured cell and those values are **published as +diagnostic evidence**, but a memory number on a diagnostic rung never gates. +Gating memory on the diagnostic rungs would reintroduce through the resource +metric exactly the per-phase veto R4 removed, which is why the scope is named +here rather than left to a reader. Every other surface in the table is **published, never gating**. A derived view may inform a reading and may never serve as a gate. From a7350c65c4823af5ae481fa473f840d56f40f86e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 09:19:49 +0500 Subject: [PATCH 04/11] docs(t0): the gray zone gets its second dimension, and the budgets get values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T0-2 defined two coordinates and T0-5 then judged a scalar `value` against a PASS_LIMIT. Nothing produced that scalar and nothing said which number it was — relative, absolute, some normalisation, the larger of the two. The decision function was underdetermined, and the missing piece was a dimension, not a limit. R5 — the gray zone is two-dimensional. PASS iff relative <= M_pass OR absolute <= A_pass; FAIL iff relative >= M_fail AND absolute >= A_fail; otherwise NO_DECISION, with M_pass < M_fail and A_pass < A_fail required. The two conditions are then mutually exclusive, so each gate is a total single-valued function. PASS_LIMIT, FAIL_LIMIT and gray_zone_margin_binding are removed as symptoms of the wrong model, not filled in. R6/R7 — eight budgets, per resource, superseding M, A and M_A_scope: time gates 5 %/50 ms to pass, 10 %/100 ms to fail; RSS gates 10 %/32 MiB to pass, 20 %/64 MiB to fail, recorded in bytes so a checker needs no arithmetic. Both regimes of a resource share its budgets; time and memory share nothing, because one absolute value cannot span milliseconds and bytes. R8 — retry_budget: 1. One initial attempt plus at most one full-session retry after INVALID; a second INVALID is NO_DECISION. R9 — a fresh manifest per session, identity rechecked after it, drift INVALID. R10-R13 — the host predicate splits declared provisioning evidence from runtime-verified invariants, and does not call the first a proof: a guest OS cannot establish what the hypervisor is doing. Power policy is pinned per platform with turbo left alone, background prohibitions name transient heavy jobs rather than a debloat ritual, and quiesce is 120 s with a measured 60 s window — whose failure is "not eligible to start", never INVALID, so it starts no clock, produces no number and cannot be outcome-selective. Zero UNRESOLVED_OWNER_DECISION slots remain. Status stays NOT_FROZEN and collection_authorized: false until the hostile freeze review is done — completeness is what makes a freeze reviewable, not the freeze itself. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 336 +++++++++++++++------- 1 file changed, 239 insertions(+), 97 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 2bd15e3f..5edf2470 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -4,8 +4,8 @@ Status: NOT_FROZEN. collection_authorized: false - STRUCTURE RESOLVED. NUMERIC AND HOST SLOTS OPEN. - MANDATORY UNRESOLVED SLOTS: 12 (T0-completion). + CONTENT COMPLETE. HOSTILE FREEZE REVIEW PENDING. + MANDATORY UNRESOLVED SLOTS: 0 (T0-completion). OPEN NORMATIVE CONFLICTS: none. The #262 ratification blocker was withdrawn as a misreading — see T0-3. NO CLOCK HAS RUN. NO OBSERVATION EXISTS. @@ -83,48 +83,58 @@ noise-cancellation property may be asserted for `R`. ## T0-2 — Acceptance margins -**FORM RESOLVED. VALUES OPEN.** +**RESOLVED (R5, R6, R7). No open value.** -A gate FAILs only when both margins are exceeded: +Two coordinates, never collapsed into a score: - FAIL(gate) iff relative_regression(gate) > M AND absolute_regression(gate) > A +| term | definition | +|---|---| +| `relative_regression` | `R - 1` for the gate's cell set, `R` per T0-1 | +| `absolute_regression` | the median over matched pairs of `median(Rust_c) - median(Python_c)`, in the gate's own unit | +| unit, time gates | milliseconds — the instrument records `perf_counter_ns`, so the conversion belongs to the reading, never to the evidence | +| unit, memory gates | bytes of peak RSS, after the instrument's own `ru_maxrss` unit normalisation (kilobytes on Linux, bytes on macOS/BSD) | Two margins, because neither alone is meaningful: a relative-only rule fails a `0.20 ms -> 0.24 ms` change that no user can perceive, and an absolute-only rule is blind to scale. -Semantics, frozen: - -| term | definition | -|---|---| -| `relative_regression` | `R - 1` for the gate's cell set, `R` per T0-1 | -| `absolute_regression` | the median over matched pairs of `median(Rust_c) - median(Python_c)`, in the gate's own unit | -| unit, time gates | milliseconds | -| unit, memory gates | bytes of peak RSS | +Each gate carries **two pairs** of budgets — one pair that admits a pass, one +pair that compels a failure — and the decision rule over them is T0-5: ```yaml -M: UNRESOLVED_OWNER_DECISION # dimensionless ratio margin -A: UNRESOLVED_OWNER_DECISION # absolute margin, carries the gate's unit: - # milliseconds for the time gates, - # bytes for the peak RSS gates -M_A_scope: UNRESOLVED_OWNER_DECISION # see the dimensional constraint below +# R6 — both primary elapsed-time gates +# launcher-e2e / process-cold / elapsed +# launcher-e2e / warm / elapsed +M_pass_time: 0.05 # +5 % +A_pass_time: 50 # milliseconds +M_fail_time: 0.10 # +10 % +A_fail_time: 100 # milliseconds + +# R7 — both primary peak-RSS gates +# launcher-e2e / process-cold / peak RSS +# launcher-e2e / warm / peak RSS +M_pass_rss: 0.10 # +10 % +A_pass_rss: 33554432 # bytes, 32 MiB +M_fail_rss: 0.20 # +20 % +A_fail_rss: 67108864 # bytes, 64 MiB ``` -**Dimensional constraint, recorded rather than decided.** `A` carries the gate's -own unit, and the primary set now spans two units — milliseconds and bytes. One -absolute value therefore cannot serve all four gates: a single `A` shared across -time and memory is not a budget the owner has yet to pick, it is not a quantity. -"One pair for all gates" is consequently unavailable for `A` as literally -phrased, and the numeric ruling should be asked in the terms the units allow: one -absolute budget for the time gates and one for the memory gates, with the open -questions being whether `M` — dimensionless, and so unconstrained by this — is -one budget or split, and whether the two gates inside a unit share one `A` or -take one each. No value, and no choice among those readings, is made here. - -`M` and `A` derive from the cutover/product budget — what a user may be made to -wait, and how much memory the migration may cost. They may not be derived from -observed Rust-vs-Python results, calibration variance, or training output. Their -relationship to the T0-5 decision limits is itself an open slot, recorded there. +Required of every gate, and true of both sets above: + + M_pass < M_fail + A_pass < A_fail + +Both regimes of a resource share that resource's budgets — not because +`process-cold` and `warm` are the same thing, but because the product price of +making a user wait is the same in either. Time and memory do **not** share +budgets: a single absolute value cannot span milliseconds and bytes, and a shared +relative budget would be a tidy symmetry bought with meaning. This is what +replaces the old `M`, `A` and `M_A_scope`: eight named per-resource budgets, with +no scope left ambiguous. + +These budgets come from the cutover/product price of latency and memory. They may +not be derived from observed Rust-vs-Python results, calibration variance, or +training output — and none of the eight was. --- @@ -259,11 +269,12 @@ eligibility (T0-7: host qualified, every required primary metric has a │ └─ budget exhausted ─► NO_DECISION └─ clean │ - primary gates, T0-2 margins read through the T0-5 limits + each of the four primary gates, by the two-dimensional rule of + T0-5 over the T0-2 budgets │ ├─ any gate FAIL ─────────────► FAIL ─► NO_GO - ├─ any gate in the gray zone ─► NO_DECISION - └─ all gates PASS ────────────► PASS ─► GO + ├─ any gate NO_DECISION ──────► NO_DECISION + └─ all four gates PASS ───────► PASS ─► GO ``` The three null-metric situations are **different states**, and collapsing them @@ -287,11 +298,40 @@ resolve. ## T0-5 — Uncertainty rule -**MODEL RESOLVED: deterministic gray zone. LIMITS OPEN.** +**RESOLVED (R5): a deterministic gray zone in two dimensions.** - value <= PASS_LIMIT => PASS - value >= FAIL_LIMIT => FAIL - PASS_LIMIT < value < FAIL_LIMIT => NO_DECISION +The gray zone is defined on the same two coordinates the margins are, and no +synthetic scalar score is constructed from them. Per gate: + +```text +PASS iff relative_regression <= M_pass + OR absolute_regression <= A_pass + +FAIL iff relative_regression >= M_fail + AND absolute_regression >= A_fail + +otherwise NO_DECISION +``` + +**An earlier draft was underdetermined and this replaces it.** T0-2 gives two +coordinates; that draft's `value <= PASS_LIMIT` named a scalar nothing produced, +and left "which number is `value`" — relative, absolute, some normalisation, the +larger of the two — unanswered. The answer was not a limit to be chosen later; it +was a missing dimension. `PASS_LIMIT`, `FAIL_LIMIT` and `gray_zone_margin_binding` +are therefore removed as symptoms of the wrong model rather than filled in. + +The two-dimensional form keeps what the dual-margin rule was for in the first +place: a small absolute difference does not become a problem merely because the +baseline is microscopic, and a small relative difference does not become a problem +merely because the workload is enormous. Between "cheap on either coordinate" and +"expensive on both" there is now a real gray zone, and it is named. + +**The two conditions cannot both hold.** `PASS` via the relative coordinate +requires `relative_regression <= M_pass < M_fail`, which contradicts `FAIL`'s +`relative_regression >= M_fail`; `PASS` via the absolute coordinate contradicts +`FAIL`'s absolute condition the same way, because `A_pass < A_fail`. The ordering +requirement in T0-2 is what makes the per-gate function total and single-valued — +one of `PASS`, `FAIL`, `NO_DECISION`, never two. **Why not a bootstrap over cells.** The cells are a fixed, preregistered set of acceptance strata — an engineering choice of workloads, rungs and regimes — not @@ -306,23 +346,16 @@ confidence level, the resampling unit, the resample count and the seed would eac have had to be frozen, and each would have been a place to negotiate with the data afterwards. -```yaml -PASS_LIMIT: UNRESOLVED_OWNER_DECISION # per gate unit; the value at or below which a gate passes -FAIL_LIMIT: UNRESOLVED_OWNER_DECISION # per gate unit; the value at or above which a gate fails -gray_zone_margin_binding: UNRESOLVED_OWNER_DECISION -# how PASS_LIMIT/FAIL_LIMIT relate to the T0-2 predicate: whether the M/A pair -# IS the FAIL_LIMIT with PASS_LIMIT below it, or the two limits bracket M/A. -# Both readings are consistent with the form; they are not the same contract. -``` - -The limits are budget quantities. They may not be derived from training results, -calibration variance or any observed comparison. +The zone's boundaries are the eight budgets of T0-2 and nothing else: there is no +separate limit to set here, which is the point of removing the scalar pair. They +may not be derived from training results, calibration variance or any observed +comparison. --- ## T0-6 — Invalidation and retry -**SEMANTICS RESOLVED. BUDGET OPEN.** +**RESOLVED (R8, R9).** The unit of invalidation is the **session** — the whole predefined measurement unit, as the instrument already treats it. A phase, a cell or a workload is never @@ -337,26 +370,45 @@ Invalidation fires only on machine-detectable predicates frozen in advance: - a cell that did not do its rung's work, proved by its post-condition; - a required primary metric that returned `null` or went missing mid-attempt (T0-4 case B); -- identity-field drift in the step-7 environment manifest, fields compared whole; +- identity-field drift in the step-7 environment manifest, fields compared whole, + on the post-session recheck (R9); - candidate byte drift within a stratum after collection started. **A performance result is never an invalidation condition.** Not a slow cell, not -a gray-zone outcome, not a disappointing `R`. +a gray-zone outcome, not a disappointing `R`. Every predicate above is +machine-detected, so no operator chooses to invalidate a session. One retry attempt is one full re-collection of the invalidated session on the -same qualified host. Retries are bounded; on exhaustion the outcome is -`NO_DECISION`, never "one more run". Every attempt, including invalidated ones, -is retained as evidence and none is deleted. +same qualified host. Every attempt, including invalidated ones, is retained as +evidence and none is deleted. ```yaml -retry_budget: UNRESOLVED_OWNER_DECISION # attempts per stratum, integer +retry_budget: 1 # R8 ``` +Read literally: + + 1 initial attempt + + at most 1 full-session retry after INVALID + = at most 2 attempts per stratum + +After a second `INVALID`, the outcome is `NO_DECISION`. There is no third throw +of the coin. One retry survives a genuine one-off environmental failure; a larger +budget would turn the campaign into a machine that runs until the infrastructure +eventually cooperates. + +**Manifest refresh is per session (R9).** A fresh environment manifest is +captured before every measurement session, and the identity-bearing fields are +rechecked after it; drift between the two is `INVALID`. A campaign-level manifest +is too weak: between an update, a reboot, a governor change and the other ways a +computer gets improved, it can become a historical document before the second +session starts. + --- ## T0-7 — Host eligibility predicate -**PARTIALLY OPEN — a freeze blocker.** +**RESOLVED (R10–R13).** Already normative, from the existing contract: @@ -377,20 +429,101 @@ Already normative, from the existing contract: before the session is eligible (T0-4 case A). On a host where peak RSS has no mechanism, the session does not start; it does not start and then fail. -Still unresolved, and each is machine-checkable only once ruled: +### R10 — single tenancy, in two classes of evidence + +A guest OS cannot look at the hypervisor and establish that no neighbour has +appeared on the same iron. Pretending otherwise would be security theatre in a lab +coat, so the predicate separates what is declared from what is checked, and never +calls the declaration a proof. + +```yaml +single_tenant_predicate: + provisioning: # declared, recorded as evidence, shape-checked + dedicated_to_p022: true + no_concurrent_user_workload: true + hosted_ci_runner: false + if_vm: + fixed_vcpu: true + fixed_ram: true + live_migration_disabled: true + dynamic_memory_disabled: true + runtime: # machine-verified each session + host_fingerprint_stable: true + logical_cpu_count_stable: true + memory_bytes_stable: true + candidate_identity_stable: true + ci_environment_absent: true # the manifest's own `ci` provenance field +``` + +The checker asserts the presence and shape of the provisioning declaration and +verifies every runtime invariant. It does not claim the first class is machine +proof. + +### R11 — power policy ```yaml -single_tenant_predicate: UNRESOLVED_OWNER_DECISION # what a checker asserts -power_policy_requirement: UNRESOLVED_OWNER_DECISION # per platform -permitted_background: UNRESOLVED_OWNER_DECISION # what may run during a session -quiesce_procedure: UNRESOLVED_OWNER_DECISION # and how it is evidenced -manifest_refresh_rule: UNRESOLVED_OWNER_DECISION # per session or per campaign +power_policy_requirement: + linux: + governor: performance # on all applicable CPUs + turbo_boost_state: recorded and unchanged through the session + windows: + power_plan: High Performance OR Ultimate Performance + processor_minimum_state: 100 + processor_maximum_state: 100 + active_plan_identity: unchanged through the session ``` -An incomplete predicate blocks the freeze. It is not an invitation to write down -one drafter's idea of a good benchmark host. Reconnaissance already performed on -a shared developer workstation is **exploratory only**: it may inform the shape of -the predicate and contributes no measurement, no manifest and no qualified host. +Turbo is **not** forcibly disabled. The subject is a production-like code path, +not SPEC CPU in a monastery, and instability is what the noise and drift probes +exist to catch. + +### R12 — permitted background + +Baseline OS services are permitted; this is not a debloat ritual. Prohibited for +the duration of a session: + +```yaml +permitted_background: + prohibited_during_session: + - OS or package updates + - scheduled antivirus or full scans + - backup jobs + - indexing rebuilds + - build or test workloads unrelated to the campaign + - interactive user workloads +``` + +Windows Defender realtime protection is not itself prohibited. If it makes the +environment unstable, the noise and drift predicates catch it — that is a +measurement question, not a reason to switch off a security stack by ritual. + +### R13 — quiesce procedure + +```yaml +quiesce_procedure: + before_session: + no_campaign_workload_for: 120 s + during_final: 60 s + mean_host_cpu_utilisation_below: 0.05 + no_5_second_sample_above: 0.20 + no_prohibited_background_job_active: true + then: opening noise probe + after_session: + - closing noise probe + - environment identity recheck +``` + +**A quiesce failure is `not eligible to start`, never `INVALID`** — no clock has +run, so there is no evidence to damage and nothing to retry. It therefore consumes +no retry budget, and it cannot be outcome-selective: a session that never started +produced no number to prefer. + +The existing 0.35 noise, drift and reproducibility limits apply unchanged after +this point. + +Reconnaissance already performed on a shared developer workstation remains +**exploratory only**: it informed the shape of this predicate and contributes no +measurement, no manifest and no qualified host. --- @@ -425,36 +558,40 @@ ladder `[5, 15, 45]`, `G = [1, 10]`, per-stratum admissible sets `Q_linux ∩ Q_windows`, and `NO_COMMON_N` is a stop with no fallback rung. Training may not change, and seeing training output grants no licence to revisit: -the statistic, the pairing unit, `M`, `A`, the gate population, the decision -limits, the uncertainty model, the decision automaton, retry semantics, host -eligibility semantics, or workload selection and replacement rules. +the statistic, the pairing unit, any of the eight per-resource budgets, the gate +population, the two-dimensional decision rule, the decision automaton, retry +semantics and budget, manifest refresh, host eligibility semantics, or workload +selection and replacement rules. --- ## T0-completion -T0 is not frozen while any mandatory slot is unresolved. Until then -`collection_authorized: false`. +**No `UNRESOLVED_OWNER_DECISION` slot remains.** Every value this contract needs +is now in it: -| # | slot | section | +| what | where | ruling | |---|---|---| -| 1 | `M` | T0-2 | -| 2 | `A` | T0-2 | -| 3 | `M_A_scope` | T0-2 | -| 4 | `PASS_LIMIT` | T0-5 | -| 5 | `FAIL_LIMIT` | T0-5 | -| 6 | `gray_zone_margin_binding` | T0-5 | -| 7 | `retry_budget` | T0-6 | -| 8 | `single_tenant_predicate` | T0-7 | -| 9 | `power_policy_requirement` | T0-7 | -| 10 | `permitted_background` | T0-7 | -| 11 | `quiesce_procedure` | T0-7 | -| 12 | `manifest_refresh_rule` | T0-7 | +| eight per-resource budgets | T0-2 | R6, R7 | +| the two-dimensional decision rule | T0-5 | R5 | +| `retry_budget: 1` | T0-6 | R8 | +| `manifest_refresh_rule: per session` | T0-6 | R9 | +| single-tenancy, in two evidence classes | T0-7 | R10 | +| power policy, per platform | T0-7 | R11 | +| permitted background | T0-7 | R12 | +| quiesce procedure | T0-7 | R13 | Removed rather than filled, because the acceptance contract does not make the -requirement: `K`, `B`, `caps_apply_to` (R4), and `null_primary_metric_outcome` -(replaced by the three distinct states of T0-4). Closed as a misreading: -ratification of the gate population against #262 (R3). +requirement: `K`, `B`, `caps_apply_to` (R4); `null_primary_metric_outcome` +(replaced by the three distinct states of T0-4); and `PASS_LIMIT`, `FAIL_LIMIT`, +`gray_zone_margin_binding` (R5 — symptoms of a scalar model that did not match the +two coordinates the margins are defined on). Superseded: `M`, `A` and `M_A_scope`, +by the eight typed per-resource budgets. Closed as a misreading: ratification of +the gate population against #262 (R3). + +**`status: NOT_FROZEN` stands until a hostile freeze review is completed.** +Content completeness is not the freeze; it is what makes the freeze reviewable. +`collection_authorized: false`. --- @@ -467,17 +604,22 @@ ratification of the gate population against #262 (R3). | change the primary gate population? | **no** — T0-3 resolved under R1/R4; a new gate is an amendment, not an adjustment | | reintroduce per-phase vetoes quietly? | **no** — the caps were removed from the contract, and a derived view may never gate | | pick the uncertainty model after the data? | **no** — deterministic gray zone chosen, with its rationale recorded in T0-5 | -| change `M`/`A` or the decision limits? | **yes while unresolved** — the remaining budget exposure, closed by the numeric packet | -| raise the retry budget after a failure? | **yes while unresolved**; once set, bounded, and exhaustion yields NO_DECISION | +| change a budget after seeing a number? | **no** — all eight are set, and T0-9 forbids revisiting | +| construct a scalar score and argue about which number it is? | **no** — the rule is two-dimensional and no scalar exists to construct | +| raise the retry budget after a failure? | **no** — `retry_budget: 1`, and a second `INVALID` is `NO_DECISION` | +| invalidate a session deliberately to buy a retry? | **no** — every invalidation predicate is machine-detected, and a performance result is never one | +| re-run quiesce until the machine looks good? | **permitted, and harmless** — a failed quiesce starts no clock and produces no number, so it cannot be outcome-selective; it consumes no retry budget | | replace a host because the result is unpleasant? | **no** — T0-8 rules 3 and 5 | | can a missing or null primary metric yield PASS? | **no** — structurally, in all three T0-4 states | | can a host with no mechanism for a required metric start a session? | **no** — T0-7 eligibility, T0-4 case A | +| can a stale manifest carry a campaign? | **no** — fresh per session, rechecked after, drift is `INVALID` | | can anyone start collecting because hosts and binding are ready? | **no** — T0-0 revoked that; `collection_authorized: false` | -| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** once the limits are set — the automaton is a function of evidence; **yes while `PASS_LIMIT`/`FAIL_LIMIT` are empty** | +| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** — per gate the two conditions are mutually exclusive by `M_pass < M_fail` and `A_pass < A_fail`, and the roll-up is a total function of the four gate outcomes | +| does the declaration of single tenancy masquerade as proof? | **no** — provisioning evidence and runtime invariants are separated, and only the latter is called machine-verified | -Three "yes" answers remain, all of them the same thing: the budget numbers are -not chosen yet. None is a structural hole, and none may be closed by looking at -data. +No "yes" answer remains that a decision could close. The one permitted item — a +repeated quiesce attempt — produces no evidence and therefore cannot select an +outcome. - T0_SKELETON_READY_FOR_NUMERIC_RULINGS + T0_CONTENT_COMPLETE_READY_FOR_FREEZE_REVIEW status: NOT_FROZEN — collection_authorized: false From 7483d95b7adebb1c17a0665099995be38a8d0df8 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 17:50:23 +0500 Subject: [PATCH 05/11] docs(t0): the population, the domain, the completeness and the eight gates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 3, in one commit, on the four findings the freeze review left plus the platform split that #355 made necessary. S1 — the gate population belongs to T0, not to a function. The gates are computed over exactly the decisive workloads of the D7-bound manifest that the `launcher-e2e` rung admits — all thirteen at the current manifest — and calibration workloads never enter a cutover gate. A missing decisive workload, a missing engine side, an unexpected extra cell or a calibration cell inside the set each make the attempt INVALID: a missing cell is not a smaller denominator. The instrument's applicability rule implements that sentence; it is not the source of it, because two readers must not be able to answer differently about which cells a gate covers. S2 — the numeric domain is checked BEFORE the two-dimensional rule, not inside it. Every quantity a gate consumes must be defined, real and finite, with medians strictly positive; None, NaN or an infinity in R or either coordinate invalidates the attempt. Checked first because the rule's OR would otherwise let `relative = NaN, absolute = 10 ms` pass on the strength of the other coordinate. A comparison against an undefined number is not one that succeeded. S3 — a primary cell holds exactly N samples, each finite, positive and carrying its stratum's declared metric kind. One null, one missing sample or one unexpected metric kind invalidates the session. A median over the surviving subset is forbidden by name: the instrument's summariser drops absent memory samples silently, so without this rule a cell that lost half its measurements reports a confident median of the other half. S8 — since the memory quantity is platform-local, gate identity carries its stratum: eight primary gates, four per stratum, with `max_process_peak_resident` on Linux and `max_process_peak_commit` on Windows. `resident == commit` is asserted nowhere, the strata are never pooled, and the two memory budget families carry identical numbers while remaining two budgets — they agree today because both came from one product budget before any data existed, and either may move without the other. S7 — the replacement conditions are closed at six, with no "other environmental reason" escape hatch, and the retry budget belongs to the STRATUM. Replacement does not reset it; a valid outcome-bearing session closes the stratum and is retained forever; re-measurement requires a previous INVALID and remaining budget. Every replacement records both binding identities and the budget left, so a reader can see what it did and did not buy. Verified by enumeration rather than by reading: the eight-gate roll-up is total and single-valued over all 6561 combinations, 108 boundary points across the three budget families yield exactly one verdict each, and the domain check rejects NaN and both infinities before the rule sees them. Stale vocabulary swept from the normative text: no generic "peak RSS" gate, no "four primary gates", no cross-platform R. The old names survive only where they are explicitly named obsolete. Status is unchanged and deliberately so: NOT_FROZEN, collection_authorized false. This closes the content; the freeze is its own review and its own commit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 308 ++++++++++++++++++---- 1 file changed, 259 insertions(+), 49 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 5edf2470..2ab061b1 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -92,7 +92,7 @@ Two coordinates, never collapsed into a score: | `relative_regression` | `R - 1` for the gate's cell set, `R` per T0-1 | | `absolute_regression` | the median over matched pairs of `median(Rust_c) - median(Python_c)`, in the gate's own unit | | unit, time gates | milliseconds — the instrument records `perf_counter_ns`, so the conversion belongs to the reading, never to the evidence | -| unit, memory gates | bytes of peak RSS, after the instrument's own `ru_maxrss` unit normalisation (kilobytes on Linux, bytes on macOS/BSD) | +| unit, memory gates | bytes of the stratum's own `memory_metric`, after the instrument's unit normalisation — resident on `linux`, committed on `windows`, never mixed | Two margins, because neither alone is meaningful: a relative-only rule fails a `0.20 ms -> 0.24 ms` change that no user can perceive, and an absolute-only rule @@ -101,24 +101,38 @@ is blind to scale. Each gate carries **two pairs** of budgets — one pair that admits a pass, one pair that compels a failure — and the decision rule over them is T0-5: +Each budget family below applies to **both regimes** of its resource, on the +stratum named. The pass pair and the fail pair belong to the same gate: no regime +owns one of them. + ```yaml -# R6 — both primary elapsed-time gates -# launcher-e2e / process-cold / elapsed -# launcher-e2e / warm / elapsed -M_pass_time: 0.05 # +5 % -A_pass_time: 50 # milliseconds -M_fail_time: 0.10 # +10 % -A_fail_time: 100 # milliseconds - -# R7 — both primary peak-RSS gates -# launcher-e2e / process-cold / peak RSS -# launcher-e2e / warm / peak RSS -M_pass_rss: 0.10 # +10 % -A_pass_rss: 33554432 # bytes, 32 MiB -M_fail_rss: 0.20 # +20 % -A_fail_rss: 67108864 # bytes, 64 MiB +# R6 — elapsed time. Both strata, both regimes: four of the eight gates, one family. +time: + M_pass: 0.05 # +5 % + A_pass: 50 # milliseconds + M_fail: 0.10 # +10 % + A_fail: 100 # milliseconds + +# R7 — memory. One family per stratum, because the quantities differ. +linux_max_process_peak_resident: # both regimes + M_pass: 0.10 # +10 % + A_pass: 33554432 # bytes, 32 MiB + M_fail: 0.20 # +20 % + A_fail: 67108864 # bytes, 64 MiB + +windows_max_process_peak_commit: # both regimes + M_pass: 0.10 # +10 % + A_pass: 33554432 # bytes, 32 MiB + M_fail: 0.20 # +20 % + A_fail: 67108864 # bytes, 64 MiB ``` +**The two memory families carry identical numbers and are not the same budget.** +Resident bytes and committed bytes are different physical quantities; the numbers +agree today because both were chosen from the same product budget before any data +existed, and either may later move without the other. Reading the coincidence as +one cross-platform metric is exactly the error #355 removed from the instrument. + Required of every gate, and true of both sets above: M_pass < M_fail @@ -128,13 +142,15 @@ Both regimes of a resource share that resource's budgets — not because `process-cold` and `warm` are the same thing, but because the product price of making a user wait is the same in either. Time and memory do **not** share budgets: a single absolute value cannot span milliseconds and bytes, and a shared -relative budget would be a tidy symmetry bought with meaning. This is what -replaces the old `M`, `A` and `M_A_scope`: eight named per-resource budgets, with +relative budget would be a tidy symmetry bought with meaning. Nor do the two +strata share a memory budget, for the same reason at one remove: resident and +committed bytes are different quantities that happen to be priced alike. This is +what replaces the old `M`, `A` and `M_A_scope`: three named budget families, with no scope left ambiguous. These budgets come from the cutover/product price of latency and memory. They may not be derived from observed Rust-vs-Python results, calibration variance, or -training output — and none of the eight was. +training output — and none of them was. --- @@ -170,7 +186,7 @@ number may never be renamed into something stronger than it proves: | surface | observable | class | |---|---|---| | launcher end-to-end run | `launcher-e2e` | `DIRECT` | -| peak RSS | `os.wait4` `ru_maxrss` (POSIX) / job object `PeakProcessMemoryUsed` (Windows), `null` with a reason elsewhere | `DIRECT` where a mechanism exists | +| peak memory | `os.wait4` `ru_maxrss` on `linux` (resident) / job object `PeakProcessMemoryUsed` on `windows` (committed), `null` with a reason elsewhere | `DIRECT` where a mechanism exists, and the quantity is named beside the number | | core startup floor | `core-usage`, composed over `process-startup-core` + `cli-argv-parse` + `cli-usage-refusal` | `DIRECT` as an interval; a **lower bound** on core startup, never relabelled "startup" | | OwnIR parse | `core-parse-refused - core-usage` | `DERIVED_ASSUMPTION_DEPENDENT` — assumes both invocations pay comparable argv handling and refusal rendering | | CLI/SARIF rendering | `core-full-sarif - core-full-human` | `DERIVED_EXACT` **for the renderer difference**; imputing "rendering in isolation" from it is not permitted | @@ -198,14 +214,31 @@ iterations, with the OS and filesystem caches warm. `machine-cold` is **not claimed** by the instrument and is therefore not a gate, not a regime and not an alias for anything here. A bare `cold` is not an identifier in this contract. -**R2 — peak RSS** remains a required resource gate wherever the contract provides -a mechanism, and it carries the same regime dimension as time. `peak_rss_bytes` -is captured on every measured cell, and a cell's key includes its regime, so -memory exists separately for `process-cold` and for `warm` rather than as one -number beside the surface. `warm` memory may not hide inside `process-cold` -memory, or the reverse. Allocation and heap profiling is diagnostic, published for selected -workloads where practical; **a missing allocation profile is neither `INVALID` -nor `FAIL`**, and no instrumentation is added under T0 to obtain one. +**R2 — peak memory** remains a required resource gate wherever the contract +provides a mechanism, and it carries the same regime dimension as time. +`peak_memory_bytes` is captured on every measured cell, and a cell's key includes +its regime, so memory exists separately for `process-cold` and for `warm` rather +than as one number beside the surface. `warm` memory may not hide inside +`process-cold` memory, or the reverse. Allocation and heap profiling is +diagnostic, published for selected workloads where practical; **a missing +allocation profile is neither `INVALID` nor `FAIL`**, and no instrumentation is +added under T0 to obtain one. + +**There is no generic "peak RSS" gate in this contract; that name is obsolete.** +The instrument names two different physical quantities and carries the name with +the number, because a witness showed they are not the same thing — a child that +commits 256 MiB and never touches a page is reported in full by the Windows job +object and not at all by `ru_maxrss`: + +| stratum | `memory_metric` | what it counts | +|---|---|---| +| `linux` | `max_process_peak_resident` | peak **resident** set over the waited-for descendant chain | +| `windows` | `max_process_peak_commit` | peak **committed** memory of any process in the job | + +`resident == commit` is asserted nowhere in this contract, and the two are never +pooled, averaged or compared across platforms. A cell whose `memory_metric` is +not the one its stratum declares does not belong to that gate, and its presence +makes the attempt `INVALID`. **R4 — Option 2, the current observable surface, with no new diagnostic veto gates.** Catastrophic per-phase caps were considered and rejected: they are an @@ -215,19 +248,59 @@ from this contract rather than filled — they are not part of it. Should a real profile later show the need for such a guardrail, it arrives as its own owner-ratified amendment, not as a silent passenger inside a preregistration. -The primary gate set is therefore exactly **four** independent gates: +### The gate workload population, owned here + +The gates are computed over **exactly the decisive workloads of the D7-bound +workload manifest that are applicable to the `launcher-e2e` rung**, and over +nothing else. At the currently frozen manifest that is all **13** decisive +workloads — every one of them is a source tree, and the launcher rung admits +every one. + +**Calibration workloads never enter a cutover gate.** They exist to size the +instrument; a gate computed over them would be answering a different question +with the same arithmetic. + +The instrument's own applicability rule is an implementation of this sentence, +not the source of it. Population semantics belong to T0: a reader must be able to +say which cells a gate covers without reading a function, and two readers must +not be able to answer differently. + +Missing cells are not a smaller denominator. Each of these makes the attempt +`INVALID`: ```text -launcher-e2e / process-cold / elapsed time (milliseconds) -launcher-e2e / warm / elapsed time (milliseconds) -launcher-e2e / process-cold / peak RSS (bytes) -launcher-e2e / warm / peak RSS (bytes) +a decisive workload absent from the gate set => INVALID +a cell present for one engine and not the other => INVALID +an unexpected extra decisive cell => INVALID +a calibration cell inside the gate set => INVALID ``` -**No compensation, in either direction**: not between `process-cold` and `warm`, -and not between time and memory. Four gates, each read on its own. +D7 binds the exact workload-manifest digest, and therefore the exact decisive +set: the population cannot be re-read later as "whatever was measured". -The roll-up over them is the automaton of T0-4, applied without addition: +### The eight gates + +Since #355 the memory quantity is platform-local, so the gate identity carries +its stratum. The primary set is exactly **eight** independent gates, four per +stratum: + +```text +linux / launcher-e2e / process-cold / elapsed (ms) +linux / launcher-e2e / warm / elapsed (ms) +linux / launcher-e2e / process-cold / max_process_peak_resident (bytes) +linux / launcher-e2e / warm / max_process_peak_resident (bytes) + +windows / launcher-e2e / process-cold / elapsed (ms) +windows / launcher-e2e / warm / elapsed (ms) +windows / launcher-e2e / process-cold / max_process_peak_commit (bytes) +windows / launcher-e2e / warm / max_process_peak_commit (bytes) +``` + +**No compensation in any direction**: not between `process-cold` and `warm`, not +between time and memory, and not between the two strata. `U_linux` and +`U_windows` are never pooled, and no ratio is formed across them. + +The roll-up over the eight is the automaton of T0-4, applied without addition: ```text any gate FAIL => FAIL @@ -235,8 +308,8 @@ else any NO_DECISION => NO_DECISION else => PASS ``` -**Peak RSS is gated on `launcher-e2e` only.** The instrument captures -`peak_rss_bytes` on every measured cell and those values are **published as +**Memory is gated on `launcher-e2e` only.** The instrument captures +`peak_memory_bytes` on every measured cell and those values are **published as diagnostic evidence**, but a memory number on a diagnostic rung never gates. Gating memory on the diagnostic rungs would reintroduce through the resource metric exactly the per-phase veto R4 removed, which is why the scope is named @@ -269,12 +342,12 @@ eligibility (T0-7: host qualified, every required primary metric has a │ └─ budget exhausted ─► NO_DECISION └─ clean │ - each of the four primary gates, by the two-dimensional rule of + each of the eight primary gates, by the two-dimensional rule of T0-5 over the T0-2 budgets │ ├─ any gate FAIL ─────────────► FAIL ─► NO_GO ├─ any gate NO_DECISION ──────► NO_DECISION - └─ all four gates PASS ───────► PASS ─► GO + └─ all eight gates PASS ──────► PASS ─► GO ``` The three null-metric situations are **different states**, and collapsing them @@ -294,6 +367,63 @@ and are kept apart because they mean different things: `INVALID` says the measurement did not happen properly, `NO_DECISION` says it happened and did not resolve. +### The numeric domain, before any rule is applied + +Every quantity a primary gate consumes must be **defined, real and finite** +before T0-5 is reached. Per cell: + +```text +median elapsed > 0 +median memory > 0 (the stratum's own metric) +``` + +and for the derived quantities `R`, `relative_regression` and +`absolute_regression`, any of + +```text +None · NaN · +inf · -inf · undefined arithmetic +``` + +makes the **whole attempt `INVALID`**. A negative finite regression is not in +that list: it is an improvement, and it passes. + +This is checked **before** the two-dimensional rule, not inside it, because the +rule's `OR` would otherwise let an undefined coordinate through on the strength +of the other one: + +```text +relative = NaN, absolute = 10 ms => INVALID, never PASS +relative = 0.01, absolute = NaN => INVALID, never PASS +``` + +A comparison against an undefined number is not a comparison that failed, and it +is certainly not one that succeeded. + +### Sample completeness + +A primary cell is admissible only when it holds **exactly the preregistered `N`** +samples. For elapsed time: + +```text +observed elapsed samples == N +every sample finite and > 0 +``` + +and for memory: + +```text +observed memory samples == N +every sample present, finite and > 0 +every sample carries the memory_metric its stratum declares +``` + +**One `null`, one missing sample or one unexpected metric kind makes the session +`INVALID`.** A median over the surviving subset is forbidden: the instrument's +summariser drops absent memory samples on the way past, so without this rule a +cell that lost half its measurements reports a confident median of the half that +survived. That is the defect this clause exists to close, and it is closed here +rather than in a reading nobody re-reads. + --- ## T0-5 — Uncertainty rule @@ -346,7 +476,7 @@ confidence level, the resampling unit, the resample count and the seed would eac have had to be frozen, and each would have been a place to negotiate with the data afterwards. -The zone's boundaries are the eight budgets of T0-2 and nothing else: there is no +The zone's boundaries are the budget families of T0-2 and nothing else: there is no separate limit to set here, which is the point of removing the scalar pair. They may not be derived from training results, calibration variance or any observed comparison. @@ -370,6 +500,14 @@ Invalidation fires only on machine-detectable predicates frozen in advance: - a cell that did not do its rung's work, proved by its post-condition; - a required primary metric that returned `null` or went missing mid-attempt (T0-4 case B); +- a primary cell holding other than exactly `N` samples, or a sample that is + absent, non-finite or not greater than zero (T0-4, sample completeness); +- a sample carrying a `memory_metric` other than the one its stratum declares; +- a gate quantity that is undefined, non-real or non-finite (T0-4, numeric + domain); +- a gate cell set that is not exactly the decisive population of T0-3 — a missing + decisive workload, a missing engine side, an unexpected extra cell, or a + calibration cell that found its way in; - identity-field drift in the step-7 environment manifest, fields compared whole, on the post-session recheck (R9); - candidate byte drift within a stratum after collection started. @@ -426,7 +564,8 @@ Already normative, from the existing contract: - per-stratum untimed builds, with `candidate_sha256` and `candidate_bytes` identical across every run of that stratum; - **every required primary metric must have a working mechanism on the host** - before the session is eligible (T0-4 case A). On a host where peak RSS has no + before the session is eligible (T0-4 case A). On a host where the stratum's + memory metric has no mechanism, the session does not start; it does not start and then fail. ### R10 — single tenancy, in two classes of evidence @@ -525,6 +664,23 @@ Reconnaissance already performed on a shared developer workstation remains **exploratory only**: it informed the shape of this predicate and contributes no measurement, no manifest and no qualified host. +### What the tooling owes this section + +The qualification layer implements these rules; it does not own them, and its +schemas are not restated here. T0 fixes the rule, the tooling fixes the +representation: + +```text +a qualification names the exact FROZEN T0 it was earned against +an execution binding names both strata, both candidates and the instrument +every session record names the execution binding it belongs to +a fresh environment manifest per session, identity compared as a whole +preflight before the clock, postflight after it +``` + +A qualification earned against a different T0 is not evidence under this one, and +a session that cannot name its binding does not belong to this campaign. + --- ## T0-8 — Selection and replacement @@ -535,13 +691,56 @@ measurement, no manifest and no qualified host. predicate and the noise floor, never against how the comparison came out. 2. The first host that passes the predicate, in a predeclared order, becomes the host of its stratum. -3. After any outcome-bearing data exists, a host may be replaced only for a - predeclared environmental failure condition. **A performance outcome is never a - replacement reason.** +3. After any outcome-bearing data exists, a host may be replaced only for one of + the six conditions below. **A performance outcome is never a replacement + reason.** 4. Replacement begins with full requalification. 5. Every replacement records: reason, the rule invoked, old identity, new identity, time and order. Evidence from the replaced host is retained. +### The replacement conditions, exhaustively + +```text +1. the host is permanently unavailable +2. hardware failure +3. OS or environment identity drift that cannot be restored +4. the required power-policy qualification cannot be restored +5. a required measurement mechanism is permanently unavailable +6. the provisioning guarantee is withdrawn +``` + +The wording of a condition may be sharpened; the class may not be widened. There +is deliberately no sixth-and-a-half "other environmental reason": a list with an +escape hatch is a list of one entry, and that entry is "whatever we felt". + +### Retry continuity — the budget belongs to the stratum + +```text +retry_budget is a property of the STRATUM, not of the host +host replacement does NOT reset it +``` + +If one `INVALID` has already spent the budget, a replacement host does not buy +another attempt. Otherwise a campaign could walk from machine to machine +collecting attempts until one of them came out well, which is the same failure +mode as an unbounded retry with extra paperwork. + +**A valid outcome-bearing session is retained as evidence forever**, and its +existence is what closes the stratum: once a valid `PASS`, `FAIL` or +`NO_DECISION` exists for a stratum, host replacement cannot create another +attempt. Re-measurement is permitted only when + +```text +the previous attempt was INVALID AND retry budget remains +``` + +A new binding identity does not erase the history of the old campaign attempt: it +starts a new campaign beside it, and both remain in the record. + +Every replacement additionally records the **old and new execution-binding +identities** and the **retry budget remaining** after it, so a reader can see +what a replacement did and did not buy. + Workloads and inputs are already frozen — 13 decisive entries, pinned. Drift on a pinned target is a **failed target**, never a newer measurement and never a substitution. @@ -558,7 +757,7 @@ ladder `[5, 15, 45]`, `G = [1, 10]`, per-stratum admissible sets `Q_linux ∩ Q_windows`, and `NO_COMMON_N` is a stop with no fallback rung. Training may not change, and seeing training output grants no licence to revisit: -the statistic, the pairing unit, any of the eight per-resource budgets, the gate +the statistic, the pairing unit, any budget of any family, the gate population, the two-dimensional decision rule, the decision automaton, retry semantics and budget, manifest refresh, host eligibility semantics, or workload selection and replacement rules. @@ -572,7 +771,7 @@ is now in it: | what | where | ruling | |---|---|---| -| eight per-resource budgets | T0-2 | R6, R7 | +| three budget families, time and one per stratum's memory metric | T0-2 | R6, R7 | | the two-dimensional decision rule | T0-5 | R5 | | `retry_budget: 1` | T0-6 | R8 | | `manifest_refresh_rule: per session` | T0-6 | R9 | @@ -580,13 +779,17 @@ is now in it: | power policy, per platform | T0-7 | R11 | | permitted background | T0-7 | R12 | | quiesce procedure | T0-7 | R13 | +| the decisive gate population | T0-3 | S1 | +| the numeric domain and sample completeness | T0-4 | S2, S3 | +| eight platform-qualified gates | T0-3 | S8 | +| the exhaustive replacement list and retry continuity | T0-8 | S7 | Removed rather than filled, because the acceptance contract does not make the requirement: `K`, `B`, `caps_apply_to` (R4); `null_primary_metric_outcome` (replaced by the three distinct states of T0-4); and `PASS_LIMIT`, `FAIL_LIMIT`, `gray_zone_margin_binding` (R5 — symptoms of a scalar model that did not match the two coordinates the margins are defined on). Superseded: `M`, `A` and `M_A_scope`, -by the eight typed per-resource budgets. Closed as a misreading: ratification of +by the three typed budget families of T0-2. Closed as a misreading: ratification of the gate population against #262 (R3). **`status: NOT_FROZEN` stands until a hostile freeze review is completed.** @@ -614,8 +817,15 @@ Content completeness is not the freeze; it is what makes the freeze reviewable. | can a host with no mechanism for a required metric start a session? | **no** — T0-7 eligibility, T0-4 case A | | can a stale manifest carry a campaign? | **no** — fresh per session, rechecked after, drift is `INVALID` | | can anyone start collecting because hosts and binding are ready? | **no** — T0-0 revoked that; `collection_authorized: false` | -| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** — per gate the two conditions are mutually exclusive by `M_pass < M_fail` and `A_pass < A_fail`, and the roll-up is a total function of the four gate outcomes | +| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** — per gate the two conditions are mutually exclusive by `M_pass < M_fail` and `A_pass < A_fail`, and the roll-up is a total function of the eight gate outcomes | | does the declaration of single tenancy masquerade as proof? | **no** — provisioning evidence and runtime invariants are separated, and only the latter is called machine-verified | +| can a calibration workload enter a cutover gate? | **no** — T0-3 owns the population: decisive workloads applicable to `launcher-e2e`, and a calibration cell in the set is `INVALID` | +| can a missing decisive workload quietly shrink the denominator? | **no** — a missing workload, a missing engine side or an unexpected extra cell each make the attempt `INVALID` | +| can a cell with fewer than `N` samples still produce a median? | **no** — a primary cell holds exactly `N`, every sample finite and positive; one `null` invalidates the session rather than yielding a median of the survivors | +| can an undefined quantity reach a verdict through the rule's `OR`? | **no** — the numeric domain is checked before T0-5; `NaN` on either coordinate is `INVALID`, never `PASS` | +| can Linux resident bytes be compared with Windows committed bytes? | **no** — the metric is part of the gate identity, the strata are never pooled, and `resident == commit` is asserted nowhere | +| can a replacement host buy another attempt? | **no** — the retry budget belongs to the stratum, replacement does not reset it, and a valid outcome closes the stratum | +| can a valid result be re-measured on a new host? | **no** — re-measurement needs a previous `INVALID` **and** remaining budget; a new binding starts a campaign beside the old one and erases nothing | No "yes" answer remains that a decision could close. The one permitted item — a repeated quiesce attempt — produces no evidence and therefore cannot select an From 5bf47fde5583273c04287111fcaa4ea39f0c78ee Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 17:56:30 +0500 Subject: [PATCH 06/11] docs(t0): the stratum is part of the cell, and the digest is the current one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three findings from the Phase-3 review, each a sentence. F1 — T0-1 cited `562a7f7232da` as the identity steps 4, 5 and 6 were accepted on. After the S8 memory-semantics repair that is no longer true: they were re-bound to `104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f`, which is now named in full. The superseded value is not kept as decoration — and the number is not removed either, because deleting a SHA to settle a mismatch would resolve it by deleting the checkability, which is the one thing this track is for. F2 — the pairing key now names the stratum: `(stratum, rung, workload, regime)`. Gates became platform-qualified in the previous commit while the definition of a cell still did not mention a platform, so a reader could have keyed on rung, workload and regime alone and formed one `R` across Linux and Windows — exactly the second admissible reading of one evidence set that S1 and S8 exist to prevent. Pairing never crosses a stratum, `median_c` is computed inside one gate's stratum, and no `R` spans the two. Every later use of cell, matched pair, the gate's cell set, `median_c` and `R` inherits that key, and no second term for it is introduced. F3 — "both sets above" became "all three budget families above": time, Linux resident and Windows commit. No other change. Status remains NOT_FROZEN, collection_authorized false. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 40 ++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 2ab061b1..7442cc86 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -41,11 +41,29 @@ zero, an infinity or an "N/A". The pairing unit is the **cell**, keyed - (rung, workload, regime) + (stratum, rung, workload, regime) stratum ∈ { linux, windows } Engine is not part of the key: it is the two sides of the pair. This is the -ratified four-part cell identity of §2.1 with `engine` projected out, so the pair -exists exactly where both engines have a timed cell. +ratified four-part cell identity of §2.1 with `engine` projected out and the +stratum named, so the pair exists exactly where both engines have a timed cell on +**one** platform. + +**Pairing never crosses a stratum.** `median_c` is computed only within one +primary gate's stratum, and no `R` is ever formed over Linux and Windows cells +together. A Linux cell and a Windows cell that agree on rung, workload and regime +are two different cells, because since #355 their memory quantities are not even +the same physical thing: + +```text +linux / launcher-e2e / W / warm Python vs Rust one pair +windows / launcher-e2e / W / warm Python vs Rust a different pair +across those two no pair, and no R +``` + +Every later use of *cell*, *matched pair*, *the gate's cell set*, `median_c` and +`R` inherits this key. There is no second term for it — a "platform-cell" would +be the same idea with a second name, and two names for one thing is how a +contract starts disagreeing with itself. For each matched pair: @@ -65,9 +83,14 @@ the fifth Rust run with the third Python run" defect, in a formula. **The harness is not to be changed to iteration-level A/B interleaving under T0.** Doing so edits `scripts/perf_baseline.py`, which is one of the two files in the -harness source set, so it moves `measurement_harness_digest 562a7f7232da…` — the -identity steps 4, 5 and 6 were accepted on. That is a new instrument and a -re-evaluation of accepted instrumentation evidence, not a T0 detail. +harness source set, so it moves the harness identity + + measurement_harness_digest + 104c384d01bf6060bdec1e7c916053ddb04b97fcbd0b39f8a4fc57b8f139672f + +to which steps 4, 5 and 6 were **re-bound** after the S8 memory-semantics repair. +Moving it again is a new instrument and a re-evaluation of accepted +instrumentation evidence, not a T0 detail. **An unpaired cell cannot reach the statistic.** A cell whose invocation did not do the rung's work is not timed at all and the collection is refused @@ -75,7 +98,8 @@ do the rung's work is not timed at all and the collection is refused T0-4 — and never a pair dropped quietly from `median_c`. **Recorded consequence.** Cell-level pairing cancels *condition* noise (same -rung, workload, regime, same session, interleaved order). It does not cancel +stratum, rung, workload, regime, same session, interleaved order). It does not +cancel per-iteration noise, because the data cannot support that claim. No stronger noise-cancellation property may be asserted for `R`. @@ -133,7 +157,7 @@ agree today because both were chosen from the same product budget before any dat existed, and either may later move without the other. Reading the coincidence as one cross-platform metric is exactly the error #355 removed from the instrument. -Required of every gate, and true of both sets above: +Required of every gate, and true of all three budget families above: M_pass < M_fail A_pass < A_fail From 2433941ccf569163626b76abc2f3a30623836def Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 18:14:04 +0500 Subject: [PATCH 07/11] docs(t0): the acceptance leaf is the cell, not a median over workloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A cross-artifact conflict the Phase-3 checks did not look for: T0 judged `D = median_c(d_c)` over a gate's whole workload population, while the frozen instrument requires a preregistered decision per `(phase, workload_id, platform, regime)` cell and then rolls up `cell -> workload_class -> phase -> overall_g3`. Internal consistency was never the problem; agreement with the accepted D7 gate was. The population median did two wrong things at once. It **hid a casualty** — one decisive workload degraded past the fail margin vanishes behind eleven healthy ones — and it **double-weighted an alias**: `large-solution-control` is `alias_of` `oss-ShareX.sln`, the same path at the same pin, declared an alias precisely so the pair is never counted twice in a denominator. The instrument already resolves aliases and refuses a duplicate canonical identity by name; T0 was the artifact out of step. So the leaf is the cell. Per cell: `relative = median(Rust)/median(Python) - 1`, `absolute = median(Rust) - median(Python)`, judged by the unchanged R5 rule against its family's unchanged R6/R7 budgets — no budget moves in this commit. The eight stratum x regime x resource combinations become **gate classes**, and the roll-up is the same operator twice: cell verdicts to a class verdict, class verdicts to overall. One failing workload fails its class however many pass. `INVALID` is not a roll-up verdict at either level; admissibility is settled before a roll-up exists. Population is now counted in canonical identities rather than manifest entries — 13 decisive entries resolve to 12 canonical identities today, read from the frozen artifacts rather than asserted — and a duplicate canonical identity joins the invalidation list. Recorded so nobody has to infer it: the time classes are the `end-to-end-csharp` phase; memory is not a phase at all but each cell's `rss_policy`; the other seven D7 phases carry an explicit `not_applicable` with a reason, which is how a diagnostic surface stays non-gating while D7 completeness is still satisfied. Nothing here asks `perf_baseline.py` to change, so the harness digest does not move. Checked by enumeration rather than by reading: a class over 12 cells is total and single-valued across all 531441 combinations, the overall roll-up over 8 class verdicts across all 6561, verdicts are invariant under 20000 random reorderings of the workloads, one FAIL makes its class FAIL, one NO_DECISION makes it NO_DECISION, and `expected_d7_cells()` contains the 12 canonical ids with the alias absent. Status unchanged: NOT_FROZEN, collection_authorized false. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 201 ++++++++++++++++------ 1 file changed, 151 insertions(+), 50 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 7442cc86..a0ed5c22 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -48,8 +48,8 @@ ratified four-part cell identity of §2.1 with `engine` projected out and the stratum named, so the pair exists exactly where both engines have a timed cell on **one** platform. -**Pairing never crosses a stratum.** `median_c` is computed only within one -primary gate's stratum, and no `R` is ever formed over Linux and Windows cells +**Pairing never crosses a stratum.** A cell comparison is computed inside one +stratum, and no comparison of any kind is formed over Linux and Windows cells together. A Linux cell and a Windows cell that agree on rung, workload and regime are two different cells, because since #355 their memory quantities are not even the same physical thing: @@ -60,18 +60,40 @@ windows / launcher-e2e / W / warm Python vs Rust a different pair across those two no pair, and no R ``` -Every later use of *cell*, *matched pair*, *the gate's cell set*, `median_c` and -`R` inherits this key. There is no second term for it — a "platform-cell" would +Every later use of *cell*, *matched pair* and *a class's cell set* inherits this +key. There is no second term for it — a "platform-cell" would be the same idea with a second name, and two names for one thing is how a contract starts disagreeing with itself. -For each matched pair: +**The cell is also the acceptance leaf.** For each matched pair: - d_c = log(median(Rust_c)) - log(median(Python_c)) - D = median_c(d_c) - R = exp(D) + P_c = median(Python_c) + R_c = median(Rust_c) -`R` is the reported Rust-vs-Python ratio: `R < 1` means Rust is faster. + relative_regression_c = R_c / P_c - 1 + absolute_regression_c = R_c - P_c + +and the rule of T0-5 is applied to **that cell**, on its own, against its +family's budgets. A cell verdict is `PASS`, `FAIL` or `NO_DECISION`; the +roll-ups of T0-3 then combine cell verdicts, never cell numbers. + +**Withdrawn: the population-level statistic.** An earlier revision computed +`d_c = log(median(Rust_c)) − log(median(Python_c))`, `D = median_c(d_c)` and +`R = exp(D)` across the whole workload population of a gate, and judged *that*. +It is removed from the decision path for two reasons, both of which the frozen +instrument already rules on: + +- a median over workloads **hides a casualty**. One decisive workload degraded + far past the fail margin disappears behind eleven healthy ones, and the gate + reports a comfortable ratio for a product that got materially worse on a real + input; +- it **double-weights an alias**. `large-solution-control` is `alias_of` + `oss-ShareX.sln` — the same path at the same pin — so a population median over + manifest entries gives that one solution two votes. + +Neither is repaired by choosing a different average. The leaf has to be the cell, +because that is the level at which the accepted D7 gate requires a preregistered +decision, and no aggregate may stand in for it. **Index pairing is forbidden.** `Rust_i / Python_i` for the i-th iteration is not a paired observation here and may not be computed, reported or gated on. @@ -95,13 +117,12 @@ instrumentation evidence, not a T0 detail. **An unpaired cell cannot reach the statistic.** A cell whose invocation did not do the rung's work is not timed at all and the collection is refused (instrument §2). Therefore a missing side is an admissibility failure — see -T0-4 — and never a pair dropped quietly from `median_c`. +T0-4 — and never a pair dropped quietly from a class's cell set. **Recorded consequence.** Cell-level pairing cancels *condition* noise (same stratum, rung, workload, regime, same session, interleaved order). It does not -cancel -per-iteration noise, because the data cannot support that claim. No stronger -noise-cancellation property may be asserted for `R`. +cancel per-iteration noise, because the data cannot support that claim, and no +stronger noise-cancellation property may be asserted for a cell comparison. --- @@ -113,8 +134,8 @@ Two coordinates, never collapsed into a score: | term | definition | |---|---| -| `relative_regression` | `R - 1` for the gate's cell set, `R` per T0-1 | -| `absolute_regression` | the median over matched pairs of `median(Rust_c) - median(Python_c)`, in the gate's own unit | +| `relative_regression_c` | `median(Rust_c) / median(Python_c) - 1`, for one cell | +| `absolute_regression_c` | `median(Rust_c) - median(Python_c)`, for one cell, in its unit | | unit, time gates | milliseconds — the instrument records `perf_counter_ns`, so the conversion belongs to the reading, never to the evidence | | unit, memory gates | bytes of the stratum's own `memory_metric`, after the instrument's unit normalisation — resident on `linux`, committed on `windows`, never mixed | @@ -122,15 +143,15 @@ Two margins, because neither alone is meaningful: a relative-only rule fails a `0.20 ms -> 0.24 ms` change that no user can perceive, and an absolute-only rule is blind to scale. -Each gate carries **two pairs** of budgets — one pair that admits a pass, one -pair that compels a failure — and the decision rule over them is T0-5: +Each cell is judged against **two pairs** of budgets — one pair that admits a +pass, one pair that compels a failure — and the decision rule over them is T0-5: Each budget family below applies to **both regimes** of its resource, on the -stratum named. The pass pair and the fail pair belong to the same gate: no regime -owns one of them. +stratum named, and to every canonical workload cell inside those classes. The +pass pair and the fail pair belong to the same cell: no regime owns one of them. ```yaml -# R6 — elapsed time. Both strata, both regimes: four of the eight gates, one family. +# R6 — elapsed time. Both strata, both regimes: four of the eight classes, one family. time: M_pass: 0.05 # +5 % A_pass: 50 # milliseconds @@ -157,7 +178,7 @@ agree today because both were chosen from the same product budget before any dat existed, and either may later move without the other. Reading the coincidence as one cross-platform metric is exactly the error #355 removed from the instrument. -Required of every gate, and true of all three budget families above: +Required of every cell, and true of all three budget families above: M_pass < M_fail A_pass < A_fail @@ -276,9 +297,27 @@ owner-ratified amendment, not as a silent passenger inside a preregistration. The gates are computed over **exactly the decisive workloads of the D7-bound workload manifest that are applicable to the `launcher-e2e` rung**, and over -nothing else. At the currently frozen manifest that is all **13** decisive -workloads — every one of them is a source tree, and the launcher rung admits -every one. +nothing else — as **canonical identities**, which is not the same as manifest +entries: + +```text +manifest decisive entries at the frozen manifest 13 +canonical decisive identities 12 + large-solution-control is alias_of oss-ShareX.sln +``` + +**An alias earns no second vote.** `large-solution-control` and +`oss-ShareX.sln` are the same path at the same pin; the manifest declares the +alias precisely so the pair is never counted twice in a denominator. The +instrument resolves an alias to the identity it aliases and refuses a duplicate +canonical identity by name. A population counted in manifest entries would give +that one solution two votes, so the population is counted in canonical +identities and this document says "12 canonical identities at the current +manifest", never "13 voting workloads". + +The number is read from the frozen artifacts, not asserted here: it is whatever +the manifest's decisive entries resolve to under the instrument's alias rule, and +it is 12 today. **Calibration workloads never enter a cutover gate.** They exist to size the instrument; a gate computed over them would be answering a different question @@ -290,23 +329,30 @@ say which cells a gate covers without reading a function, and two readers must not be able to answer differently. Missing cells are not a smaller denominator. Each of these makes the attempt -`INVALID`: +`INVALID`, and the semantics match the accepted D7 verifier rather than being +restated loosely here: ```text -a decisive workload absent from the gate set => INVALID -a cell present for one engine and not the other => INVALID -an unexpected extra decisive cell => INVALID -a calibration cell inside the gate set => INVALID +a canonical decisive identity absent from the gate set => INVALID +a cell present for one engine and not the other => INVALID +an unexpected extra decisive cell => INVALID +a duplicate canonical identity (an alias counted twice) => INVALID +a calibration cell inside the gate set => INVALID ``` D7 binds the exact workload-manifest digest, and therefore the exact decisive set: the population cannot be re-read later as "whatever was measured". -### The eight gates +### The eight primary gate classes -Since #355 the memory quantity is platform-local, so the gate identity carries -its stratum. The primary set is exactly **eight** independent gates, four per -stratum: +Since #355 the memory quantity is platform-local, so the identity carries its +stratum. The primary set is exactly **eight gate classes**, four per stratum. + +They are **classes, not leaves**: each one covers the canonical decisive +workloads, and the acceptance decision happens per workload cell inside it +(T0-1). Calling them eight gates was the previous revision's error — it implied +one verdict per class computed from an aggregate, which is exactly the masking +this section now forbids. ```text linux / launcher-e2e / process-cold / elapsed (ms) @@ -320,18 +366,34 @@ windows / launcher-e2e / process-cold / max_process_peak_commit (bytes) windows / launcher-e2e / warm / max_process_peak_commit (bytes) ``` -**No compensation in any direction**: not between `process-cold` and `warm`, not -between time and memory, and not between the two strata. `U_linux` and -`U_windows` are never pooled, and no ratio is formed across them. +**No compensation in any direction**: not workload against workload, not +`process-cold` against `warm`, not time against memory, and not Linux against +Windows. `U_linux` and `U_windows` are never pooled, and no ratio is formed +across them. -The roll-up over the eight is the automaton of T0-4, applied without addition: +### Two roll-ups, one operator ```text -any gate FAIL => FAIL -else any NO_DECISION => NO_DECISION -else => PASS +inside a class, over canonical workload cell verdicts: + any FAIL => class FAIL + else any NO_DECISION => class NO_DECISION + else => class PASS + +over the eight class verdicts: + any FAIL => overall FAIL + else any NO_DECISION => overall NO_DECISION + else => overall PASS ``` +**One failing workload fails its class**, even when every other workload in it +passes. That is the property the withdrawn population median destroyed, and it is +the reason the leaf is the cell. + +`INVALID` is **not** a roll-up verdict and never appears at either level: an +admissibility failure invalidates the attempt under T0-4 and T0-6 *before* any +roll-up is computed. A session that reached a roll-up is a session whose evidence +was already complete. + **Memory is gated on `launcher-e2e` only.** The instrument captures `peak_memory_bytes` on every measured cell and those values are **published as diagnostic evidence**, but a memory number on a diagnostic rung never gates. @@ -342,6 +404,38 @@ here rather than left to a reader. Every other surface in the table is **published, never gating**. A derived view may inform a reading and may never serve as a gate. +### How this lands in the accepted D7 payload + +The frozen instrument already fixes the shape D7 must fill, and this contract is +written to fit it rather than asking it to move: + +```text +D7_CELL_DIMENSIONS = (phase, workload_id, platform, regime) +D7_ROLLUP_LEVELS = (workload_class, phase, overall_g3) +cell universe = 8 phases x 12 canonical workloads x 2 platforms x 2 regimes + = 384 cells, each needing a rule or an explicit not_applicable +``` + +The mapping, stated so nobody has to infer it: + +- the **time** classes are the `end-to-end-csharp` phase, per platform and + regime — the user-visible path, and the only phase this contract gates; +- the **memory** classes are not a phase. Memory is decided on the same cells + through the cell's `rss_policy` key, which is why this document never asks D7 + for a memory phase it does not have; +- the other seven phases carry an explicit `not_applicable` with the reason + "published as diagnostic evidence; not a cutover gate under T0-3" — under R4 a + diagnostic surface never becomes a veto, and D7 completeness is satisfied by a + recorded decision rather than by silence; +- the per-cell rule keys are filled by this contract: `pass_fail_rule` and + `inconclusive_band` by T0-5, `bound` by the T0-2 families, `comparison_statistic` + by T0-1's per-cell ratio and difference, `repetition_ladder` by `N`, + `rss_policy` by the stratum's memory metric, `allocation_policy` by R2's + diagnostic-only ruling. + +Nothing here requires a change to `scripts/perf_baseline.py`, and therefore +nothing here moves the harness digest. + --- ## T0-4 — Decision automaton @@ -366,12 +460,13 @@ eligibility (T0-7: host qualified, every required primary metric has a │ └─ budget exhausted ─► NO_DECISION └─ clean │ - each of the eight primary gates, by the two-dimensional rule of - T0-5 over the T0-2 budgets + every canonical workload cell, by the two-dimensional rule of + T0-5 over its family's T0-2 budgets, then rolled up inside its + class and over the eight classes (T0-3) │ - ├─ any gate FAIL ─────────────► FAIL ─► NO_GO - ├─ any gate NO_DECISION ──────► NO_DECISION - └─ all eight gates PASS ──────► PASS ─► GO + ├─ any class FAIL ────────────► FAIL ─► NO_GO + ├─ any class NO_DECISION ─────► NO_DECISION + └─ all eight classes PASS ────► PASS ─► GO ``` The three null-metric situations are **different states**, and collapsing them @@ -401,8 +496,8 @@ median elapsed > 0 median memory > 0 (the stratum's own metric) ``` -and for the derived quantities `R`, `relative_regression` and -`absolute_regression`, any of +and for each cell's derived quantities `relative_regression_c` and +`absolute_regression_c`, any of ```text None · NaN · +inf · -inf · undefined arithmetic @@ -455,7 +550,8 @@ rather than in a reading nobody re-reads. **RESOLVED (R5): a deterministic gray zone in two dimensions.** The gray zone is defined on the same two coordinates the margins are, and no -synthetic scalar score is constructed from them. Per gate: +synthetic scalar score is constructed from them. Per **cell**, against the +budget family its class belongs to: ```text PASS iff relative_regression <= M_pass @@ -537,7 +633,7 @@ Invalidation fires only on machine-detectable predicates frozen in advance: - candidate byte drift within a stratum after collection started. **A performance result is never an invalidation condition.** Not a slow cell, not -a gray-zone outcome, not a disappointing `R`. Every predicate above is +a gray-zone outcome, not a disappointing cell comparison. Every predicate above is machine-detected, so no operator chooses to invalidate a session. One retry attempt is one full re-collection of the invalidated session on the @@ -841,7 +937,7 @@ Content completeness is not the freeze; it is what makes the freeze reviewable. | can a host with no mechanism for a required metric start a session? | **no** — T0-7 eligibility, T0-4 case A | | can a stale manifest carry a campaign? | **no** — fresh per session, rechecked after, drift is `INVALID` | | can anyone start collecting because hosts and binding are ready? | **no** — T0-0 revoked that; `collection_authorized: false` | -| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** — per gate the two conditions are mutually exclusive by `M_pass < M_fail` and `A_pass < A_fail`, and the roll-up is a total function of the eight gate outcomes | +| can one evidence set yield both PASS and FAIL under two admissible readings? | **no** — per cell the two conditions are mutually exclusive by `M_pass < M_fail` and `A_pass < A_fail`, and both roll-ups are total functions of the verdicts beneath them | | does the declaration of single tenancy masquerade as proof? | **no** — provisioning evidence and runtime invariants are separated, and only the latter is called machine-verified | | can a calibration workload enter a cutover gate? | **no** — T0-3 owns the population: decisive workloads applicable to `launcher-e2e`, and a calibration cell in the set is `INVALID` | | can a missing decisive workload quietly shrink the denominator? | **no** — a missing workload, a missing engine side or an unexpected extra cell each make the attempt `INVALID` | @@ -849,6 +945,11 @@ Content completeness is not the freeze; it is what makes the freeze reviewable. | can an undefined quantity reach a verdict through the rule's `OR`? | **no** — the numeric domain is checked before T0-5; `NaN` on either coordinate is `INVALID`, never `PASS` | | can Linux resident bytes be compared with Windows committed bytes? | **no** — the metric is part of the gate identity, the strata are never pooled, and `resident == commit` is asserted nowhere | | can a replacement host buy another attempt? | **no** — the retry budget belongs to the stratum, replacement does not reset it, and a valid outcome closes the stratum | +| can one degraded workload hide behind the others? | **no** — the leaf is the cell; one `FAIL` fails its class however many workloads pass, and the population median that allowed it is withdrawn by name | +| can an alias vote twice? | **no** — the population is counted in canonical identities, an alias resolves to what it aliases, and a duplicate canonical identity is `INVALID` | +| can a workload be dropped to improve a class? | **no** — a missing canonical identity is `INVALID`, not a smaller denominator | +| does reordering the workloads change a verdict? | **no** — the roll-up operator is order-independent by construction, and it is checked that way | +| does T0 ask D7 for a payload it cannot express? | **no** — time maps to the `end-to-end-csharp` phase, memory to each cell's `rss_policy`, and the seven non-gating phases carry an explicit `not_applicable` with a reason | | can a valid result be re-measured on a new host? | **no** — re-measurement needs a previous `INVALID` **and** remaining budget; a new binding starts a campaign beside the old one and erases nothing | No "yes" answer remains that a decision could close. The one permitted item — a From dc1529b7be8b84975299dc6a4aabb9e1456480a5 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 18:27:11 +0500 Subject: [PATCH 08/11] docs(t0): prove the D7 serialization instead of calling it compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit G3 — the accepted verifier checks that `rollups` carries `workload_class`, `phase` and `overall_g3`, each present and non-empty, and `_present()` inspects "presence and container shape only… nothing compares, orders, or records a value". Correct for a gate forbidden to read a threshold, and it means several different reductions would pass the same check. No accepted artifact says what the three levels mean. T0 said "compatible" and left it there, which is the structural-green, semantics-unproved failure this whole track keeps catching. So the mapping is written down: `workload_class` is the reduction over the canonical workload leaf verdicts of one (platform, regime, resource); `phase` is the gating `end-to-end-csharp`, with the seven diagnostic phases carried as `not_applicable` and contributing no verdict at any level; `overall_g3` is the same operator over what remains, which is T0's own roll-up over the eight classes. And the equality is proved, not asserted. The operator is `max` under PASS < NO_DECISION < FAIL, so it is associative, commutative and idempotent: the result depends on the SET of leaf verdicts and not on grouping, ordering or nesting, and the serialized three-level reduction is therefore the same function as the two-level one. The proof is scoped in the text to discrete verdicts only — no elapsed or memory number is ever pooled across workloads, regimes, platforms or resources. G3b — one D7 cell has one set of rule keys while this contract produces two independent verdicts on it. Their location is now fixed rather than left to a later payload author: `bound`, `pass_fail_rule`, `inconclusive_band` and `comparison_statistic` each carry an `elapsed` and a `memory` sub-object, `rss_policy` names the platform-local metric, `allocation_policy` stays diagnostic. `_present` accepts a non-empty object, so this needs no schema change, no instrument change, and the harness digest does not move. Neither resource can compensate the other, and a NO_DECISION propagates unless the other is FAIL — which is the operator, not a special case. G1 — the normative rule in T0-5 and its mutual-exclusion argument now name `relative_regression_c` and `absolute_regression_c`. No unsubscripted aggregate name survives anywhere in the contract. G2 — the completion table no longer says "eight platform-qualified gates"; it lists the classes, the per-canonical-workload leaf decision, both roll-ups and the D7 serialization, each against its section. Checked: 9 resource pairs exhaustively (no compensation in either direction), 6561 class combinations for grouping and ordering invariance, 20000 random 8 x 12 verdict trees where the T0 roll-up, the D7 serialization and a flat reduction agree every time, 13 manifest entries resolving to 12 canonical identities with the alias absent from `expected_d7_cells()`. Status unchanged: NOT_FROZEN, collection_authorized false. No freeze commit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 100 ++++++++++++++++++++-- 1 file changed, 91 insertions(+), 9 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index a0ed5c22..205a6f5c 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -57,7 +57,7 @@ the same physical thing: ```text linux / launcher-e2e / W / warm Python vs Rust one pair windows / launcher-e2e / W / warm Python vs Rust a different pair -across those two no pair, and no R +across those two no pair, no comparison ``` Every later use of *cell*, *matched pair* and *a class's cell set* inherits this @@ -416,6 +416,17 @@ cell universe = 8 phases x 12 canonical workloads x 2 platforms x 2 regimes = 384 cells, each needing a rule or an explicit not_applicable ``` +**What the accepted verifier proves, and what it leaves open.** +`_d7_protocol_problems()` requires `rollups` to be an object carrying +`workload_class`, `phase` and `overall_g3`, each `_present`, and `_present` +inspects presence and container shape only — "nothing compares, orders, or +records a value, so no threshold can leak through the verifier". That is right +for a gate forbidden to read a threshold, and it has a consequence this contract +must absorb: **the verifier would accept several different reductions**, and no +accepted artifact says what the three levels mean. So T0 says it. A freeze whose +serialization is settled afterwards by "it was obvious what we meant" is not a +freeze. + The mapping, stated so nobody has to infer it: - the **time** classes are the `end-to-end-csharp` phase, per platform and @@ -426,13 +437,80 @@ The mapping, stated so nobody has to infer it: - the other seven phases carry an explicit `not_applicable` with the reason "published as diagnostic evidence; not a cutover gate under T0-3" — under R4 a diagnostic surface never becomes a veto, and D7 completeness is satisfied by a - recorded decision rather than by silence; + recorded decision rather than by silence. A `not_applicable` cell contributes + **no verdict at any level**, so no diagnostic phase can move the acceptance + outcome in either direction; - the per-cell rule keys are filled by this contract: `pass_fail_rule` and `inconclusive_band` by T0-5, `bound` by the T0-2 families, `comparison_statistic` by T0-1's per-cell ratio and difference, `repetition_ladder` by `N`, `rss_policy` by the stratum's memory metric, `allocation_policy` by R2's diagnostic-only ruling. +### Two resources inside one D7 cell + +A D7 cell identity has no resource axis: `(end-to-end-csharp, workload_id, +platform, regime)` is one cell, and this contract produces **two** independent +verdicts on it — elapsed time and memory. Where each rule lives is fixed here, so +a payload author cannot choose an interpretation afterwards: + +```text +bound { "elapsed": , + "memory": } +pass_fail_rule { "elapsed": , "memory": } +inconclusive_band { "elapsed": , "memory": } +comparison_statistic { "elapsed": , + "memory": } +rss_policy names this cell's platform-local metric: + max_process_peak_resident on linux, + max_process_peak_commit on windows +allocation_policy diagnostic only, never gating (R2) +repetition_ladder N and its escalation, identical for both resources +``` + +`_present` accepts a non-empty object, so these nested rules are structurally +valid under the accepted verifier: **no schema change, no instrument change, and +the harness digest does not move.** + +Both resources yield **independent leaf verdicts** that enter the reduction side +by side. A `FAIL` on either is never compensated by a `PASS` on the other, and a +`NO_DECISION` on either propagates unless the other is `FAIL` — not as a special +case, but as the ordinary behaviour of the operator below. + +### Why the serialized reduction returns the same verdict + +T0 reduces cell verdicts to eight class verdicts to one overall verdict; the D7 +payload reduces at `workload_class`, then `phase`, then `overall_g3`. These must +not be two different answers wearing one name, so the equality is proved rather +than asserted. + +The roll-up operator is **maximum under the total order** + +```text +PASS < NO_DECISION < FAIL +``` + +"any FAIL ⇒ FAIL; else any NO_DECISION ⇒ NO_DECISION; else PASS" is exactly `max` +over that order. Maximum over a total order is **associative, commutative and +idempotent**, so the result depends only on the *set* of leaf verdicts and never +on how they are grouped, ordered or nested. Therefore: + +```text +workload_class : max over the canonical workload leaf verdicts of one + (platform, regime, resource) -> a class verdict +phase : max over the class verdicts of end-to-end-csharp; + not_applicable cells contribute nothing +overall_g3 : max over the phase level — which by associativity equals + max over all eight class verdicts, which is T0's own roll-up +``` + +The two reductions are the same function of the same multiset, so they cannot +disagree. + +Regrouping is safe **only for discrete verdicts**. No elapsed or memory *number* +is ever pooled, averaged or otherwise combined across workloads, regimes, +platforms or resources: the algebra above applies to the three words `PASS`, +`NO_DECISION` and `FAIL`, and to nothing else. + Nothing here requires a change to `scripts/perf_baseline.py`, and therefore nothing here moves the harness digest. @@ -554,11 +632,11 @@ synthetic scalar score is constructed from them. Per **cell**, against the budget family its class belongs to: ```text -PASS iff relative_regression <= M_pass - OR absolute_regression <= A_pass +PASS iff relative_regression_c <= M_pass + OR absolute_regression_c <= A_pass -FAIL iff relative_regression >= M_fail - AND absolute_regression >= A_fail +FAIL iff relative_regression_c >= M_fail + AND absolute_regression_c >= A_fail otherwise NO_DECISION ``` @@ -577,8 +655,8 @@ merely because the workload is enormous. Between "cheap on either coordinate" an "expensive on both" there is now a real gray zone, and it is named. **The two conditions cannot both hold.** `PASS` via the relative coordinate -requires `relative_regression <= M_pass < M_fail`, which contradicts `FAIL`'s -`relative_regression >= M_fail`; `PASS` via the absolute coordinate contradicts +requires `relative_regression_c <= M_pass < M_fail`, which contradicts `FAIL`'s +`relative_regression_c >= M_fail`; `PASS` via the absolute coordinate contradicts `FAIL`'s absolute condition the same way, because `A_pass < A_fail`. The ordering requirement in T0-2 is what makes the per-gate function total and single-valued — one of `PASS`, `FAIL`, `NO_DECISION`, never two. @@ -901,7 +979,11 @@ is now in it: | quiesce procedure | T0-7 | R13 | | the decisive gate population | T0-3 | S1 | | the numeric domain and sample completeness | T0-4 | S2, S3 | -| eight platform-qualified gates | T0-3 | S8 | +| eight platform-qualified gate **classes** | T0-3 | S8 | +| the leaf decision: one verdict per canonical workload cell | T0-1, T0-5 | P3.5 | +| the within-class roll-up over canonical workload verdicts | T0-3 | P3.5 | +| the overall roll-up over the eight class verdicts | T0-3 | P3.5 | +| the D7 serialization and its equivalence proof | T0-3 | P3.5 | | the exhaustive replacement list and retry continuity | T0-8 | S7 | Removed rather than filled, because the acceptance contract does not make the From 387fac664f0761d41c84f0fc759fefc555c0324d Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 21:04:22 +0500 Subject: [PATCH 09/11] =?UTF-8?q?docs(t0):=20R14=20=E2=80=94=20decisive=20?= =?UTF-8?q?repetition=20is=20single-stage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit K1: the accepted D7 cell requires a repetition_ladder with five non-empty keys, and T0 owned only `initial_n` through `N`. The other three had no owner at all — training may derive `N` and nothing else, D7 adds no analytical decision of its own, and T0 was silent — so the only people able to fill them were the ones forbidden to, after the data existed. R14 settles it in the direction the rest of the contract had already chosen: the single global `N` selected by training is both the initial and the maximum sample count. Collect exactly `N`, apply admissibility, apply the decision; PASS, FAIL and NO_DECISION are all terminal. `NO_DECISION` is never a transition predicate and never buys a larger `N`. `INVALID` is not part of the ladder at all — it belongs to the retry mechanism, and a retry runs at the same `N`, which is what makes it a retry rather than an escalation stage. The reasons are recorded rather than left to be reconstructed: T0-9 gives training no mandate for a ladder, sample completeness already demands exactly `N` so a cell grown to N+k would fail its own admissibility rule, T0-5 deliberately makes the gray zone terminal, and an adaptive N -> larger N after seeing a decisive result is a post-observation degree of freedom — the campaign asking for more data precisely because the data it has did not answer conveniently. The exact D7 serialization is fixed here too, because `_present()` treats an empty list or object as absent and "none" in prose is a freedom waiting to be discovered later: both absent mechanisms are written as the non-empty object `{kind: none}`, `terminal_outcome` is `{kind: cell_verdict, values: [PASS, FAIL, NO_DECISION]}`, and `initial_n = max_n = N`. A different JSON syntax must preserve that structure, never an empty container and never free prose. No budget, population, verdict operator or roll-up changes. No instrument change, no digest movement. Status remains NOT_FROZEN, collection_authorized false; this is not a freeze commit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 72 ++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 205a6f5c..80192745 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -442,7 +442,7 @@ The mapping, stated so nobody has to infer it: outcome in either direction; - the per-cell rule keys are filled by this contract: `pass_fail_rule` and `inconclusive_band` by T0-5, `bound` by the T0-2 families, `comparison_statistic` - by T0-1's per-cell ratio and difference, `repetition_ladder` by `N`, + by T0-1's per-cell ratio and difference, `repetition_ladder` by R14, `rss_policy` by the stratum's memory metric, `allocation_policy` by R2's diagnostic-only ruling. @@ -464,7 +464,9 @@ rss_policy names this cell's platform-local metric: max_process_peak_resident on linux, max_process_peak_commit on windows allocation_policy diagnostic only, never gating (R2) -repetition_ladder N and its escalation, identical for both resources +repetition_ladder single-stage, by R14: initial_n = max_n = N, both + mechanisms recorded as {kind: none}, terminal outcome is + the cell verdict. Identical for both resources ``` `_present` accepts a non-empty object, so these nested rules are structurally @@ -733,6 +735,71 @@ of the coin. One retry survives a genuine one-off environmental failure; a large budget would turn the campaign into a machine that runs until the infrastructure eventually cooperates. +### R14 — decisive repetition is single-stage + +Training selects one global `N` under T0-9. That `N` is both the initial **and** +the maximum sample count of the decisive campaign. **There is no decisive +escalation after a result has been seen.** + +```text +initial_n = N +max_n = N + +collect exactly N samples for the cell +apply the T0-4 admissibility rules +apply the T0-5 decision + +PASS => terminal +FAIL => terminal +NO_DECISION => terminal +``` + +`NO_DECISION` is never a transition predicate and never licenses a larger `N`. +`INVALID` does not belong to the repetition ladder at all: it is handled by the +retry mechanism above, and only `INVALID` with retry budget remaining permits a +full repeat session — **at the same `N`**, which makes it a retry and not an +escalation stage. + +The reason is recorded rather than left to be reconstructed: + +- T0-9 lets training derive `N` and nothing else, so an escalation ladder has no + owner who is allowed to choose it; +- sample completeness (T0-4) already requires *exactly* `N` samples in a primary + cell, and a cell that grew to `N + k` would fail its own admissibility rule; +- T0-5 deliberately makes the gray zone a terminal `NO_DECISION`; +- an adaptive `N -> larger N` after seeing a decisive result would create a new + post-observation degree of freedom — the campaign asking for more data + precisely because the data it has did not answer conveniently. A + preregistration turns into a menu at exactly the moment a menu is least + affordable. + +**The exact D7 representation**, fixed here so the word "none" cannot become a +freedom later. The accepted verifier's `_present()` treats an empty list or +object as absent, so the two absent mechanisms are written as non-empty objects +rather than as `[]`: + +```yaml +repetition_ladder: + initial_n: N # the single global N selected by T0-9 training + escalation_stages: + kind: none + transition_predicates: + kind: none + max_n: N + terminal_outcome: + kind: cell_verdict + values: + - PASS + - FAIL + - NO_DECISION +``` + +`N` is substituted with the selected value when the D7 payload is built; nothing +else in this block is a choice. Should a JSON serialization need different +syntax, it must preserve **this** semantic structure: a non-empty object +`{"kind": "none"}` for each absent mechanism, never an empty container and never +free prose. + **Manifest refresh is per session (R9).** A fresh environment manifest is captured before every measurement session, and the identity-bearing fields are rechecked after it; drift between the two is `INVALID`. A campaign-level manifest @@ -972,6 +1039,7 @@ is now in it: | three budget families, time and one per stratum's memory metric | T0-2 | R6, R7 | | the two-dimensional decision rule | T0-5 | R5 | | `retry_budget: 1` | T0-6 | R8 | +| single-stage decisive repetition, and its exact ladder serialization | T0-6 | R14 | | `manifest_refresh_rule: per session` | T0-6 | R9 | | single-tenancy, in two evidence classes | T0-7 | R10 | | power policy, per platform | T0-7 | R11 | From 2eac6a2430ceefb09f91dbea347edabda2972b69 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 01:45:30 +0500 Subject: [PATCH 10/11] docs(t0): close the five freeze-blockers the full review found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F1 — the campaign join. The accepted D7 payload binds the reference, harness digest and version, and workload manifest, and nothing else; `execution_binding` does not occur in the instrument, and an extra payload key is tolerated without ever being verified. T0 also claimed D7 "records exact numbers", which described a stronger mechanism than the one that exists. Both are corrected: D7 freezes rules and bindings before collection while the numbers belong to #263-B evidence, and a campaign link — verified fail-closed at preflight and again at postflight — ties the execution binding to the D7 payload and its attestation by exact bytes. The limit is stated rather than hidden: the instrument's firewall stays unaware of the campaign, so a clock can physically run outside one; what cannot happen is that such a run becomes admissible. F2 — the acceptance leaf is `(cell, resource)`, not the cell. T0 had said both in different sections, which let two different implementations each claim to follow it. 12 canonical workloads x 2 platforms x 2 regimes = 48 end-to-end D7 cells; 48 x 2 gated resources = 96 acceptance resource leaves. The resource axis lives in this contract and not in `D7_CELL_DIMENSIONS`; no schema change. F3 — reproducibility is no longer an invalidation predicate. Listing a median change above `REPRODUCIBILITY_MAX_MEDIAN_CHANGE` among the INVALID triggers turned an observed number into a ticket for another throw of the coin, one paragraph above the sentence promising that a performance result never invalidates anything. The accepted instrument keeps `timings_reproduced` and `environment_valid` apart precisely because a timing disagreement does not say what caused it. Statistical non-reproduction now grants no retry, and INVALID keeps only integrity and environment failures. F4 — the authority state machine (R15). Freezing this contract is the owner act that sets FROZEN and collection_authorized: true together; the flag is necessary and never sufficient, and three of the four combinations refuse — including NOT_FROZEN+true, because an authorisation without a fixed protocol is a contradiction. The step-7 tooling enforces it fail-closed on both paths. F5 — retry scope. R8 governs the decisive campaign only. Step-7 training keeps its own frozen rule: exactly one collection, no automatic retry, and an INVALID training collection yields no admissible Step-8 input. T0 does not amend Step 6 by implication — a fixed thirty-run collection does not remain the same object after a second attempt. Presentation: the status block no longer denies observations that exist — it narrows to T0-governed training and decisive collection, leaving the historical calibration and Round-7 evidence alone — and T0-5 names the per-resource-leaf decision function. Status unchanged: NOT_FROZEN, collection_authorized false. Not a freeze commit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 135 ++++++++++++++++++++-- 1 file changed, 125 insertions(+), 10 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index 80192745..c4ddbd6a 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -8,7 +8,9 @@ Status: MANDATORY UNRESOLVED SLOTS: 0 (T0-completion). OPEN NORMATIVE CONFLICTS: none. The #262 ratification blocker was withdrawn as a misreading — see T0-3. - NO CLOCK HAS RUN. NO OBSERVATION EXISTS. + NO T0-GOVERNED CLOCK HAS RUN. NO TRAINING OR DECISIVE OBSERVATION EXISTS. + (Historical calibration and Round-7 observations exist and are untouched + by this contract; they are not training or decisive evidence.) ``` **What this is.** The contract that fixes *how numbers will be judged*, before any @@ -17,14 +19,40 @@ the decisive campaign (#263-B) alike, because a rule chosen after a look at training data is not a preregistered rule — it is a preference with a timestamp. **What this is not.** It is not D7. T0 says how a verdict is computed; D7 later -records *which* exact numbers, candidate, digests and host instances the verdict -was computed from, and adds no analytical decision of its own. +**freezes the rules and the bindings before collection** — the reference, the +harness identity, the workload manifest and a preregistered rule for every cell — +and adds no analytical decision of its own. The measured numbers are not in D7 at +all: they belong to the #263-B evidence produced afterwards. An earlier revision +said D7 "records exact numbers", which described a stronger mechanism than the +one that exists. **Authority.** T0-0 revoked the automatic authorisation of the first step-7 collection (`docs/notes/p022-263a-step7-environment-capture.md`). Until this document is frozen, `collection_authorized` is `false` and no training, first or decisive collection may run, however ready the hosts are. +**The freeze is the authorising act, and it is not sufficient on its own (R15).** +Freezing this contract sets both `status: FROZEN` and +`collection_authorized: true` in the same commit — one owner act, one state — and +the flag is then a *necessary* condition, never a permission slip. Host +qualification, an exact execution binding and a session preflight are still +required, and each can still refuse. + +The two fields are read as one state, and three of the four combinations are +refusals: + +```text +NOT_FROZEN + false refuse — the protocol is not fixed +FROZEN + false refuse — frozen, but the owner has not authorised collection +NOT_FROZEN + true refuse — an authorisation without a fixed protocol is a + contradiction, and a tool that accepted it would be + honouring a flag over the contract +FROZEN + true may proceed to the remaining gates, which may still refuse +``` + +The step-7 tooling enforces this state machine fail-closed; neither the +qualification path nor the binding path may accept `FROZEN + false`. + **Slot discipline.** Every value this document does not already hold appears as a typed `UNRESOLVED_OWNER_DECISION` slot with its unit and its scope stated. A slot is filled by an owner ruling recorded here, never by a plausible default and @@ -65,7 +93,18 @@ key. There is no second term for it — a "platform-cell" would be the same idea with a second name, and two names for one thing is how a contract starts disagreeing with itself. -**The cell is also the acceptance leaf.** For each matched pair: +**The cell is not the acceptance leaf; a resource inside it is.** A D7 cell +carries two gated resources — elapsed time and the stratum's memory metric — and +each is decided on its own. The leaf is therefore + + (cell, resource) resource ∈ { elapsed, the stratum's memory metric } + +and this document says "resource leaf" wherever the decision is meant, reserving +"cell" for the measurement identity D7 enumerates. An earlier revision called the +cell the leaf, which made two different implementations able to claim they +followed T0. + +For each matched pair, per resource: P_c = median(Python_c) R_c = median(Rust_c) @@ -371,6 +410,18 @@ windows / launcher-e2e / warm / max_process_peak_commit (bytes) Windows. `U_linux` and `U_windows` are never pooled, and no ratio is formed across them. +### Cells and leaves are not the same count + +```text +12 canonical workloads x 2 platforms x 2 regimes = 48 end-to-end D7 cells +48 cells x 2 gated resources (elapsed, memory) = 96 acceptance resource leaves +``` + +The resource axis exists in this contract and **not** in `D7_CELL_DIMENSIONS`; +adding it there would be a schema change, and none is made. The two resource +verdicts of one cell are independent and are combined only by the operator below, +never inside the cell. + ### Two roll-ups, one operator ```text @@ -513,6 +564,45 @@ is ever pooled, averaged or otherwise combined across workloads, regimes, platforms or resources: the algebra above applies to the three words `PASS`, `NO_DECISION` and `FAIL`, and to nothing else. +### The campaign join, and what it is not + +The accepted D7 payload binds `python_reference_commit`, +`python_reference_tree`, `harness_digest`, `harness_version` and +`workload_manifest_sha256`. It does **not** bind the execution binding: +`execution_binding_sha256` appears nowhere in `D7_PAYLOAD_BINDING_KEYS`, and the +string `execution_binding` does not appear in the instrument at all. The gate +checks that the listed keys are *present* and matching; an extra key in the +payload is tolerated and never verified. So a payload could name a campaign and +the gate would not notice if it named the wrong one. + +That gap is closed by a **campaign link**, an artifact of the step-7 layer that +ties the three identities together and is verified fail-closed before the clock +and again after it: + +```text +campaign link binds, by exact bytes: + execution_binding_sha256 + the D7 payload's sha256, its blob id and the commit that carries it + the D7 attestation's exact identity +``` + +**A decisive session is admissible only with it.** The session preflight refuses +to start when the link is absent, when it does not name this execution binding, +or when the D7 payload and attestation now on disk do not hash to what the link +names; the postflight refuses to issue an admissibility record on the same +grounds. Admissibility under this contract *is* the existence of that postflight +record, so evidence produced without the link is not inadmissible by opinion — +there is no artifact that can say it is admissible. + +**What the link does not do, stated plainly.** It does not make the instrument's +firewall aware of the campaign. The `IdentityGate` arms from the D7 payload and +attestation alone, so a decisive clock can physically run with no execution +binding in existence; what cannot happen is that such a run becomes admissible +evidence. Making the firewall itself refuse would require editing +`scripts/perf_baseline.py`, which moves `measurement_harness_digest` and re-opens +steps 4, 5 and 6 — a price this contract does not pay for a property it can +obtain by making admissibility, rather than execution, the thing that is gated. + Nothing here requires a change to `scripts/perf_baseline.py`, and therefore nothing here moves the harness digest. @@ -630,8 +720,9 @@ rather than in a reading nobody re-reads. **RESOLVED (R5): a deterministic gray zone in two dimensions.** The gray zone is defined on the same two coordinates the margins are, and no -synthetic scalar score is constructed from them. Per **cell**, against the -budget family its class belongs to: +synthetic scalar score is constructed from them. This is the **per-resource-leaf +decision function**, applied to one resource of one cell against the budget +family that resource belongs to: ```text PASS iff relative_regression_c <= M_pass @@ -696,7 +787,6 @@ Invalidation fires only on machine-detectable predicates frozen in advance: - opening or closing noise probe relative IQR above `NOISE_PROBE_MAX_RELATIVE_IQR` (0.35); - drift between opening and closing probes above `NOISE_PROBE_MAX_DRIFT` (0.35); -- reproducibility median change above `REPRODUCIBILITY_MAX_MEDIAN_CHANGE` (0.35); - a cell that did not do its rung's work, proved by its post-condition; - a required primary metric that returned `null` or went missing mid-attempt (T0-4 case B); @@ -713,7 +803,22 @@ Invalidation fires only on machine-detectable predicates frozen in advance: - candidate byte drift within a stratum after collection started. **A performance result is never an invalidation condition.** Not a slow cell, not -a gray-zone outcome, not a disappointing cell comparison. Every predicate above is +a gray-zone outcome, not a disappointing cell comparison — and, since this +revision, not a failure to reproduce a median either. + +**Statistical non-reproduction is not `INVALID` and buys no retry.** An earlier +revision listed a reproducibility median change above +`REPRODUCIBILITY_MAX_MEDIAN_CHANGE` among the invalidation predicates, which +turned an observed number into a ticket for another throw of the coin — the +outcome-selective surface this contract exists to close. The accepted instrument +keeps the two questions apart on purpose: `timings_reproduced` and +`environment_valid` are separate verdicts, and a timing disagreement does not +establish whether contention, a variable workload or the uncertainty of a median +caused it. `INVALID` remains for integrity and environment failures that are +knowable without looking at the comparison: noise and drift probes, missing or +corrupt evidence, the wrong population, identity or candidate drift, a missing +required metric, a broken numeric domain. Reproducibility keeps the meaning the +accepted calibration policy gives it, and T0 does not reclassify it. Every predicate above is machine-detected, so no operator chooses to invalidate a session. One retry attempt is one full re-collection of the invalidated session on the @@ -724,7 +829,15 @@ evidence and none is deleted. retry_budget: 1 # R8 ``` -Read literally: +**Scope: the decisive campaign only.** `retry_budget` governs #263-B and nothing +else. Step-7 training keeps the rule its own frozen preregistration already +carries — `exactly_one_collection`, `abort_semantics.no_automatic_retry`, and an +`INVALID` training collection yields no admissible Step-8 input. No training +attempt is created by R8, and this document does not amend Step 6 by implication: +a fixed thirty-run collection does not remain the same object after a second +attempt, whatever a later reader would prefer. + +Read literally, for the decisive campaign: 1 initial attempt + at most 1 full-session retry after INVALID @@ -1048,7 +1161,9 @@ is now in it: | the decisive gate population | T0-3 | S1 | | the numeric domain and sample completeness | T0-4 | S2, S3 | | eight platform-qualified gate **classes** | T0-3 | S8 | -| the leaf decision: one verdict per canonical workload cell | T0-1, T0-5 | P3.5 | +| the leaf decision: one verdict per (cell, resource) leaf | T0-1, T0-5 | P3.5, F2 | +| the authority state machine, freeze as the authorising act | preamble | R15 | +| the campaign link joining execution binding, D7 payload and attestation | T0-3 | F1 | | the within-class roll-up over canonical workload verdicts | T0-3 | P3.5 | | the overall roll-up over the eight class verdicts | T0-3 | P3.5 | | the D7 serialization and its equivalence proof | T0-3 | P3.5 | From 30d2f32edaa946dd58beae3f3b86e6746e6915fc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 07:06:31 +0500 Subject: [PATCH 11/11] freeze(t0): FROZEN, collection_authorized true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The terminal owner act. Nothing else changes: the diff is the status block and nothing but the status block. status: NOT_FROZEN -> FROZEN collection_authorized: false -> true The freeze record carries the claim boundary in the words that have to survive six months of reading: Execution isolation is NOT claimed. Evidence admissibility isolation IS claimed and mechanically enforced. The instrument's IdentityGate arms from the D7 payload and attestation alone, so a clock can physically run outside a registered campaign; such a run cannot become admissible evidence, because admissibility is the postflight record and it cannot be issued without the campaign link closing on this exact freeze. Whoever next reads the binding as "the harness cannot start outside a campaign" will find the sentence saying otherwise before they go looking through perf_baseline.py for a firewall nobody claimed. Recorded with it: `collection_authorized: true` is necessary and never sufficient — qualification, the execution binding, the campaign link and the session preflight are all still required and may each still refuse — and any later amendment is a NEW state of this contract rather than an edit of this one. This commit is not to be amended, rebased or force-pushed. No budget, population, statistic, roll-up, predicate, retry rule or schema moves here. No instrument change; the harness digest does not move. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018xhcg5opoFbSTdYHpkSXCh --- docs/notes/p022-263-t0-protocol-freeze.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/notes/p022-263-t0-protocol-freeze.md b/docs/notes/p022-263-t0-protocol-freeze.md index c4ddbd6a..174c1ac6 100644 --- a/docs/notes/p022-263-t0-protocol-freeze.md +++ b/docs/notes/p022-263-t0-protocol-freeze.md @@ -2,15 +2,32 @@ ```text Status: - NOT_FROZEN. - collection_authorized: false - CONTENT COMPLETE. HOSTILE FREEZE REVIEW PENDING. + FROZEN. + collection_authorized: true + CONTENT COMPLETE. HOSTILE FREEZE REVIEW PASSED. MANDATORY UNRESOLVED SLOTS: 0 (T0-completion). OPEN NORMATIVE CONFLICTS: none. The #262 ratification blocker was withdrawn as a misreading — see T0-3. NO T0-GOVERNED CLOCK HAS RUN. NO TRAINING OR DECISIVE OBSERVATION EXISTS. (Historical calibration and Round-7 observations exist and are untouched by this contract; they are not training or decisive evidence.) + + What this freeze claims, and what it does not: + Execution isolation is NOT claimed. Evidence admissibility isolation IS + claimed and mechanically enforced. + The instrument's IdentityGate arms from the D7 payload and attestation + alone, so a clock can physically run outside a registered campaign. Such a + run cannot become admissible evidence: admissibility is the postflight + record, and it cannot be issued without the campaign link closing on this + exact freeze. Read this before reopening perf_baseline.py in search of a + firewall that was never claimed. + + collection_authorized: true is NECESSARY, NEVER SUFFICIENT. Host + qualification, an exact execution binding, the campaign link and the + session preflight are still required, and each may still refuse. + + Amendments after this line are a new state of the contract, never an edit of + this one. This commit is not to be amended, rebased or force-pushed. ``` **What this is.** The contract that fixes *how numbers will be judged*, before any