Skip to content

pdfnative-mcp 1.6.0 ecosystem alignment + 1.7.0 conformity audit - #76

Merged
Nizoka merged 15 commits into
mainfrom
docs/mcp-1.6.0
Aug 25, 2026
Merged

pdfnative-mcp 1.6.0 ecosystem alignment + 1.7.0 conformity audit#76
Nizoka merged 15 commits into
mainfrom
docs/mcp-1.6.0

Conversation

@Nizoka

@Nizoka Nizoka commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Documentation PR — pdfnative-mcp 1.6.0 ecosystem alignment + 1.7.0 conformity audit

Scratchpad for the GitHub PR description. Gitignored (RELEASE_PR_*.md).
Branch: docs/mcp-1.6.0main. Open as draft.

Title

docs: align documentation with pdfnative-mcp 1.6.0 (28 tools, PAdES ladder, MCP 2026-07-28) + full 1.7.0 conformity audit and Open Graph refresh

Summary

This is a documentation-only branch. No src/ product changes, no version bump, no CI changes, no new dependency, no touched fonts or generators. (One docs-infrastructure test, tests/docs/verify-docs.test.ts, updates its hard-coded stale-token canary from the old canonical 24 tools to the new 28 tools — a required consequence of the manifest bump, so the perturbation test keeps testing a live value.)

Two workstreams:

A. MCP 1.6.0 alignment — the entire documentation surface follows the pdfnative-mcp 1.6.0 release (2026-08-23), along five axes:

  1. Source of truth firstdocs/assets/ecosystem.json bumps pdfnative-mcp to 1.6.0 / pin ^1.7.0 / toolCount: 28 (+ add_ltv, timestamp_pdf, update_metadata, inspect_layout) / six prompts, and the mcp-tool-count assertion canonical moves to "28 tools". versions.js offline fallbacks follow (incl. the stale pdfnative 1.6.0 engine fallback → 1.7.0).
  2. Core docs — the MCP guide gains four new tool sections, a 10-variable environment table with the operator network charter (TSA / OCSP / CRL egress class behind an SSRF guard), the six-prompt table, the v1.6.0 error codes, full-engine-coverage notes on generate_basic_pdf (13 block kinds, layout, build-time encrypt, print production, honest PDF/A, creationDate), PAdES guidance on sign_pdf, and a "What's new in v1.6.0" release-history entry with the six migration notes. README, llms.txt (root + docs/ copy, byte-identical), AGENTS.md, ROADMAP.md, onboarding, architecture and agentic-workflows follow.
  3. Site + SEO — landing page #mcp section at 28 rows, JSON-LD softwareVersion: "1.6.0" on both the landing page #mcp node and the playground about node (the latter is a manual bump — no @id), guide/learn/playground blurbs, architecture.svg desc + MCP box at "28 tools", ocsp / crl keywords on the landing page, sitemap.xml lastmod 2026-08-25 on the 13 touched pages, llms-full.txt regenerated via npm run docs:llms.
  4. Playground — two new runnable cards on the MCP explorer: update_metadata (real openPdfcreateModifierupdateMetadatasave incremental pipeline) and inspect_layout (real inspectDocumentLayout dry run, printing the pagination JSON in place — a new runJson card variant since the tool produces no PDF). add_ltv / timestamp_pdf are documented as deliberately card-less (operator-configured network providers a browser page cannot supply). Coverage restated as eleven of 28 tools without a card; stale card blurbs refreshed.
  5. Fixed in passing — three pre-existing inconsistencies: onboarding.md said "v1.4.0 ships 24 tools", ROADMAP.md said "Built on pdfnative 1.6.0 as of v1.5.0", the playground intro stopped at v1.4.0; plus one stale claim in the MCP guide ("RFC 3161 timestamp validation is … not part of this server" — false since 1.6.0) and the renamed SDK package on responsibility.html (@modelcontextprotocol/sdk@modelcontextprotocol/server).

