Skip to content

fix(runtime): let a refreshed verification marker republish - #339

Merged
aviggiano merged 1 commit into
mainfrom
fix/marker-republication-refresh
Aug 7, 2026
Merged

aviggiano merged 1 commit into
mainfrom
fix/marker-republication-refresh

Conversation

@aviggiano

@aviggiano aviggiano commented Aug 7, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #280.

A runtime-refreshed marker byte-compared against the published copy and threw identically on every retry, stranding the attempt permanently. Now permits a difference confined to an entry's sha256 and only when it matches the file actually published. path, contract, contract_digest, primary, attempt_id, node_id, schema_version, and entry add/drop/reorder all still rejected. The source-proof path keeps its unconditional byte compare — that anti-tampering guarantee is deliberately not widened.

Greptile Summary

The PR allows a previously published verification marker to be replaced when runtime sanitization has changed only artifact digests and those digests match the current local files.

  • Compares parsed marker skeletons after blanking only recognized sha256 fields.
  • Requires at least one changed digest and verifies every changed digest against its in-tree artifact.
  • Retains strict immutable byte comparison for ordinary publication files and source proofs.
  • Adds regression tests for successful republication, unmatched digests, and non-digest marker changes.

Confidence Score: 5/5

The PR appears safe to merge, with the marker replacement exception constrained to verified digest refreshes.

The changed path retains immutable publication checks by default and bypasses byte equality only after confirming an otherwise identical marker whose changed digests match regular, non-symlinked files inside the artifact directory.

Important Files Changed

Filename Overview
packages/modal/src/node-provider.ts Introduces a narrowly scoped marker-republication exception that preserves non-digest fields and validates changed digests against safe local artifact files.
packages/modal/test/node-provider.test.ts Adds focused coverage for the successful refresh path and rejection of unmatched digests or changes outside digest fields.

Sequence Diagram

sequenceDiagram
  participant Remote as Remote result
  participant Provider as Modal node provider
  participant Local as Local publication
  participant Gate as Runtime artifact gate
  Gate->>Local: Sanitize artifact and refresh marker digest
  Remote->>Provider: Return original artifact and marker
  Provider->>Provider: Compare marker skeletons
  Provider->>Local: Verify changed digest against current artifact
  Provider->>Local: Replace artifact directory
  Provider->>Local: Republish original marker
Loading

Reviews (1): Last reviewed commit: "fix(modal): let a runtime-refreshed veri..." | Re-trigger Greptile

Context used:

`publishModalNodeResult` byte-compared the artifact verification marker
against the one already on disk and threw on any difference. When a
runtime gate sanitizes an already-verified artifact it refreshes that
marker's recorded digest so the marker still attests the bytes on disk
(`refreshVerifiedArtifactDigest`), and republishing the same attempt —
a resumed or recovered sandbox — then hit the byte compare. Because
`stableAttemptId` keeps the attempt id, artifact directory and marker
name identical across retries, the throw repeated on every retry and
stranded the attempt permanently.

Permit exactly that one difference: the two markers must be identical
once the `sha256` of every `artifacts`/`publications` entry is blanked,
at least one digest must differ, and every differing local digest must
be the sha256 of the artifact this machine currently publishes at that
entry's path. Anything else — a changed path, node or attempt id, an
added, dropped or reordered entry, a digest naming no local file, or a
marker that is not JSON — stays rejected, and the source-proof path
keeps its unconditional byte compare.

Fixes #280

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aviggiano
aviggiano merged commit 0adfd31 into main Aug 7, 2026
7 of 8 checks passed
@aviggiano
aviggiano deleted the fix/marker-republication-refresh branch August 7, 2026 15:53
aviggiano pushed a commit that referenced this pull request Aug 7, 2026
Four files conflicted; every resolution keeps both sides' behaviour.

workflow.tsx -- both destructuring imports were unions, not choices. Kept
#344's `checkInvariantSourcePinned` / `invariantPinnedSourceRefExists` and
#342's `validateWorkspacePatchCapture` alongside #188's cloud-selected-task,
finding-provenance and dynamic-topology symbols. The rest of the file merged
without overlap: #334's `invariantSuiteGitPaths` still bounds all five
invariant-discovery enumerations, #342's single ancestor-wide suite budget and
depth bound are intact, #343's per-path publisher resolution still fails closed
on unordered siblings, and #188's dynamic `taskSpecs` reassignment happens
before any of those helpers read it, so they see the expanded node set.

public-worker.ts -- kept #188's `REFERENCE_GITHUB_TOKEN_ENV` import and dropped
`redactSecretsInText`, whose only consumer (`sanitizePublicDiagnosticMessage`)
#335 deleted when it routed the stderr tail through
`sanitizeWorkerDiagnosticMessage`. The two compose: the reference token #188
adds to `publicBenchmarkWorkerSecretValues` is now redacted from the bounded
stderr tail as well.

node-provider.test.ts -- unioned `logicalDispatchFingerprint` and
`verificationMarker` into one options type, and moved #339's three new
verification-marker tests onto #188's two-argument `createResultArchive`
signature so their bundles carry a real `logical_dispatch_fingerprint` instead
of bypassing the provenance check.

topology-transform.test.ts -- kept both new tests. #342's invariant-only
exclusion test now reads the `REPOSITORY_ROOT` constant #188 hoisted rather than
recomputing the path, so the file keeps one spelling of the repository root.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Modal marker republication byte-compares, so a runtime-refreshed verification marker can strand an attempt

1 participant