Skip to content

L04-03: compute isolated plan-bound previews with fidelity and residue contract (#35) - #213

Merged
mberrys merged 4 commits into
l04-02-save-impact-policyfrom
l04-03-isolated-preview
Oct 5, 2026
Merged

mberrys merged 4 commits into
l04-02-save-impact-policyfrom
l04-03-isolated-preview

Conversation

@mberrys

@mberrys mberrys commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

L04-03 (#35), slice 3 of the L04 Governed Operation Engine stack (refs #5). The Core preview becomes an explicitly isolated, nonpublishing computation: it is bound to one exact analyzed plan (fail-closed plan-digest check), it carries an explicit fidelity mode, it honors cancellation through the whole serialize/compare path, and it removes what it created when it cancels or fails.

Stack position

Slice 3 of 8. Base: l04-02-save-impact-policy (#212). Children stack on this branch; land bottom-up. (The whole stack was just re-based onto current dev; every slice's patch-id is unchanged, so the proofs below carry at the rebased heads.)

Fidelity vocabulary (P1)

PDFRepairPreviewFidelity { Exact, Simulated }, serialized as fidelity_mode on both previews and the diff report: technical preview = exact (structural comparison over the serialized + reopened candidate bytes), visual preview = simulated (rendered simulation, never proof of print safety). This is artifact-computation fidelity and is deliberately distinct from the L03 canvas-render vocabulary (exact/approximate/authoritative = render-path authority), documented in one sentence in docs/GOVERNED_EXECUTION.md.

Per-criterion: already satisfied vs built here

Acceptance criterion State Proof
Preview exposes intended and unexpected changes already satisfied (Core) existing Expected/Unexpected classification + unexpected_changed_pixel_count; unchanged
Preview does not publish already satisfied no path from the builders to publishGovernedArtifact; D2 test unchanged
Preview does not modify the source mechanics already satisfied; proven at preview level here previewLeavesSourceBytesUntouched (source re-hashed across technical + visual runs; candidate hash equals candidateSha256)
Candidate identity / exact plan binding built here planDigest was an opaque echoed input; now validatePreviewPlanDigest recomputes it from the transaction's plans + source bytes + merged policy and refuses missing/malformed/mismatched. previewRefusesPlanDigestMismatch (RED: pre-change it echoed the digest opaquely)
Fidelity mode built here fidelity_mode on both previews; slot asserts exact/simulated
Failure: cancel/failure leaves no artifact built here cancellation propagated into both builders and compareCandidate; buildSerializedCandidate checks cancel before and after the write and removes what this call created (candidate, rendered PNGs, a directory it created via mkpath). cancelledPreviewLeavesNoArtifacts (RED: pre-change left candidate + PNGs)
Failure: no approval residue already satisfied; pinned previewCrashLeavesNoPartialArtifactAndNoApproval (RED: no seam existed)

Required proof

  • python scripts/agent/check-change.py --base 5985b011 --head 99e08022 --head-branch l04-03-isolated-preview --build-dir <loop-build-l04> -> status: pass, 72/72 checks (LoopLibCore/PdfTool/loop-pdf-worker builds, mapped suites, clang-tidy, format, changelog, architecture contracts).
  • Provenance: the proof was recorded at the pre-rebase head 2787787b. The stack rebase left this slice's own diff unchanged (patch-id verified) and the only later edit is a documentation-only fragment correction, so the proof carries for the code; CI re-runs the mapped lanes on the head above.
  • Focused: UnitTestsRepairDiff / UnitTestsRepairOperation / UnitTestsGovernedExecution / UnitTestsPdfToolContract -> 4/4; UnitTestsActionList + UnitTestsRepairOperatorAcceptance -> 2/2.
  • Crash harness: probe exits 91 (in-window kill) / 91 / 93 (armed-but-never-fired) as expected; the suite asserts exit 91 exactly.
  • Rebase note: the stack was re-based onto dev after the L03 merge train landed; slice patch-ids are identical before and after, so the verdict carries. Remote heads: l04-01 3effd51, l04-02 2d1d5dc, l04-03 eed425d.
  • Pre-existing flake: UnitTestsPdfWorkerIsolation::supervisorFaults(cpu) (filed UnitTestsPdfWorkerIsolation supervisorFaults(cpu) is a razor-margin race against the 135s client timeout #211) can redden any mapped run; it did not fire on this proof.

Notes

  • Closes #35.
  • Crash-seam deviation, flagged honestly: the candidate-committed seam fires after the atomic write, so a hard kill there leaves a complete candidate rather than no file. The crash slot therefore asserts no partial file, no staging temp, and no approval; the literal "no artifact" observable is proven by the cancel slot (cancelledPreviewLeavesNoArtifacts). The repo's own PageMaster kill harness uses the same shape.
  • Breaking-change: no.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…sidue contract (#35)

Technical and visual previews become explicit, plan-bound, nonpublishing
computations:

- P1 fidelity: add PDFRepairPreviewFidelity {Exact, Simulated} and serialize
  fidelity_mode on both preview JSONs and the diff report. Technical preview is
  exact (structural comparison over the serialized+reopened candidate bytes);
  visual preview is simulated (a rendered simulation, never print-safety proof).
  This is artifact-computation fidelity, distinct from PreviewStateModel
  canvas render authority.
- P2 residue: a cancelled or failed preview removes what that call created —
  its candidate file, its rendered PNGs, and a mkpath-created parent directory
  when now empty.
- P3 crash seam: add PDFRepairDiffOptions::previewStageHook (empty in
  production), invoked at "candidate-committed" (buildSerializedCandidate,
  after the write) and "visual-page" (render loop, after a page renders).
- P4 plan-digest binding: both builders refuse an empty/malformed planDigest
  and a mismatch against
  computeOperationPlanDigest(transaction.plans(), sourceSha256(), savePolicy()).
  Add PDFRepairTransaction::sourceSha256(); the PdfTool caller already computes
  the digest from the same three inputs.
- P5 cancellation: propagate the transaction's operationControl into both
  builders and into compareCandidate's options; add cancel checks in
  buildSerializedCandidate (before mkpath/write, after write/before reopen)
  with status Incomplete + reason "cancelled".

Tests (guard vs RED, labelled honestly):
- previewLeavesSourceBytesUntouched — source byte-immutability leg is a GUARD
  (passes pre-change); the fidelity_mode assertions are RED.
- cancelledPreviewLeavesNoArtifacts — RED (pre-change left the candidate + PNGs).
- previewRefusesPlanDigestMismatch — RED (pre-change echoed the digest opaquely).
- previewCrashLeavesNoPartialArtifactAndNoApproval — RED (no seam existed).
@mberrys
mberrys force-pushed the l04-03-isolated-preview branch from 8e829af to bb37286 Compare October 5, 2026 12:59
@mberrys
mberrys added this pull request to stack #220 October 5, 2026 21:52
@mberrys
mberrys merged commit bef8e06 into l04-02-save-impact-policy Oct 5, 2026
5 checks passed
@mberrys
mberrys deleted the l04-03-isolated-preview branch October 5, 2026 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant