Skip to content

fix(ci): retain hygiene and native export diagnostics - #2545

Merged
schlessera merged 1 commit into
mainfrom
fix/1903-remaining-proof-artifacts-044
Oct 22, 2026
Merged

schlessera merged 1 commit into
mainfrom
fix/1903-remaining-proof-artifacts-044

Conversation

@schlessera

Copy link
Copy Markdown
Owner

Refs #1903

What changed

Hygiene commands retain each screenshot's exact returned bytes in a unique tmp/hygiene-proof/capture-* directory, while preserving their existing local scratch paths and return values. The layout artifact collects those copies. The browser artifact collects only the six prepared native diagram exports and their producer.json under each session/engine. Existing artifacts, gates, runtime/action pins, offline image, hidden files, failure collection and seven-day retention remain intact.

Why this shape

#2435 already retained workspace attachments and handed off unit-worker SVG outputs. Hygiene screenshots still disappeared with container scratch, and the native producer already published the required origin exports/identity receipt outside the collected directory. Retaining the producer's original bounded files avoids a second export or manufactured provenance. Independent capture directories preserve earlier evidence when filenames repeat.

No changeset: only test evidence and CI collection change; no shipped package, dependency, public API, CLI/MCP or provider-history behavior changes.

Proof

Head 3c3a3af23acb386b1d838be716883e5401a9d9f5; branch starts at origin/main 7b8a755ea329bd48a11b790e916c417b6f608eee.

  • bun run check:pr --base origin/main: PASS on final committed head 3c3a3af2 against base 7b8a755e (including lint and import-graph feedback).
  • bunx tsc --noEmit, bun run build, and 49 focused tests / 301 assertions pass. Preflight includes lint and the complete selected fast invariants.
  • Failing first: hygiene command retains each capture after container scratch cleanup fails on the original command at the intended assertion: expected two surviving files, received zero. Restored code passes all six assertions, including preserved scratch return paths and independent repeated-filename bytes.
  • Mutation: remove the retained-byte write from hygieneCapture; the same named test fails with expected two files / received zero. Restore the write: pass.
  • Actual upload collector: source-verified actions/upload-artifact@v7 resolves to cf430e030ddbb5b0abf93d22962f4752f3646cd9; unmodified bundle SHA-256 7199f63dd3e149ca4b8071705021fb3a680d03dd71cd3a4e8d3049e3f117380b. Replace only its entrypoint with an export of the original collector and execute in a network namespace with no network. The old browser path list fails native origin exports and producer receipt are collected: .../origin.svg; the old layout list independently fails hygiene captures are collected: .../c6-stalled-320.png. Current lists pass, retaining existing evidence and excluding unrelated temporary files and Linux baselines. Parsed workflow comparison confirms only additive upload paths changed.
  • Actual native files: the collector includes all 30 generated hygiene PNGs (1,240,909 bytes; valid PNG chunk CRCs, nonzero dimensions and identical scratch/copy bytes) and 14 native files across Chromium/WebKit: two producer receipts and 12 exports. Every export matches its producer hash. Native diagram proof passes all 76 cases.
  • Hygiene native limitation: the unchanged review/full-loop population runs 60 cases: 59 pass, one existing dark-320 configuration-retry assertion fails at hygiene-review.layout.tsx:307. Both full-loop widths pass; no timeout/assertion was changed or retry claimed. Filed separately as ui-react: hygiene retry can retain the configuration blocker after Start again #2544.

The native runs used checkout 7b8a755e plus the retention-only working diff subsequently committed unchanged as 3c3a3af2. Native producer receipts retain their actual 7b8a755e checkout identity. These local receipts are not hosted candidate confirmation for this head.

Downloaded hosted artifact audit of the shipped slice

Successful main run 39699155671, attempt 1 executed b17e349b7c8ff0f69c4cade3a953c86008d3ede8, tree 1dee2f6e9b5dcc5b5070597b5d235e0763e137e4, parent ca8842828ed8634a84c4e8aa4a88e487238721b4. All 17 actual job checkout logs agree. All 13 proof ZIPs were downloaded; sizes and SHA-256 digests match the API; safe unique paths and every ZIP CRC, PNG signature/chunk CRC, nonempty raster payload, dimensions, size and SHA-256 were checked.

Generated class Downloaded artifact / actual job Verified result
Durable-action headers layout-proof-2, 12392802709, job 119564123392 Four PNGs; 288 or 324 × 135, 6,727–6,860 bytes
Keyboard fine/coarse browser-proof-3, 12392567047, job 119564123475 Five fine + five coarse PNGs
Keyboard mixed browser-proof-1, 12391858643, job 119564123772 Five mixed PNGs
Keyboard live change and module settings browser-proof-2, 12393027535, job 119564123189 Two live fine/coarse PNGs; 36 module-settings PNGs; root hidden attachments preserved
Worker SVG outputs unit-proof-4, 12392368685, job 119564123220 Worker 1 owns the actual recovery cases and retains two PNGs (694 × 521 / 928; 2,677 / 4,146 bytes) + two PDFs

The 17 keyboard files are 10,050–68,008 bytes; module-settings files are 13,853–91,886 bytes. Across all ZIPs there are 1,353 PNG instances. Exactly 234 instances match the same 18 tracked numeric reference paths and hashes; they are excluded from generated/failure-evidence claims. No generated automatic-failure PNG is present. The audited run has zero hygiene copies and zero native origin exports/producer receipts, reproducing the remaining retention boundary without relabeling historical evidence as this candidate's proof.

