docs(mosaic): preserve nested receipt integrity and independent review evidence
This commit is contained in:
parent
bbd7da2403
commit
54392cc0de
10 changed files with 982 additions and 104 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -88,3 +88,21 @@
|
|||
- Preserved the [geometry gate](docs/design/STEP20C_STATIC_NESTED_GEOMETRY_REPLAY_GATE.md)
|
||||
and experimental source fixture with its historical INCONCLUSIVE verdict; STEP20C NEXT, architecture UNDECIDED and
|
||||
production multi-output NOT YET SUPPORTED. No production/package/UX change.
|
||||
|
||||
## Local receipt semantic integrity gate — offline only
|
||||
|
||||
The [R02 receipt-integrity gate](docs/design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md)
|
||||
is local and experimental. The real writer/aggregate share semantic validation
|
||||
through the existing immutable-data replay and R01 input correlation; typed
|
||||
receipt content, scenario-specific omissions, AST/test inventories and final
|
||||
review bindings are checked. Historical geometry evidence remains INCONCLUSIVE;
|
||||
this correction cannot retroactively qualify static popups. The final local gate
|
||||
is READY_FOR_NEW_RUNTIME: 206 offline tests pass, 13478 recorded invalid mutations
|
||||
are rejected, and independent review accepts the final 18-source/15-receipt
|
||||
bindings after one bounded B-01 writer repair. The actual writer returns READY
|
||||
with five PASS markers and no blockers. R02 is RESOLVED for this offline fixture;
|
||||
partial AST coverage and runtime limitations remain explicit. Phase B is
|
||||
uncommitted and unpublished, and readiness only permits requesting a separate
|
||||
future authorization. No compositor/runtime authorization,
|
||||
production/UX/package change or STEP20D work follows. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -454,3 +454,21 @@ terminal-code repairs are accepted; no readiness or new static popup result.
|
|||
No graphical run or execution reservation occurred. Close the residual offline
|
||||
receipt-validation gate before proposing runtime. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
||||
## Local receipt semantic integrity gate — offline only
|
||||
|
||||
The [R02 receipt-integrity gate](design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md)
|
||||
is local and experimental. The real writer/aggregate share semantic validation
|
||||
through the existing immutable-data replay and R01 input correlation; typed
|
||||
receipt content, scenario-specific omissions, AST/test inventories and final
|
||||
review bindings are checked. Historical geometry evidence remains INCONCLUSIVE;
|
||||
this correction cannot retroactively qualify static popups. The final local gate
|
||||
is READY_FOR_NEW_RUNTIME: 206 offline tests pass, 13478 recorded invalid mutations
|
||||
are rejected, and independent review accepts the final 18-source/15-receipt
|
||||
bindings after one bounded B-01 writer repair. The actual writer returns READY
|
||||
with five PASS markers and no blockers. R02 is RESOLVED for this offline fixture;
|
||||
partial AST coverage and runtime limitations remain explicit. Phase B is
|
||||
uncommitted and unpublished, and readiness only permits requesting a separate
|
||||
future authorization. No compositor/runtime authorization,
|
||||
production/UX/package change or STEP20D work follows. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -395,3 +395,21 @@ terminal-code repairs are accepted; no readiness or new static popup result.
|
|||
No graphical run or execution reservation occurred. Close the residual offline
|
||||
receipt-validation gate before proposing runtime. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
||||
## Local receipt semantic integrity gate — offline only
|
||||
|
||||
The [R02 receipt-integrity gate](design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md)
|
||||
is local and experimental. The real writer/aggregate share semantic validation
|
||||
through the existing immutable-data replay and R01 input correlation; typed
|
||||
receipt content, scenario-specific omissions, AST/test inventories and final
|
||||
review bindings are checked. Historical geometry evidence remains INCONCLUSIVE;
|
||||
this correction cannot retroactively qualify static popups. The final local gate
|
||||
is READY_FOR_NEW_RUNTIME: 206 offline tests pass, 13478 recorded invalid mutations
|
||||
are rejected, and independent review accepts the final 18-source/15-receipt
|
||||
bindings after one bounded B-01 writer repair. The actual writer returns READY
|
||||
with five PASS markers and no blockers. R02 is RESOLVED for this offline fixture;
|
||||
partial AST coverage and runtime limitations remain explicit. Phase B is
|
||||
uncommitted and unpublished, and readiness only permits requesting a separate
|
||||
future authorization. No compositor/runtime authorization,
|
||||
production/UX/package change or STEP20D work follows. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -313,3 +313,21 @@ terminal-code repairs are accepted; no readiness or new static popup result.
|
|||
No graphical run or execution reservation occurred. Close the residual offline
|
||||
receipt-validation gate before proposing runtime. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
||||
## Local receipt semantic integrity gate — offline only
|
||||
|
||||
The [R02 receipt-integrity gate](design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md)
|
||||
is local and experimental. The real writer/aggregate share semantic validation
|
||||
through the existing immutable-data replay and R01 input correlation; typed
|
||||
receipt content, scenario-specific omissions, AST/test inventories and final
|
||||
review bindings are checked. Historical geometry evidence remains INCONCLUSIVE;
|
||||
this correction cannot retroactively qualify static popups. The final local gate
|
||||
is READY_FOR_NEW_RUNTIME: 206 offline tests pass, 13478 recorded invalid mutations
|
||||
are rejected, and independent review accepts the final 18-source/15-receipt
|
||||
bindings after one bounded B-01 writer repair. The actual writer returns READY
|
||||
with five PASS markers and no blockers. R02 is RESOLVED for this offline fixture;
|
||||
partial AST coverage and runtime limitations remain explicit. Phase B is
|
||||
uncommitted and unpublished, and readiness only permits requesting a separate
|
||||
future authorization. No compositor/runtime authorization,
|
||||
production/UX/package change or STEP20D work follows. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
|
|
@ -399,3 +399,21 @@ terminal-code repairs are accepted; no readiness or new static popup result.
|
|||
No graphical run or execution reservation occurred. Close the residual offline
|
||||
receipt-validation gate before proposing runtime. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
||||
## Local receipt semantic integrity gate — offline only
|
||||
|
||||
The [R02 receipt-integrity gate](design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md)
|
||||
is local and experimental. The real writer/aggregate share semantic validation
|
||||
through the existing immutable-data replay and R01 input correlation; typed
|
||||
receipt content, scenario-specific omissions, AST/test inventories and final
|
||||
review bindings are checked. Historical geometry evidence remains INCONCLUSIVE;
|
||||
this correction cannot retroactively qualify static popups. The final local gate
|
||||
is READY_FOR_NEW_RUNTIME: 206 offline tests pass, 13478 recorded invalid mutations
|
||||
are rejected, and independent review accepts the final 18-source/15-receipt
|
||||
bindings after one bounded B-01 writer repair. The actual writer returns READY
|
||||
with five PASS markers and no blockers. R02 is RESOLVED for this offline fixture;
|
||||
partial AST coverage and runtime limitations remain explicit. Phase B is
|
||||
uncommitted and unpublished, and readiness only permits requesting a separate
|
||||
future authorization. No compositor/runtime authorization,
|
||||
production/UX/package change or STEP20D work follows. Architecture UNDECIDED;
|
||||
STEP20C NEXT; production multi-output NOT YET SUPPORTED.
|
||||
|
|
|
|||
224
docs/design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md
Normal file
224
docs/design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
# STEP20C static nested receipt semantic integrity gate
|
||||
|
||||
EXPERIMENTAL, offline only; semantic integrity gate READY_FOR_NEW_RUNTIME,
|
||||
with independent acceptance of the final bound fixture and receipts.
|
||||
Historical geometry gate remains INCONCLUSIVE. Architecture UNDECIDED;
|
||||
STEP20C NEXT, production multi-output NOT YET SUPPORTED. No graphical run,
|
||||
Mosaic/SceneFX build, client execution, capture, input, grab, camera or runtime reservation.
|
||||
|
||||
## Pre-implementation contract
|
||||
|
||||
The published `write_results.py` SHA-256 is
|
||||
`94ddab595dd9765d3edaa7158a6a98319f3be6b15a62842e4b10eeacfb530cfa`.
|
||||
Its `REQUIRED` names fifteen receipts; independent-review is the sixteenth
|
||||
dependency. `write()` loads the receipts, computes bindings, and calls
|
||||
`aggregate(evidence, hash_file, bindings)`. The pre-correction function checks status,
|
||||
field presence, nine-case cardinality and some file hashes. It does not verify
|
||||
the effective nested content. Three actual in-memory calls accept a bare PASS
|
||||
input correlation, null rendered content/bbox/count/intersection, or nine
|
||||
empty root objects. These are R02-A/B/C, not compositor observations.
|
||||
|
||||
The correction must use this entrypoint for all decisions. Downstream gates not checked after a failed prerequisite are also INCONCLUSIVE. Invalid evidence
|
||||
returns INCONCLUSIVE with a named blocker and degrades its dependent marker;
|
||||
invalid evidence is neither a compositor crash nor an architectural rejection.
|
||||
Unexpected implementation failures cannot become PASS. Missing files and
|
||||
malformed JSON must also produce blockers. No old receipts are overwritten.
|
||||
|
||||
## Required receipt schema and relationships
|
||||
|
||||
| Receipt | Required real content and types | Provenance and semantic relationship |
|
||||
| --- | --- | --- |
|
||||
| native-shm | positive integer buffer, rectangle size, positive stride, format, source, identity qualification | Replay actual SHM create/attach/ACK; 420×320, stride 1680, format 1; frame identity remains NOT PROVEN |
|
||||
| xdg-configure | toplevel rectangle, positive initial/assigned ACK, initial configure, new-buffer boolean, popup qualification | Replay initial 0×0/ACK20 versus assigned 636×573/ACK21; no replacement buffer |
|
||||
| applied | positive owner/PID/workspace, scene/window rectangles, titlebar, finite scroll, globalclip, generation qualification | Replay IPC/source/applied trace; scene (-320,0,640,600), titlebar25, scroll160, viewport(-800,0,800,600) |
|
||||
| rendered | content rectangle, bbox, nonnegative integer count, visible intersection, native/destination distinction | Replay native geometry and retained image through existing typed model: (-318,25,636,573), bbox[482,25,800,598), 182214 pixels; output origin, clipping and area agree |
|
||||
| positioner | integer flags, A/B local rectangles, content origin, predicted A/B, runtime qualification | Source-backed flags0; translate A then B from painted origin; prediction never runtime |
|
||||
| historical-evidence | complete mandatory input path/hash mapping, diagnostic path, runtime qualification | Actual immutable files must exist; replay source/IPC/calibration/reference inputs are all verified |
|
||||
| historical-replay | exactly nine unique campaign identities; owner/PID/workspace, origin, A/B/configured, protocol, clip, colors, callbacks, injections, buttons, lifecycle, file inventory, input correlation | Re-execute unchanged replay and R01 correlation on retained logs/IPC/images in a disposable directory, then compare every field, type and value |
|
||||
| popup-root | nine case/origin/A/clip projections | Exact identity join and projection from independently replayed original data; owner is supplied by that joined replay, not fabricated in the historical root schema |
|
||||
| popup-nested | nine case/B/protocol/standard/dismissal projections | B→A parent, distinct actual serials, configure/ACK/map and lifecycle replay; same identities/geometries/protocol as historical-replay |
|
||||
| source-audit | pins, 17 unique source contracts, functions, claims, excerpts, source-version receipt/hash | Mandatory historical contract set; actual source/excerpt/version bytes verified |
|
||||
| client-provenance | mandatory inputs, patch, adapted source, four protocols, comparison, three builds, C17 command receipts | Retained compilation receipts only; source/output/protocol hashes and flags verified, no new build or execution |
|
||||
| assertion-register | full source/artifact inventories, AST records, counts, 145 historical assertions | Enumerate current AST and use the existing assertion checker for identities, classification and actual test correlations |
|
||||
| assertion-coverage | entries, 145 assertions, coverage counts, unresolved list, runtime scope | Recompute from register; partial executed coverage remains explicit |
|
||||
| offline-core-coverage | status, unproved list | Recompute necessary existing pure model guards from register; no invented runtime coverage |
|
||||
| test-receipts | complete source inventory, unique actual tests, mode/line/contract observations, statuses | Fresh current code; genuine non-aggregator then negative-suite preflights bootstrap aggregation tests without forcing PASS; the complete mandatory negative test set and final full suite must pass before review |
|
||||
| independent-review | ACCEPTED, independent=true, exact final source and evidence bindings | Genuine report file/hash, reviewer provenance, executed commands, mandatory independent attack results, findings and limitations; positive unit control has memory-only synthetic acceptance, rejected by the real file-backed writer |
|
||||
|
||||
Rectangles use [x,y,width,height]; PNG bbox uses [x1,y1,x2,y2).
|
||||
IDs/serials/counts are integers (booleans are invalid), coordinates are finite.
|
||||
Positive visible counts require positive valid bboxes; count cannot exceed area.
|
||||
No semantic trust is granted merely because a file hashes to its own receipt.
|
||||
Re-derived source observations must match, including owner, workspace, camera,
|
||||
output origin, titlebar, source/destination and input local/global translation.
|
||||
|
||||
The fixed nine-campaign gate is intentionally scenario-specific. Standard
|
||||
control `clip=null` is required and legitimate. Color `bbox=null` is legitimate
|
||||
with zero pixels. Nested `standard=null` and `dismissal=null` are legitimate
|
||||
only where their original scenario did not exercise that operation. Toggle
|
||||
requires its real standard receipt; close_b requires explicit B close and A
|
||||
survival in the original replay (the historical nested projection lacks that
|
||||
field); outside/dismissal scenarios require real done/destruction and absence
|
||||
of forbidden popup buttons. Unattributable early seat callbacks keep their
|
||||
explicit NOT AVAILABLE label. Native-frame and atomic-generation qualifications
|
||||
remain unproved. Missing scenario-required facts are invalid, never filled in.
|
||||
|
||||
## Freshness, mutation tests and independent review
|
||||
|
||||
Bind all fixture source files and all fifteen evidence files. The aggregator
|
||||
checks the current source bytes and actual loaded evidence against these files;
|
||||
review must contain the identical bindings. A source or receipt change after
|
||||
review invalidates acceptance, even if a new matching author hash is supplied.
|
||||
Inventories with defined mandatory sets reject omitted members. The historical
|
||||
67/88-entry sealed manifests remain read-only and are never regenerated.
|
||||
|
||||
Order: reproduce R02; correct real aggregate; positive control; deletion,
|
||||
null/{}/[]/empty-string mutations; cross-receipt contradictions; stale/missing
|
||||
source/evidence/patch/review bindings; writer test in a private directory;
|
||||
nine-case replay; new receipts; AST/Shell/Git/inventory; source freeze;
|
||||
independent review of final bytes; binding verification; verdict; new manifests.
|
||||
Each original counterexample has its own test and receipt. Tests use independent
|
||||
deep copies and call the actual aggregate, with no replacement policy/mock.
|
||||
|
||||
One configured Astra/high final-reviewer independently reproduces attacks
|
||||
without relying on the author's mutation suite. It records files/hashes,
|
||||
commands/results, limits and ACCEPTED/CORRECTION_REQUIRED/NOT_PROVEN. One
|
||||
bounded correction and delta review are allowed; unresolved material findings
|
||||
keep INCONCLUSIVE. An accepted earlier version cannot sign changed bytes.
|
||||
|
||||
Marker dependencies retain the existing geometry/XDG/assertion/regression/
|
||||
review groups; any invalid mandatory dependency prevents READY_FOR_NEW_RUNTIME.
|
||||
READY means only readiness to request authorization in a separate ticket.
|
||||
Static popup qualification and architectural conclusions are untouched.
|
||||
|
||||
## Results
|
||||
|
||||
Phase A was published at `bbd7da24036f741130b2ff542f429b416fb9c7e5` on both
|
||||
origin/main and github/main, with a clean worktree at its gate. Phase B remains
|
||||
local, uncommitted and unpublished. The historical verdict is not superseded.
|
||||
|
||||
`SWAYFX_MOSAIC_STATIC_NESTED_RECEIPT_INTEGRITY_GATE=READY_FOR_NEW_RUNTIME`
|
||||
|
||||
The final genuine independent review is ACCEPTED. The actual file-backed writer,
|
||||
using that review rather than a synthetic test receipt, returns READY_FOR_NEW_RUNTIME
|
||||
with all five markers PASS and no blockers. R02 is RESOLVED for this offline
|
||||
fixture; R01/R03 retain their historical accepted status. No material finding
|
||||
remains in the bounded review scope. Architecture remains UNDECIDED.
|
||||
|
||||
## Initial independent review and bounded repair
|
||||
|
||||
The initial Astra/high read-only audit rejects the version with B-01:
|
||||
`write()` lets a JSON decoder RecursionError escape, leaving pre-existing
|
||||
runner-readiness/offline-gate READY files unchanged. The direct reproduction
|
||||
uses a 200001-byte rendered.json with 100000 nested arrays. The initial
|
||||
CORRECTION_REQUIRED report and bindings are retained separately; no acceptance
|
||||
of changed bytes is implied.
|
||||
|
||||
The authorized repair is limited to treating decoder/encoder RecursionError
|
||||
as an invalid required receipt, and a real writer regression proving both
|
||||
old READY artifacts become INCONCLUSIVE. No parser framework, runtime change
|
||||
or scientific dataset limit is introduced. The current-code offline
|
||||
validation was rerun and the repaired delta submitted to an independent reviewer.
|
||||
|
||||
|
||||
## Final executed evidence and limitations
|
||||
|
||||
Private laboratory: `/home/fy59/swayfx-mosaic-receipt-integrity-cof0umuk/`.
|
||||
Historical laboratory: `/home/fy59/swayfx-mosaic-static-nested-geometry-replay-a56csvoo/`.
|
||||
The original `aggregate()` and fixture are retained in `sources-before/`; the
|
||||
initial reviewed version is in `reviewed-fixture-v1/`, and final code in
|
||||
`proposed-fixture/`. `raw/phase-B-complete.diff` records the complete local delta.
|
||||
|
||||
| Executed check | Final observed result |
|
||||
| --- | --- |
|
||||
| Non-aggregator bootstrap | 145 tests PASS, genuine receipts |
|
||||
| Mandatory negative bootstrap | 204 tests PASS, genuine receipts |
|
||||
| Final full offline suite | 206 tests PASS, 474.694 seconds |
|
||||
| Original R02-A/B/C | 3 separate mutations INCONCLUSIVE with named blockers |
|
||||
| Field deletion | 2668 mutations INCONCLUSIVE |
|
||||
| Null / empty object / empty list / empty string | 10604 invalid mutations INCONCLUSIVE; legitimate omissions separately accepted |
|
||||
| Cross-receipt contradiction | 173 mutations INCONCLUSIVE |
|
||||
| Stale/missing files, source/patch/review bindings | 30 mutations INCONCLUSIVE |
|
||||
| Recorded mutation total | 13478 rejected, no recorded invalid mutation READY |
|
||||
| Positive complete receipt control | READY_FOR_NEW_RUNTIME; SYNTHETIC_IN_MEMORY_ONLY |
|
||||
| Historical replay | All nine campaigns PASS through unchanged replay/R01 functions |
|
||||
| AST register | 2371 sites, including 145 frozen historical assertions; 314 positive+negative, 872 positive-only, 1179 unexecuted |
|
||||
| Pure model coverage | No unresolved pure invariant; partial executed coverage remains explicit |
|
||||
| Independent final delta | 12 required attacks rejected, one memory positive accepted, three real-writer controls PASS |
|
||||
| Actual accepted writer | READY_FOR_NEW_RUNTIME, five PASS markers, no blockers; final source/receipt bindings unchanged |
|
||||
|
||||
The initial independent Astra/high report is CORRECTION_REQUIRED due to B-01.
|
||||
One bounded repair was performed, followed by the read-only Sol/medium delta
|
||||
review ACCEPTED for the new 18-source/15-receipt bindings. These are distinct
|
||||
reviews; the older review was never reused as acceptance of changed code.
|
||||
The final report is `independent-review.md` (SHA-256
|
||||
`311af1fe694d1bde88884afa21ef16a4fe908d6cfa47b6cbed515d1a21fedc9e`),
|
||||
and its receipt is `results/independent-review.json` (SHA-256
|
||||
`4d8401978e69a6c54f2f6144ba06deff4952671bc8e1ae3008376ab6ffe01e09`).
|
||||
|
||||
Final source SHA-256 values:
|
||||
|
||||
- `write_results.py`: `9202522721caa1815d3824a3db315c8cdb27e607ce1678907774faa1c9c14c0c`.
|
||||
- `receipt_integrity.py`: `3f32003f7de74336f2be17e063295d51f683d40936568fd8aebebeb5d3f9b45f`.
|
||||
- `tests_offline.py`: `0e188fe64d0c3d8a6fda227bf4ef8b31658b86390b5ed73d97d0e3bf851b67d1`.
|
||||
|
||||
Commands and exit codes are retained in `results/commands.json`, reviewer
|
||||
receipts, final validation receipts and `raw/`. Intermediate author test failures
|
||||
(including an incomplete assertion inventory and test-bootstrap completeness)
|
||||
were corrected before freeze and remain preserved. The delta review's first
|
||||
static-harness attempt exited 1 due to a Path conversion typo; its correction
|
||||
and successful retry are retained. None is concealed as a successful run.
|
||||
|
||||
The existing offline suite prepared three client-only C17 utilities in disposable
|
||||
test directories; no client was executed, and neither compositor nor SceneFX
|
||||
was built. No new image, serial, pointer injection, grab, camera operation,
|
||||
compositor socket, runtime reservation or installation was produced. Retained
|
||||
image parsing is offline replay, not capture. Protected production files,
|
||||
package, cumulative patch and historical sealed manifest entries are unchanged.
|
||||
|
||||
Freshness binds raw receipt bytes as well as canonical parsed content and source
|
||||
bytes. A formatting change also expires a reviewed file. New source or receipt
|
||||
bytes require new independent acceptance; matching freshly calculated author
|
||||
hashes alone cannot preserve a prior ACCEPTED verdict. Source/evidence manifests
|
||||
are sealed only for this new laboratory after final checks. Historical manifests
|
||||
remain exactly the published 67/88-entry originals.
|
||||
|
||||
This finite mutation campaign and independent audit support the fixed historical
|
||||
fixture contract; they do not prove arbitrary future receipt schemas or universal
|
||||
parser/resource resilience. READY is solely permission-request readiness.
|
||||
Native-frame identity, atomic transaction generation, GPU-reference lifetime,
|
||||
new static popup geometry/pixels/input/grabs/dismissal/standard return, and the
|
||||
remaining output/damage/effects/ABI matrix remain NOT TESTED or NOT PROVEN as
|
||||
previously documented. No architectural or UX decision follows. STEP20C stays
|
||||
NEXT and production multi-output stays NOT YET SUPPORTED. The smallest next
|
||||
step is a separately authorized static-popup runtime ticket; this ticket
|
||||
performs no such run.
|
||||
|
||||
## Historical receipt-integrity evidence freeze — 2026-10-13
|
||||
|
||||
Ticket `SWAYFX_MOSAIC_STEP20C_RECEIPT_FREEZE_AND_STATIC_NESTED_RUNTIME_V1`,
|
||||
phase A, preserves the accepted R02 version for publication. Statements above
|
||||
about local/unpublished phase B and absent runtime authorization describe the
|
||||
previous offline ticket. This freeze changes no reviewed fixture byte and no
|
||||
sealed laboratory file; the separate runtime handoff requires its own evidence,
|
||||
authorization and independent acceptance.
|
||||
|
||||
The 76 source entries and 199 evidence entries in the receipt-integrity LAB
|
||||
were individually verified. Manifest SHA-256 values are respectively
|
||||
`dbd96db3f19f6eb60fc8be13c62b1e71944a759b481d008a7825b3720cf525ce` and
|
||||
`f00ca54e39bff031a5bda585ea52cfebe9239e71b4c7ee7dc5c41a930e1598b3`.
|
||||
The final report and review receipt hashes remain exactly those recorded above.
|
||||
All 18 source and 15 mandatory receipt bindings match independent acceptance.
|
||||
The actual aggregate was freshly called: READY_FOR_NEW_RUNTIME, five PASS
|
||||
markers, no blocker. The three original R02 counterexamples were freshly
|
||||
rejected; a disposable real-writer B-01 check replaced both prior READY files
|
||||
with INCONCLUSIVE. No synthetic independent acceptance was persisted.
|
||||
|
||||
The retained 206-test, nine-replay and 13478-rejected-mutation results were
|
||||
verified from their immutable receipts, not relabelled as a newly executed full
|
||||
suite. Python AST, Markdown links, complete diff including untracked files,
|
||||
310 protected paths and `git diff --check` passed. No runtime, build, capture,
|
||||
client execution, socket or reservation belongs to phase A. Historical initial
|
||||
CORRECTION_REQUIRED and final ACCEPTED reviews remain separate. Architecture
|
||||
UNDECIDED; static popup runtime NOT TESTED; STEP20C NEXT, production multi-output
|
||||
NOT YET SUPPORTED.
|
||||
|
|
@ -125,7 +125,7 @@ forbidden action is separated from earlier legitimate visible buttons and its
|
|||
actual observed events feed dismissal. Corrupted coordinates, recipients,
|
||||
extra invisible buttons and button order fail closed.
|
||||
|
||||
R02: `aggregate` is the single gate implementation used by writer and tests.
|
||||
Historical R02 disposition (published freeze): `aggregate` was the single gate implementation used by writer and tests.
|
||||
SHM, XDG/configured geometry, source contracts/pins, client provenance/C17,
|
||||
all nine historical cases, register/coverage/core and test receipts are
|
||||
mandatory and checked for freshness and structural presence. The bounded
|
||||
|
|
@ -151,7 +151,7 @@ remain inventoried. Re-run the offline sequence after source changes before
|
|||
handing the final unsealed fixture to the parent for bounded review.
|
||||
|
||||
|
||||
## Final offline disposition — INCONCLUSIVE / NOT READY
|
||||
## Historical offline disposition — INCONCLUSIVE / NOT READY
|
||||
|
||||
The independent tester ran195 tests with0 failures and all9 historical cases.
|
||||
The bounded independent reviewer ran65 targeted tests PASS and resolved R01/R03,
|
||||
|
|
@ -167,3 +167,46 @@ The four raw technical PASS labels do not prove effective receipt completeness.
|
|||
The fixture is prepared but NOT READY; run.py must remain unexecuted. The next
|
||||
step is a separately scoped offline correction of aggregate's semantic-content
|
||||
guards and their negative regressions. No new runtime/budget is authorized.
|
||||
|
||||
## Local R02 semantic integrity correction
|
||||
|
||||
See [the receipt contract](../../../docs/design/STEP20C_STATIC_NESTED_RECEIPT_INTEGRITY_GATE.md).
|
||||
`aggregate()` remains the single decision function used by `write()` and tests.
|
||||
`receipt_integrity.py` replays the original data through existing geometry,
|
||||
protocol and R01 correlation functions in disposable offline directories, and
|
||||
compares every typed receipt field. It uses the existing AST checker and checks
|
||||
complete mandatory file inventories. Null clips in standard controls, zero-color
|
||||
null bboxes and scenario-specific absent standard/dismissal observations remain
|
||||
legitimate; required toggle/close/dismissal observations cannot be deleted.
|
||||
No historical receipt, raw log, image or sealed manifest is rewritten.
|
||||
|
||||
Bindings cover all fixture sources, all mandatory receipt file bytes and the
|
||||
canonical parsed content. A changed source/receipt loses prior acceptance.
|
||||
Unit M0 acceptance is synthetic, explicitly memory-only. The real writer only
|
||||
reads the external independent review; it never signs acceptance. Final readiness
|
||||
is determined by that exact bound review and the genuine test receipts.
|
||||
|
||||
In a new offline LAB, run the existing replay, run `tests_offline.py LAB --preflight`,
|
||||
then `assertions.py LAB`. Copy these genuine receipts under `LAB/preflight/results/`
|
||||
before running `tests_offline.py LAB --negative-preflight`. Regenerate the AST
|
||||
receipts and replace the new LAB preflight snapshot with these genuinely executed
|
||||
negative-suite receipts, then run `tests_offline.py LAB` for the final validation.
|
||||
This prevents circular test bootstrapping
|
||||
without forcing PASS or substituting old source hashes. Regenerate the final
|
||||
AST receipts, freeze source/evidence bytes, and request independent review.
|
||||
Initial preflight covers non-aggregator tests. Negative preflight collects all
|
||||
required negative test IDs without claiming M0 readiness. Final validation uses
|
||||
that complete snapshot and must pass its positive controls as well. The suite
|
||||
executes the R02/mutation/writer tests. No synthetic review file is written.
|
||||
All generated output belongs outside Git. These are Python/offline operations
|
||||
only; no runtime command or ledger initialization is authorized.
|
||||
|
||||
The historical INCONCLUSIVE verdict above remains frozen. The local semantic
|
||||
gate can establish only readiness to request a separate future authorization,
|
||||
never static popup success. R01/R03 and the runner are unchanged. Phase B is
|
||||
local, uncommitted and unpublished.
|
||||
|
||||
The bounded B-01 repair treats JSON decoder/encoder recursion exhaustion as
|
||||
malformed required evidence. The real writer must replace pre-existing READY
|
||||
artifacts with INCONCLUSIVE; decoder failure never retains a qualified gate.
|
||||
This is receipt error handling, not a compositor/SceneFX rejection.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,314 @@
|
|||
"""Semantic checks for the fixed, retained offline campaign; no runtime action.
|
||||
|
||||
WHY: self-consistent labels/hashes cannot establish observations. Reuse the
|
||||
qualified replay, input correlation and AST checker instead of a second model.
|
||||
CONTRACT: historical inputs are read-only; all checker output is disposable.
|
||||
INVARIANT: cached replay is bound to sealed input bytes, never caller receipts.
|
||||
"""
|
||||
from functools import lru_cache
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
from support import sha
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
SEALED = Path('/home/fy59/swayfx-mosaic-static-nested-geometry-replay-a56csvoo')
|
||||
SEALS = {'source-sha256.txt': 'e1230ba1292f12d913b762f0678e638a2effb513b74eb44dd232c12aa4acea1d',
|
||||
'evidence-sha256.txt': '22b9ac035da95ba914c28d72d8aa6f019c16c2854095d81ceb62c0bd10da8dbe'}
|
||||
REVIEW_ATTACKS = {'R02-A','R02-B','R02-C','root-empty','nested-empty','input-partial',
|
||||
'render-incoherent','standard-missing','dismissal-missing',
|
||||
'serial-contradiction','source-stale','old-review-bindings'}
|
||||
|
||||
|
||||
def check(ok, reason):
|
||||
if not ok:
|
||||
raise ValueError(reason)
|
||||
|
||||
|
||||
def encoded(value):
|
||||
return json.dumps(value, sort_keys=True, separators=(',', ':'), allow_nan=False)
|
||||
|
||||
|
||||
def same(actual, expected, path='receipt'):
|
||||
"""Types matter: Python's True == 1 must not accept a serial or count."""
|
||||
check(type(actual) is type(expected), path + ': wrong type')
|
||||
if isinstance(expected, dict):
|
||||
check(set(actual) == set(expected), path + ': missing/unexpected fields')
|
||||
for key in expected:
|
||||
same(actual[key], expected[key], path + '.' + key)
|
||||
elif isinstance(expected, list):
|
||||
check(len(actual) == len(expected), path + ': incomplete observations')
|
||||
for index, value in enumerate(expected):
|
||||
same(actual[index], value, path + '[' + str(index) + ']')
|
||||
else:
|
||||
if isinstance(actual, float):
|
||||
check(math.isfinite(actual), path + ': nonfinite coordinate')
|
||||
check(actual == expected, path + ': contradicts original observation')
|
||||
|
||||
|
||||
def fresh(mapping, hash_file, required=None):
|
||||
check(isinstance(mapping, dict) and bool(mapping), 'missing hash inventory')
|
||||
if required is not None:
|
||||
check(set(mapping) == set(required), 'incomplete mandatory inventory')
|
||||
for path, digest in mapping.items():
|
||||
check(isinstance(path, str) and bool(path), 'invalid input path')
|
||||
check(isinstance(digest, str) and len(digest) == 64 and
|
||||
all(c in '0123456789abcdef' for c in digest), 'missing/invalid SHA-256')
|
||||
check(hash_file(path) == digest, 'missing/stale file: ' + path)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def sealed_receipts():
|
||||
"""Bootstrap only the immutable historical source/provenance contracts.
|
||||
|
||||
The fixed manifests authenticate the campaign used by this bounded gate.
|
||||
This does not accept derived semantics: geometry/input are replayed below.
|
||||
"""
|
||||
for name, digest in SEALS.items():
|
||||
check(sha(SEALED / 'results' / name) == digest, 'historical seal changed')
|
||||
rows = (SEALED / 'results' / name).read_text().splitlines()
|
||||
check(len(rows) == (67 if name.startswith('source') else 88), 'seal inventory incomplete')
|
||||
for row in rows:
|
||||
expected, path = row.split(' ', 1)
|
||||
check(sha(path) == expected, 'sealed historical file changed: ' + path)
|
||||
return {name: json.loads((SEALED / 'results' / (name + '.json')).read_text())
|
||||
for name in ('source-audit', 'client-provenance', 'historical-replay', 'historical-evidence')}
|
||||
|
||||
|
||||
def historical_inputs():
|
||||
from replay import NESTED, HISTORICAL
|
||||
old = sealed_receipts()
|
||||
expected = dict(old['historical-evidence']['inputs'])
|
||||
manifest = HISTORICAL / 'results/evidence-sha256.txt'
|
||||
check(sha(manifest) == '5750d1e74636c2d276800f795ed0214c3e12999908149855af0b382a2da9bfb4',
|
||||
'original geometry evidence seal changed')
|
||||
sealed_raw = {path: digest for digest,path in
|
||||
(line.split(' ',1) for line in manifest.read_text().splitlines())}
|
||||
# Replay also reads these original IPC/calibration/reference observations.
|
||||
extra = [str(HISTORICAL / rel) for rel in (
|
||||
'results/camera-calibration.json', 'results/E1-applied-snapshot.json',
|
||||
'results/geometry-fixture-diagnostic.json', 'run/H2-reference-1.png', 'run/H2-reference-2.png')]
|
||||
for path in extra:expected[path]=sealed_raw[path]
|
||||
for row in old['historical-replay']['cases']:
|
||||
expected.update({str(NESTED / row['case'] / name): digest for name,digest in row['files'].items()})
|
||||
fresh(expected, sha)
|
||||
return dict(sorted(expected.items()))
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def rederived(input_key):
|
||||
"""Bounded cache: one replay, keyed by every raw input's real SHA-256.
|
||||
|
||||
Rechecking hashes before lookup prevents a stale cache from authorizing
|
||||
changed observations. No subprocess, client or compositor is executed.
|
||||
"""
|
||||
from replay import replay_native, replay_nested
|
||||
with tempfile.TemporaryDirectory(prefix='mosaic-receipt-replay-') as tmp:
|
||||
root = Path(tmp)
|
||||
(root / 'results').mkdir()
|
||||
replay_native(root)
|
||||
replay_nested(root)
|
||||
values = {p.stem: json.loads(p.read_text()) for p in (root / 'results').glob('*.json')}
|
||||
# The positioner is a source prediction, separate from historical configure.
|
||||
values['positioner'] = dict(status='PASS source-backed prediction', flags=0,
|
||||
A=[100,80,350,170], B=[100,60,300,130], predicted_content_origin=[-318,25],
|
||||
predicted_A=[-218,105,350,170], predicted_B=[-118,165,300,130],
|
||||
runtime='NOT TESTED; actual configure/ACK/map required')
|
||||
return values
|
||||
|
||||
|
||||
@lru_cache(maxsize=16)
|
||||
def checked_historical(name, receipt_key, input_key):
|
||||
same(json.loads(receipt_key), rederived(input_key)[name], name)
|
||||
|
||||
|
||||
def validate_historical(name, data, hash_file, inputs=None):
|
||||
inputs = historical_inputs() if inputs is None else inputs
|
||||
# Exact typed comparisons include all scenario-specific observations, not
|
||||
# just lists/status. Standard/null/zero-color cases follow the real replay.
|
||||
checked_historical(name, encoded(data), tuple(inputs.items()))
|
||||
|
||||
|
||||
def validate_source_audit(data, hash_file):
|
||||
expected = sealed_receipts()['source-audit']
|
||||
same(data, expected, 'source-audit')
|
||||
for contract in data['contracts']:
|
||||
fresh({contract['source']: contract['sha256']}, hash_file)
|
||||
lines = Path(contract['source']).read_text().splitlines()
|
||||
for excerpt in contract['excerpts']:
|
||||
check(excerpt['token'] in lines[excerpt['line'] - 1], 'source excerpt token/line mismatch')
|
||||
check(excerpt['text'] in '\n'.join(lines), 'source excerpt absent')
|
||||
fresh({data['source_version_receipt']: data['source_version_sha256']}, hash_file)
|
||||
|
||||
|
||||
def validate_client(data, hash_file):
|
||||
expected = sealed_receipts()['client-provenance']
|
||||
same(data, expected, 'client-provenance')
|
||||
fresh(data['inputs'], hash_file, expected['inputs'])
|
||||
fresh({str(HERE / 'placement.patch'): data['patch']}, hash_file)
|
||||
builds = {b['client']: b for b in data['builds']}
|
||||
for command in data['commands']:
|
||||
check(command['exit'] == 0, 'historical C17 command failed')
|
||||
label, argv = command['label'], command['argv']
|
||||
if label.endswith('-compile') and label[:-8] in builds:
|
||||
build = builds[label[:-8]]
|
||||
source = next(v for v in argv if v.endswith('/' + label[:-8] + '.c'))
|
||||
output = argv[argv.index('-o') + 1]
|
||||
fresh({source: build['source'], output: build['binary']}, hash_file)
|
||||
fresh({str(Path(source).parent / n): v for n, v in data['protocols'].items()}, hash_file)
|
||||
|
||||
|
||||
def validate_tests(data, hash_file):
|
||||
check(set(data)=={'status','source_inventory','tests'}, 'missing test receipt fields')
|
||||
files = {str(p) for p in HERE.iterdir() if p.suffix in ('.py', '.patch', '.json')}
|
||||
fresh(data['source_inventory'], hash_file, files)
|
||||
tests = data['tests']
|
||||
check(isinstance(tests, list) and bool(tests), 'missing executed tests')
|
||||
ids = set()
|
||||
# WHY: M0 must consume a genuinely completed negative suite. Excluding the
|
||||
# two positive controls avoids a circular requirement for their own PASS.
|
||||
import tests_offline
|
||||
mandatory = {'Case.' + n for n in dir(tests_offline.Case)
|
||||
if n.startswith('test_') and n not in (
|
||||
'test_positive_aggregate_complete_bound','test_integrity_legitimate_omissions')}
|
||||
allowed={'Case.'+n for n in dir(tests_offline.Case) if n.startswith('test_')}
|
||||
for test in tests:
|
||||
check(isinstance(test, dict), 'malformed test receipt')
|
||||
check(test['status'] == 'PASS' and test['mode'] in ('positive', 'negative'), 'failed/unclassified test')
|
||||
check(isinstance(test['id'], str) and '.Case.test_' in test['id'], 'invalid test identity')
|
||||
check(test['id'] not in ids, 'duplicate test identity')
|
||||
ids.add(test['id'])
|
||||
check(test['id'].split('.Case.')[0] in ('__main__','tests_offline') and
|
||||
test['id'][test['id'].index('Case.'):] in allowed,'unknown executed test identity')
|
||||
for field in ('executed_lines', 'failed_lines', 'contracts'):
|
||||
check(isinstance(test[field], list), 'missing test trace: ' + field)
|
||||
check(bool(test['executed_lines']) and all(isinstance(line,str) and bool(line)
|
||||
for line in test['executed_lines']), 'empty executed test trace')
|
||||
for c in test['contracts']:
|
||||
check(isinstance(c['contract'], str) and bool(c['contract']) and type(c['pass']) is bool,
|
||||
'invalid executed contract')
|
||||
check(mandatory <= {n[n.index('Case.'):] for n in ids}, 'incomplete mandatory negative suite')
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def checked_register(key):
|
||||
"""Use the original qualified AST checker, writing only to a temp LAB."""
|
||||
import assertions
|
||||
evidence = json.loads(key)
|
||||
with tempfile.TemporaryDirectory(prefix='mosaic-receipt-register-') as tmp:
|
||||
lab = Path(tmp)
|
||||
(lab / 'results').mkdir()
|
||||
for name, data in evidence.items():
|
||||
(lab / 'results' / (name + '.json')).write_text(json.dumps(data))
|
||||
# WHY: checking existing AST keys alone allowed null or misleading
|
||||
# derived classification/coverage fields. Regenerate every record
|
||||
# through the same classifier and executed-receipt logic as the writer
|
||||
# workflow, then compare the full caller-provided register and core.
|
||||
coverage=assertions.build(lab)
|
||||
generated=json.loads((lab/'results/assertion-register.json').read_text())
|
||||
same(evidence['assertion-register'],generated,'assertion-register effective content')
|
||||
same(evidence['offline-core-coverage'],json.loads((lab/'results/offline-core-coverage.json').read_text()),'offline-core-coverage effective content')
|
||||
return coverage
|
||||
|
||||
|
||||
def validate_register(name, evidence, hash_file):
|
||||
import assertions
|
||||
register = evidence['assertion-register']
|
||||
check(set(register)=={'status','source_inventory','artifact_inventory','records','counts','historical_asserts'},
|
||||
'missing register receipt fields')
|
||||
same(register['historical_asserts'],145,'historical assertion count')
|
||||
same(register['status'],'CLASSIFIED; execution status is per-entry','register classification scope')
|
||||
paths = [assertions.HISTORY / n for n in assertions.HISTORICAL_FILES] + [
|
||||
p for p in sorted(HERE.glob('*.py')) if p.name != 'tests_offline.py']
|
||||
required = {str(p.relative_to(assertions.REPO)) for p in paths}
|
||||
check(set(register['source_inventory']) == required, 'incomplete AST source inventory')
|
||||
fresh({str(assertions.REPO / p): v for p,v in register['source_inventory'].items()}, hash_file)
|
||||
artifacts = {str(p) for p in HERE.iterdir() if p.suffix in ('.patch', '.json')}
|
||||
fresh(register['artifact_inventory'], hash_file, artifacts)
|
||||
selected = {n: evidence[n] for n in ('assertion-register', 'test-receipts', 'offline-core-coverage')}
|
||||
coverage = checked_register(encoded(selected))
|
||||
records = register['records']
|
||||
counts = {kind: sum(r['kind'] == kind for r in records) for kind in sorted({r['kind'] for r in records})}
|
||||
same(register['counts'], counts, 'AST counts')
|
||||
same(evidence['assertion-coverage'], coverage, 'assertion-coverage')
|
||||
core = {'model.py', 'ledger.py', 'authorization.py', 'observations.py', 'pixels.py'}
|
||||
unproved = [r['id'] for r in records if Path(r['source']).name in core and
|
||||
r['kind'] == 'checked invariant' and not
|
||||
(r['positive_executed_test_ids'] and r['negative_executed_test_ids'])]
|
||||
same(evidence['offline-core-coverage'], dict(status='PASS' if not unproved else 'FAIL NOT PROVEN', unproved=unproved), 'offline-core-coverage')
|
||||
check(not unproved and coverage['unresolved_pure_invariants'] == [], 'necessary pure coverage unproved')
|
||||
|
||||
|
||||
def make_bindings(evidence, evidence_files=None):
|
||||
"""Canonical content digest supports M0 in memory and binds real receipts.
|
||||
|
||||
WHY: raw file hashes alone cannot bind a caller's mutated parsed object.
|
||||
File hashes remain separate; formatting changes after review also expire it.
|
||||
"""
|
||||
from write_results import REQUIRED
|
||||
result = dict(source_delta={p.name: sha(p) for p in HERE.iterdir() if p.is_file()},
|
||||
evidence_content={n: hashlib.sha256(encoded(evidence[n]).encode()).hexdigest() for n in REQUIRED})
|
||||
if evidence_files is not None:
|
||||
result['evidence_files'] = {n: str(p) for n,p in evidence_files.items()}
|
||||
result['evidence_sha256'] = {n: sha(p) for n,p in evidence_files.items()}
|
||||
else:
|
||||
# Memory-only tests bind canonical bytes, not imaginary evidence files.
|
||||
result['evidence_sha256'] = dict(result['evidence_content'])
|
||||
return result
|
||||
|
||||
|
||||
def validate_review(evidence, bindings, hash_file):
|
||||
from write_results import REQUIRED
|
||||
check(isinstance(bindings, dict), 'missing final bindings')
|
||||
current = make_bindings(evidence)
|
||||
same(bindings['source_delta'], current['source_delta'], 'review final sources')
|
||||
fresh({str(HERE / n): v for n,v in bindings['source_delta'].items()}, hash_file)
|
||||
same(bindings['evidence_content'], current['evidence_content'], 'review final receipt content')
|
||||
check(set(bindings['evidence_sha256']) == set(REQUIRED), 'missing evidence bindings')
|
||||
if 'evidence_files' in bindings:
|
||||
check(set(bindings['evidence_files']) == set(REQUIRED), 'missing evidence paths')
|
||||
for name in REQUIRED:
|
||||
path = bindings['evidence_files'][name]
|
||||
fresh({path: bindings['evidence_sha256'][name]}, hash_file)
|
||||
same(json.loads(Path(path).read_text()), evidence[name], 'loaded proof ' + name)
|
||||
else:
|
||||
same(bindings['evidence_sha256'], current['evidence_content'], 'memory evidence hashes')
|
||||
review = evidence['independent-review']
|
||||
check(review['status'] == 'ACCEPTED' and review['independent'] is True, 'review not independently ACCEPTED')
|
||||
for key, value in bindings.items():
|
||||
same(review[key], value, 'review not bound to final source/evidence hashes: ' + key)
|
||||
if 'evidence_files' not in bindings:
|
||||
# CONTRACT: only the in-memory positive control may use synthetic
|
||||
# acceptance. The writer always supplies evidence_files and cannot
|
||||
# turn this test receipt into independent publication authority.
|
||||
check(review['scope']=='SYNTHETIC_IN_MEMORY_ONLY','unqualified memory review')
|
||||
return
|
||||
check(review['scope']=='FINAL_OFFLINE_RECEIPT_INTEGRITY','synthetic/incorrect persisted review scope')
|
||||
check(review['reviewer_role'] in ('final-reviewer','reviewer') and
|
||||
isinstance(review['reviewer_agent'],str) and bool(review['reviewer_agent']) and
|
||||
review['read_only'] is True,'missing independent reviewer provenance')
|
||||
fresh({review['report_file']:review['report_sha256']},hash_file)
|
||||
report=Path(review['report_file']).read_text()
|
||||
check('RECEIPT_INTEGRITY_REVIEW=ACCEPTED' in report,'report does not accept final version')
|
||||
commands=review['commands']
|
||||
check(isinstance(commands,list) and bool(commands),'missing executed review commands')
|
||||
for command in commands:
|
||||
check(isinstance(command['argv'],list) and bool(command['argv']) and
|
||||
all(isinstance(a,str) and bool(a) for a in command['argv']) and
|
||||
type(command['exit_code']) is int and command['exit_code']==0,
|
||||
'review command absent/failed')
|
||||
mutations=review['mutations']
|
||||
check(isinstance(mutations,dict) and REVIEW_ATTACKS<=set(mutations),'incomplete independent mutation set')
|
||||
for name in REVIEW_ATTACKS:
|
||||
result=mutations[name]
|
||||
check(result['status']=='INCONCLUSIVE' and isinstance(result['blockers'],list) and
|
||||
bool(result['blockers']) and all(isinstance(b,str) and bool(b) for b in result['blockers']),
|
||||
'independent attack not rejected: '+name)
|
||||
check(isinstance(review['findings'],list) and
|
||||
all(isinstance(f,dict) and f.get('severity') in ('NON_BLOCKING','FUTURE_SCOPE') for f in review['findings']),
|
||||
'material independent finding unresolved')
|
||||
check(isinstance(review['limitations'],list) and bool(review['limitations']) and
|
||||
all(isinstance(s,str) and bool(s) for s in review['limitations']), 'review scope absent')
|
||||
|
|
@ -20,6 +20,9 @@ from support import save
|
|||
|
||||
HERE=Path(__file__).resolve().parent
|
||||
RECEIPTS=[]
|
||||
FIXTURE_SNAPSHOT=None
|
||||
BASELINE_CHECKED=False
|
||||
BOOTSTRAP=False
|
||||
ACTIVE=None
|
||||
TRACKED={str(p.resolve()) for p in HERE.glob('*.py')}
|
||||
LINES={}
|
||||
|
|
@ -331,8 +334,8 @@ class Case(unittest.TestCase):
|
|||
auth['registered_lab']='wrong';f.write_text(json.dumps(auth));self.reject('registered-fresh-lab-required',lambda:authorize(root,f))
|
||||
def test_negative_offline_lab_authorization(self):
|
||||
with tempfile.TemporaryDirectory(prefix='geometry-auth-test-') as tmp:
|
||||
root=Path(tmp);f=root/'auth.json';f.write_text(json.dumps(dict(scope='one-new-static-nested-headless-run',explicit_user_authorization=True,ticket='synthetic-future-unit-test',registered_lab=str(LAB.resolve()))))
|
||||
self.reject('historical-or-offline-lab-forbidden',lambda:authorize(LAB,f))
|
||||
root=Path(tmp);f=root/'auth.json';f.write_text(json.dumps(dict(scope='one-new-static-nested-headless-run',explicit_user_authorization=True,ticket='synthetic-future-unit-test',registered_lab=str(HISTORICAL.resolve()))))
|
||||
self.reject('historical-or-offline-lab-forbidden',lambda:authorize(HISTORICAL,f))
|
||||
def test_negative_ledger_sequences(self):
|
||||
with tempfile.TemporaryDirectory(prefix='geometry-ledger-test-') as tmp:
|
||||
p=Path(tmp)/'budget.json';initial_for_offline_test(p);reserve(p,'click');state=json.loads(p.read_text());state['events'][0]['seq']=5
|
||||
|
|
@ -455,40 +458,41 @@ class Case(unittest.TestCase):
|
|||
data,recorded=self.exchange(invocation=True);self.assertIsNone(data['ipc_exit'])
|
||||
self.assertIn('ipc_error',data);self.assertFalse(data['scientific_cleanup_pass']);self.assertEqual(recorded,[])
|
||||
|
||||
def test_receipt_fail_closed_empty(self):
|
||||
from write_results import aggregate
|
||||
result=aggregate({},lambda path:None,{})
|
||||
self.assertEqual(result['status'],'INCONCLUSIVE')
|
||||
self.assertTrue(result['blockers'])
|
||||
|
||||
def test_receipt_fail_closed_status_only(self):
|
||||
from write_results import aggregate,REQUIRED
|
||||
result=aggregate({n:{'status':'PASS'} for n in REQUIRED},lambda path:None,{})
|
||||
self.assertEqual(result['status'],'INCONCLUSIVE')
|
||||
self.assertEqual(set(result['markers'].values()),{'INCONCLUSIVE'})
|
||||
|
||||
def aggregate_fixture(self):
|
||||
from write_results import REQUIRED,aggregate
|
||||
from support import sha
|
||||
evidence={n:json.loads((LAB/'results'/(n+'.json')).read_text()) for n in REQUIRED}
|
||||
# CONTRACT: all acceptance here is a synthetic complete snapshot in memory.
|
||||
# The real receipts are written only after the entire suite finishes.
|
||||
evidence['test-receipts']['status']='PASS'
|
||||
for receipt in evidence['test-receipts']['tests']:receipt['status']='PASS'
|
||||
# CONTRACT: this is synthetic independent acceptance in memory only.
|
||||
bindings={'source_delta':{'fixture':'synthetic-final-hash'},'evidence_sha256':{'proof':'synthetic-proof-hash'}}
|
||||
evidence['independent-review']=dict(status='ACCEPTED',independent=True,**bindings)
|
||||
# INVARIANT: immutable synthetic hash provider avoids bootstrapping current
|
||||
# test receipts from the suite that is still producing those receipts.
|
||||
# WHY: source inventories in this synthetic snapshot must describe the
|
||||
# same bytes even while the real on-disk register awaits regeneration.
|
||||
evidence['test-receipts']['source_inventory']={n:sha(n) for n in evidence['test-receipts']['source_inventory']}
|
||||
evidence['assertion-register']['source_inventory']={n:sha(HERE.parents[2]/n) for n in evidence['assertion-register']['source_inventory']}
|
||||
hashes={}
|
||||
for name in ('historical-evidence','client-provenance','test-receipts'):
|
||||
hashes.update(evidence[name].get('inputs',{}));hashes.update(evidence[name].get('source_inventory',{}))
|
||||
reg=evidence['assertion-register'];hashes.update({str(HERE.parents[2]/n):v for n,v in reg['source_inventory'].items()});hashes.update(reg['artifact_inventory'])
|
||||
audit=evidence['source-audit'];hashes.update({c['source']:c['sha256'] for c in audit['contracts']})
|
||||
hashes[audit['source_version_receipt']]=audit['source_version_sha256']
|
||||
for case in evidence['historical-replay']['cases']:
|
||||
hashes.update({str(NESTED/case['case']/n):v for n,v in case['files'].items()})
|
||||
client=evidence['client-provenance'];hashes[str(HERE/'placement.patch')]=client['patch']
|
||||
builds={v['client']:v for v in client['builds']}
|
||||
for command in client['commands']:
|
||||
label=command['label'];argv=command['argv']
|
||||
if label.endswith('-compile') and label[:-8] in builds:
|
||||
build=builds[label[:-8]];source=next(v for v in argv if v.endswith('/'+label[:-8]+'.c'))
|
||||
hashes[source]=build['source'];hashes[argv[argv.index('-o')+1]]=build['binary']
|
||||
hashes.update({str(Path(source).parent/n):v for n,v in client['protocols'].items()})
|
||||
return aggregate,evidence,lambda path:hashes.get(str(path)),bindings
|
||||
from receipt_integrity import make_bindings
|
||||
# WHY: bootstrap with genuine current preflight receipts, collected
|
||||
# before aggregation tests, not forced statuses or obsolete hashes.
|
||||
root=LAB/'preflight'/'results'
|
||||
global FIXTURE_SNAPSHOT
|
||||
import pickle,copy
|
||||
if FIXTURE_SNAPSHOT is None:
|
||||
evidence={n:json.loads((root/(n+'.json')).read_text()) for n in REQUIRED}
|
||||
FIXTURE_SNAPSHOT=(pickle.dumps(evidence),make_bindings(evidence))
|
||||
# Separate object graphs for every mutation. The serialization is an
|
||||
# in-memory copy of our own JSON, never untrusted external pickle input.
|
||||
evidence=pickle.loads(FIXTURE_SNAPSHOT[0])
|
||||
bindings=copy.deepcopy(FIXTURE_SNAPSHOT[1])
|
||||
# CONTRACT: synthetic acceptance exists in this independent memory
|
||||
# snapshot only. It is never persisted as the real review.
|
||||
evidence['independent-review']=dict(status='ACCEPTED',independent=True,scope='SYNTHETIC_IN_MEMORY_ONLY',**__import__('copy').deepcopy(bindings))
|
||||
def safe_hash(path):
|
||||
try:return sha(path)
|
||||
except (OSError,ValueError):return None
|
||||
return aggregate,evidence,safe_hash,bindings
|
||||
|
||||
def test_positive_aggregate_complete_bound(self):
|
||||
fn,e,h,b=self.aggregate_fixture();result=fn(e,h,b)
|
||||
|
|
@ -576,24 +580,237 @@ for gate in REQUIRED:
|
|||
current=copy.deepcopy(original);current['evidence_sha256'][gate]='changed-proof'
|
||||
result=fn(e,h,current)
|
||||
self.assertEqual(result['status'],'INCONCLUSIVE')
|
||||
self.assertTrue(any('review not bound' in x for x in result['blockers']))
|
||||
self.assertTrue(any(x.startswith('independent-review:') for x in result['blockers']))
|
||||
setattr(Case,'test_negative_aggregate_'+gate.replace('-','_')+'_stale_review_binding',test)
|
||||
|
||||
|
||||
def integrity_negative(self, label, mutate, group, category):
|
||||
import copy
|
||||
from receipt_integrity import make_bindings
|
||||
fn,e,h,b=self.aggregate_fixture()
|
||||
global BASELINE_CHECKED
|
||||
if not BOOTSTRAP and not BASELINE_CHECKED:
|
||||
self.assertEqual(fn(e,h,b)['status'],'READY_FOR_NEW_RUNTIME','mutation baseline must be complete')
|
||||
BASELINE_CHECKED=True
|
||||
mutate(e)
|
||||
# Rebind the synthetic memory-only review to the mutation so the semantic
|
||||
# checker itself must reject it; stale-review rejection alone is inadequate.
|
||||
if group!='independent-review':
|
||||
import hashlib
|
||||
from receipt_integrity import encoded
|
||||
b=copy.deepcopy(b)
|
||||
b['evidence_content'][group]=hashlib.sha256(encoded(e[group]).encode()).hexdigest()
|
||||
b['evidence_sha256'][group]=b['evidence_content'][group]
|
||||
e['independent-review']=dict(status='ACCEPTED',independent=True,scope='SYNTHETIC_IN_MEMORY_ONLY',**copy.deepcopy(b))
|
||||
r=fn(e,h,b)
|
||||
self.assertEqual(r['status'],'INCONCLUSIVE',label)
|
||||
self.assertTrue(any(x.startswith(group+':') for x in r['blockers']),(label,r['blockers']))
|
||||
for marker,dependencies in r['marker_scope'].items():
|
||||
if group in dependencies:self.assertEqual(r['markers'][marker],'INCONCLUSIVE',label)
|
||||
MUTATIONS.append(dict(label=label,category=category,gate=group,status=r['status'],blockers=r['blockers'],markers=r['markers']))
|
||||
|
||||
|
||||
MUTATIONS=[]
|
||||
def original_R02(self, name):
|
||||
def mutate(e):
|
||||
if name=='A':e['historical-replay']['cases'][0]['input_correlation']={'status':'PASS'}
|
||||
elif name=='B':
|
||||
for k in ('content','PNG_bbox','count','visible_intersection'):e['rendered'][k]=None
|
||||
else:e['popup-root']['cases']=[{} for _ in range(9)]
|
||||
integrity_negative(self,'R02-'+name,mutate,{'A':'historical-replay','B':'rendered','C':'popup-root'}[name],'original')
|
||||
|
||||
for letter in 'ABC':
|
||||
def test(self,letter=letter):original_R02(self,letter)
|
||||
setattr(Case,'test_integrity_R02_'+letter,test)
|
||||
|
||||
|
||||
def essential_paths(evidence):
|
||||
"""Required fields, including scenario-specific nested original facts.
|
||||
|
||||
All root/nested observations are inspected in all nine cases. Empty
|
||||
failed_lines/contracts and scenario nulls are legitimate and not mutated
|
||||
into the same value; deleting their schema key still must be rejected.
|
||||
"""
|
||||
for gate in REQUIRED:
|
||||
for key in evidence[gate]:yield gate,[key]
|
||||
for gate in ('historical-replay','popup-root','popup-nested'):
|
||||
for index,row in enumerate(evidence[gate]['cases']):
|
||||
def walk(value,path):
|
||||
if isinstance(value,dict):
|
||||
for k,v in value.items():
|
||||
yield path+[k]
|
||||
# File inventories are complete mappings, not samples.
|
||||
yield from walk(v,path+[k])
|
||||
elif isinstance(value,list) and value and isinstance(value[0],dict):
|
||||
for i,v in enumerate(value):yield from walk(v,path+[i])
|
||||
for path in walk(row,['cases',index]):yield gate,path
|
||||
|
||||
|
||||
def access(e,gate,path):
|
||||
node=e[gate]
|
||||
for part in path[:-1]:node=node[part]
|
||||
return node,path[-1]
|
||||
|
||||
|
||||
def test_deletions(self):
|
||||
# WHY: bulk mutation receipts prove returned verdicts, not line coverage.
|
||||
# Individual R02/positive tests keep tracing; suppressing tracing here
|
||||
# avoids charging repeated read/hash loops as scientific branch proof.
|
||||
sys.settrace(None)
|
||||
_,e,_,_=self.aggregate_fixture()
|
||||
for gate,path in essential_paths(e):
|
||||
def mutate(d,gate=gate,path=path):
|
||||
parent,key=access(d,gate,path);del parent[key]
|
||||
integrity_negative(self,gate+'/'+str(path),mutate,gate,'deletion')
|
||||
|
||||
|
||||
def test_nullifications(self):
|
||||
sys.settrace(None)
|
||||
_,e,_,_=self.aggregate_fixture()
|
||||
for gate,path in essential_paths(e):
|
||||
parent,key=access(e,gate,path);original=parent[key]
|
||||
for value in (None,{},[], ''):
|
||||
if type(value) is type(original) and value==original:continue
|
||||
def mutate(d,gate=gate,path=path,value=value):
|
||||
parent,key=access(d,gate,path);parent[key]=value
|
||||
integrity_negative(self,gate+'/'+str(path)+'='+repr(value),mutate,gate,'nullification')
|
||||
|
||||
|
||||
def test_contradictions(self):
|
||||
sys.settrace(None)
|
||||
attacks=[('rendered',['content',3],320),('rendered',['content',1],0),
|
||||
('rendered',['PNG_bbox',0],483),('rendered',['count'],182215),
|
||||
('rendered',['count'],True),('applied',['scroll'],161.0),
|
||||
('applied',['globalclip',0],0),('applied',['titlebar'],0),
|
||||
('native-shm',['stride'],1280),('native-shm',['buffer'],True),
|
||||
('xdg-configure',['assigned_ACK'],20),('positioner',['flags'],1)]
|
||||
attacks += [('assertion-register',['records',0,'test_status'],None),
|
||||
('assertion-register',['records',0,'domain'],'invented classification'),
|
||||
('assertion-register',['historical_asserts'],True),
|
||||
('test-receipts',['tests',0,'executed_lines'],[]),
|
||||
('test-receipts',['tests',0,'id'],'__main__.Case.test_fabricated')]
|
||||
for index in range(9):
|
||||
for field,value in [('owner',999),('workspace',999),('origin',[0,0]),('A',[0,0,300,170]),('B',[0,0,300,130]),('case','unknown')]:
|
||||
attacks.append(('historical-replay',['cases',index,field],value))
|
||||
attacks += [('historical-replay',['cases',index,'protocol','grabs',1,'parent'],'TOPLEVEL'),
|
||||
('historical-replay',['cases',index,'protocol','grabs',1,'serial'],55),
|
||||
('historical-replay',['cases',index,'input_correlation','buttons',0,'target'],'POPUP_B'),
|
||||
('historical-replay',['cases',index,'input_correlation','buttons',0,'serial'],999),
|
||||
('historical-replay',['cases',index,'input_correlation','buttons',1,'state'],1),
|
||||
('historical-replay',['cases',index,'input_correlation','callbacks',-1,'local'],[99999.0,1.0]),
|
||||
('historical-replay',['cases',index,'input_correlation','actions',0,'motion_msec'],99999),
|
||||
('popup-root',['cases',index,'origin'],[0,0]),
|
||||
('popup-root',['cases',index,'clip'],[0,0,1,1]),
|
||||
('popup-nested',['cases',index,'B'],[0,0,300,130]),
|
||||
('popup-nested',['cases',index,'protocol','grabs',1,'ack'],999)]
|
||||
for gate,path,value in attacks:
|
||||
def mutate(d,gate=gate,path=path,value=value):
|
||||
parent,key=access(d,gate,path);parent[key]=value
|
||||
integrity_negative(self,gate+'/'+str(path),mutate,gate,'contradiction')
|
||||
for gate in ('historical-replay','popup-root','popup-nested'):
|
||||
integrity_negative(self,gate+' duplicated identity',lambda d,gate=gate:d[gate]['cases'].__setitem__(1,__import__('copy').deepcopy(d[gate]['cases'][0])),gate,'contradiction')
|
||||
|
||||
|
||||
def test_freshness(self):
|
||||
import copy
|
||||
fn,e,h,b=self.aggregate_fixture()
|
||||
from receipt_integrity import make_bindings
|
||||
from support import sha
|
||||
# A correct source hash replaced by the hash of its own mutated file must
|
||||
# still lose the previously signed acceptance.
|
||||
for key in ('source_delta','evidence_sha256','evidence_content'):
|
||||
current=copy.deepcopy(b);first=next(iter(current[key]));current[key][first]='0'*64
|
||||
r=fn(e,h,current);self.assertEqual(r['status'],'INCONCLUSIVE');self.assertTrue(r['blockers'])
|
||||
MUTATIONS.append(dict(label='stale '+key,category='freshness',status=r['status'],blockers=r['blockers']))
|
||||
for gate in REQUIRED:
|
||||
d=copy.deepcopy(e);d[gate]={};current=make_bindings(d)
|
||||
# Old acceptance, even with fresh current bindings, is not reusable.
|
||||
r=fn(d,h,current);self.assertEqual(r['status'],'INCONCLUSIVE')
|
||||
self.assertTrue(any(x.startswith('independent-review:') for x in r['blockers']))
|
||||
for key in ('status','independent','scope','source_delta','evidence_sha256','evidence_content'):
|
||||
for value in (None,{},[], ''):
|
||||
integrity_negative(self,'review '+key+'='+repr(value),lambda d,key=key,value=value:d['independent-review'].__setitem__(key,value),'independent-review','freshness')
|
||||
for file in (str(HERE/'placement.patch'),str(HERE/'receipt_integrity.py'),next(iter(e['historical-evidence']['inputs']))):
|
||||
r=fn(e,lambda p,file=file:None if str(p)==file else h(p),b)
|
||||
self.assertEqual(r['status'],'INCONCLUSIVE');self.assertTrue(r['blockers'])
|
||||
MUTATIONS.append(dict(label='missing '+file,category='freshness',status=r['status'],blockers=r['blockers']))
|
||||
|
||||
|
||||
def test_omissions(self):
|
||||
fn,e,h,b=self.aggregate_fixture()
|
||||
self.assertIsNone(e['popup-root']['cases'][4]['clip'])
|
||||
self.assertIsNone(e['popup-nested']['cases'][0]['standard'])
|
||||
self.assertIsNone(e['popup-nested']['cases'][2]['dismissal'])
|
||||
self.assertIsNone(e['historical-replay']['cases'][0]['colors']['right']['POPUP_B']['bbox'])
|
||||
self.assertEqual(e['historical-replay']['cases'][0]['colors']['right']['POPUP_B']['count'],0)
|
||||
self.assertEqual(fn(e,h,b)['status'],'READY_FOR_NEW_RUNTIME')
|
||||
|
||||
|
||||
def test_writer(self):
|
||||
import contextlib,io,copy
|
||||
from write_results import write,aggregate
|
||||
from receipt_integrity import make_bindings
|
||||
fn,e,h,b=self.aggregate_fixture()
|
||||
# CONTRACT: no synthetic acceptance is persisted, even in the writer test.
|
||||
e['independent-review']={'status':'NOT RUN','independent':False}
|
||||
with tempfile.TemporaryDirectory(prefix='mosaic-real-writer-') as tmp:
|
||||
root=Path(tmp);(root/'results').mkdir()
|
||||
for name,data in e.items():save(root,name,data)
|
||||
current=make_bindings(e,{n:root/'results'/(n+'.json') for n in REQUIRED})
|
||||
expected=aggregate(e,h,current)
|
||||
with contextlib.redirect_stdout(io.StringIO()):observed=write(root)
|
||||
self.assertEqual(observed['status'],expected['status']);self.assertEqual(observed['markers'],expected['markers'])
|
||||
e['rendered']['count']=None;save(root,'rendered',e['rendered'])
|
||||
with contextlib.redirect_stdout(io.StringIO()):observed=write(root)
|
||||
self.assertEqual(observed['status'],'INCONCLUSIVE')
|
||||
self.assertEqual(observed['markers']['STATIC_NESTED_SHM_RENDER_GEOMETRY_REPLAY'],'INCONCLUSIVE')
|
||||
self.assertTrue(any(x.startswith('rendered:') for x in observed['blockers']))
|
||||
# CONTRACT B-01: decoder exhaustion must invalidate persisted READY,
|
||||
# not merely raise before publication. The fake prior marker is an
|
||||
# adversarial receipt in this test-owned temp LAB, not signed review.
|
||||
prior={'status':'READY_FOR_NEW_RUNTIME','marker':'SWAYFX_MOSAIC_STATIC_NESTED_GEOMETRY_OFFLINE_GATE=READY_FOR_NEW_RUNTIME'}
|
||||
save(root,'runner-readiness',prior);save(root,'offline-gate',prior)
|
||||
(root/'results/rendered.json').write_text('['*100000+'0'+']'*100000)
|
||||
with contextlib.redirect_stdout(io.StringIO()):observed=write(root)
|
||||
self.assertEqual(observed['status'],'INCONCLUSIVE')
|
||||
self.assertTrue(any(x.startswith('rendered:') for x in observed['blockers']))
|
||||
for name in ('runner-readiness','offline-gate'):
|
||||
persisted=json.loads((root/'results'/(name+'.json')).read_text())
|
||||
self.assertEqual(persisted['status'],'INCONCLUSIVE')
|
||||
self.assertEqual(persisted['markers']['STATIC_NESTED_SHM_RENDER_GEOMETRY_REPLAY'],'INCONCLUSIVE')
|
||||
save(LAB,'writer-entrypoint-test',dict(status='PASS',aggregate_source=str(Path(aggregate.__code__.co_filename)),mock=False,synthetic_review_persisted=False,invalid=observed['blockers']))
|
||||
|
||||
|
||||
Case.test_integrity_deletions=test_deletions
|
||||
Case.test_integrity_nullifications=test_nullifications
|
||||
Case.test_integrity_contradictions=test_contradictions
|
||||
Case.test_integrity_freshness=test_freshness
|
||||
Case.test_integrity_legitimate_omissions=test_omissions
|
||||
Case.test_integrity_writer=test_writer
|
||||
|
||||
|
||||
class Result(unittest.TextTestResult):
|
||||
def addSuccess(self,test):
|
||||
super().addSuccess(test);RECEIPTS.append(dict(id=test.id(),status='PASS',mode='negative' if '.test_negative_' in test.id() else 'positive',executed_lines=sorted(LINES.get(test.id(),set())),failed_lines=sorted(FAILED.get(test.id(),set())),contracts=[{'contract':c,'pass':v} for c,v in sorted(CONTRACTS.get(test.id(),set()))]))
|
||||
super().addSuccess(test);RECEIPTS.append(dict(id=test.id(),status='PASS',mode='negative' if '.test_negative_' in test.id() else 'positive',executed_lines=sorted(LINES.get(test.id(),set())),failed_lines=sorted(FAILED.get(test.id(),set())),contracts=[{'contract':c,'pass':v} for c,v in sorted(CONTRACTS.get(test.id(),set()))]));sys.settrace(trace)
|
||||
def addFailure(self,test,err):
|
||||
super().addFailure(test,err);RECEIPTS.append(dict(id=test.id(),status='FAIL',error=str(err[1])))
|
||||
super().addFailure(test,err);RECEIPTS.append(dict(id=test.id(),status='FAIL',error=str(err[1])));sys.settrace(trace)
|
||||
def addError(self,test,err):
|
||||
super().addError(test,err);RECEIPTS.append(dict(id=test.id(),status='FAIL',error=str(err[1])))
|
||||
super().addError(test,err);RECEIPTS.append(dict(id=test.id(),status='FAIL',error=str(err[1])));sys.settrace(trace)
|
||||
|
||||
if __name__=='__main__':
|
||||
parser=argparse.ArgumentParser();parser.add_argument('lab',type=Path);args=parser.parse_args();LAB=args.lab
|
||||
parser=argparse.ArgumentParser();parser.add_argument('lab',type=Path);parser.add_argument('--preflight',action='store_true');parser.add_argument('--negative-preflight',action='store_true');args=parser.parse_args();LAB=args.lab
|
||||
sys.settrace(trace)
|
||||
result=unittest.TextTestRunner(verbosity=2,resultclass=Result).run(unittest.defaultTestLoader.loadTestsFromTestCase(Case))
|
||||
suite=unittest.defaultTestLoader.loadTestsFromTestCase(Case)
|
||||
if args.preflight:suite=unittest.TestSuite(t for t in suite if 'aggregate' not in t.id() and 'integrity' not in t.id())
|
||||
if args.negative_preflight:suite=unittest.TestSuite(t for t in suite if t._testMethodName not in ('test_positive_aggregate_complete_bound','test_integrity_legitimate_omissions'))
|
||||
BOOTSTRAP=args.negative_preflight
|
||||
result=unittest.TextTestRunner(verbosity=2,resultclass=Result).run(suite)
|
||||
sys.settrace(None)
|
||||
save(LAB,'test-receipts',dict(source_inventory={str(p):__import__('hashlib').sha256(p.read_bytes()).hexdigest() for p in HERE.iterdir() if p.suffix in ('.py','.patch','.json')},status='PASS' if result.wasSuccessful() else 'FAIL',tests=RECEIPTS))
|
||||
save(LAB,'positive',{'tests':[r for r in RECEIPTS if r.get('mode')=='positive']})
|
||||
save(LAB,'negative',{'tests':[r for r in RECEIPTS if r.get('mode')=='negative']})
|
||||
if not args.preflight:
|
||||
save(LAB,'aggregate-negative',{'status':'PASS' if result.wasSuccessful() else 'FAIL', 'mutations':MUTATIONS})
|
||||
for category in ('deletion','nullification','contradiction','freshness','original'):
|
||||
save(LAB,category+'-tests',{'status':'PASS' if result.wasSuccessful() else 'FAIL','mutations':[r for r in MUTATIONS if r['category']==category]})
|
||||
raise SystemExit(0 if result.wasSuccessful() else 1)
|
||||
|
|
|
|||
|
|
@ -20,71 +20,48 @@ def aggregate(evidence,hash_file,bindings):
|
|||
WHY: no author test or successful compile can substitute for another gate.
|
||||
Bindings describe the exact final evidence/source bytes reviewed independently.
|
||||
"""
|
||||
from receipt_integrity import (validate_historical, validate_source_audit,
|
||||
validate_client, validate_register, validate_tests, validate_review, historical_inputs, fresh)
|
||||
failures={}
|
||||
def need(name,ok,reason):
|
||||
if not ok:failures.setdefault(name,[]).append(reason)
|
||||
def fresh(mapping):
|
||||
return bool(mapping) and all(hash_file(path)==digest for path,digest in mapping.items())
|
||||
def guarded(name, validator):
|
||||
# CONTRACT: invalid/missing evidence degrades its gate, never crashes
|
||||
# the writer or becomes a compositor/SceneFX architectural failure.
|
||||
try:
|
||||
validator()
|
||||
except (OSError, ValueError, TypeError, KeyError, IndexError, AttributeError,
|
||||
AssertionError, RuntimeError, StopIteration) as error:
|
||||
need(name,False,str(error) or type(error).__name__)
|
||||
if not isinstance(evidence,dict):evidence={}
|
||||
for name in REQUIRED:
|
||||
d=evidence.get(name)
|
||||
need(name,isinstance(d,dict) and bool(d),'missing evidence')
|
||||
need(name,isinstance(d,dict) and bool(d),'missing/malformed evidence')
|
||||
if not isinstance(d,dict):continue
|
||||
status=d.get('status','')
|
||||
need(name,status=='PASS' or status.startswith('PASS ')
|
||||
or name=='assertion-register' and status=='CLASSIFIED; execution status is per-entry','gate not PASS')
|
||||
def record(name):return evidence.get(name) or {}
|
||||
for name in ('native-shm','xdg-configure','applied','rendered','positioner'):
|
||||
fields={'native-shm':('size','buffer','stride','format'), 'xdg-configure':('toplevel','initial_ACK','assigned_ACK'),
|
||||
'applied':('owner','workspace','scene','window','titlebar','globalclip'),
|
||||
'rendered':('content','PNG_bbox','count','visible_intersection'),
|
||||
'positioner':('flags','A','B')}[name]
|
||||
need(name,all(k in record(name) for k in fields),'incomplete geometry proof')
|
||||
need('historical-evidence',fresh(record('historical-evidence').get('inputs',{})),'stale/missing historical inputs')
|
||||
cases=record('historical-replay').get('cases',[])
|
||||
expected={'run-private_mosaic-crossing-b_cross','run-private_mosaic-crossing-both_cross',
|
||||
'run-private_mosaic-toggle-b_cross','run-private_mosaic-outside-visible',
|
||||
'run-control-crossing-b_cross','run-control-crossing-both_cross','run-control-outside-visible',
|
||||
'run-private_mosaic-close_b-visible','run-control-close_b-visible'}
|
||||
need('historical-replay',len(cases)==9 and {c.get('case') for c in cases}==expected,'required nine cases incomplete')
|
||||
for c in cases:
|
||||
need('historical-replay',c.get('status')=='PASS historical sampled replay' and c.get('input_correlation',{}).get('status')=='PASS','case/input proof incomplete')
|
||||
need('historical-replay',fresh({str(__import__('replay').NESTED/c.get('case','')/n):v for n,v in c.get('files',{}).items()}),'stale case files')
|
||||
for name in ('popup-root','popup-nested'):
|
||||
need(name,len(record(name).get('cases',[]))==9,'incomplete popup proof')
|
||||
audit=record('source-audit');contracts=audit.get('contracts',[])
|
||||
need('source-audit',len(contracts)==17 and all(c.get('claim') and c.get('excerpts') and hash_file(c.get('source',''))==c.get('sha256') for c in contracts),'incomplete/stale source contracts')
|
||||
need('source-audit',bool(audit.get('pins')) and hash_file(audit.get('source_version_receipt',''))==audit.get('source_version_sha256') and bool(audit.get('source_version_sha256')),'stale pinned receipt')
|
||||
client=record('client-provenance');commands=client.get('commands',[])
|
||||
need('client-provenance',fresh(client.get('inputs',{})),'stale client sources')
|
||||
need('client-provenance',all(client.get(k) for k in ('patch','adapted_nested','protocols','protocol_comparison','builds')),'incomplete provenance')
|
||||
needed={n+'-'+mode for n in ('nested-client','pointer-daemon','static-reference') for mode in ('syntax','compile')}
|
||||
need('client-provenance',needed<={c.get('label') for c in commands} and all(c.get('exit')==0 for c in commands),'C17 commands missing/failed')
|
||||
for command in commands:
|
||||
if command.get('label') in needed:need('client-provenance','-std=c17' in command.get('argv',[]) and '-Werror' in command.get('argv',[]),'C17 flags incomplete')
|
||||
need('client-provenance',hash_file(str(HERE/'placement.patch'))==client.get('patch'),'stale placement patch')
|
||||
builds={c.get('client'):c for c in client.get('builds',[])}
|
||||
need('client-provenance',set(builds)=={'nested-client','pointer-daemon','static-reference'},'missing client builds')
|
||||
for command in commands:
|
||||
label=command.get('label','');argv=command.get('argv',[])
|
||||
if label.endswith('-compile') and label[:-8] in builds:
|
||||
build=builds[label[:-8]]
|
||||
output=argv[argv.index('-o')+1] if '-o' in argv else ''
|
||||
source=next((v for v in argv if v.endswith('/'+label[:-8]+'.c')),'')
|
||||
need('client-provenance',bool(output) and hash_file(output)==build.get('binary') and bool(source) and hash_file(source)==build.get('source'),'stale built client/source')
|
||||
directory=Path(source).parent
|
||||
need('client-provenance',all(hash_file(str(directory/n))==v for n,v in client.get('protocols',{}).items()),'stale generated protocols')
|
||||
register=record('assertion-register');inventory=register.get('source_inventory',{})
|
||||
need('assertion-register',fresh({str(HERE.parents[2]/p):v for p,v in inventory.items()}) and fresh(register.get('artifact_inventory',{})),'stale inventory')
|
||||
need('assertion-register',register.get('historical_asserts')==145 and bool(register.get('records')),'incomplete register')
|
||||
coverage=record('assertion-coverage')
|
||||
need('assertion-coverage',coverage.get('status')=='PASS' and coverage.get('historical_asserts')==145 and coverage.get('entries')==len(register.get('records',[])) and coverage.get('unresolved_pure_invariants')==[],'coverage incomplete')
|
||||
need('offline-core-coverage',record('offline-core-coverage').get('unproved')==[],'core unproved')
|
||||
tests=record('test-receipts');receipts=tests.get('tests',[])
|
||||
need('test-receipts',fresh(tests.get('source_inventory',{})),'stale test sources')
|
||||
need('test-receipts',bool(receipts) and all(t.get('status')=='PASS' for t in receipts) and len({t.get('id') for t in receipts})==len(receipts),'missing/failed test receipts')
|
||||
review=record('independent-review')
|
||||
need('independent-review',review.get('status')=='ACCEPTED' and review.get('independent') is True,'review not independently ACCEPTED')
|
||||
need('independent-review',bool(bindings.get('source_delta')) and bool(bindings.get('evidence_sha256')) and all(review.get(k)==v for k,v in bindings.items()),'review not bound to final source/evidence hashes')
|
||||
status=d.get('status')
|
||||
need(name,isinstance(status,str) and (status=='PASS' or status.startswith('PASS ')
|
||||
or name=='assertion-register' and status=='CLASSIFIED; execution status is per-entry'),'gate not PASS')
|
||||
input_error=None
|
||||
try:
|
||||
inputs=historical_inputs()
|
||||
fresh(inputs,hash_file)
|
||||
except (OSError,ValueError,TypeError,KeyError,AssertionError) as error:
|
||||
inputs=None;input_error=str(error) or type(error).__name__
|
||||
for name in ('native-shm','xdg-configure','applied','rendered','positioner',
|
||||
'historical-evidence','historical-replay','popup-root','popup-nested'):
|
||||
if input_error:need(name,False,input_error)
|
||||
else:guarded(name,lambda name=name:validate_historical(name,evidence.get(name),hash_file,inputs))
|
||||
# CONTRACT: after a failed prerequisite, unchecked downstream gates are
|
||||
# INCONCLUSIVE too. This bounds work on invalid input without granting PASS.
|
||||
def downstream(name,validator):
|
||||
if failures:need(name,False,'not qualified after failed prerequisite')
|
||||
else:guarded(name,validator)
|
||||
downstream('source-audit',lambda:validate_source_audit(evidence.get('source-audit'),hash_file))
|
||||
downstream('client-provenance',lambda:validate_client(evidence.get('client-provenance'),hash_file))
|
||||
downstream('test-receipts',lambda:validate_tests(evidence.get('test-receipts'),hash_file))
|
||||
for name in ('assertion-register','assertion-coverage','offline-core-coverage'):
|
||||
downstream(name,lambda name=name:validate_register(name,evidence,hash_file))
|
||||
downstream('independent-review',lambda:validate_review(evidence,bindings,hash_file))
|
||||
groups={'STATIC_NESTED_SHM_RENDER_GEOMETRY_REPLAY':('native-shm','applied','rendered','historical-evidence'),
|
||||
'STATIC_NESTED_XDG_GEOMETRY_AUDIT':('xdg-configure','positioner','historical-replay','popup-root','popup-nested','source-audit','client-provenance'),
|
||||
'STATIC_NESTED_ASSERTION_COVERAGE':('assertion-register','assertion-coverage','offline-core-coverage'),
|
||||
|
|
@ -99,16 +76,25 @@ def write(lab):
|
|||
results=lab/'results'
|
||||
def read(name):
|
||||
path=results/(name+'.json')
|
||||
return json.loads(path.read_text()) if path.exists() else {}
|
||||
try:return json.loads(path.read_text()) if path.exists() else {}
|
||||
# WHY: a decoder-depth failure must not leave previous READY artifacts
|
||||
# authoritative. CONTRACT: malformed proof reaches the same aggregate
|
||||
# as missing proof, which publishes explicit INCONCLUSIVE markers.
|
||||
except (OSError,ValueError,RecursionError):return {}
|
||||
aliases={'native-shm-geometry':'native-shm','xdg-configure-geometry':'xdg-configure','applied-content-geometry':'applied','rendered-paint-geometry':'rendered','popup-positioner-audit':'positioner','historical-popup-replay':'historical-replay','root-clip-model':'popup-root','nested-clip-model':'popup-nested','positive-tests':'positive','negative-tests':'negative'}
|
||||
for name,source in aliases.items():save(lab,name,read(source))
|
||||
coverage=read('assertion-coverage');tests=read('test-receipts');core=read('offline-core-coverage')
|
||||
coverage=coverage if isinstance(coverage,dict) else {}
|
||||
tests=tests if isinstance(tests,dict) else {}
|
||||
reviewfile=results/'independent-review.json'
|
||||
review=read('independent-review') if reviewfile.exists() else {'status':'NOT RUN','independent':False}
|
||||
evidence={name:read(name) for name in REQUIRED}
|
||||
evidence['independent-review']=review
|
||||
source_delta={p.name:sha(p) for p in HERE.iterdir() if p.is_file()}
|
||||
bindings=dict(source_delta=source_delta,evidence_sha256={name:sha(results/(name+'.json')) for name in REQUIRED if (results/(name+'.json')).exists()})
|
||||
from receipt_integrity import make_bindings
|
||||
try:
|
||||
bindings=make_bindings(evidence,{name:results/(name+'.json') for name in REQUIRED})
|
||||
except (OSError,ValueError,TypeError,KeyError,RecursionError):
|
||||
bindings={} # Missing/malformed proof cannot carry accepted bindings.
|
||||
def safe_hash(path):
|
||||
try:return sha(path)
|
||||
except (OSError,ValueError):return None
|
||||
|
|
@ -117,7 +103,10 @@ def write(lab):
|
|||
save(lab,'popup-geometry-model',dict(status=markers['STATIC_NESTED_XDG_GEOMETRY_AUDIT'],scope='offline typed model and sampled historical replay; new runtime NOT TESTED',root=read('popup-root'),nested=read('popup-nested'),prediction=read('positioner'),source='source-audit.json',native_input='Opening click must lie in actual native surface bounds; destination scaling alone is insufficient'))
|
||||
readiness=dict(status=status,marker='SWAYFX_MOSAIC_STATIC_NESTED_GEOMETRY_OFFLINE_GATE='+status,markers=markers,marker_scope=gates['marker_scope'],review_bindings=bindings,blockers=blockers,runtime='NOT TESTED',architectural_conclusion='UNDECIDED',fixture_only=True,current_ticket_runtime_authorized=False,runtime_budget_initialized=False,independent_review=review)
|
||||
save(lab,'runner-readiness',readiness);save(lab,'offline-gate',readiness)
|
||||
save(lab,'summary',dict(status=status,markers=markers,tests=len(tests.get('tests',[])),coverage=coverage,core=core,historical_cases=len(read('historical-replay').get('cases',[])),runtime_runs=0,new_popups=0,new_grabs=0,new_captures=0,new_camera_operations=0,runtime_budget_initialized=False,production_changes=False,source_delta={p.name:sha(p) for p in HERE.iterdir() if p.is_file()},manifest='UNSEALED; parent review required',next='independent review of final fixture/register/evidence; separate future authorization required for runtime',limitations=['atomic transaction-generation/native-buffer-frame identity NOT PROVEN','new static popup crossing/grab/input/standard NOT TESTED','vertical/scaled/rotated/migration/full damage NOT TESTED','production cross-output viewport NOT YET SUPPORTED']))
|
||||
def count_rows(value,key):
|
||||
rows=value.get(key) if isinstance(value,dict) else None
|
||||
return len(rows) if isinstance(rows,list) else 0
|
||||
save(lab,'summary',dict(status=status,markers=markers,tests=count_rows(tests,'tests'),coverage=coverage,core=core,historical_cases=count_rows(read('historical-replay'),'cases'),runtime_runs=0,new_popups=0,new_grabs=0,new_captures=0,new_camera_operations=0,runtime_budget_initialized=False,production_changes=False,source_delta={p.name:sha(p) for p in HERE.iterdir() if p.is_file()},manifest='UNSEALED; parent review required',next='independent review of final fixture/register/evidence; separate future authorization required for runtime',limitations=['atomic transaction-generation/native-buffer-frame identity NOT PROVEN','new static popup crossing/grab/input/standard NOT TESTED','vertical/scaled/rotated/migration/full damage NOT TESTED','production cross-output viewport NOT YET SUPPORTED']))
|
||||
(lab/'independent-review-input.md').write_text('''# Independent review input — EXPERIMENTAL
|
||||
|
||||
Review this final fixture against the offline gate; review E1/E2, actual
|
||||
|
|
@ -134,6 +123,7 @@ ACCEPTED/CORRECTION_REQUIRED/NOT PROVEN findings. No author review PASS, runtime
|
|||
launch, budget initialization or manifest sealing is authorized here.
|
||||
''')
|
||||
print(json.dumps(readiness,indent=2))
|
||||
return readiness
|
||||
|
||||
if __name__=='__main__':
|
||||
parser=argparse.ArgumentParser();parser.add_argument('lab',type=Path);write(parser.parse_args().lab)
|
||||
|
|
|
|||
Loading…
Reference in a new issue