Skip to content

fix(review): the Paper stored-preview banner names what is on screen and matches the Legacy status label - #2697

Merged
Chris0Jeky merged 4 commits into
mainfrom
issue-1434/paper-banner
Sep 5, 2026
Merged

fix(review): the Paper stored-preview banner names what is on screen and matches the Legacy status label#2697
Chris0Jeky merged 4 commits into
mainfrom
issue-1434/paper-banner

Conversation

@Chris0Jeky

@Chris0Jeky Chris0Jeky commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

The Paper review surface showed one read-only banner sentence for three different things. Whenever the diff pane was in stored mode it said "showing the stored preview from the original submission", including the two modes where no stored preview exists: the recorded-operations listing the pane synthesizes from the proposal's own operations (the common expired path, since normal creation flows never populate diffPreview), and the state where nothing was captured at all. PR #2655 fixed exactly this on the Legacy card; this is the Paper half of #1434 finding 2, plus finding 3.

The banner now names the content that is on screen, in the wording the Legacy card settled on:

  • a captured stored preview keeps the existing sentence;
  • the recorded-operations fallback says "showing the proposal's recorded operations";
  • with nothing to show, the banner states the status and the read-only fact and stops. review.diff.storedEmpty renders directly below it and stays the empty state's sentence.

The recorded-operations sentence lives on the banner alone. The Legacy card renders a note under its banner saying the same thing, which is the LOW recorded on that side; the Paper pane has no such note, so this pane states the fact once. The revised-proposal caveat already picked storedTail or fallbackTail per mode, so banner and caveat now describe the same content instead of contradicting each other; a spec pins that.

Finding 3, the Applied status label: Legacy renders it as "Applied to board" through reviewStatusLabel, Paper rendered the bare normalized status. reviewStatusLabel is local to ReviewProposalCard.vue and is not exported from a composable or util, so importing it would create a new view-to-component dependency. The shells converge through a catalog key instead (review.status.appliedToBoard), which is the fallback the issue's acceptance names. Every other status already matched.

That label renders through the read-only conversion rather than through a key press, and the specs drive the whole route: the preview key is inert once a record is applied (useReviewKeymap's isActionEnabled allows only onReject there), but a pane opened BEFORE the apply survives it — nothing on the approve/execute path clears the pane, the proposal-change watcher sees the same id and a revision identity that only went to null, and the decision receipt keeps the applied proposal active — so the #1397 LOW-5 watcher converts the live pane to the stored presentation with the Applied label on it. The Italian and Spanish forms of the label are asserted in the DOM for that same route, not only in the catalog guard.

Finding 1, the recorded-operations listing format, is already converged on main, in commit 7ca3a8a51 ("Present readable proposal identifiers", 2026-08-18) rather than in #2655. That commit removed the Paper · separator the issue cites and gave both shells the same quoted target-label suffix. What remains is the action-label transform: Paper renders formatActionLabel(actionType) ("Create Card"), Legacy renders the raw actionType through proposalDisplayNames.operationHeadline ("CreateCard"). Converging that means editing ReviewProposalCard.vue and its diff spec, which are outside this slice's file boundary, so it is left as-is and reported. That is why this PR uses Refs, not Closes.

Refs #1434, #2655, #1397, #1414

Changes

test(review): pin the Paper read-only banner to what the pane actually shows — five specs in PaperReviewView.spec.ts, four red on the unmodified view.

fix(review): name the content the Paper read-only banner is actually showing:

  • src/views/paper/PaperReviewView.vue — a previewReadOnlyBanner computed selects the banner message by content mode; the template renders it instead of the unconditional review.diff.storedBanner; previewReadOnlyLabel maps Applied to the Legacy wording's key.
  • src/locales/{en,es,it}/review.tsreview.diff.storedBannerRecorded, review.diff.storedBannerNone (both keep the {status} placeholder) and review.status.appliedToBoard in all three catalogs.

test(review): drive the Applied banner conversion instead of calling it unreachable — the review finding below: three more specs (the en rendered label on the conversion route, plus an it.each for the Italian and Spanish labels under a switched locale), the corrected comment, and two catalog comment fixes.

Test plan

Verified, in the worktree at frontend/taskdeck-web, on the branch merged with origin/main (c574b2f19):

  • npx vitest --run --maxWorkers=2 src/tests/views/paper/review/PaperReviewView.spec.ts src/tests/components/review/ReviewProposalCard.diff.spec.ts src/tests/i18n/catalogs.spec.ts — Test Files 3 passed (3), Tests 240 passed (240). Three files named, three ran.
  • npx vitest --run --maxWorkers=2 src/tests/views/paper/review/ src/tests/i18n/ — Test Files 18 passed (18), Tests 408 passed (408) (run before the last three specs were added).
  • npm run typecheck — clean.
  • npx eslint src/views/paper/PaperReviewView.vue src/locales/{en,es,it}/review.ts src/tests/views/paper/review/PaperReviewView.spec.ts — clean.
  • git diff --check — clean.

Red-first, on the unmodified view (npx vitest --run --maxWorkers=2 src/tests/views/paper/review/PaperReviewView.spec.ts -t "#1434" → Tests 4 failed | 1 passed):

  1. recorded-operations fallback: expected showing the proposal's recorded operations, received Expired · read-only — showing the stored preview from the original submission.
  2. nothing captured: banner expected not to contain stored preview, received the same stored-preview sentence.
  3. revised caveat consistency: the caveat said "recorded operations" while the banner said "stored preview" for the same pane.
  4. enReview.status.appliedToBoard — expected Applied to board, received undefined.

The fifth spec (a captured stored preview keeps the Legacy sentence) passes on both sides and is the parity anchor.

Red-first for the rendered Applied route, by reverting the appliedToBoard mapping in previewReadOnlyLabel and re-running the same filter (Tests 3 failed | 5 passed): the banner reads Applied · read-only — showing the stored preview from the original submission., Applicata · sola lettura — mostra l'anteprima salvata dell'invio originale. and Aplicada · solo lectura — muestra la vista previa guardada del envío original. The other five stay green, since the catalog assertion only proves the key exists — which is why the rendered assertions were added.

ReviewProposalCard.diff.spec.ts is unchanged and green: no key it asserts moved, since the Legacy card holds its banner copy as literals rather than catalog keys.

NOT verified:

  • No browser or Playwright run; the Spanish and Italian strings are asserted as rendered copy but are not native-reviewed (catalog parity and placeholder membership are enforced by catalogs.spec.ts).
  • No backend, full frontend suite, or build run: this changes copy in one view and three catalogs only.
  • A queue poll that maps the applied status in without a decision receipt does not reach the banner — the surface lands on "This proposal left the review queue" instead. That is existing behaviour, unchanged here, and not the route the specs claim.

Boundaries and risks

Files touched: PaperReviewView.vue (the diff pane's banner and the read-only label computed), the three locales/*/review.ts, and PaperReviewView.spec.ts. Not touched: useReviewProposals.ts, useReviewActions.ts, ReviewMain.vue, the receipt recorders and the poll disclosures in the same view, ReviewProposalCard.vue and its diff spec.

Copy-only. No behaviour, control-flow, network, or access-control change: the same three modes render exactly the same content as before, only the sentence above them changed. review.status.applied keeps its plain value for any future consumer; the board-specific wording is a separate key used only by the banner.

Residuals for the tracking issue, neither touched here:

Worktree gitignored state is frontend/taskdeck-web/node_modules from npm ci plus build caches. Nothing there needs to survive; nothing was copied out.

…y shows

Red-first coverage for #1434 findings 2 and 3 on the Paper surface. Four of the
five assertions fail on the unmodified view:

- the recorded-operations fallback (the common expired path) is announced as a
  "stored preview from the original submission";
- the no-content state is announced the same way, on top of the empty-state
  sentence below it;
- the revised caveat says "recorded operations" while the banner above it says
  "stored preview" for the same pane;
- there is no catalog key carrying the Legacy card's "Applied to board" status
  wording.

The stored-preview case already matches the Legacy card and passes; it is kept
as the parity anchor for the other two modes.
…showing

The banner said "showing the stored preview from the original submission"
whenever the pane was in stored mode, including the two modes where no stored
preview exists: the recorded-operations fallback synthesized from the
proposal's own operations (the common expired path, since normal creation
flows never populate diffPreview) and the state where nothing was captured at
all. It now names each mode, in the wording the Legacy card settled on in
PR #2655:

- a captured preview keeps the existing sentence;
- the fallback says "showing the proposal's recorded operations", the sentence
  the Legacy card puts in a note under its banner. It stays on the banner here
  and nowhere else, so this pane does not repeat itself the way the Legacy card
  does;
- with nothing to show, the banner states the status and the read-only fact
  only. review.diff.storedEmpty renders directly below it and remains the
  empty state's sentence.

The banner's status also converges on the Legacy card's "Applied to board"
(#1434 finding 3). reviewStatusLabel is local to ReviewProposalCard.vue, so
importing it would be a new view-to-component dependency; the shells converge
through review.status.appliedToBoard instead. Every other status already
matched. That branch has no route to the screen today: the preview key is
inert on an applied record, which the spec records.

All three catalogs carry the new keys.

Refs #1434, #2655, #1397, #1414
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Review record (alpha product-trust lane, review-and-ship round 1 at head 657729075).

Reviewer: one fresh-context independent reviewer subagent (read-only; Codex credits exhausted, SC-9), given the worktree at the head and the merge-base diff. Verdict: SHIP, no merge-blocking items; one MEDIUM fixed in round 2 because it is a false safety claim.

Lenses that found nothing: the banner's three-way branch uses exactly the predicates the template's content branches and the revised caveat use, so no mode states a fact it does not render or repeats one; a stale live diff cannot be relabelled as stored (both routes into stored mode overwrite the preview and bump the request id, and the section is gated on the previewed proposal's id); the Applied mapping intercepts only Applied, with Expired, Rejected, Failed and Dismissed unchanged; the Paper copy matches the Legacy card byte-for-byte for the stored and recorded-operations sentences, and the empty mode's shortened banner keeps the same fact set with storedEmpty below it (ADR-0038 direction honoured, the Legacy card untouched); es and it carry the new keys with {status} where it belongs and the catalog parity spec would catch a miss; the fallback, empty and caveat specs mount the states they claim, the occurrence counts are scoped to the diff section, and the Space-inert assertion is a real regression guard the existing keymap test did not cover; scope is the five files, the receipt recorders and the poll disclosures untouched.

Findings, triaged once:

  • MEDIUM, fixed in round 2 (spec and comments, no logic): the spec comment claimed the read-only banner cannot be opened on an applied record; the keymap half is true, but an open live pane converts to the stored banner when its proposal is applied (nothing on the apply path clears the pane, the revision-move check treats the apply's rev-X to null as no move, the receipt branch keeps the applied proposal active, and the Expired/zero-op proposals: graceful preview presentation + frontend coverage for the new diff 400 contract #1397 LOW-5 watcher flips the mode), so "Applied to board" and its es/it copy do ship. The comment is corrected and a rendered assertion drives that path; the PR body and the lane's records say the same.
  • LOW, taken in round 2 if trivial: the en docblock says all three banner modes are worded exactly as the Legacy card's, false for the empty mode by design; review.status.applied is now unreachable in all three catalogs.

Round count: 2 after the fix push. Merge gate: CI green at the fix head plus the three-minute age; no second pass is owed (the fixes change specs and comments only).

…it unreachable

Review finding (MEDIUM): the spec comment and the PR body claimed the
"Applied to board" banner has no route to the screen, because the preview key
is inert on an applied record. The keymap half is right, but onPreviewDiff is
not the only way into stored mode. Driven end to end and confirmed: open the
live pane on a pending proposal, approve it, apply it through the phase-2
dialog — nothing on that path clears the pane, the proposal-change watcher
sees the same id and a revision identity that only went to null, the decision
receipt keeps the applied proposal active, and the #1397 LOW-5 watcher
converts the pane to the stored presentation with the Applied label on it.
The es/it appliedToBoard copy therefore ships to users, so it is now asserted
in the DOM rather than only in the catalog.

- the comment says what is actually true: the banner cannot be OPENED on an
  applied record (still asserted), but a pane opened before the apply converts;
- a rendered assertion for the en label on that path, and an it.each for the
  Italian and Spanish labels under a switched locale;
- red-first: reverting the appliedToBoard mapping in previewReadOnlyLabel fails
  exactly those three rendered assertions (banner reads "Applied · read-only",
  "Applicata · sola lettura", "Aplicada · solo lectura") and leaves the other
  five green, since the catalog assertion only proves the key exists.

Two LOWs from the same review: the en diff docblock no longer claims all three
banner modes match the Legacy wording (the third drops Legacy's trailing
clause on purpose, because storedEmpty renders below it), and review.status
records that appliedToBoard supersedes applied for the read-only label.

Refs #1434
@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Round-2 record (alpha product-trust lane; fix head bbbcccfeb, one commit on top of 657729075, specs and comments only).

The reviewer's trace was right and the round-1 claim was wrong: driven in a mounted spec, a PendingReview proposal with the live pane open (Space), approved and applied through the dialog, converts to the stored banner reading "Applied to board · read-only — showing the stored preview from the original submission." The earlier measurement had started from an already-Approved proposal without proving the pane was open. The false claim is removed from the spec comment, the view comment and the PR body; a helper drives the path with a rendered en assertion and an it.each for it and es under a switched locale (restored in finally); the Space-inert assertion stays. Red-first for the rendered path: reverting the appliedToBoard mapping fails the three rendered assertions (en, it, es) while the catalog assertion stays green, which is why the rendered ones were needed. The two LOWs were taken: the en docblock now says the first two banner modes match the Legacy card exactly and the third deliberately drops the trailing clause because storedEmpty renders below; review.status.applied keeps its value with a note that appliedToBoard supersedes it for the read-only label.

Verified at the fix head: the Paper review, Legacy diff and catalog specs 3 files, 240 passed (three new); typecheck clean; eslint on the changed files clean; git diff --check clean; origin/main unmoved at c574b2f19.

Not verified: no browser run; the it/es strings reach the DOM in the spec but are not native-reviewed. Recorded as existing behaviour, not a change: a queue poll that maps Applied in without a decision receipt does not reach the banner (the surface shows that the proposal left the queue).

Merge gate remaining: CI green at bbbcccfeb and the three-minute age. Round count: 2; no second pass is owed (no logic changed).

@Chris0Jeky
Chris0Jeky merged commit 1807c39 into main Sep 5, 2026
37 checks passed
@github-project-automation github-project-automation Bot moved this from Pending to Done in Taskdeck Execution Sep 5, 2026
Chris0Jeky added a commit that referenced this pull request Sep 5, 2026
…ss retraction, #2696 headline, residual list, D-13 clause)

Answers the docs review of PR #2699: the #2694 bullet no longer claims the explicit list read's 403 is toast-free (the toast stays beside the revoked panel, the recorded LOW) nor that a success leaves a risen refusal standing (a successful list read retracts it); the #2696 headline says the listed literals render from the catalogs rather than that the components render no hardcoded English; the not-shipped line names the hash-watcher residual; item 2 is described as the list leg plus the explicit path; the #2697 bullet says its round 2 touched specs and comments only; OUTSTANDING_TASKS.md D-13 no longer says item 3 waits on a merged PR.
@Chris0Jeky
Chris0Jeky deleted the issue-1434/paper-banner branch September 6, 2026 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant