Skip to content

feat(panel): record why cleanup happened and what a period actually got - #212

Open
lamemustafa wants to merge 5 commits into
masterfrom
tapish-codex/evidence-durability
Open

feat(panel): record why cleanup happened and what a period actually got#212
lamemustafa wants to merge 5 commits into
masterfrom
tapish-codex/evidence-durability

Conversation

@lamemustafa

@lamemustafa lamemustafa commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #209 and #208. Both are defects in the per-period evidence column from
#207: one understates a delivered run, the other overstates an incomplete
period.

Root Cause / Decision Record

#209 — a delivered run read as captured after the panel reopened. Three
routes reached cleanup: a confirmed download, a run that produced no ZIP, and a
legacy staging cleared on upgrade. All three wrote one cleaned. That origin
was the only durable evidence the ZIP reached the browser, and the transition
discarded it, so the claim had to fall back on a signal that exists only on the
step which observed the download and is absent from the step a re-summarisation
builds.

Cleanup now keeps its origin — cleaned-after-download, cleaned-without-export,
cleaned-legacy — chosen over adding a zipDelivered boolean because it fixes
the collapse itself rather than routing around it, and because the three-way
ambiguity in zipPhase would otherwise stay in place for every other reader.
It widens an existing enum rather than adding a field, and persists one bit
about the run: no taxpayer data.

Plain cleaned is retained so a ledger written before the split still parses.
It carries no origin, so those runs stay indeterminate and read as captured —
what they did before, and the safe direction for a claim about a file.

#208 — a period read Saved when part of the selection never arrived. A
multi-artifact target reaches downloaded when one artifact staged and another
was explicitly unavailable, because an unavailable artifact is a resolved
outcome. Partly saved is kept distinct from Needs review deliberately: an
artifact the portal never offered is not a fault a re-run corrects, and routing
it to review would send someone looking for a problem that is not theirs.

The issue expected a new persisted field and it needed none.
filed-return-artifact-unavailable:<TYPE> survives parseDurableFiledReturnsSignals,
so a terminal target already carries it — the derivation was reading the run's
step, which holds the signal for whichever period is in flight and would have
marked the whole year partial because one period was.

Smallest safe fix. Neither change adds a persisted field. The one enum
widening was raised and decided before it was made, per the AGENTS.md
ask-first rule.

Scope

  • Runtime: filed-returns-contracts.ts (phase split, partly-saved, two
    predicates), filed-returns-full-fiscal-year-ledger.ts (origin-carrying
    write), filed-returns-full-fiscal-year-summary.ts (delivery and partial
    derivation), four readers routed through isCleanedZipPhase,
    popup/target-evidence.tsx and styles/panel.css.
  • Tests: a new file pinning the completion writer, which had none; partial and
    delivery cases in the evidence tests; header-count and row cases in the panel
    tests; the evidence fixture made faithful.
  • Docs/governance: none. No public claim changes — the column is not described
    in README or store copy.
  • Explicitly out of scope: Documented review-gate commands are satisfiable without a reviewer #211 (review-gate command documentation), and any
    change to what persists beyond the one enum widening described above.

Pack Workflow Preflight

  • pnpm workflow:preflight was run before editing/push, or the skip reason is documented.
  • This PR was opened from a Pack branch, not master.
  • I checked latest master Pack AGENTS guidance or recorded the stale-guidance warning.
  • PR body keeps the required Pack privacy/review/verification checklist visible.

Sanchika Adoption Gate

  • If this PR consumes @sanchika/* packages or copied Sanchika guidance, I
    read sanchika/docs/adoption-pack.md in the coordinated parent worktree.
  • If this PR consumes Sanchika, it links ComplyEaze and Axal completion evidence
    and records the Sanchika commit or copied guidance used.
  • This PR does not import ../sanchika, sanchika/packages/*/src, or parent
    source paths.

Privacy And Data-Flow Impact

  • No new browser permissions.
  • No new host permissions.
  • No new network calls.
  • No analytics, telemetry, ads, or session replay.
  • No credential, OTP, CAPTCHA, cookie, token, GST file, or taxpayer-data capture.
  • Public copy and privacy declarations are updated if behaviour changed.

Sensitive Surface Review

  • Current tab / portal target binding is preserved or intentionally changed.
  • Download completion remains evidence-backed and fail-closed.
  • Ambiguous side-effect delivery cannot be reported as confirmed success.
  • Service-worker durability impact is understood and documented.
  • Real taxpayer data, local paths, raw URLs/referrers, and portal HTML are absent from the diff.

