chore(canary-phase5): pdf generator complete
Phase 5 ships the fourth generator in the canary registry. PDF canary tokens are produced by in-place byte-replacing a 76-char fixed-width placeholder in a committed template.pdf — the placeholder occupies a direct dictionary value in the page's /AA /O /URI action (uncompressed, not inside any Flate stream), so substitution preserves byte length and keeps the cross-reference table valid. Implementation commits in this phase: -c9c93332feat(canary): pdf template (binary blob + build helper) -13cd6cd1feat(canary): pdf generator (byte-replace fixed-width URI action) -73dd8373feat(canary): register pdf generator in registry Deliverables: - 477-byte committed template.pdf (sha256 70c63590…7e103), reproducible via go run ./cmd/buildpdftemplate -out ... (rebuild produces byte- identical output) - cmd/buildpdftemplate hand-builds the PDF-1.4 with computed xref byte offsets, validates via pdfcpu.api.Validate before writing - pdf.Generator: ErrTriggerURLTooLong sentinel, length-preservation guard, post-substitution bytes.Contains check, _ underscore padding (handoff overrides spec §9.4 line 1150 space padding — see anti- relitigation set), defaultFilename fallback for nil/empty/whitespace *string Filename - 22 top-level tests + 11 IP-precedence subtests + 4 filename subtests + 3 trigger-URL subtests = ~40 effective cases under -race. All 5 spec-required tests present (LengthUnchanged, ContainsTriggerURL, PlaceholderRemoved, TooLongURL_ReturnsError, PdfcpuValidates) plus template-invariant + boundary + same-position regression guards - Registry expanded 3 → 4; pending list shrinks to {kubeconfig, envfile, mysql} Audit outcome (2 agents in parallel per standing pattern): - superpowers:code-reviewer: PASS (0 BLOCKER, 0 SHOULD-FIX, 5 NITs all flagged by the agent as "not actionable" / "leave as-is") - general-purpose spec-adherence vs §9.4 + §8.5: PASS (0 BLOCKER, 0 SHOULD-FIX, 2 NITs: N1 was a miscount — pdf has 11 IP precedence subcases identical to docx, verified via grep; N2 was the Chromium/PDF.js /AA-stripping caveat, sanctioned-deferred to learn/04-CHALLENGES.md per the post-Phase-17 learn/ allowance) No audit-fix commit needed this phase — zero actionable findings. Unlike Phase 3 (a46fa446) and Phase 4 (10ae118d) which cleared real findings before rollup, Phase 5 lands clean. Pre-rollup acceptance gates clean at HEAD 73dd8373: - go build ./... + go vet ./... clean - go test -race -timeout=60s ./... — all packages pass - go test -tags=integration -race -timeout=300s ./internal/token/... ./internal/event/... — all pass - golangci-lint run ./... → 0 issues. - grep -rn "//nolint" --include="*.go" returns nothing (lint discipline inherited from Phase 0 supplement preserved) - BACKLOG.md open section still _(none)_ Forward state for Phase 6 (kubeconfig generator): different shape from file-artifact generators — kubeconfig is YAML text + a path-based /k/{id}/* handler that records kubectl method/path/UA and responds with a Kubernetes-shaped 403. Trigger pattern departs from the /c/{id}+GIF convention webbug/slowredirect/docx/pdf share.
This commit is contained in:
parent
73dd837362
commit
2856e2444f