v1.2.0 — Charts v2, print production, and the conformance channel - #26
Merged
Conversation
Tracks engine 1.7.0 (peer ^1.6.0 -> ^1.7.0) with full JSX <-> DocSpec <-> registry <-> schema parity: - Charts v2: 9 chart kinds, axis.scale log, axis2, xAxis (category/linear/ time), dataLabels, labelStride/labelRotation, series xValues/yAxis. - <Document print> sugar (+ DocSpec.print), metadata.trapped, print-dialog viewer preferences, layout.outputIntent passthrough. - PDF/A diagnostics channel reachable via layout.strict/onDiagnostic. - Lint 18 -> 25 rules; L_PRINT_BOXES delegates to the engine validator; L_CHART_CATEGORIES now skips positional axes (engine parity). - Streaming pre-flight: renderToStream runs validateDocumentStreamable eagerly so renderToResponse cannot fail mid-response. - setDeflateImpl + PdfColors re-exports; doctor() graded 1.7.0 probe. - 1.1.0 deferred backlog: cacheControl/etag on renderToResponse, ES2022 ErrorOptions cause, eslint-plugin-react-hooks, validateSpec fuzzing, PDF/UA round-trip test, coverage thresholds 90/84/92/90. - 292 tests, 3 new samples, all docs updated; release notes + PR draft + upstream issue draft (validatePdfUA vs embedded fonts) staged for human review.
The release panel (two validators + an arbiter ruling by execution) traced a disputed validatePdfUA failure to this package, not the engine: resolveFonts emitted fontRef without the leading slash, so every document rendered through the documented font path carried `BT latin 10 Tf` where ISO 32000 requires the name `/latin`. Normalize the ref; upgrade the PDF/UA round-trip to the embedded-fonts + pdfa2b configuration it previously could not pass; withdraw the upstream issue draft (no engine bug); fix the sample and test that taught the broken pattern. Also from the panel: lockfile version synced to 1.2.0, AGENTS.md golden rule 1 scoped to src/ with the sanctioned tests exception, ROADMAP quotation restored verbatim, release-artifact figures re-measured after the fixes (292 tests, coverage 95.04/89.80/97.83/95.92, tree-shake probe 3354 bytes). Rejected with reasons: dating CHANGELOG headings (breaks house anchors), strongEtag hardening (documented as change-detection by design).
…agents Port the ecosystem's most mature veraPDF setup (pdfnative-cli pattern) into pdfnative-react: a 10-file manifest-driven PDF/A corpus rendered through the built package (JSX + DocSpec doors, all four conformance targets, Charts v2 and print production under a claim, two negative canaries incl. the known engine /Helv form gap), validated by scripts/validate-pdfa.mjs (six-outcome taxonomy, fail-closed VERAPDF_REQUIRED, CVE-2024-27980 .bat quoting). Blocking CI workflow with pinned veraPDF greenfield 1.30.2 and SHA-256- verified installer; the same gate runs pre-publish before the SBOM. Fix samples/layout/page-setup.tsx: it claimed PDF/A-2b without embedded fonts — non-conformant, and invisible to L_TAGGED_NO_FONTS because the claim rides on RenderOptions.layout. Root-anchored /*.pdf gitignore for stray sample outputs. Add dry-run tier 5 to the agent contract — verifying the RENDERED output: extractText, validatePdfUA/veraPDF, and rasterize-and-look for vision-capable agents (pdftoppm/mutool, deliberately external, nothing bundled), with samples/agent/visual-verify.tsx degrading gracefully to the geometry report. Repairs docs/LINTING.md's dangling veraPDF cross-reference via a new RECIPES section; CONTRIBUTING gains the install guide and PR checklist gate.
Two fresh validators re-controlled the entire release (conformity/philosophy/ breaking changes; factuality/standards, every claim executed) and an arbiter ruled on seven residual findings: five legitimate, all documentation-level — the local veraPDF install recipe now SHA-256-checks the installer like CI, the PR draft coverage figures and sample count are exact, the knowledge base no longer overstates the tests-import exception, and the attribute-order fragility of the shared failedRules regex is recorded as an ecosystem-wide upstream follow-up. Two findings rejected with evidence (flush race: diagnostics-only with independent report files; lint TypeError premise wrong: the call sits in the rule try/catch and a stale peer fails at module load). Panel verdicts recorded in the PR draft: zero breaking changes, philosophy conformant on all eight golden rules, factual.
Rewrite the package description around what 1.2.0 actually ships — nine vector chart types, print production, veraPDF-validated tagged PDF/A, streaming responses, and the autonomous-agent surface (DocSpec, capability manifest, versioned schemas, llms.txt, self-verification loop). Grow keywords 42 -> 68, cluster-ordered: the print/charts/PDF-A vocabulary the ecosystem siblings already share, agent-discovery terms (llm, agent-tools, and the react-original docspec / capability-manifest / verapdf), platform terms (edge, serverless-pdf) and the documented react-pdf-alternative anchor. Signature/PAdES terms, MCP client names and factur-x deliberately excluded; every keyword maps to a documented capability, and nothing pins these fields (verified).
…rong First blocking veraPDF run rejected the corpus with a fatal XPASS on form-pdfa2b.pdf: the engine PDFA_UNEMBEDDED_FORM_FONT diagnostic is conservative (the AcroForm /DA merely references /Helv), but with embedded fontEntries and no field values nothing renders through /Helv, and veraPDF 1.30.2 correctly accepts the file — ISO 19005 embeds fonts USED for rendering. The validator caught our wrong expectation exactly as designed. form-pdfa2b becomes a CI-proven positive (forms + embedded fonts pass under PDF/A); a genuine negative replaces it — form-nofonts-pdfa2b.pdf, the AcroForm content path of ISO 19005-2 6.2.11.4.1, same proven-rejection class as nofonts-pdfa2b. Corpus 10 -> 11 files, still 2 negative canaries; counts swept across CHANGELOG, CONTRIBUTING, KNOWLEDGE_BASE, release notes and the PR draft, which also records the round-4 event and an upstream observation for pdfnative-mcp (same expectation, advisory gate likely masking the same XPASS; their entry renders field values so the verdict may differ).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v1.2.0 — Charts v2, print production, and the conformance channel
Summary
Tracks the
pdfnativeengine's 1.7.0 release and delivers the one capabilitythis package had promised in writing (
docs/CHARTS.md: Charts v2 "reach thispackage as new
ChartPropsfields"), plus print production, the PDF/Aconformance diagnostics channel, seven new lint rules (18 → 25), and the
quality backlog deferred from the 1.1.0 review (
cacheControl/etagonrenderToResponse,ErrorOptions/cause,eslint-plugin-react-hooks,validateSpecfuzzing, the PDF/UA round-trip test, raised coveragethresholds). No public API was removed or changed.
Install-time floors
pdfnative(peer + devDep)^1.6.0^1.7.0layout.printand the diagnostics channel do not exist before 1.7.0;ChartPropsCoversChartBlockcannot even compile against 1.6.0 typings.doctor()reports a 1.6.x engine with a dedicated upgrade message (second capability probe:validatePrintOptions).Changes
src/components.tsxChartProps+ 5 projections (axis2,xAxis,dataLabels,labelStride,labelRotation), each typed asChartBlock['…']so future inner-shapechanges absorb automatically. The
ChartTypewidening (5 → 9),axis.scaleand
ChartSeries.xValues/yAxisflowed through the existing projectionswith zero code. The
ChartPropsCoversChartBlockcompile lock forced all ofthis on peer bump — exactly its design intent; its docblock now records the
first firing.
DocumentProps.print?: PrintOptions— new sugar prop (watermark/attachmentsprecedent).
TableProps.cellVAligndocblock corrected: omitted ≠'top'(the enginekeeps its historic baseline placement; behaviour was always right, the
JSDoc was not).
src/reconciler/serialize.tscompact()(no compile-timelock covers this list — the extended golden snapshot is the guard).
resolveLayoutfoldsprintintolayout.print. Invariants re-pinned bytests: explicit
layoutwins; no sugar + no layout ⇒layout === undefined.src/spec/(types, validate, compile, schema)DocSpec.print(+KNOWN_FIELDS, forced byKnownFieldsAreExhaustive;specToElementpasses it).ChartSpecBody = ChartPropsinherited everything.union order, series
xValues/yAxis,axis.scale,axis2,xAxis,dataLabelsoneOf,labelStride≥ 1,labelRotation0–90);printon thedoc-spec schema (boxes as 4-number arrays,
userUnit1–75000,bleedexclusiveMinimum 0);
metadatadescription namestrapped; render-optionslayout description enumerates
print/outputIntent/strict/onDiagnosticand the four new viewerPreferences keys, with the explicit note that
onDiagnosticis function-valued and JSON-unrepresentable (strict: trueis the JSON-safe switch). Link/svg opts descriptions completed
(
fontSize/color,alt) after the exhaustiveness audit.outputIntent,strict,onDiagnosticare NOTDocSpec top-level fields — non-JSON or niche; they remain reachable through
the
layoutpassthrough. Every added top-level field is permanent API.src/registry.ts+src/lint.ts(18 → 25 rules)L_CHART_LOG_SCALE,L_CHART_X_AXIS,L_CHART_LABELS(errors) — everyCharts v2 constraint verified against the engine's
validate()inpdf-chart.ts, reported pre-render.L_CHART_CATEGORIESnow skipspositional-axis charts (mirrors engine 1.7.0 exactly — the old behaviour
would have been a false positive).
L_PRINT_BOXES(error) — delegates to the engine's ownvalidatePrintOptions(with the engine's realPG_W/PG_Hdefaults) in atry/catch; the finding carries the engine's message verbatim. Zero
duplicated geometry rules, zero drift, by construction.
L_VIEWER_PRINT_RANGE(error),L_OUTPUT_INTENT_IGNORED(warning — theengine silently ignores
outputIntentwithouttagged),L_TAGGED_FORM_FONTS(warning — mirrorsPDFA_UNEMBEDDED_FORM_FONT).xAxis" (does notthrow — scatter defaults to a linear axis; verified in engine source),
"
axis2without a right-bound series" (silently ignored, harmless), "CMYKimage under PDF/A" (would require parsing JPEG bytes in a pure linter; the
engine's
PDFA_DEVICE_CMYK_IMAGEdiagnostic covers it at render time).src/render.ts+src/response.ts<TableOfContents>and{pages}templates on its streaming path, butchecked inside the generator —
renderToResponse(streaming by default)failed mid-response, after status and headers were sent.
renderToStreamnow calls the engine's
validateDocumentStreamableeagerly; all streamingentries throw catchably at call time. Two regression tests pin it.
renderToResponse: opt-incacheControlandetag(string verbatim, ortrueto derive a strong FNV-1a validator from the bytes — impliesbuffering). Defaults byte-identical when unset.
src/doctor.ts,src/manifest.ts,src/core-bridge/index.ts,src/index.tsREQUIRED_ENGINE = '1.7.0'; graded probe (validatePrintOptions→ ok;estimateChartHeightonly → "1.6.x — this release needs >= 1.7.0"; neither→ missing/older).
contract.engine: '^1.7.0'; new manifest entrypointsetDeflateImpl.validatePrintOptions(probe + lint delegate),PG_W/PG_H,validateDocumentStreamable,setDeflateImpl; −buildDocumentPDFStream(imported since 1.1.0, used nowhere — dead surface in the "small, auditable
slice"). New type re-exports:
PrintOptions,PrinterMarksOptions,PageBox,CustomOutputIntent,PdfDiagnostic,PdfDiagnosticCode,PdfDiagnosticHandler,PdfColors.setDeflateImpl(closes the browser-compression asymmetry withinitNodeCompression) and the eight new types.src/errors.ts,src/hooks.ts,eslint.config.jsPdfReactError/PdfStructureErroraccept ES2022ErrorOptions(
error.causereachable; JSON envelope unchanged — asserted key-exact by atest).
eslint-plugin-react-hooks@7(recommended-latest, flat config). Its twonew rules flag the deliberate latest-value-ref and loading-flag patterns in
hooks.ts; each of the four sites carries a per-siteeslint-disable-next-linewith the reason, keeping the rules armed forfuture code instead of a rule-wide opt-out.
scripts/generate-pdfa-corpus.mjs+scripts/validate-pdfa.mjs+.github/workflows/verapdf.yml(new)implementation (
pdfnative-cli): an 11-file manifest-driven corpus renderedthrough the built package (9 positives across pdfa1b/2b/2u/3b through
both authoring doors, incl. Charts v2 dual axis, print production, and a
form with embedded fonts; 2 negative canaries — plain text and the AcroForm
content path, both without embedded fonts, ISO 19005-2 §6.2.11.4.1).
Runner: strict single-
<validationReport>parsing,6-outcome taxonomy, fail-closed
VERAPDF_REQUIRED=1,.bat-through-shellquoting (CVE-2024-27980), raw-report artifacts. CI blocking (user
decision; engine/CLI precedent), pinned veraPDF greenfield 1.30.2 with
installer SHA-256 verified before
java -jar; the same gate runspre-publish in
publish.ymlbefore the SBOM.samples/layout/page-setup.tsxfixed: it claimed PDF/A-2b without fonts —non-conformant, and invisible to
L_TAGGED_NO_FONTS(claim viaRenderOptions.layout). Now embeds Noto Sans and documents the blind spot..gitignore: root-anchored/*.pdffor stray sample outputs.Tier 5 — visual verification for vision agents (new)
docs/AGENT_CONTRACT.mdgains the post-render tier (extractText→validatePdfUA/veraPDF → rasterize + look);docs/RECIPES.mdgains thematching recipe (also repairing
docs/LINTING.md's dangling veraPDFcross-reference);
llms.txtdocuments it for agents;samples/agent/visual-verify.tsxruns it end to end with gracefuldegradation to the tier-4 geometry report when no rasterizer
(
pdftoppm/mutool) is installed. No dependency added — the rasterizer isdeliberately external.
npm discovery metadata (
package.json)descriptionrewritten for the 1.2.0 surface (charts, print production,veraPDF-validated PDF/A, the agent surface);
keywords42 → 68, cluster-ordered — the ecosystem's shared print/charts/PDF-A vocabulary plus
agent-discovery terms (
llm,agent-tools, and the react-originaldocspec/capability-manifest/verapdf), and the documentedreact-pdf-alternativeanchor. Deliberately excluded: signature/PAdESterms (authoring-only boundary), MCP client names (a library is not a
server),
factur-x(no dedicated recipe). Nothing pins these fields(verified); every keyword maps to a documented capability.
Version plumbing
src/version.ts→ 1.2.0;package.json;CITATION.cff(+date-released: 2026-08-26). Governance spec (.github/ai-governance.json/governance.ts)stays at 1.1.0 deliberately: the policy content is unchanged, and bumping
a spec version without changing the spec is drift in the other direction.
Samples & tests
samples/charts/charts-v2.tsx(8 charts: stacked, area, scatter, time axis,dual axis, log scale, data labels, label rotation),
samples/layout/print-production.tsx(bleed + marks,trapped, duplex /printPageRange / numCopies),
samples/quality/diagnostics.tsx(onDiagnostic collector,
strictthrow, and the lint tier side by side),and
samples/agent/visual-verify.tsx(the tier-5 visual loop, describedbelow).
samples/README.mdrows added.DocSpec parity, real renders for all four new kinds + time/log/dual-axis),
print sugar folding +
layout === undefinedre-pinned, one assertion pernew lint rule (with clean-case counterparts and the positional-axis
regression), cache-validator behaviour (deterministic ETag, merge-last),
causein-process but out of the envelope, streaming pre-flight, extendedgolden snapshot (+81/−6, the diff read before
-u), newtests/fuzz-validate.test.ts(seeded PRNG, 700 malformed/mutated inputs,never-throws + well-formed reports), new
tests/pdfua.test.tsx(rendertagged → engine
validatePdfUA→ no violations; the 1.1.0-deferredround-trip).
95.0/89.8/97.8/95.9).
Docs & governance
src/fonts.ts— correctness fix found by the panel (see round 2):resolveFontsemittedfontRefwithout the leading slash; the enginewrites it verbatim into content streams as a PDF name, so every document
produced through the documented font path (
resolveFonts/options.fonts) was malformed (BT latin 10 Tf). Now normalized(
/-prefix), with the sample and test expectations updated and the PDF/UAround-trip upgraded to the embedded-fonts configuration it originally
could not pass.
README.md(component table, page-furniture section, "Upgradingto 1.2"),
llms.txt(full 1.2.0 surface, 25-rule table, streamingrestriction, setDeflateImpl),
docs/CHARTS.md("Charts v2 — a promisekept"),
docs/LINTING.md(25 rules, the diagnostics channel as "tier 4½"),docs/SERVER.md("What cannot stream", caching),docs/KNOWLEDGE_BASE.md(probes, test map, design boundaries incl. the newly-written table-builder
exclusion rationale),
docs/AGENT_CONTRACT.md,docs/RECIPES.md(PAdESLTV pointer),
ROADMAP.md(1.2.0 shipped; fixed the stale "five" count),CLAUDE.md,.github/copilot-instructions.md.release-notes/v1.2.0.md+ this draft.validatePdfUAwas preparedduring test-writing and withdrawn in round 2: the panel's factuality
validator could not reproduce it, and the arbiter proved by bisection that
the failure was this package's own
fontRefbug (above). There is noengine bug to report.
Validation
Adversarial review
Round 1 — two independent exhaustiveness audits (blind to each other)
Audit A walked the engine's 445-export barrel down; audit B walked every
parity chain (JSX ↔ DocSpec ↔ schema ↔ manifest) field-by-field up. B's
verdict: parity complete, two cosmetic schema-description gaps. A's verdict:
"not exhaustive — narrowly", eight findings. All fixed or dispositioned:
<TableOfContents>/{pages}inside the generator — breaksrenderToResponsemid-response, undocumented (A)validateDocumentStreamableinrenderToStream; documented in SERVER.md, llms.txt, JSDoc (the "feature-equivalent" claim corrected); 2 regression testssetDeflateImplunreachable — browserlayout.compresssilently produced larger output (A)buildPDF/PdfParams) excluded without recorded rationale (A)PdfColorsnot re-exported whilelayout.colorsis documented (A)cellVAlignJSDoc claimed default'top'; engine keeps historic baseline (A)RenderOptions.fontsJSDoc omittedrenderToResponsefrom the honored list (A)alt; link opts omittedfontSize/color(A + B, independently)buildDocumentPDFStream(A)Rejected findings, with reasons:
buildDocumentPDF(string twin),buildDocumentPDFStreamPageByPage,wrapText,PAGE_SIZES, font-registry introspection helpers (A: "not-findings")tickstointeger >= 2(B, cosmetic)validateSpecdoes not enforce it (opts objects stay open).Round 2 — post-implementation panel: conformity/standards, factuality, and an arbiter
Two independent validators (one on conformity and OSS/industry standards, one
on factuality — every claim executed, not read), then a third agent arbitrated
the legitimacy of every finding, resolving the one head-on contradiction by
execution and bisection.
The headline: the factuality validator could not reproduce the upstream
validatePdfUAbug the test-writing pass had reported (and drafted an issuefor), while the original observation demonstrably happened. The arbiter ran
both sides' reproductions and proved a third explanation: the engine has no
bug — this package's
resolveFontsemittedfontRefwithout the leadingslash, so every document rendered through the documented font path was
genuinely malformed (
BT latin 10 Tf— a keyword where ISO 32000 requires aname). The validator was the messenger. One bisection table settled it:
fontRef: '/F3'valid,'latin'invalid,'/latin'valid,'F3'invalid.resolveFontsnormalizesfontRef; issue draft withdrawn (no engine bug); pdfua test upgraded to the embedded-fonts +pdfa2bconfiguration and its docblock rewritten; sample + test expectations updated; CHANGELOG entry with re-render guidancerelease/v1.2.0before round 2 closed (this table lands as its own commit)package-lock.jsonroot version still 1.1.0 (conformity)src/and names the tests exception## [x.y.z] — tagline; dating only 1.2.0 would be inconsistent and break the GitHub anchors the release notes link to. If dates are ever wanted: all headings + both anchors in one housekeeping change, not mid-release.strongEtagis FNV-1a, not cryptographic (conformity)Round 3 — full-release control panel (post-veraPDF/vision work)
Two fresh validators re-controlled the entire release (all three commits):
validator A on conformity, project philosophy and breaking changes; validator
B on factuality (every claim executed, both ports diffed against their
pdfnative-cli source) and 2026 OSS standards. A third agent arbitrated.
Verdicts: A — zero breaking changes (the two judged cases: the
resolveFontsbyte change corrects spec-violating output and is disclosedwith a re-render note; new lint rules add at most a warning on pre-existing
documents,
report.okpreserved) and philosophy conformant on all 8 goldenrules. B — factual: both ports are logic-identical to the CLI originals
(prose-only deltas), the SHA-256 pin matches byte-for-byte, fail-closed
behaviour was executed and confirmed (exit 3 under
VERAPDF_REQUIRED=1without veraPDF), and the corpus/canaries behave exactly as documented.
sha256sum -cline added — local and CI now verify the same pinned artefactvisual-verify.tsxnamed in the bulletfailedRulesregex in the validator is attribute-order-dependent (A)pdfnative-clifirst, re-port everywhere).2> >(tee …)flush race in the workflow (A)PIPESTATUS; per-file stderr is independently written and uploaded; identical construct runs in production upstream CI.L_PRINT_BOXEScould surface a raw TypeError on a 1.6.x peer (A)doctor()reports it).Round 4 — first blocking CI veraPDF run: the XPASS guard fired, and was right
The very first CI run of the new gate failed with
XPASS form-pdfa2b.pdf (negative canary ACCEPTED)— exactly the fatal guardworking as designed, against us: the manifest's expectation was wrong,
not the validator. Analysis: the engine's
PDFA_UNEMBEDDED_FORM_FONTdiagnostic is conservative — it fires because the AcroForm
/DAreferences/Helv— but in this corpus entry (embeddedfontEntries, no field values)no text actually renders through
/Helv, so veraPDF 1.30.2 correctly acceptsthe file. ISO 19005 requires embedding for fonts used for rendering.
Resolution:
form-pdfa2b.pdfbecame a positive (empirically CI-proven,and now valuable coverage: forms + embedded fonts pass under PDF/A), and a
genuine negative replaced it —
form-nofonts-pdfa2b.pdf(form + text with noembedded fonts, the AcroForm content path of §6.2.11.4.1, same
proven-rejection class as
nofonts-pdfa2b). Corpus 10 → 11 files, still 2negative canaries; all counts swept.
Upstream observation for
pdfnative-mcp: its corpus carries the sameform-pdfa2b/expectCompliant: falseexpectation ("veraPDF reports6.2.11.4.1") that this CI run disproved for the no-values case — and its
veraPDF workflow is advisory (
continue-on-error), so an XPASS there wouldcurrently pass unnoticed. Worth re-checking when mcp's gate goes blocking;
note their entry fills field values through
/DA /Helv, which may genuinelyrender through the unembedded font — the verdict may legitimately differ.
Backward compatibility
^1.6.0→^1.7.0doctor()explains at runtime. Not an API change.renderToStreamvalidates streamability eagerlyetag: trueimplies buffering/ToUnicode, x-label stride)layout === undefinedinvariant re-pinned; golden snapshot diff reviewed).Out of scope (by design)
PdfModifier.updateMetadata,form fill/flatten, merge/split, extraction — byte-level post-processing
(golden rule 7);
docs/RECIPES.mdpoints at the engine, now including theLTV ladder.
"Later" (user decision on this release's scope).
Nizoka/pdfnative:docs/assets/ecosystem.json(packages.pdfnative-react.version/pin) anddocs/data/surfaces.jsonReact cells must move to 1.2.0 /^1.7.0as partof the engine repo's release train, or its
verify:docswill fail.Optionally, an ergonomics suggestion for the engine: validate or normalize
fontRefformat at the API boundary, so a missing slash fails loudlyinstead of corrupting output.
failedRulesregex (here,pdfnative-cliandpdfnative-mcp— all verbatim ports of the sameoriginal) assumes veraPDF's
<rule>attribute order; harden it upstream inpdfnative-clifirst, then re-port, so the three repos stay identical.Self-review checklist
pdfnativeimports only viasrc/core-bridge/index.ts;src/types.tstype-only; peer dependency intact (test-pinned).<Section>remains the onlytag: nullentry);printis a prop, not a component, because it is page furniture.react-reconciler@^0.31/@types@^0.32).any; lint green including the new hooks plugin.'use client'only via the client subpath;src/spec/stays pure; postbuild asserts both directions.src/version.tsbumped; version triple +$ids test-pinned.verify:issuepasses; no autonomous GitHub writes occurred.Compliance report
no_new_runtime_dependency_confirmeddependenciesis still exactly["react-reconciler"](test-pinned).eslint-plugin-react-hooksis a devDependency.reproduction_commandnpm run typecheck:all && npm run lint && npm test && npm run buildreproduction_resultduplicate_search_performedaffected_packagespdfnative-react(this repo). Follow-ups noted forpdfnative(ecosystem manifest, surfaces.json — doc alignment only; no engine bug).identity_reminder_shown