The local audit inventory, replay scripts, bundle and logs are preserved in this worktree's ignored tmp/1903-artifact-audit/. The following independent downloaded-byte check is repeatable from the repository root (writes only to an owned temporary directory):

python3 - <<'PYCODE'
import hashlib, json, pathlib, struct, subprocess, tempfile, zipfile, zlib
call = lambda *args: subprocess.check_output(["gh", "api", *args])
meta = json.loads(call("repos/schlessera/brain-kit/actions/runs/39699155671/artifacts"))
with tempfile.TemporaryDirectory(prefix="odysseus-proof-audit-") as directory:
    for artifact in meta["artifacts"]:
        if artifact["name"] == "proof-reuse-ledger": continue
        data = call(f"repos/schlessera/brain-kit/actions/artifacts/{artifact['id']}/zip")
        assert len(data) == artifact["size_in_bytes"]
        assert "sha256:" + hashlib.sha256(data).hexdigest() == artifact["digest"]
        path = pathlib.Path(directory) / (artifact["name"] + ".zip")
        path.write_bytes(data)
        with zipfile.ZipFile(path) as archive:
            names = archive.namelist()
            assert len(names) == len(set(names)) and archive.testzip() is None
            assert all(not pathlib.PurePosixPath(n).is_absolute() and ".." not in pathlib.PurePosixPath(n).parts for n in names)
            receipt = json.loads(archive.read("tmp/proof-checkout.json"))
            assert receipt["checkout"]["sha"] == "b17e349b7c8ff0f69c4cade3a953c86008d3ede8"
            pngs = []
            for name in names:
                if not name.endswith(".png"): continue
                image = archive.read(name)
                assert image[:8] == bytes([137,80,78,71,13,10,26,10])
                width, height = struct.unpack(">II", image[16:24])
                assert width > 0 and height > 0
                offset, pixels = 8, b""
                while offset < len(image):
                    size = struct.unpack(">I", image[offset:offset+4])[0]
                    kind, payload = image[offset+4:offset+8], image[offset+8:offset+8+size]
                    assert zlib.crc32(kind + payload) & 0xffffffff == struct.unpack(">I", image[offset+8+size:offset+12+size])[0]
                    if kind == b"IDAT": pixels += payload
                    offset += 12 + size
                    if kind == b"IEND": break
                assert offset == len(image) and zlib.decompress(pixels)
                pngs.append(dict(path=name,width=width,height=height,bytes=len(image),sha256=hashlib.sha256(image).hexdigest()))
            (path.parent / (artifact["name"] + "-pngs.json")).write_text(json.dumps(pngs, indent=2))
            print(artifact["id"], artifact["name"], len(pngs), "PNG instances verified")
PYCODE

Checklist

  • Focused local preflight/behavioral receipts and complete selected hosted proof passed; actual head/base/job checkout evidence is in Proof.
  • Acceptance criteria from the issue are all met, or the gap is named below.
  • The PR and completed/advanced issues have verified release milestones under docs/process/github.md.
  • A changeset is included, or this changes nothing a consumer can see.
  • No personal data anywhere in the diff — the leakage gate covers the whole tree.
  • The integration contract index or relevant component is updated in this same commit, or nothing in the machine surface moved.
  • Docs under docs/ reflect the change, or nothing documented moved.
  • Provider history stays append-only (docs/decisions/provider-history.md): the provider-history guard passes, or nothing on a turn's path changed.

Anything left open

  • Coordinator-owned current-candidate confirmation, download and audit of the new hygiene/native output paths; no ready transition, confirmation reservation or merge was requested here. Keep ci: retain consumer UI screenshots in hosted proof artifacts #1903 open. Historical downloaded headers/keyboard/module-settings/worker evidence proves the shipped slice only.
  • Genuine generated automatic-failure screenshot evidence remains absent; unchanged tracked numeric images and the simulated failure-state hygiene review captures do not establish that coverage. The native full-loop stalled diagnostic branch was routed through the helper but did not execute in the passing loop cases.
  • Fixture-owned temporary artifact-*.png captures removed in test teardown, opt-in externally directed captures and standalone navigation/software diagnostics retain their existing inventory boundary; this PR neither sweeps arbitrary temporary paths nor claims these outputs as newly retained. Required original criteria are not moved to another issue.
  • The independent hygiene retry failure is ui-react: hygiene retry can retain the configuration blocker after Start again #2544; it remains a separate unresolved failure receipt.

@schlessera schlessera added this to the 0.44.0 milestone Oct 22, 2026
@schlessera schlessera added type: fix Something is broken and must behave the way it is documented. area: ui-react React chat/files/voice components, stores, WebSocket transport. area: ci CI workflows, the gates they run, release scripts, packaging. labels Oct 22, 2026
@schlessera
schlessera marked this pull request as ready for review October 22, 2026 09:38
@schlessera
schlessera merged commit cbcbb13 into main Oct 22, 2026
22 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, the gates they run, release scripts, packaging. area: ui-react React chat/files/voice components, stores, WebSocket transport. type: fix Something is broken and must behave the way it is documented.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant