fix(review): the Paper stored-preview banner names what is on screen and matches the Legacy status label - #2697
Conversation
…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
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Review record (alpha product-trust lane, review-and-ship round 1 at head 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 Findings, triaged once:
Round count: 2 after the fix push. Merge gate: |
…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
|
Round-2 record (alpha product-trust lane; fix head 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 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; 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: |
…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.
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:
review.diff.storedEmptyrenders 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
storedTailorfallbackTailper 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.reviewStatusLabelis local toReviewProposalCard.vueand 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'sisActionEnabledallows onlyonRejectthere), 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 rendersformatActionLabel(actionType)("Create Card"), Legacy renders the rawactionTypethroughproposalDisplayNames.operationHeadline("CreateCard"). Converging that means editingReviewProposalCard.vueand its diff spec, which are outside this slice's file boundary, so it is left as-is and reported. That is why this PR usesRefs, notCloses.Refs #1434, #2655, #1397, #1414
Changes
test(review): pin the Paper read-only banner to what the pane actually shows— five specs inPaperReviewView.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— apreviewReadOnlyBannercomputed selects the banner message by content mode; the template renders it instead of the unconditionalreview.diff.storedBanner;previewReadOnlyLabelmaps Applied to the Legacy wording's key.src/locales/{en,es,it}/review.ts—review.diff.storedBannerRecorded,review.diff.storedBannerNone(both keep the{status}placeholder) andreview.status.appliedToBoardin 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 anit.eachfor 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 withorigin/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):showing the proposal's recorded operations, receivedExpired · read-only — showing the stored preview from the original submission.stored preview, received the same stored-preview sentence.enReview.status.appliedToBoard— expectedApplied to board, receivedundefined.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
appliedToBoardmapping inpreviewReadOnlyLabeland re-running the same filter (Tests 3 failed | 5 passed): the banner readsApplied · read-only — showing the stored preview from the original submission.,Applicata · sola lettura — mostra l'anteprima salvata dell'invio originale.andAplicada · 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.tsis unchanged and green: no key it asserts moved, since the Legacy card holds its banner copy as literals rather than catalog keys.NOT verified:
catalogs.spec.ts).Boundaries and risks
Files touched:
PaperReviewView.vue(the diff pane's banner and the read-only label computed), the threelocales/*/review.ts, andPaperReviewView.spec.ts. Not touched:useReviewProposals.ts,useReviewActions.ts,ReviewMain.vue, the receipt recorders and the poll disclosures in the same view,ReviewProposalCard.vueand 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.appliedkeeps 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_modulesfromnpm ciplus build caches. Nothing there needs to survive; nothing was copied out.