Skip to content

Proposal B PR-1: batch prior-resolution (appropriate-bleed machine-vote lean) - #72

Merged
WilfordGrimley merged 4 commits into
masterfrom
claude/e2-bleed-prior-batch-resolution
Jul 18, 2026
Merged

Proposal B PR-1: batch prior-resolution (appropriate-bleed machine-vote lean)#72
WilfordGrimley merged 4 commits into
masterfrom
claude/e2-bleed-prior-batch-resolution

Conversation

@WilfordGrimley

Copy link
Copy Markdown

entry

Description

Stacks on #66 (base branch set accordingly, so this diff shows only the new work). Full report: docs/reports/proposal-b-pr1-bleed-prior-batch-resolution.md.``

Builds the 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). This populates PDFProps.bleedPriors (added in #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 — APIGetTagConsensus's CSRF header needs document.cookie, which doesn't exist inside pdf.worker.ts's Worker context — resolved right before the render call in downloadPDF/saveToDrivePDF, skipped entirely when no remote backend is configured.

New: frontend/src/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), frontend/src/features/pdf/bleedPriorResolution.ts (netPolarity → BleedPrior mapping, per-card failure tolerance).

Checklist

  • I have installed pre-commit and installed the hooks with pre-commit install before creating any commits.
  • I have updated any related tests for code I modified or added new tests where appropriate. 13 new tests (6 for the concurrency utility, 7 for the resolution logic).
  • I have manually tested my changes as follows:
    • npx tsc --noEmit clean, npx eslint 0 errors/warnings, npx prettier@2.7.1 --write applied.
    • Full npx jest --runInBand: 282/282 passing, zero regressions.
    • Full npx playwright test tests/PDFGenerator.spec.ts: 4/4 passing, same timing as before this PR. That suite has no tagConsensus mock at all, so every lookup genuinely fails during the run — passing cleanly is real end-to-end confirmation of the failure-tolerance path, not just a unit-test assertion.
  • I have updated any relevant documentation or created new documentation where appropriate. (docs/proposals/proposal-b-bleed-normalization.md, docs/reports/proposal-b-pr1-bleed-prior-batch-resolution.md)

Merge-time checklist


Generated by Claude Code

claude added 3 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
@WilfordGrimley
WilfordGrimley merged commit 796b1e7 into master Jul 18, 2026
5 checks passed
@WilfordGrimley
WilfordGrimley deleted the claude/e2-bleed-prior-batch-resolution branch July 18, 2026 17:09
WilfordGrimley added a commit that referenced this pull request Jul 18, 2026
…_request+push:master

Confirmed via API (workflows/test-pre-commit.yml/runs?branch=X, total_count)
that the on:push:branches:["*"] trigger silently dropped events under this
session's high-push-volume merge sweep: zero runs ever fired on 3 confirmed
feature branches (#68, #69/#72, #70), while it fired reliably (2/2) earlier
in the session on a lower-volume branch. test-frontend.yml's on:pull_request
trigger never missed a beat under the same load. Switching to
pull_request (proper PR check) + push:branches:["master"] (covers direct
pushes to master, which this session did twice today for formatting
fixes) - dropping the wildcard branch-push trigger entirely closes both
gaps: PR branches get a reliable check, and direct-to-master pushes still
get checked too.
WilfordGrimley added a commit that referenced this pull request Jul 18, 2026
…staleness mini-pass (#79)

* publish_wiki.py: fix link rewriting for parent-relative paths and slug casing

GitHub wiki's native [[...]] auto-linking reinterprets our own docs/
[[file.md]] convention: [[../troubleshooting.md]] became a dead literal
slug, and [[printing-tags.md]] linked the raw filename casing instead of
the published page name "Printing-Tags" (both visible live on
Catalog-Completion-Plan). Every internal link is now resolved against
its source file's real repo path and mapped through
wiki-publish-map.json: a published target becomes a same-wiki link using
its real page name, an unpublished-but-real target becomes an absolute
GitHub blob URL, and a target resolving to neither is a hard publish
error. docs_lint.py can't catch this class of bug since it only checks
links within docs/ itself, not the wiki-transform's own reinterpretation
downstream - the script now self-checks at publish time instead.

Also adds two docs/ pages that were listed in docs/README.md's index
but missing from the mapping entirely (found via the new validation):
documentation-process.md and upstream-wiki-drift.md.

* Docs staleness pass: Part 3 write-pass status + proposal B/C/E-1/E-2 markers

catalog-completion-plan.md: Part 3 heading and Status section updated to
reflect the completed write pass (run_id 20260718T145157-a12b1387, 13,275
votes, all hard bounds passed, 0/7,124 zero-resolution violations at full
population), pointing to docs/reports/2026-07-18-part3-write-pass-complete.md.
Filled the dangling "see the follow-up entry below" reference and replaced
the now-stale "HOLD #P3 stands" language. Part 4's heading now notes it's
confirmed unstarted with HOLD #B prep queued.

proposal-b-bleed-normalization.md: top summary no longer lists the
prior-resolution batch fetch as remaining work - it shipped as PR-1 (#72).

proposal-g-user-accounts-saved-decks.md: noted the build-order queue
(E-1 #61, E-2 #62, Level-2 grid fix #63, audit pass #64, GIS error UX #65,
Proposal B #66/#72, Proposal C part (a) #67) has fully cleared.

docs/README.md: added proposal-b and proposal-c to the "Plans & proposals"
table - both have dedicated docs but were missing from the index entirely,
despite the section's own stated policy that any proposal with a dedicated
doc gets a row.

printing-tags.md and vote-system.md checked per the mini-pass's minimum
list; no changes needed - printing-tags.md already defers Stage 8+ status
to catalog-completion-plan.md, and vote-system.md has no AI-terminology or
merged-PR staleness.

* Report relay: wiki review findings (publish-script fix, Part 3 status, staleness mini-pass)

* CI: black-format publish_wiki.py, prettier-format cache-transition-resilience.md

black reformatting for publish_wiki.py (never run locally - only
py_compile was checked, missing the repo's black rev 22.8.0 pinned in
.pre-commit-config.yaml). cache-transition-resilience.md's prettier
drift predates this PR (introduced by #75) and is unrelated to its
content - swept here since the "Formatting and static type checking"
check runs pre-commit against all files, not just the diff, and this
PR's own CI needs to go green.

---------

Co-authored-by: Claude <noreply@anthropic.com>
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