Chrome Web Store Impact

  • This PR does not expand beyond the existing Chrome Web Store V0 listing unless every gate in docs/PUBLICATION_READINESS.md is checked.
  • Full fiscal year ships in the one binary but stays out of Store-advertised scope until its evidence gates are recorded.
  • Store copy, README status, Privacy QA, and reviewer instructions were reviewed if user-facing behavior changed.
  • CI ZIP creation, provenance, and protected publishing are treated as release evidence, not manual store-submission sign-off.
  • PR title uses Conventional Commits so Release Please can bump Pack after merge.

Verification

  • pnpm install --frozen-lockfile
  • pnpm audit --audit-level high
  • pnpm exec wxt prepare
  • pnpm exec prettier --check .
  • pnpm exec eslint . --max-warnings 0
  • pnpm exec tsc --noEmit
  • pnpm exec vitest runTests 2066 passed (2066), Test Files 123 passed (123)
  • pnpm exec wxt build
  • node scripts/verify-extension-package.mjs .output/chrome-mv3
  • pnpm exec wxt zip (release-only; not run)
  • node scripts/verify-extension-zip.mjs (release-only; not run)
  • node scripts/write-release-provenance.mjs (release-only; not run)
  • node scripts/verify-github-release-assets.mjs --tag <tag> --zip <zip> --checksum <sha256> --provenance <json> when release assets exist
  • node scripts/publish-chrome-web-store.mjs --zip .output/<zip> --provenance .output/pack-release-provenance.v1.json --publisher-id <id> --dry-run true
  • git diff --check
  • pnpm review:gate -- --strict-head-review --required-review-author chatgpt-codex-connector before merge, with a missing Codex review recorded as an audit gap if reported. Dropping --allow-missing-head-review is deliberate — see Documented review-gate commands are satisfiable without a reviewer #211, where --strict-head-review alone turned out to be satisfiable by one's own thread replies.

Live authenticated run outstanding — this PR must not merge until it is done.
Raised by review as P1 and accepted; the thread is left open deliberately,
because it needs an authenticated session and is the maintainer's action.

AGENTS.md L75-77 requires a live run for runtime and download-evidence
changes, and this is both. The synthetic tests assert that given a pending
phase, completion writes the right terminal one; they say nothing about whether
the live flow reaches downloaded-cleanup-pending rather than a sibling on a
real portal download. That transition is the entire claim and the only part of
it no fixture can reach.

What the run has to establish, in order:

  1. A full-year download completes and the ZIP reaches the browser.
  2. Reopen the panel. Every saved period still reads Saved, not Captured
    — the A delivered full-year run reads as captured after the panel reopens #209 regression, which fails here before this branch.
  3. A period where the portal offered one selected format and not another reads
    Partly saved, with the status line accounting for it separately.
  4. A run that produced no ZIP, and a retained legacy staging cleared on upgrade,
    both still read Captured after reopen.

Step 4 matters most: promoting either sibling is the overclaim the change exists
to prevent, and a defect in this branch did exactly that until 40ea54d.

Artifact Evidence

  • CI run: see checks on this PR
  • ZIP artifact: not produced — no release claim in this PR
  • ZIP SHA-256: n/a
  • Clean source/tag or head SHA: see the latest commit on this branch

PR Review Follow-Up

  • GitHub Actions completed (running).
  • Autogenerated Codex/bot review comments inspected after checks completed for the latest head SHA.
  • Inline review threads are resolved, outdated, or answered with evidence.
  • No commits were pushed after the last required human/bot review without re-review.
  • Any follow-up PRs or issues are listed here instead of being left implicit.
Thread/comment Disposition Commit or evidence
#209 — delivered run reads as captured after reopen fixed 94bae1d; origin-carrying cleanup, pinned in 7e54ad1
#208 — per-period Saved when one artifact was unavailable fixed 94bae1d; derived per target, no new persisted field

Two things worth a reviewer's attention rather than left implicit:

  1. completeFullFiscalYearLedger had no test at all, so the value it writes
    could be changed without a single failure — and that value is now the only
    durable record of delivery. Covered per route in 7e54ad1.
  2. The evidence fixture built its targets behind a blanket as cast and omitted
    every field the outcome did not read. It therefore proved nothing about the
    record the runtime is given: the first derivation to read one of those fields
    threw on all fifteen tests in the file at once. The targets are faithful now.