B. 1.7.0 conformity audit — a cross-verified audit (two auditors + one verification pass) of every root doc and every /docs page against pdfnative 1.7.0 and pdfnative-mcp 1.6.0 ground truth, catching what the 17 verify-docs rules do not cover:

  1. Open Graph card regenerated. The served og-image.png had never been re-rasterised since the v1.4.0 docs audit (git history proof: PNG last touched at 52cbbdd, SVG edited later in f88c3b0) — every social card still advertised the pre-1.6.0 feature line. The SVG subtitle now names the 1.7.0 headliners (LTV Signatures, Print Production) and the PNG was re-captured headless at 1200×630 per the procedure in the SVG header comment. playgrounds/charts.html was the only page missing og:image:width/height — fixed.
  2. Factual corrections (MUST). Stale counters in AGENTS.md (2664→2665 tests, 241→242 PDFs) and .github/instructions|prompts (2396+/105→2665+/122, 44→48 generators); SECURITY.md supported-versions table (1.7.x/1.6.x) and signature algorithms (RSA SHA-256/384/512); the vanished MIRROR_MAP symbol replaced by BIDI_MIRRORING_PAIRS (428 UCD pairs); four selectable signature algorithms in ROADMAP/pdf-core instructions; ETSI.CAdES.detached/ETSI.RFC3161 in the compliance-audit prompt; the no-JS Library badge (v1.6.0→v1.7.0); "26 reference guides"→28 on the learn pages; two "nine chart types" enumerations that listed seven labels; ltv.md and responsibility.html mischaracterising pdfnative-cli verify (full cryptographic verification; OCSP/CRL only behind --revocation online; no TSA contact) and the now-broken grep proof (v1.7.0 provider JSDoc @example blocks); charts cards/metas frozen at five kinds/v1.6.0.
  3. Engine-version over-propagation. cli.md, react.md, mcp.md's v1.5.0 history, README's CLI v1.3.0 / MCP v1.5.0 lines and llms.txt claimed "built on pdfnative 1.7.0" for packages published against the 1.6 engine (CLI 1.3.0 and React 1.1.0 pin ^1.6.0; MCP 1.5.0 shipped on pdfnative 1.6 per its own release notes). Restated as "the pdfnative 1.6 engine (pins ^1.6.0, semver-accepts 1.7.0)" — regex-safe for the version-token rule without suppressing it.
  4. 1.7.0 omissions (SHOULD). Guide-index cards and HTML shell metas for signatures/emoji/PDF-A/CLI updated to the current release; landing page gains print production (feature grid + #library JSON-LD + footer links to print.html/ltv.html) and the emoji-sequences line; four guides gain their 1.7.0 note (form-filling /ToUnicode byte-change, text-extraction coverage, pdf-manipulation page-box survival, accessibility declaration guards); api-design/pdfa-conformance/copilot agent instruction files catch up with the 1.7.0 API surface.
  5. Manifest hardening. The test-count-homepage canonical read "665+ tests across 122 files" (dropped leading 2) — corrected so the assertion can catch the drift class it exists for.

Deliberately not changed (audited and rejected): comparison-2026-07-28.json (honest self-dated snapshot), the benchmarks date, "95%+ measured at v1.6.0" coverage statements (exact as written), a chart preset in app.js (feature work), and the toolkit playground's 1.4.0→1.6.0 framing (describes its actual coverage).

C. Adoption showcase (Waves 1+2 of the docs-evolution study) — a strategist/verifier study (2 analysts + 1 arbitration pass) of how /docs can drive organic adoption for humans AND AI agents, then implemented in full:

  1. Every guide pre-rendered server-side. The 30 guide shells used to serve "Loading…" to any fetcher that does not execute JavaScript (most AI crawlers); scripts/build-guides.ts now bakes the rendered article + server-side TechArticle/BreadcrumbList (FAQPage for the FAQ) JSON-LD with dateModified, deterministic GitHub-convention heading ids and visible anchors (heading ids had never actually existed — marked ≥ 5 dropped them), policed by the guide-render-sync rule. guide.js keeps runtime rendering as a fallback and adds copy buttons + a "Copy page as Markdown" bar.
  2. Machine surface. llms-index.json (per-page URLs/anchors/sizes), agent-brief.md (paste-into-context pack with the six verified pitfalls), assets/api.json (445 exports derived from src/index.ts — the substitute for the gitignored index.d.ts), data/surfaces.json (capability × surface matrix), data/errors.json (engine diagnostic registry), llms-recipes.txt; llms.txt/robots/sitemap now reference all of it, incl. the 30 raw .md URLs.
  3. Executable documentation. recipes/ — 14 standalone TypeScript recipes importing only from pdfnative, executed in CI with every @expect assertion verified by the engine's own readers (16 tests).
  4. The demo becomes a proof. Split view with inline PDF preview (auto-renders on scroll-into-view), real ES-module execution via Blob URLs (genuine imports, real error line numbers), a JSON DocumentParams mode with "Copy as CLI command / MCP call", data-only #doc= share links (CompressionStream + defensive decode — never code), and a run-it-on-your-device benchmark under .bench-live-* classes.
  5. Tenth playground inspect.html — drop any PDF and read a full report (openPdf/extractText/validatePdfUA/listSignatures/readFormFields) entirely client-side, with the verifiable network claim and honest caveats; full parity paid (switchers ×10, ItemList, counters, sitemap).
  6. Two new guideschoose (surface decision tree + matrix) and self-verify (the generate→inspect→assert→correct loop) — guide count 28 → 30.
  7. Five new verify-docs rules (17 → 22): guide-render-sync, llms-index-sync, api-json-sync, anchor-parity (which immediately caught really-broken deep links), error-parity — plus an api-exists graduated from ~4 watched identifiers to the whole documented surface (it caught four rotten internal names in the agent instruction files). Each new rule has a perturbation test.

D. Triple review + fixes — three user-reported UI bugs plus a three-auditor review (factuality / front-end / engineering-CI) with an arbitration pass, all confirmed findings fixed:

  1. User bugs: the live benchmark crashed on missing required PdfParams fields (params completed; engine boundary guard deferred to an engine PR to keep this branch docs-only); "Copy link" was hidden behind the preview (three stacked causes: no flex-wrap, 382px panes, and [hidden] defeated by author display rules — global [hidden]{display:none!important} added); the re-encrypt example previewed an encrypted PDF, cramming the viewer's password prompt into a half-width iframe (declarative encryptedOutput flag → honest note + Download, excluded from autorun, /Encrypt tail-sniff as safety net).
  2. Review blockers: the demo's mode buttons reused .tab-btn and clicking "JSON" emptied the homepage Examples section (tablist scoped, mode switch is now an aria-pressed group); api.json attributed each module's banner comment as every export's summary — 77 distinct summaries for 445 exports (tempered regex → 389, all distinct); llms-index.json measured working-tree sizes (CRLF-inflated on Windows clones) — now LF-normalised content bytes.
  3. Factuality: metadata also takes trapped (v1.7.0); the invoice recipe used the reserved /F1 its own docs forbid (→ /F3); test count re-measured at 2686 tests / 123 files and updated everywhere incl. the self-validating canonical; README said "nine" playgrounds; missing since annotations added (validatePdfUA 1.3.0, addSignaturePlaceholder 1.2.0, <Chart> react 1.1.0); dateModified removed from guide JSON-LD (a false date is worse than none — git dates are unavailable to the CI's shallow checkout); FAQPage now serialises table-only answers (25/25 questions); the "22 scripts with real OpenType shaping" phrasing tightened to the ten shaped scripts.
  4. Responsive/a11y majors (phantom preview pane on mobile, touch-visible copy buttons with 24px targets, 2s layout shift on pre-rendered guides, inspect theme/aria/honest-tally fixes, mcp.html 360px overflow, desktop-only autorun, permalink race + scroll, guarded clipboard helper) and ~15 minors (print stylesheet, chunked #doc= inflation cap, link-URL scheme validation, drop-outside guard, dark-theme banners…).
  5. Infra hardening: digit-initial anchors now policed (11 real links), sandbox copies recipes/ + an "unperturbed sandbox is clean" control test (the negative tests were vacuous without it), docs.yml triggers cover the new inputs, one shared slugger, error-parity three-directional, exact-path isMain, $-safe JSON-LD injection, unknown-derived-key guard, recipes scanned directly by the corpus (22 rules across 129 files). Docs suites 40/40.

Ground-truth facts (verified)

All MCP facts were verified against the local D:/Github/pdfnative-mcp source (package.json, release-notes/v1.6.0.md, src/server.ts).

pdfnative-mcp 1.6.0 (released 2026-08-23)

  • 28 tools (+4 vs 24): add_ltv (PAdES B-LT, /DSS + /VRI), timestamp_pdf (B-LTA, /DocTimeStamp), update_metadata (incremental /Info + XMP), inspect_layout (pagination dry run) — src/server.ts TOOLS registry, 28 entries.
  • 6 MCP prompts (+4): pades_ladder, print_ready, reproducible_output, pdfa_valid join governance_contract, draft_issue_workflowsrc/server.ts l.1236-1268.
  • 10 operator environment variables (+7): HTTP_TOKEN, MAX_INFLATE_BYTES, TSA_URL, TSA_AUTH, REVOCATION, NETWORK_ALLOWED_HOSTS, NETWORK_TIMEOUT_MS join OUTPUT_DIR, CACHE_DIR, PORT (plus the deprecated PDFNATIVE_MPC_OUTPUT_DIR alias).
  • Engine pin pdfnative ^1.7.0 (was ^1.6.0); SDK @modelcontextprotocol/server ^2.0.0 + zod ^4.2.0 (still three runtime dependencies); Node ≥ 22; MCP spec 2026-07-28 with automatic 2025-era fallback.
  • 13 block kinds in generate_basic_pdf; charts v2 (9 types); build-time encrypt on 7 document tools (keeps the AcroForm); print production (print, metadata, outputIntent); honest PDF/A (embedFonts / strict / includeDiagnostics); network charter: no egress by default, single permitted class = operator-configured TSA / OCSP / CRL, never a URL from a tool argument.
  • Not shipped (not announced anywhere in this branch): redact_pdf, telemetry, per-page HTTP streaming.

Terminology guard

  • "28 tools" is the new canonical (literal string required in the five requireIn files by canonical-present).
  • The MCP surface counts 25 lang codes (22 shaping scripts + latin + emoji + math); the engine canonical "22 scripts" is untouched (script-count assertion, expect 22). The server's own "24 scripts" phrasing is never quoted verbatim, to avoid colliding with that assertion.
  • Historical totals (12 / 17 / 19 / 24 tools) stay in release-history prose under verify-docs:allow stale-token (historical: …) markers, per house style.

Files touched (~45)

  • Manifest / infra: docs/assets/ecosystem.json (version bump + mcp-tool-count canonical + test-count-homepage typo), docs/assets/versions.js, tests/docs/verify-docs.test.ts (canary follows the canonical)
  • Open Graph: docs/assets/og-image.svg, docs/assets/og-image.png (regenerated), docs/playgrounds/charts.html
  • Core docs: docs/guides/mcp.md, README.md, llms.txt, docs/llms.txt, AGENTS.md, ROADMAP.md, SECURITY.md, docs/guides/onboarding.md, docs/guides/architecture.md, docs/guides/agentic-workflows.md, docs/guides/cli.md, docs/guides/react.md, docs/guides/ltv.md
  • Agent files: .github/copilot-instructions.md, .github/instructions/{testing,pdf-core,text-shaping,api-design,pdfa-conformance}.instructions.md, .github/prompts/{quality-gate,compliance-audit}.prompt.md
  • Site: docs/index.html, docs/guides/{mcp,index,charts,signatures,pdfa,cli,colour-emoji}.html, docs/learn/{index,08-next-steps}.html, docs/playgrounds/{index,charts}.html, docs/responsibility.html, docs/assets/architecture.svg, docs/sitemap.xml, docs/llms-full.txt (generated)
  • Playground: docs/playgrounds/mcp.html (two new runnable cards + refreshed blurbs)
  • Cross-cutting guides: docs/guides/{signatures,pdfa,ai-governance,form-filling,text-extraction,pdf-manipulation,accessibility}.md

Checklist

  • npm run verify:docs passes — 17 rules across 109 files, source of truth verified 2026-08-25
  • npx vitest run tests/docs/verify-docs.test.ts — 18/18
  • docs/llms-full.txt regenerated via npm run docs:llms (never hand-edited)
  • llms.txtdocs/llms.txt (byte-identical, llms-sync)
  • JSON-LD softwareVersion bumped in both blocks (landing #mcp via jsonld-version; playground about manually)
  • og-image.png regenerated at 1200×630 from the updated SVG (headless Chromium screenshot, per the SVG header procedure; no tooling committed) and visually verified
  • sitemap.xml lastmod = 2026-08-25 on touched pages only, never in the future
  • No src/ product change, no package.json change, no workflow change, no new dependency
  • Playground module scripts pass node --check (playground-syntax); CDN imports stay pinned to pdfnative@1.7.0 with SRI-pinned Prism

Nizoka added 13 commits August 25, 2026 12:55
…r, MCP 2026-07-28)

Bump the ecosystem manifest (single source of truth) to pdfnative-mcp 1.6.0:
version, pin ^1.7.0, toolCount 28 (+ add_ltv, timestamp_pdf, update_metadata,
inspect_layout), six prompts, and the mcp-tool-count assertion canonical
"28 tools". versions.js fallbacks follow (incl. the stale pdfnative 1.6.0
engine fallback, corrected to 1.7.0).

The MCP guide gains four new tool sections, the 10-variable environment
table with the operator network charter (TSA / OCSP / CRL egress class,
SSRF guard), the six-prompt table, the v1.6.0 error codes, the 13 block
kinds / layout / build-time encrypt / print production / honest PDF/A
coverage on generate_basic_pdf, PAdES guidance on sign_pdf, and a
"What's new in v1.6.0" release-history entry with the six migration notes.
The stale claim that RFC 3161 validation was "not part of this server" is
corrected — verify_pdf now validates /DocTimeStamp tokens.

README, llms.txt (root + docs copy, byte-identical), AGENTS.md, ROADMAP.md,
onboarding, architecture and agentic-workflows follow the manifest. Two
pre-existing inconsistencies are fixed in passing: onboarding said "v1.4.0
ships 24 tools" and ROADMAP said "Built on pdfnative 1.6.0 as of v1.5.0".
All MCP facts verified against the local D:/Github/pdfnative-mcp source
(package.json, release-notes/v1.6.0.md, src/server.ts).
…and SEO

The landing page #mcp section grows to 28 rows with the four v1.6.0 tools
(add_ltv, timestamp_pdf, inspect_layout, update_metadata) and its JSON-LD
node bumps softwareVersion to 1.6.0; the architecture SVG desc and MCP box
now read "28 tools"; the guides/learn/playground index blurbs and the
mcp.html guide shell follow. responsibility.html names the SDK v2 package
(@modelcontextprotocol/server) that replaced @modelcontextprotocol/sdk.

The MCP playground gains two runnable cards: update_metadata drives the
real openPdf -> createModifier -> updateMetadata -> save incremental
pipeline on a browser-built source PDF, and inspect_layout runs the real
inspectDocumentLayout dry run and prints the pagination report in place
(a new runJson card variant, since the tool produces no PDF by design).
add_ltv and timestamp_pdf are documented as deliberately card-less: they
need the operator-configured TSA / OCSP / CRL providers a browser page
cannot supply. Coverage arithmetic is restated as eleven of 28 without a
card. Stale card blurbs (five chart types, 24 lang codes, no listbox,
pre-PAdES sign_pdf) are refreshed, and the intro no longer stops at v1.4.0.

Cross-cutting guides: signatures.md documents the MCP PAdES ladder
(sign_pdf -> add_ltv -> timestamp_pdf, verify_pdf ltv: true), pdfa.md adds
the embedFonts / strict / includeDiagnostics honesty note with the known
AcroForm /DR /Helv limitation, and ai-governance.md states the single
permitted egress class mirrored from the pdfnative-mcp 1.6.0 charter.

sitemap.xml lastmod moves to 2026-08-25 for the 13 touched pages,
llms-full.txt is regenerated (never hand-edited), and the stale-token
canary in tests/docs/verify-docs.test.ts follows the manifest canonical
(28) so the perturbation test keeps testing a live value.
verify:docs: 17 rules passed across 109 files; vitest docs suite: 18/18.
…-count canonical

The served og-image.png had never been re-rasterised since the v1.4.0 docs
audit: its git history stops at 52cbbdd while og-image.svg was edited later
in f88c3b0, so every social card still advertised the pre-1.6.0 feature
line. The SVG subtitle now names the 1.7.0 headliners (LTV Signatures,
Print Production) alongside the engine constants, and the PNG was
re-captured per the procedure in the SVG header comment:

  chrome --headless --disable-gpu --hide-scrollbars \
    --window-size=1200,630 --screenshot=og-image.png og-image.svg

Verified 1200x630 with the new line rendered. No conversion tooling is
committed - the SVG header comment remains the documented procedure.

charts.html was the only page referencing og-image without
og:image:width/height; the pair is added, and its og:description now
enumerates all nine chart kinds instead of seven labels.

ecosystem.json: the test-count-homepage canonical read "665+ tests across
122 files" - a dropped leading 2 that made the substring assertion unable
to catch the very drift it exists for. Corrected to "2665+"; verify:docs
stays green (docs/index.html carries the full string).
…round truth

A cross-verified conformity audit of the whole documentation surface found
the errors that the 17 verify-docs rules do not cover - counters, versions
and API claims living outside the rule corpus, plus engine-version prose.

Counters and versions: AGENTS.md said 2664+ tests and ~241 sample PDFs
(manifest: 2665 / 242); testing.instructions.md was frozen at "2396+ tests
across 105 files" with 44 generator modules (2665+ / 122 / 48) and its
test tree missed tests/docs, tests/tools and tests/visual;
quality-gate.prompt.md expected 2396+; SECURITY.md still supported
1.6.x/1.5.x (now 1.7.x/1.6.x).

Signature claims: SECURITY.md, ROADMAP.md and pdf-core.instructions.md
described two selectable algorithms - v1.7.0 has four (rsa-sha256/384/512,
ecdsa-sha256, src/crypto/cms.ts); compliance-audit.prompt.md audited only
adbe.pkcs7.detached where the engine now also emits ETSI.CAdES.detached
and ETSI.RFC3161. MIRROR_MAP no longer exists in the code - the shaping
instructions now name BIDI_MIRRORING_PAIRS and its full 428-pair UCD
table, plus the v1.7.0 I1/I2 conformance work.

Engine-version over-propagation: cli.md, react.md, mcp.md's v1.5.0
history entry, README's CLI v1.3.0 / MCP v1.5.0 history lines and
llms.txt claimed "built on pdfnative 1.7.0" for packages whose published
manifests pin ^1.6.0 (CLI 1.3.0, React 1.1.0) or shipped on the 1.6
engine (MCP 1.5.0, per its own release notes). All now state 1.6.0 with
the pin/semver-accepts nuance, matching versions.js and the manifest.

Site: the no-JS Library badge fallback said v1.6.0; the charts cards,
metas and playground badge were frozen at five kinds/v1.6.0 while the
engine has nine since 1.7.0; two "nine types" enumerations listed seven
labels (barH and stackedBarH restored, also in README and llms.txt);
learn pages said 26 reference guides (28); ltv.md and responsibility.html
mischaracterised pdfnative-cli verify (full cryptographic verification,
OCSP/CRL only behind --revocation online, no TSA contact) - and the
published grep proof on responsibility.html is rephrased now that the
v1.7.0 provider interfaces carry @example JSDoc showing user-land fetch.

llms.txt (root + docs copy, byte-identical) also gains the v1.6/v1.7
roadmap detail its "v1.0 -> v1.7" line promised.
…mitted

The audit''s second class of findings: pages whose facts were not wrong but
whose framing predated 1.7.0. The guide index cards and HTML shell metas
for signatures (PAdES profile, RSA SHA-384/512, multiple signatures,
listSignatures), colour emoji (sweep gradients, the 73 flag/ZWJ sequences,
--sequences / --sequence-list), PDF/A (declaration guards, dropping the
"v1.1.0" framing) and the CLI (all 17 commands, verify with RFC 3161 +
OCSP/CRL) now describe the current release. The landing page gains the
print-production sentence in the Rich Content card, print in the #library
JSON-LD description, the emoji-sequences line in the scripts card, and
print.html / ltv.html in the footer guide list.

Four guides gain the 1.7.0 note their subject now requires: form-filling
(AcroForm /Helv carries /ToUnicode in every mode - searchable form text,
byte change on every form document), text-extraction (complete base-14 and
form-field coverage), pdf-manipulation (page boxes and /UserUnit survive
merge/split/extract), accessibility (PDF/A declaration guards).

Agent instruction files catch up with the 1.7.0 API surface:
api-design.instructions.md gains the LTV/PAdES, print-production and
PDF/A-diagnostics export categories; pdfa-conformance.instructions.md
gains the "Declaration guards (v1.7.0)" section AGENTS.md routes to;
copilot-instructions.md names all nine playgrounds.

The "built on pdfnative 1.6.0" phrasings introduced by the audit fixes are
restated as "the pdfnative 1.6 engine (pins ^1.6.0, semver-accepts
1.7.0)" so the version-token rule keeps guarding real drift instead of
being suppressed - the pin carries the exact floor. llms.txt (root + docs,
byte-identical) follows, llms-full.txt is regenerated, and sitemap
lastmod moves to 2026-08-25 for the newly touched pages.
verify:docs 17 rules green; vitest docs suite 18/18.
…e index

The 28 guide pages used to ship an empty <article> filled in by guide.js at
runtime: any fetcher that does not execute JavaScript - most AI crawlers,
social scrapers, curl - received the word "Loading..." instead of the
guide, and the JSON-LD injected by the same script was equally invisible.

scripts/build-guides.ts now renders each guide''s Markdown into its shell
between guide:render markers, with deterministic GitHub-style heading ids
plus visible anchor links (marked >= 5 stopped emitting heading ids, so
in-page anchors had never actually existed), externalised links, and
server-side TechArticle + BreadcrumbList JSON-LD (FAQPage for the FAQ)
carrying dateModified from the manifest''s verifiedOn. marked@12.0.2 is
pinned as an exact devDependency - the same version the pages load from
the CDN. The new guide-render-sync rule rebuilds every shell in memory
and fails CI when a committed render is stale, exactly as llms-sync
polices llms-full.txt; the served site stays fully static. guide.js
detects the pre-rendered article, skips the fetch, and keeps its old
render path as a fallback; it now also adds copy buttons to every code
block and a "Copy page as Markdown / View Markdown source" bar on both
paths.

Machine discoverability: llms.txt gains a "Machine-readable artefacts"
section; robots.txt points AI pipelines at llms.txt and llms-full.txt;
the sitemap lists the 28 raw .md URLs plus llms.txt and llms-full.txt;
the major page heads declare rel="alternate" links to llms.txt; and the
new generated docs/llms-index.json publishes per-guide HTML/Markdown
URLs, titles, summaries, section anchors and exact byte / approximate
token sizes (policed by llms-index-sync) - sizes live there rather than
in llms.txt so no artefact embeds its own size. llms-full.txt now also
embeds the README, the largest API reference in the repo and previously
absent from the ingestible corpus.

The docs test suite gains perturbation tests for both new rules (20/20),
with the repo''s node_modules junction-linked into the sandbox so the
generator''s marked import resolves there. Rule count 17 -> 19 updated in
CONTRIBUTING and copilot-instructions. verify:docs: 19 rules green.
…rst guides

The homepage demo becomes a split view: the example code runs as a real
ES module through a Blob URL (its import-from-pdfnative lines are real,
top-level await works natively, and errors carry genuine line numbers
instead of the old new Function + import-stripping regex), downloadBlob
is routed to an inline PDF preview iframe - the same Blob/object-URL
pattern the React playground already used - and the first example
renders automatically when the section scrolls into view, so a visitor
sees a real PDF without clicking. Download becomes an explicit button,
navigator.pdfViewerEnabled gates an honest no-inline-preview note for
mobile browsers, and #preset=<id> permalinks restore and share the
selected example. No new dependency, no code-encoding permalinks.

docs/agent-brief.md is the new paste-into-context pack for coding
agents: the core API table, the six verified pitfalls that produce
wrong code (synchronous builder, top-level title, reserved /F1-/F2,
registerFont-without-fontEntries, PDF/A claim in layout, and the
pdfkit/jsPDF ghost APIs - named under explicit verify-docs:allow
markers), the surface decision tree, and the generate-inspect-assert
self-verification loop. Linked from llms.txt, llms-index.json, the
sitemap, and a "Copy as prompt" button in the homepage MCP section.
It joins the verify-docs corpus (110 files), so its counters and
identifiers are policed like every other page.

Six guides that opened without an answer-first summary (accessibility,
architecture, pdfa, quickstart, signatures, troubleshooting) gain one,
extractable by answer engines; signatures.md''s intro claim "both with
SHA-256" is corrected (RSA gained SHA-384/512 in 1.7.0). The nine learn
pages share a new learn/learn.css instead of nine duplicated inline
style blocks. verify:docs 19 rules green; docs suite 20/20.
…i-exists

Three machine-truth artefacts join the served surface, each policed by a
sync rule cloned from the llms-sync pattern:

- recipes/ - 14 standalone TypeScript recipes importing only from
  ''pdfnative'', each carrying @task/@surface/@since/@expect headers and
  executed in CI (tests/docs/recipes.test.ts, 16 tests: every @expect is
  asserted with the engine''s own readers - extractText, openPdf,
  listSignatures, inspectDocumentLayout). Deterministic output where the
  API allows (pinned creationDate/signingTime/modDate); signed-pades
  takes its signing material as a parameter and the test injects the
  existing mock PKI. vitest aliases pdfnative -> src/index.ts. Served
  concatenated as docs/llms-recipes.txt - the cheapest high-signal fetch
  for a coding agent, because the code it copies is proven in CI.
- docs/assets/api.json (445 exports) - the public API surface derived
  mechanically from src/index.ts export statements with signatures and
  TSDoc summaries where extractable, null where not; the substitute for
  the gitignored dist/index.d.ts. Rule api-json-sync; npm run docs:api.
- docs/data/surfaces.json + two new guides: choose (the library/CLI/
  MCP/React decision tree with a 12-capability matrix, every MCP tool
  and CLI command name checked against ecosystem.json) and self-verify
  (the generate->inspect->assert->correct loop across all four surfaces,
  with the honest caveats: shared measurement code, structural PDF/UA,
  no cryptographic verifier in the engine). Guide count 28 -> 30
  everywhere (manifest, TOC, ItemList, learn pages, sitemap incl. .md).

The api-exists rule graduates from ~4 watched identifiers to the whole
documented surface: any identifier written call-shaped at the start of an
inline code span must exist in src/ (or scripts/), with markdown-vs-HTML
span openers distinguished (a backtick in HTML is a JS template literal),
companion-package guides scoped out (their APIs belong to their repos),
import-example detection for companion names, and a small allow-list for
platform/test globals and conventional-commit prefixes. The wider net
immediately caught four genuinely rotten identifiers in the agent
instruction files (_renderToc, _renderPageTemplate, _estimateTocHeight,
and assertNotEncrypted - removed in 1.6.0 when encrypted sources became
ingestible) - all corrected.

llms.txt gains the recipes/api/surfaces artefact entries; rule count
19 -> 20 in CONTRIBUTING/copilot-instructions; perturbation tests added
(docs suites 37/37 green; verify-docs 20 rules across 115 files).
…or-parity

docs/playgrounds/inspect.html is the tenth playground: drop any PDF (or
generate a sample in-page) and read a full report - version, page count,
encryption, /Info, extracted text with runs, PDF/UA structural verdict,
signature inventory, form fields - produced entirely in the tab via
openPdf / extractText / validatePdfUA / listSignatures / readFormFields.
The privacy claim is stated verifiably (all requests happen at page load,
before any file is dropped; FileReader only) and every card carries its
rs-verify source link plus the honest caveats: PDF/UA checks are
structural, the signature card is an inventory not cryptographic
verification, and listSignatures/validatePdfUA take no password. Full
parity paid: switcher updated across all ten pages, playgrounds index
card + ItemList (10) + "Nine" -> "Ten" prose, ecosystem
derived.playgrounds, sitemap, homepage footer, learn pages.

The homepage demo gains a JSON mode: a DocumentParams editor whose
object is exactly what the library, pdfnative-cli render and the
generate_basic_pdf MCP tool consume - with "Copy as CLI command" and
"Copy as MCP call" buttons, and #doc= share links that encode DATA
(deflate-raw via the native CompressionStream, base64url, defensively
decoded against the 13-kind block union with a size cap - never code).
Below the CI benchmark bars, "Run this benchmark in your browser"
measures 100/500/1000 rows on the visitor''s own device with
performance.now(), rendered under .bench-live-* classes so the
bench-parity rule keeps guarding the committed reference figures, and
framed honestly as indicative, not a benchmark.

New verify-docs rule anchor-parity (21 rules): every internal link
fragment must match an id in its pre-rendered target - internal-links
deliberately ignored fragments, so deep links rotted invisibly. It
immediately caught real rot: guide deep links written with GitHub''s
double-hyphen slugs while the renderer collapsed whitespace (slugger
aligned to the GitHub convention), and a tables.md link to a section
that never existed. Perturbation test added; docs suites 38/38 green.
Above the "How It Compares" table, a small quiz derives its verdicts
from the table itself: tick what your project needs and the matching
rows highlight while a factual conclusion appears - including the cases
where another library is the better fit ("if reading and modifying
existing PDFs is your whole need, pdf-lib is a solid, widely used
choice"; "pdfkit, jsPDF and pdfmake also offer AES"). A comparison
that sometimes recommends the competitor is the only kind that is
believed - the direct translation of responsibility.html''s doctrine
into an interactive component. Rows are tagged data-cap; no data is
duplicated outside the table the caption already sources and dates.

docs/data/errors.json is the served registry of the engine''s diagnostic
codes (the three PDFA_* conformance guards from pdf-diagnostics.ts,
with severity, trigger, ISO clause, remedy, sink semantics), and the
new error-parity rule (22 rules total) checks it both ways: every
PDFA_* token in the docs must exist in the registry AND in src/, and
every registry entry must still be emitted by src/ - a registry entry
for a ghost code would teach agents an API that no longer exists. The
CLI''s E_* and the MCP codes stay in their own repositories by design,
noted in the registry''s $comment. Perturbation test added; docs suites
39/39; served-content smoke check: a guide fetched without JavaScript
carries its full article, TechArticle JSON-LD and heading anchors.
…w found

User-reported bugs, root-caused by a three-auditor review:

- Live benchmark crashed with "Cannot read properties of undefined
  (reading ''length'')": makeParams omitted four required PdfParams fields
  (infoItems/balanceText/countText/footerText - the engine boundary only
  validates rows/headers). Params completed; errors now land in an
  aria-live note instead of destroying the button label. The engine-side
  boundary guard is deferred to an engine PR to keep this branch docs-only.
- "Copy link" half-hidden behind the PDF preview - three stacked causes:
  .demo-actions had no flex-wrap; the demo container was 780px wide
  (382px per split pane); and [hidden] was silently defeated by author
  display rules (.btn{display:inline-flex}), so the Copy-as-CLI/MCP
  buttons were visible in Code mode too. Fixed with a global
  [hidden]{display:none!important}, flex-wrap, a full-width status line,
  and an 1120px demo container.
- The re-encrypt example previewed an AES-256-protected PDF, cramming
  the browser viewer''s password prompt into a half-width iframe. The
  example now declares encryptedOutput: the preview is skipped for an
  honest note (password: rotated, use Download), such presets never
  auto-run, and a /Encrypt tail-sniff covers user-authored code.

Review blockers, worse than the reported bugs:

- The new Code/JSON mode buttons reused .tab-btn, and the homepage
  tablist binds every .tab-btn on the page - clicking "JSON" emptied the
  Examples section entirely and arrow keys jumped between the two groups.
  The tablist is now scoped to #examples and the mode switch is a proper
  aria-pressed button group (.demo-mode-btn).
- docs/assets/api.json attributed each module''s banner comment as the
  summary of every export (leftmost-match regex): 77 distinct summaries
  for 445 exports. A tempered regex now binds to the JSDoc immediately
  above each declaration - 389 summaries, all distinct, verified.
- llms-index.json measured artefact sizes with statSync on the working
  tree - CRLF-inflated on autocrlf Windows clones, making a pristine
  checkout fail verify:docs. Sizes now come from the LF-normalised
  content, the bytes GitHub Pages actually serves.

Also in this pass: the invoice recipe used the reserved /F1 fontRef its
own documentation forbids (now /F3 + lang); the exact test count is
re-measured at 2686 tests across 123 files and updated everywhere with
the test-count canonical (the old literal validated its own staleness);
README''s playground list gains inspect and says ten.
…1y, infra

Front-end majors: the preview pane no longer reserves 320-420px when the
iframe is hidden on mobile; inline preview is now an explicit opt-in on
navigator.pdfViewerEnabled === true; guide copy buttons and heading
anchors become visible with 24px targets on touch devices (opacity:0
hover-reveal is unusable there); the pre-rendered guide path enhances
immediately and only the Prism highlight waits (kills a 2s layout
shift); inspect.html''s theme toggle adopts app.js semantics (explicit
light/dark - removing the attribute made "light" a no-op on dark-OS
machines and the empty stored value leaked to every page); its status
banners gain aria-live, theme-aware classes, and an honest tally when
sections fail; mcp.html cards no longer force a horizontal scrollbar at
360px; the demo autorun is desktop-only; #doc= permalinks scroll to the
demo and the autorun awaits their async decode; all four homepage copy
affordances share one guarded copyText helper with an execCommand
fallback for non-secure contexts.

Minors: quiz grid and verdict aria-live; demo status aria-live; darker
active mode-button background in dark theme (white on #3b82f6 was
3.7:1); guide copy buttons move into a positioned wrapper outside the
scrollable pre (they scrolled away with wide code and polluted manual
selection); rewriteImports handles multi-line and namespace imports and
explains unsupported forms; inspect gains a document-level drop guard
with a dragenter counter, a size warning above 25MB, yields between the
five readers, and a capped /Info key column; a minimal @media print
sheet (a PDF library''s docs should print); the #doc= inflater reads in
chunks and aborts past the cap instead of materialising first; link
block URLs from shared payloads are scheme-validated.

Infrastructure: docs.yml triggers cover recipes/, bench/ and the two
new generators; the JSON-LD injection uses a function replacer ($-safe);
isMain is an exact-path check in all three generators (a substring match
would let importers rewrite 30 shells as a side effect); ''run'' leaves
the span-scan allow-list (nothing references it); error-parity gains the
src->registry direction; one shared slugger feeds both heading ids and
the llms index anchors; manifest-shape rejects unknown derived keys;
the recipes count in tests reads the manifest instead of a literal; the
sandbox path is quoted for shell:true; llms-recipes.txt leaves the scan
corpus in favour of recipes/*.ts scanned directly (22 rules across 129
files); sitemap lastmod tolerates +1 day of timezone skew; arabic-rtl
registers its font inside run() so importing the recipe has no global
side effect. verify:docs green; docs suites 40/40.
… honest

The extreme-scripts colour-emoji preset showed tofu for U+1F4E6 (package):
verified against the bundled noto-color-emoji-data cmap, that codepoint is
simply outside the curated 1167-glyph subset - a data-coverage limit, not
a playground or engine bug - and it was the only character on the page
not covered. Replaced with U+1F381 (gift), which is in the subset and
keeps the "objects" theme. No engine or font-data change.

PDF/A discoverability and honesty: the charts donut preset now says
"PDF/A-2b tagged" in its label (it embeds Noto Sans, so its claim is the
real thing), and the inspect playground''s generated sample - which
claims PDF/A-2b while using unembedded base-14 text AND form fields
under the claim - now says so in its own body text, naming the two
documented engine limitations and pointing at veraPDF and the PDF/A
guide. A deliberately non-conformant sample is a fine teaching aid;
a silently non-conformant claim is not.
@Nizoka Nizoka self-assigned this Aug 25, 2026
@Nizoka Nizoka added the documentation Improvements or additions to documentation label Aug 25, 2026
Comment thread docs/guides/guide.js Fixed
Nizoka added 2 commits August 25, 2026 22:04
CodeQL flagged guide.js line 98: the data-md attribute value flows from
getAttribute() into the source-bar link href (and into fetch() and the
GitHub fallback URLs) without validation - a crafted `javascript:` value
would become an executable link. The attribute is author-controlled
static HTML in practice, but the hardening is one line: src must match a
plain same-directory Markdown filename (^[A-Za-z0-9][A-Za-z0-9_-]*\.md$)
or the renderer bails, which sanitises every downstream sink at once.
All 30 committed shells pass the filter; node --check and verify:docs
(22 rules / 129 files) stay green.
…M text

CodeQL kept flagging js/xss-through-dom on the source-bar href: the query
tracks getAttribute() values into href/fetch sinks and does not accept a
regex test as a barrier, so validating the data-md string was not enough
- the taint had to die at the root. The Markdown filename is now DERIVED
from location.pathname (every guide pairs name.html with name.md) and
filtered to a plain same-directory filename; data-md is demoted to an
opt-in marker that must agree with the derived name but never flows into
any sink. Behaviour is unchanged - the name.html/name.md pairing is the
documented authoring convention (AGENTS.md) and all 30 committed shells
satisfy it, verified. node --check and verify:docs (22 rules) green.
@Nizoka
Nizoka merged commit 438e985 into main Aug 25, 2026
8 checks passed
@Nizoka
Nizoka deleted the docs/mcp-1.6.0 branch August 25, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants