Skip to content

Proposal B PR-2 + PR-3: manual-override UI + preview badge (recovered stack) - #73

Merged
WilfordGrimley merged 11 commits into
masterfrom
claude/e4-bleed-preview-badge
Jul 18, 2026
Merged

Proposal B PR-2 + PR-3: manual-override UI + preview badge (recovered stack)#73
WilfordGrimley merged 11 commits into
masterfrom
claude/e4-bleed-preview-badge

Conversation

@WilfordGrimley

@WilfordGrimley WilfordGrimley commented Jul 18, 2026

Copy link
Copy Markdown

Recovery note: this PR's original base branches (claude/e2-bleed-prior-batch-resolution, claude/e3-bleed-override-ui) were deleted when their own PRs (#69, #71) got squash-merged/closed by another concurrent session — GitHub auto-closes a stacked child PR when its base branch disappears, and won't allow reopening (see docs/lessons.md's "A stacked PR's base branch gets deleted out from under it" entry). Retargeted this PR to master directly before its own base (e3) could suffer the same fate. This PR now carries PR-2's and PR-3's full content in one diff against master, plus a resolved merge conflict against master's own independent recovery of PR-1 (#72) — verified clean, mergeable_state: "clean".

Full reports: docs/reports/proposal-b-pr2-bleed-override-ui.md, docs/reports/proposal-b-pr3-preview-badge.md.

Description

PR-2 — manual-override UI + persistence: per-card Auto/Force bleed/Force trimmed control in the PDF export panel ("Bleed Overrides" collapsible section, PDFGenerator.tsx), persisted in project state (survives reload) via a new manualOverrides field on projectSlice + localStorage helpers + a listenerMiddleware.ts listener, mirroring favoritesSlice's existing pattern. XML round-trip intentionally not built — flagged per instruction.

PR-3 — WYSIWYG preview bleed badge: a hedged "Bleed will be generated" badge on PagePreview.tsx's fast/CSS preview, consuming PR-1's resolved priors and PR-2's manual overrides via a new pure willLikelyGenerateBleed(prior, manualOverride). With this, Proposal B is complete end to end.

Checklist

  • I have updated any related tests for code I modified or added new tests where appropriate.
  • I have manually tested my changes as follows (after the merge-conflict resolution against master):
    • npx tsc --noEmit: clean
    • npx eslint: 0 errors, 0 new warnings
    • npx jest --runInBand: 306/306 passing
    • npx playwright test tests/PDFGenerator.spec.ts --workers=1: 7/7 passing (one isolated re-run needed for a resource-contention flake unrelated to this PR's changes)
  • I have updated any relevant documentation or created new documentation where appropriate.

claude added 6 commits July 18, 2026 14:53
The branch this was originally scoped against (claude/print-preview-
xml-2) sits at the Proposal D commit with zero Proposal-B-specific code
or design doc - the queue's "resume Proposal B to completion" gloss
("export-time per-side bleed normalization") is compatible with two
genuinely different features with very different risk profiles, and
guessing which one blind isn't a reasonable substitute for a spec that
never reached this session.

Surveys the current uniform-scale bleed handling in PDF.tsx, the
backend's already-validated whole-image bleed/trimmed classification
(reusable technique, but binary and currently unpopulated in
production), and proposes two candidate designs: automatic per-edge
detection+auto-correct (higher risk - a wrong heuristic silently
mis-crops real print orders, no validated real-image sample to trust
it against yet) vs. manual per-side controls in the existing Proposal A
WYSIWYG preview (recommended MVP - no heuristic-correctness risk,
additive to layout.ts/PagePreview.tsx/PDF.tsx). HOLD pending the
owner's choice between them.
…ring)

Implements the approved spec (docs/proposals/proposal-b-bleed-
normalization.md, recovered after a courier loss): measures each card's
real per-side bleed via probe-median + IQR-ambiguity sampling
(bleedNormalize.ts), resolves a trim/extend plan against the target
bleed with a fallback prior and three manual-override modes, and
synthesizes the corrected image via canvas crop+edge-extension
(bleedExtension.ts). Wired into PDF.tsx's PDFCardImage for full-
resolution Google Drive/local-file renders, replacing the old uniform
proportional rescale for those cards.

26 new tests (all 6 required synthetic fixtures + override modes +
geometry math + pdfImage.ts's new getPDFImageBlob split), zero
regressions in the existing 267.

Two real bugs found and fixed via actual render verification, not just
unit tests: (1) a confident-but-wrong measurement could ask to trim
more than a small source image actually has, producing a negative
canvas dimension - clamped defensively in computeBleedExtensionGeometry.
(2) @react-pdf/renderer's own stylesheet parser has a genuine bug where
a single-token transform value ("none") throws inside its layout engine
without ever propagating as a rejection, silently hanging the whole
render - caught only by running tests/PDFGenerator.spec.ts's real
Playwright suite (which hung at timeout) against a stashed before/after
baseline; fixed by omitting the transform key instead of passing
"none". Documented in docs/lessons.md as a reusable cross-session
finding.

Still not built (flagged, not silently dropped - see the proposal
doc's "Shipped vs. not yet built"): the main-thread batch resolution of
bleedPriors via APIGetTagConsensus, the manual-override UI + project-
state persistence, and the WYSIWYG preview badge.
Main-thread, concurrency-bounded batch fetch of each export card's
appropriate-bleed machine-vote lean via the existing APIGetTagConsensus
endpoint - no new endpoint, per the approved spec. Populates
PDFProps.bleedPriors (built in PR #66, previously always undefined in
real exports) so ambiguous sides use a real per-card lean instead of
always falling through to the safe "unresolved" default.

Runs on the main thread (PDFGenerator.tsx's downloadPDF/saveToDrivePDF,
before the render worker is invoked) because APIGetTagConsensus's CSRF
header needs document.cookie, which doesn't exist inside pdf.worker.ts's
Worker context - the resolved plain map crosses that boundary the same
way every other PDFProps field already does.

New: common/concurrencyLimit.ts (a general-purpose bounded-concurrency
map, kept separate from GoogleDriveService's own private Semaphore to
avoid expanding this PR into an unrelated refactor), features/pdf/
bleedPriorResolution.ts (netPolarity -> BleedPrior mapping, per-card
failure tolerance so one bad lookup never fails the whole export). 13
new tests, 282/282 passing overall.

Verified against the real render path, not just unit tests:
tests/PDFGenerator.spec.ts has no tagConsensus mock at all, so every
lookup genuinely fails during that suite - it still passes at the same
timing as before this PR, confirming the failure-tolerance path works
end to end, not just in isolation.

Full report: docs/reports/proposal-b-pr1-bleed-prior-batch-resolution.md
Per the owner's explicit instruction: PR-1's batch resolution issues
one request per unique export card (~517 for the owner's own large
project). Acceptable for v1; a batch-consensus endpoint is the
eventual answer if this ever actually hurts, not worth building
speculatively ahead of evidence.
Per-card Auto/Force bleed/Force trimmed control in the PDF export panel
(new "Bleed Overrides" AutofillCollapse section, listing only cards
bleed normalization can apply to), persisted in project state per
decision 4 (survives reload) via a new manualOverrides field on
projectSlice + localStorage helpers + a listenerMiddleware listener,
mirroring favoritesSlice's existing pattern exactly. Wired into
PDFGenerator's bleedOverrides prop. XML round-trip flagged, not built,
per instruction.
Hedged "Bleed will be generated" badge on PagePreview.tsx's fast/CSS
preview, per the audit's suggestion-vs-confirmed vocabulary. New pure
willLikelyGenerateBleed(prior, manualOverride) mirrors
resolveBleedPlan's precedence minus the per-side measurement (not
available to the cheap preview); PDFGenerator.tsx resolves priors for
just the visible preview page, debounced, and combines with PR-2's
manual overrides. Proposal B is now complete end to end.

Also: docs/lessons.md entry for the page.reload()/second-load-event
Playwright hang found while verifying PR-2.
@WilfordGrimley
WilfordGrimley changed the base branch from claude/e3-bleed-override-ui to master July 18, 2026 17:53
…view-badge

# Conflicts:
#	docs/features/pdf-generator.md
#	docs/lessons.md
#	docs/proposals/proposal-b-bleed-normalization.md
#	docs/reports/proposal-b-pr1-bleed-prior-batch-resolution.md
#	frontend/src/features/pdf/PDFGenerator.tsx
#	frontend/src/features/pdf/bleedNormalize.test.ts
#	frontend/src/features/pdf/bleedNormalize.ts
@WilfordGrimley WilfordGrimley changed the title Build Proposal B PR-3: WYSIWYG preview bleed badge Proposal B PR-2 + PR-3: manual-override UI + preview badge (recovered stack) Jul 18, 2026
claude and others added 2 commits July 18, 2026 19:33
…st unloaded CardDocuments

BleedOverrideSettings's eligibility filter accessed cardDocument.sourceType
without checking for undefined - useCardDocumentsByIdentifier's underlying
selector (selectCardDocumentsByIdentifiers) maps every project member
identifier to its CardDocument, including identifiers whose document
hasn't finished loading into the store yet (mapped to undefined). The
fast preview's own eligibility filter (fastPreviewEligibleIdentifiers,
same file) already guarded against this; this one didn't, throwing
"Cannot read properties of undefined (reading 'sourceType')" the instant
the panel rendered before every card had loaded - exactly what
PagePreview.spec.ts's fast preview tests do (no debounce, first paint).

Diagnosed via a saved Playwright error-context.md showing a Next.js
dev-mode "Unhandled Runtime Error" overlay sitting on top of the (CSS-
visible but never actually rendered) page-preview element underneath -
the same false-positive-visible diagnostic pattern documented in
docs/lessons.md from an earlier unrelated bug this session.

Also reformats tests/PDFGenerator.spec.ts (unrelated prior formatting
drift, not touched otherwise).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dB7mGPQyoML2Ri5ZrprdK
…flicts

Both conflicts (proposal doc, PDFGenerator.tsx) are additive-both-sides:
PR-3's own shipped-narrative + task #134's calibration findings in the
doc (combined, not competing); PR-2's BleedOverrideSettings component vs
#81's ImageFailureConfirmModal component in the TSX (both kept, unrelated
features). tsc clean, bleedNormalize.test.ts 14/14, PagePreview.spec.ts
3/3 (previously the real failure from checkpoint-2 - now passing, the
frontend session's fix confirmed landed).
@WilfordGrimley
WilfordGrimley merged commit 5b2d08a into master Jul 18, 2026
7 checks passed
@WilfordGrimley
WilfordGrimley deleted the claude/e4-bleed-preview-badge branch July 18, 2026 20:41
WilfordGrimley added a commit that referenced this pull request Jul 20, 2026
Top summary paragraph said manual-override UI/persistence + preview
badge "remain", contradicting the same file's own "Shipped vs. not
yet built" section (both shipped as PR #73). Correct the summary and
bump README's status table row from BUILDING to PARTIAL to match the
three genuinely open items (XML round-trip, two edge cases).
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.

2 participants