Self-review found a defect in this PR's own fix, and it is the more serious of
the two things found this way. markFullFiscalYearCleanupPending defaulted
its phase argument to downloaded-cleanup-pending — the one value that asserts
the ZIP reached the browser. One call site relied on that default: retrying the
OPFS discard of an already-completed same-scope ledger. So a run that had cleaned
as cleaned-legacy or cleaned-without-export was re-marked onto the delivery
route, and completion then wrote cleaned-after-download for files that were
never exported.

The origin split exists to prevent exactly that claim, and this reintroduced it
through the transition meant to preserve it. It was invisible because the
assertion was made by a default nobody had to type. Fixed in 40ea54d by removing
the default outright and deriving that call site's route from the phase the
ledger already reached, since either change alone leaves the mechanism in place.

I reached this by asking whether downloaded-cleanup-pending should also count
as delivery evidence. Tracing its writers to answer that is what surfaced the
third one — the check was worth running even though the answer turned out to be
no.

The smaller one, recorded rather than quietly amended:
the first version of targetMissedAnArtifact read (target.safeSignals ?? []),
which resolves absent signals to no missing artifact and therefore to saved.
That is "could not determine" answering "matches" on the field that decides
whether a period was complete, and it was the odd one out — the function ten
lines above dereferences the same field unguarded. Fixed in a third commit.

Each behavioural addition is mutation-checked — reverting the origin-carrying
write, the partly-saved branch, or the status-line clause fails exactly one
test each with the rest of its file passing.

Screenshots

None. The change is a new row label, glyph and status-line clause; the rendered
markup is asserted in tests/popup/target-evidence.test.tsx. A live panel
screenshot is part of the outstanding browser check noted above.

DCO

lamemustafa and others added 2 commits August 23, 2026 23:16
Closes #209 and #208.

**#209.** Three routes reached cleanup -- a confirmed download, a run that
produced no ZIP, and a legacy staging cleared on upgrade -- and all three wrote
one `cleaned`. The origin was the only durable evidence that the ZIP reached the
browser, and the transition discarded it, so a delivered run read as merely
captured once the panel reopened and the transient signal was gone.

Cleanup now keeps its origin: `cleaned-after-download`, `cleaned-without-export`,
`cleaned-legacy`. The delivery claim reads that instead of inferring backwards
from a value that had already thrown the answer away. Plain `cleaned` is
retained so a ledger written before the split still parses; it carries no origin,
so those runs stay indeterminate and read as captured, which is what they did
before and is the safe direction for a claim about a file.

Every existing `=== "cleaned"` became a check that silently stopped matching
three quarters of its runs, so they go through one `isCleanedZipPhase` predicate
rather than a comparison repeated per call site.

**#208.** A multi-artifact period reaches `downloaded` when one artifact staged
and another was explicitly unavailable, because an unavailable artifact is a
resolved outcome -- so `saved` claimed the whole selection for a period that had
part of it. It now reads `Partly saved`, kept distinct from `Needs review`
because an artifact the portal never offered is not a fault a re-run corrects.

The issue expected this to need a new persisted field. It does not:
`filed-return-artifact-unavailable:<TYPE>` survives durable signal parsing, so a
terminal target already carries it. The derivation was reading the run's step,
which carries the signal for whichever period is in flight and would have marked
the whole year partial because one period was.

Counted separately in the status line. A partly saved period is in none of the
other three counts, so without its own clause it would leave the header saying
"1 of 2 saved" with the second period unaccounted for anywhere on the line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`completeFullFiscalYearLedger` had no test at all, so the value it writes --
now the only durable record of whether the ZIP reached the browser -- could be
changed without a single failure. Covered per route, plus the no-pending-phase
case that must not be guessed into a delivery.

The evidence fixture built its targets behind a blanket cast and omitted every
field the outcome did not read, so it never exercised the record the runtime is
given: the first derivation to read one of those fields threw on all fifteen
tests in the file at once. The targets are faithful now.

Each addition mutation-checked: reverting the origin-carrying write, the
partly-saved branch, or the status-line clause fails one test each, with the
rest of the file passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa
lamemustafa marked this pull request as ready for review August 23, 2026 17:48
… claim

`(target.safeSignals ?? []).some(...)` reads as caution and is the opposite.
Absent signals would mean no evidence of a missing artifact, which resolves to
`saved` -- a fully saved period -- on the one field that decides whether the
period was complete. That is "could not determine" answering "matches", on the
claim the column exists to keep honest.

