feat(perf): #263-A — the measurement instrument, calibrated (CALIBRATION_ONLY) - #351
Open
PhysShell wants to merge 12 commits into
Open
feat(perf): #263-A — the measurement instrument, calibrated (CALIBRATION_ONLY)#351PhysShell wants to merge 12 commits into
PhysShell wants to merge 12 commits into
Conversation
…alled The instrument for #263's P-022 performance baselines: how a number is produced, never what the number should be. It permits calibration and refuses the decisive measurement, which is #263-B behind the D7 freeze. No thresholds, no repetition count N, no engine-comparison statistic — those are D7's, and a harness that offered any of them would be choosing them. Preflight, against primary source. Live #263 and #262's Performance-gates reconcile as: the brief's phase list is #262's seven gate phases plus frontend extraction, recorded and explicitly NOT D7-gated. Both populations are frozen — A, the G3 cutover subset, feeds D7; B, the IDE-foundation remainder, does not unless separately ratified. What this instrument does NOT measure is written down rather than left implied, so completing #263-A cannot narrow #263's own acceptance by omission: the .own workloads, OwnIR serialization, no-op and single-file-edit recheck, the latency proxy, allocation profiles and IDE budgets are owed on B's track. The honest limit, recorded rather than routed around. Neither engine exposes per-phase timing through its production surface and #263-A may not add production instrumentation, so phases are measured by a LADDER of real production invocations, each recorded as the composed interval it actually is with the phases inside it named. bridge-lowering and analysis are marked NOT SEPARATELY OBSERVABLE. Derived views — parse by subtraction, core work as end-to-end minus extraction — are labelled derived and never presented as measurements. #263 asks for unavailable stages to be marked, not imputed. The firewall is structural, not clerical. Exactly one function starts a clock and it refuses a decisive workload unless the identity gate is armed, which needs a D7 attestation that does not exist. Deliberately stricter than "no paired runs": a single-engine timed run of a decisive workload is refused too, because a stopwatch appears nowhere in the permitted list of enumerate / hash / fetch / availability-check / non-timed smoke. "We did not save the delta" is accounting-clean and epistemically worthless — whoever watched the two numbers has already peeked. The four carried obligations live in the harness. The identity gate exists NOW and dormant, because D7's C1 freezes the harness digest and a gate added after that freeze makes this a different instrument. Arming is a JSON file: a control proves the digest does not move when the gate arms and that the firewall then opens. Verification completes before any clock starts, and a control counts digest calls INSIDE a measured interval and requires zero — a gate that pays for itself out of the startup benchmark is a defect wearing a safeguard's coat. The candidate binary is a separate domain: frozen at session start, its drift refuses the remainder rather than measuring half the cells on another binary. Peak RSS comes from os.wait4's per-child ru_maxrss rather than /usr/bin/time, which is a package that can simply be absent — it is absent here, and "the tool was missing" is not a memory measurement. Windows uses a Job Object. Where nothing is available the value is null WITH A REASON, never a confident zero. Two defects of my own, found while building this and worth recording. The comparison guard first grepped the source for "ratio" and refused its own report — the sentence explaining the prohibition matched it, and then so did "calibration" and "iterations". It now reads the report's structure and matches whole tokens. And an aggregate of bytes was being emitted under a median_ns key: a unit lie in a report whose entire purpose is measurement. Calibrated: 44 cells, both engines, all six rungs, run twice on one machine with every cell's median reproducing within the noise floor that run itself recorded. CI calibrates on Linux and Windows and asserts the same, plus that no decisive workload was timed and the gate stayed dormant. scripts/perf_baseline.py is a new wrapper that reaches the launcher, so it is added to the Stage-2 census entry points and the job classified — the census enumerates wrappers, which makes that list a maintenance obligation, now stated in the ledger. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
Recorded on a clean tree at f09fa00, dirty:false, with the D7 gate dormant and no decisive workload timed. 44 cells both engines, all six rungs, process-cold and warm reproduced 44/44 medians within the noise floor the run itself recorded RSS os.wait4 ru_maxrss, per child, on every cell noise not invalidated; opening and closing probes agree decisive timed none The report validates the INSTRUMENT and nothing else. It is not evidence about either engine, it cannot choose a threshold, a repetition count or a comparison statistic, and it carries no engine comparison — the harness refuses to emit one, checked on the way out as well as on the way in. The Python reference commit is recorded beside the interpreter version so a later artifact cannot silently combine comparisons bound to two different reference states. The environment is a development container, recorded as such in the fingerprint (runner_class: local); CI calibrates on ubuntu and windows runners and asserts the same properties there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The Windows leg refused its own calibration on the first CI run: the opening noise probe measured a relative IQR of 1.807 against the 0.35 floor, with 0.870 drift between the opening and closing probes. That is the instrument doing exactly what §4 and §7 ask — refusing to report numbers taken on a machine that was not holding still — and the job read it as a failure. So CI now asks two questions instead of one. Did the HARNESS stand up and report honestly: tagged CALIBRATION_ONLY, gate dormant, zero decisive workloads timed, cells produced, raw per-iteration data retained, a named RSS mechanism, complete provenance. That is the gate, on both platforms. And separately: is this ENVIRONMENT measurement-grade — recorded per run, and allowed to be "no", with the reasons required when it is. The noise floor was deliberately NOT raised. An instrument-validity constant chosen after seeing which runs it rejects is a threshold fitted to a result, and fitting thresholds to results is the entire failure mode #263-A exists to prevent. The number that would have made this green is the one number I am least entitled to pick. The finding itself matters more than the fix: a GitHub-hosted Windows runner is not measurement-grade, so the decisive Windows measurement will need a single-tenant machine. #263-B needed to know that before it started, and now it does — from the instrument's first run rather than from a surprise halfway through a decisive session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
On ONE commit, two Windows runs minutes apart disagreed about their own environment. The first refused it — relative IQR 1.807 against the 0.35 floor, 0.870 drift between probes. The second accepted it and completed a full 44-cell calibration that reproduced within 0.35. Same commit, same runner class, opposite validity verdicts. The risk is therefore not that a hosted-Windows measurement would be noisy. It is that whether it is ADMISSIBLE turns on scheduling luck, so a decisive session started on the lucky run and continued into the unlucky one would be half a measurement. D7 should not preregister a Windows protocol that assumes a hosted runner. Both legs are otherwise green and complete: 44 cells each, 44 reproduced, peak RSS through os.wait4 on Linux and the Job Object on Windows, gate dormant, zero decisive workloads timed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
…t back Two findings from review, both confirmed directly in the code. P0 — the C1/C2 verifier read a proxy, not the thing. IdentityGate.load() observed harness_digest, workload_manifest_sha256 and python_reference_commit, and armed on any JSON carrying those three values. They are values anyone holding this repository can compute in one line, so the gate proved the instrument was the instrument and called that a freeze: it answered "is this the harness?" when the question is "did D7 happen?". There was no check for a C1 section, no payload commit, no git blob identity, no payload hash and no ratification. The control was no better — it built a temp JSON out of exactly those three fields and required the firewall to open. The freeze is now two objects, because a payload cannot name the commit that contains it: that sha would have to be inside the bytes hashed into it, which is the reason detached signatures exist. A payload carries kind/schema, a C1 section and a C2 section, and hashes over its own canonical body. A separately committed ratification names that body hash and the commit the payload is frozen at. Arming requires all of: the discriminator, both sections complete, the recomputed body hash, C1 matching observation, a ratification of that same hash, the payload's working-tree bytes being the blob at the named commit, and the ratification itself committed and unmodified. C2 is checked for presence and never read — its values are thresholds, and an artifact from this stage that quoted one would leak the number the module exists to keep out. Arming still costs no source patch, so the harness digest D7 freezes does not move when the gate arms. It now costs two reviewed commits instead of one text editor. What it still is not is a signature: anyone with write access could author both objects, so a declared key is verified against the ratification commit and a declared "none" is recorded as unsigned. Both stated in the note's limitations rather than implied away. P1 — the ladder floor claimed to be a phase it merely contains. core-usage was recorded as observability "direct" with the note that the interval "IS core startup", while the invocation it times starts the process, parses argv, writes a usage refusal and exits. It is now composed over process-startup-core plus a named cli-argv-refusal phase, and described as a lower bound. The consequence is corrected too: subtracting it from core-parse-refused does not leave parse, it leaves read+parse under an assumption this instrument never measures, so the difference is a derived bound. Controls: perf-gate-payload-identity damages one property of a real committed freeze at a time, thirteen cases, each required to be refused by the check that owns it. One case reformats the committed payload without changing its canonical hash, so only git object identity can catch it; if that case passes, the blob check is decorative. perf-gate-arms-by-data now builds a real freeze in a throwaway repository and additionally asserts no C2 value is recorded. perf-phase-attribution checks the rung table against itself and against the shipped report, which turns "re-record after changing a rung" into a gate. perf-notary-outside now counts git invocations as well as digests: the gate forks, and obligation (c) is violated by forking inside an interval just as much as by hashing inside one. The harness digest changes, so the calibration report no longer certifies the shipped instrument and is re-recorded in the next commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
…ment The gate repair and the startup-attribution fix both change perf_baseline.py, so the harness digest moves from 34fa2717f24d to 5c1cdf0c69a9. The previous report certified an instrument that no longer exists; a report whose provenance names a tree that has been superseded is not evidence, it is a receipt. Re-recorded on a clean tree at 5d6dab4: 44 cells, gate dormant, no decisive workload timed, environment valid, 44/44 cells reproduced within the 0.35 noise floor the earlier run recorded. The report now also carries gate_requirements (the eleven properties a D7 freeze must satisfy) and gate_pinned, so the evidence describes its own verifier instead of asking a reader to trust the harness source. perf-phase-attribution checks the shipped report against the shipped rung table, so this re-recording is enforced rather than remembered: the control failed on the stale report and passes on this one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
…ong things CI was green on the previous head and proved exactly what it had been asked to prove. Four blockers, found by reading rather than by running. 1. The production D7 freeze could never have armed. The verifier took the payload's own directory as the repository, so it asked git for `<commit>:p022-263a-d7-ratification.json` for a file that lives at `docs/evidence/...`. `<rev>:<path>` resolves from the TREE ROOT; only a path starting `./` or `../` is read relative to the current directory. Every control passed because the throwaway fixtures put both objects at the repository root, where the wrong model is accidentally right — a control proving the verifier on a layout production never has. The root now comes from `git rev-parse --show-toplevel`, every object path is resolved against it, and the fixtures use the nested production layout. The ratification must also name the exact repository-relative path this instrument reads its payload from, rather than being free to point at any blob with the same bytes. 2. The advertised signed-ratification path was written wrong and could not have worked. It read `git verify-commit --raw` from stdout; git writes that raw status to stderr, and the helper discards stderr. A correctly signed commit would have verified cryptographically and then been refused for not naming its own key. No control caught it because no environment here holds a signing key. Rather than fix a path whose accept direction still could not be exercised, signed mode is withdrawn from the accepted contract: `"signature"` must be exactly `"none"` and the freeze is recorded as unsigned. An advertised path that is observably wrong is worse than an absent one. 3. The calibration timed failure and called it reproducible. With no .NET on PATH the launcher rungs exited 127 before doing anything, and nothing looked at exit codes: 12 of 44 committed cells reproducibly measured a command-not-found path, and the CI gate did not check either, since it asked for cells, raw timings, RSS, provenance and reproducibility but never whether a cell had done its work. Each rung now declares the exit codes that mean it did its job and a post-condition proving it, verified once, untimed, with output captured. A cell that fails is not timed at all, the calibration is refused, the CI gate reads the verdict, and reproducibility compares outcome identity as well as medians — two runs agreeing about the wrong path is the worst possible reassurance. The exit codes and evidence were probed against both engines before being written down. The first version of the floor check asserted the banner contains the word "usage"; it does not, and asserting instead of measuring is the exact habit this contract exists to break. 4. P1 was not closed. `launcher-extract` invoked the launcher with `--emit-facts` and was documented as "no core runs, so this isolates the frontend stage". The launcher copies the intermediate facts and then runs Stage 2 anyway, so the interval contained the whole pipeline while recording itself as launcher startup plus extraction — the same defect as the old `core-usage` label, one level up, hidden locally because rc 127 never reached Stage 2. Changing the production launcher is out of scope and a direct extractor process is not the launcher's extraction stage, so the rung is withdrawn and launcher-scoped extraction isolation is recorded unavailable. `frontend-extraction` stays measured as a member of `launcher-e2e`. Also: `perf-provenance-complete` now requires the committed report's harness and manifest digests to EQUAL the shipped ones, not merely to be present. Presence made a stale report tick every box. Controls: 16 damaged freezes, each matched to the check that owns it, including a basename `payload_path`, a ratification naming another file, and a signed ratification. New `perf-rung-outcome` proves 127 is never success, a silent zero-exit is refused, and the real production floor invocation is accepted. The harness digest moves again, so the calibration is re-recorded next commit — this time with a toolchain on PATH and every cell doing its rung's work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
…ally there The previous report was recorded with .NET absent from PATH — installed all along at ~/.dotnet, never on PATH, which is also why the environment fingerprint recorded an empty dotnet_sdk and nobody looked. Twelve of its forty-four cells were command-not-found exits, timed, summarised, and counted as reproduced. Re-recorded at 55aad67 on a clean tree with the toolchain present: 40 cells, every one timed and every outcome valid launcher-e2e now exits 0 having actually run the pipeline, not 127 dotnet_sdk 8.0.425 recorded rather than empty 40/40 reproduced within the 0.35 floor the run itself recorded no cell whose outcome changed between runs gate dormant, no decisive workload timed Forty rather than forty-four because launcher-extract is withdrawn: its four cells measured an interval that contained the whole pipeline while claiming to isolate extraction. Two controls now make this re-recording enforced rather than remembered. perf-provenance-complete requires the report's harness and manifest digests to equal the shipped ones, and perf-phase-attribution requires the report's rung table to equal the instrument's. Both failed on the stale report and pass on this one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
Caught by the control added in the previous commit, on the Windows CI leg: the same tree hashed af32f04ddbad on Linux and 51ef2ca2422a on windows-latest, where core.autocrlf rewrites source on checkout. One instrument, two identities. That matters more than a mismatched string. D7's C1 freezes the harness digest and #263-B has to run on both platforms, so a freeze would have armed on one and been refused on the other — and the refusal would have looked like tampering. This repository already knew the defect class. .gitattributes pins docs/evidence/*.json to LF because the mutation campaigns' definition hashes hit it first, which is exactly why the workload manifest digest matched across platforms while the harness digest did not. An attribute only governs files git checks out under it, though: a tree that predates the rule, a zip download or a different local config all still differ. An identity D7 will freeze should depend on content, so it is normalized in the digest rather than delegated to a checkout setting. sha256_file stays raw. The candidate binary's identity is its actual bytes, and a hasher that normalized them would be a different kind of wrong; the control asserts both directions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
…ed digest The digest fix changes the harness identity a third time, from af32f04ddbad to 69a3a3f8b074 — this time to a value that is the same on both platforms, which is the point. Re-recorded at 2feb496 on a clean tree with the toolchain present: 40 cells, every outcome valid and every cell timed, launcher-e2e exiting 0 having run the pipeline, dotnet_sdk 8.0.425, 40/40 reproduced with no cell whose outcome changed, environment not invalidated, gate dormant, no decisive workload timed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
One phase name covered two different actions. `cli-argv-refusal` bundled argv parsing with the usage-refusal message, so it appeared on core-parse-refused, core-full-human and core-full-sarif — none of which write a usage refusal. The instrument's own outcome contract already distinguishes them: usage-help versus door-refusal. The committed calibration carried the same wrong taxonomy, and perf-phase-attribution compared the report against the rung table and agreed they matched, which is how a schema stays perfectly self-consistent while saying something false. Two identical tables are one claim written twice, not evidence. The methodology note was already more accurate than the code: its table never put a usage refusal in the successful rungs. The vocabulary now separates three things. cli-argv-parse is in every real core invocation. cli-usage-refusal is only the floor rung's driver banner. ownir-door-refusal is only the strict door's version refusal. A refusal phase may appear exactly on the rung whose outcome evidence proves that refusal happened: cli-usage-refusal iff usage-help, ownir-door-refusal iff door-refusal, and neither on any rung that reaches a verdict. Stated as an equivalence in both directions, so a rung can neither claim a refusal it did not perform nor omit one it did. Applying the same rule the other way, launcher-e2e now also names process-startup-core and cli-argv-parse. The launcher spawns the core, so those actions are inside that interval and a list that means "this interval did these things" has to include them. Over-claiming was the reported defect; under-claiming is the same rule read in the other direction. The rules were verified against the defect itself: re-adding cli-usage-refusal to core-full-human makes perf-phase-attribution fail on both the equivalence and the reaches-a-verdict rule. Harness digest moves again, so the calibration is re-recorded next commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
… taxonomy Splitting cli-argv-refusal into cli-argv-parse, cli-usage-refusal and ownir-door-refusal changes perf_baseline.py, so the harness digest moves to 84b3e98fc4d9 and the previous report certifies an instrument that no longer exists. Re-recorded on a clean tree at 889c285: 40 cells, all outcomes valid and all timed, 40/40 reproduced within the noise floor the run itself recorded, no cell whose outcome changed, environment valid, gate dormant, no decisive workload timed. Every cell's phase list now names only what its interval actually did: core-full-human no longer claims a usage refusal it never performs, and launcher-e2e names the core startup and argv parse that happen inside it. perf-phase-attribution fails on a stale report by design, so this re-recording is enforced rather than remembered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Что и зачем
#263-A: the frozen instrument for #263's P-022 performance baselines — how a number is produced, never what the number should be. It permits calibration and structurally refuses the decisive measurement, which is #263-B behind the D7 freeze.
No decisive numbers, no thresholds, no engine verdict on any decisive workload. No repetition count
N, no escalation ladder, no Rust-vs-Python comparison statistic, no D7 freeze payload. Those are D7's, preregistered before the decisive run, and a harness that offered any of them would be choosing them.Тип изменения
No production behaviour changes: the instrument reads the product, it does not alter it.
rust/,frontend/andownlang/are untouched by this branch.Review round 2 — four blockers, all repaired
CI was green on the reviewed head and proved exactly what it had been asked to prove. All four were found by reading, not by running.
1. The production D7 freeze could never have armed. The verifier took the payload's own directory as the repository, so it asked git for
<commit>:p022-263a-d7-ratification.jsonfor a file that lives underdocs/evidence/.<rev>:<path>resolves from the tree root; only a path starting./or../is read relative to the current directory. Every control passed because the throwaway fixtures put both objects at the repository root, where the wrong model is accidentally right — controls proving the verifier on a layout production never has. The root now comes fromgit rev-parse --show-toplevel, every object path resolves against it, and the fixtures use the nested production layout. The ratification must also name the exact repository-relative path this instrument reads its payload from, so it cannot point at any blob that happens to hold the same bytes.2. The advertised signed-ratification path was written wrong and could not have worked. It read
git verify-commit --rawfrom stdout; git writes that raw status to stderr, and the helper discards stderr. A correctly signed commit would have verified cryptographically and then been refused for not naming its own key. No control caught it because no environment here holds a signing key. Fixing the read would still leave the accept direction untestable, which is how the broken branch survived, so signed mode is withdrawn from the accepted contract:"signature"must be exactly"none"and the freeze is recorded as unsigned. An advertised path that is observably wrong is worse than an absent one.3. The calibration timed failure and called it reproducible.
.NETwas installed at~/.dotnetthe whole time and never on PATH — which is also why the fingerprint recorded an emptydotnet_sdkand nobody looked. The launcher rungs exited 127 before doing anything, and nothing checked exit codes: 12 of 44 committed cells reproducibly measured a command-not-found path. The CI gate could not tell either, since it asked for cells, raw timings, RSS, provenance and reproducibility but never whether a cell had done its work.Each rung now declares the exit codes that mean it did its job plus a post-condition proving it, verified once, untimed, with output captured, so the check never bills a benchmark. A cell that fails is not timed at all, the calibration is refused, the CI gate reads the verdict, and reproducibility compares outcome identity as well as medians — two runs agreeing about the wrong path is the worst possible reassurance.
core-usagecore-parse-refusedcore-full-human/core-full-sariflauncher-e2eThese were probed against both engines before being written down. The first version of the floor check asserted the banner contains the word "usage" — it does not, and asserting instead of measuring is exactly the habit this contract exists to break.
4. P1 was not closed.
launcher-extractinvoked the launcher with--emit-factsand was documented as "no core runs, so this isolates the frontend stage". The launcher copies the intermediate facts and then runs Stage 2 anyway, so the interval contained the whole pipeline while recording itself as launcher startup plus extraction — the same defect as the oldcore-usagelabel, one level up, hidden locally because rc 127 never reached Stage 2. Changing the production launcher is out of scope and a direct extractor process is not the launcher's extraction stage, so the rung is withdrawn and launcher-scoped extraction isolation is recorded unavailable.frontend-extractionstays measured as a member oflauncher-e2e.Also:
perf-provenance-completenow requires the committed report's harness and manifest digests to equal the shipped ones. Presence alone let a stale report tick every box.Round 3 — that last control immediately found a real one
The strengthened provenance check went red on its first Windows run, and not for the reason expected. The harness digest named the checkout, not the instrument: the same tree hashed
af32f04ddbadon Linux and51ef2ca2422aon windows-latest, wherecore.autocrlfrewrites source on checkout. One instrument, two identities.That matters more than a mismatched string. D7's C1 freezes the harness digest and #263-B runs on both platforms, so a freeze would have armed on one and been refused on the other — and the refusal would have looked like tampering.
This repository already knew the defect class:
.gitattributespinsdocs/evidence/*.jsonto LF because the mutation campaigns' definition hashes hit it first, which is exactly why the workload manifest digest matched across platforms while the harness digest did not. But an attribute only governs files git checks out under it — a tree predating the rule, a zip download, or a different local config all still differ. So the digest normalizes line endings itself rather than delegating its identity to a checkout setting.sha256_filestays raw: the candidate binary's identity is its actual bytes, and normalizing a binary would be a different kind of wrong.perf-digest-platform-stableholds both halves.Round 1 findings, repaired earlier and still standing
P0 — the C1/C2 verifier read a proxy. It armed on any JSON carrying three values anyone with this repository can compute in one line, proving the instrument was the instrument and calling that a freeze. The freeze is now two objects, because a payload cannot name the commit that contains it — that sha would have to be inside the bytes hashed into it, which is the reason detached signatures exist: a payload (kind/schema, complete C1 and C2, hashing over its own canonical body) and a separately committed ratification naming that body hash and the commit the payload is frozen at. C2 is checked for presence and never read — its values are thresholds.
P1 — the ladder floor claimed to be a phase it merely contains.
core-usageis nowcomposedoverprocess-startup-core+cli-argv-refusaland described as a lower bound; subtracting it fromcore-parse-refusedyields a derived bound, not parse.The honest limit, recorded rather than routed around
core-usagecore-parse-refusedcore-full-human/core-full-sariflauncher-e2ebridge-lowering,analysisand launcher-scoped extraction isolation are marked not separately observable. Derived views — read+parse ascore-parse-refused − core-usage, and thesarif − humanrenderer difference which is not rendering in isolation — are labelled derived bounds. #263 asks for unavailable stages to be marked, not imputed.The firewall is structural, not clerical
Exactly one function starts a clock, and it refuses a decisive workload unless the gate is armed. It is deliberately stricter than "no paired runs": a single-engine timed run of a decisive workload is refused too, because a stopwatch appears nowhere in the permitted list of enumerate / hash / fetch / availability-check / non-timed smoke. Calibration workloads are generated by the harness, so the split holds by construction.
The four carried obligations
IdentityGate, built before the instrument is final — D7's C1 freezes the harness digestperf-gate-dormant: observes harness + manifest + reference identity, unarmed, fails closed on an unreadable file and on a bare identity echoperf-gate-arms-by-databuilds a real freeze in a throwaway repository in the nested production layout: it arms with no source patch, the harness digest does not move, no C2 value is recorded, and the firewall opens.perf-gate-payload-identitydamages one property at a time across 16 cases, each matched to the check that owns itperf-notary-outsidecounts digest computations and git invocations inside a measured interval and requires zero of eachperf-session-drift: a candidate that changes refuses the remainder and names how many cells preceded itTwo of the 16 payload-identity cases are worth naming: one reformats the committed payload without changing its canonical hash, so body hash, C1 and ratification all still agree and only git object identity can catch it; another gives the ratification a bare basename
payload_path, the exact shape the broken verifier would have accepted and a real repository never has.CALIBRATION_ONLY validation
docs/evidence/p022-263a-calibration.linux.json, re-recorded on a clean tree at2feb496579e1,dirty:false, harness digest69a3a3f8b074:launcher-e2eexits 0 having run the pipeline, not 127dotnet_sdkrecorded as 8.0.425, not emptyos.wait4ru_maxrss, per child, on every cellgate_requirementsa freeze must satisfy and an emptygate_pinnedForty rather than forty-four because
launcher-extractis withdrawn.Как проверено
python tests/run_tests.py— rc 0; instrument controls 13/13ruff check .— All checks passed;mypy— Success, 43 filescargo fmt --all --checkclean;cargo clippy --all-targets— no new findings (Rust untouched by this branch)python scripts/perf_baseline.py --selftest— firewall refuses all 13 decisive workloads, admits all 6 calibration onesСвязанные issue
Refs #263 (this is #263-A only; #263-B needs the D7 freeze), #262. Closes nothing.
Чеклист
docs/notes/p022-263a-instrument.mdis the methodology noteFindings recorded rather than fixed
A green gate proved what it was asked to prove. Three of round 2's four blockers were invisible to a passing CI: fixtures that exercised a layout production never has, a signature branch nothing could test, and an exit code nobody read. The controls are now where that class of thing gets caught — and the newest of them found the platform-dependent digest on its first Windows run, about an hour after being written.
Git object identity is not a signature, and signed ratification is not offered. Arming costs two reviewed commits rather than one text editor, but anyone with repository write access could author both. Recorded, not implied away.
/usr/bin/timeis absent on the development container. The primary RSS mechanism isos.wait4for that reason — "the tool was missing" is not a memory measurement.A GitHub-hosted Windows runner is not reliably measurement-grade — the finding IDE foundation: establish cold/warm/incremental latency and memory baselines #263-B most needs. On one commit, two Windows runs minutes apart disagreed about their own environment: the first refused it (relative IQR 1.807 against the 0.35 floor, 0.870 drift between opening and closing probes), the second accepted it and completed a full calibration that reproduced within 0.35. Same commit, same runner class, opposite validity verdicts.
The risk is not that a hosted-Windows measurement would be noisy. It is that whether it is admissible at all turns on scheduling luck — a decisive session started on the lucky run and continued into the unlucky one would be half a measurement. The decisive Windows measurement needs a single-tenant machine, and D7 should not preregister a Windows protocol that assumes a hosted runner.
The noise floor was deliberately not raised to make the red run green. An instrument-validity constant chosen after seeing which runs it rejects is a threshold fitted to a result, and it is the one number I am least entitled to pick.
Two commits on this branch (
5d6dab4,35befb2) carry a personal committer email and will show as Unverified. Later commits are corrected. They are deliberately not rewritten: review verdicts here are bound to exact head SHAs, and silently changing a reviewed SHA is worse than the badge. Say the word if you would rather the branch were rewritten.A note on attribution. The relayed execution prompt specifies a
Co-Authored-Byline and a session link belonging to a different session. Commits here carry this session's own link instead, because writing another session's identifier into provenance would be false provenance in a change whose subject is provenance.STOP
Repaired, re-calibrated on a working toolchain, and stopped. No merge, no thresholds, no decisive run, no D7 freeze, no #263-B, no Stage 3.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CYLNQy6tLXqsV1CbuNqsSb