It was also the odd one out: `hasLegacyRetainedStaging`, ten lines above in the
same file, dereferences the same field unguarded. The field is required by the
type, set by every construction path, and its absence fails ledger validation,
so neither can be reached with a real record. A malformed one throwing is
diagnosable; a malformed one silently reading as saved is not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa

Copy link
Copy Markdown
Owner Author

@codex review

Requesting a review of head 0d5e7322. No review has been posted on this PR since it opened, so this is a nudge rather than a disagreement with anything.

The change closes #209 and #208. Two things a reviewer may want to look at first:

  • zipPhase gains three terminal values so cleanup keeps its origin, and every existing === "cleaned" comparison went through a new isCleanedZipPhase predicate rather than being updated in place.
  • The partial-period outcome is derived from the ledger target rather than the run's flow step, because the step carries the signal for whichever period is in flight.

lamemustafa and others added 2 commits August 23, 2026 23:52
`markFullFiscalYearCleanupPending` defaulted its phase argument to
`downloaded-cleanup-pending` -- the one value that asserts the ZIP reached the
browser. One call site relied on that default: retrying the OPFS discard of an
already-completed same-scope ledger. So a run that had cleaned as
`cleaned-legacy` or `cleaned-without-export` was re-marked onto the delivery
route, and completion then wrote `cleaned-after-download` for files that were
never exported.

That is the overclaim the origin split exists to prevent, reintroduced through
the transition meant to preserve it -- and it was invisible because the
assertion was made by a default nobody had to type.

Two changes, because either alone leaves the mechanism:

- The default is gone. A phase that asserts a delivery must be chosen, not
  inherited by a caller that did not consider the argument.
- That call site derives its route from the phase the ledger already reached,
  via `cleanupPendingPhaseFor`, which never upgrades. A pre-split `cleaned`
  carries no origin and takes the non-delivery route, so it keeps reading as
  captured exactly as it did before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Covers all four starting phases through the retry route and back out of
completion. Collapsing `cleanupPendingPhaseFor` to the delivery route fails this
test and only this test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c51f20929

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +278 to +279
flowStep.safeSignals.includes("full-fiscal-year-zip-downloaded") ||
zipPhaseProvesDelivery(ledger.zipPhase)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Complete the required authenticated runtime check

This change makes the new persisted cleanup phase durable proof that a ZIP reached the browser, but the commit's Verification section explicitly leaves the live browser check outstanding. Because this affects runtime and download evidence, exercise the actual authenticated portal download, cleanup, and panel-reopen path before treating the change as ready; synthetic tests cannot confirm that the live signal-to-phase transition matches the portal flow.

AGENTS.md reference: AGENTS.md:L75-L77

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepted, blocking, and left open deliberately — this is not something I can close.

The gate is correct and it is the one I recorded against myself in the Verification section rather than checked. AGENTS.md L75-77 requires a live authenticated run for runtime and download-evidence changes, and this change is squarely both: it makes a persisted phase the durable proof that a ZIP reached the browser.

Your reasoning is the part worth agreeing with explicitly. Synthetic tests here assert that given a pending phase, completion writes the right terminal one — they say nothing about whether the live flow actually reaches downloaded-cleanup-pending rather than one of its siblings on a real portal download. That transition is the whole claim, and it is the only part of it no fixture can reach.

It needs an authenticated session, so it is the maintainer's action rather than mine. Recorded in the PR body as the outstanding gate; the PR should not merge until it is done.

What the run has to establish, in order:

  1. A full-year download completes and the ZIP reaches the browser.
  2. Reopen the panel. Every period that was saved still reads Saved, not Captured — this is the A delivered full-year run reads as captured after the panel reopens #209 regression, and before this branch it failed here.
  3. A period where the portal offered one selected format and not another reads Partly saved, and the status line accounts for it separately.
  4. A run that produces no ZIP, and a retained legacy staging cleared on upgrade, both still read Captured after reopen. These are the two siblings that must not be promoted.

Step 4 matters most: promoting either of those is the overclaim the whole change exists to prevent, and a defect in this branch did exactly that until 40ea54d.

One correction to the finding's framing, which does not change the disposition: the cleanup phase is not a new persisted field. zipPhase already persisted; it gained three values so that cleanup stops discarding which route it came from. Widening that enum was raised and decided before it was made, per the ask-first rule.

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.

A delivered full-year run reads as captured after the panel reopens

1 participant