feat(library): inline cross-links via bosco: protocol #88

Merged
manlycucumber merged 1 commit from feat/library-cross-links into develop 2026-07-11 02:28:31 +00:00
manlycucumber commented 2026-07-11 02:27:29 +00:00 (Migrated from github.com)

Authors can now link from one article's prose to another Library topic with a bosco: protocol:

Clever foxes even star in old fables … once the [printing press](bosco:world/printing-press) made
books cheap and easy to copy.

A build-time remark plugin rewrites bosco:category/slug to the real prerendered route
/library/category/slug/ after validating the target ships in this build — the inline sibling of
the frontmatter related/See-also validateCrossLinks. A dangling or (in production) unreviewed
target fails the build. Rendered links are real /library/** anchors, so the desktop's delegated
handler opens them in-window while deep-links/no-JS follow the route.

Split from PR2b

A design workshop (3 proposals → synthesis → 3 critics) recommended splitting the original PR2b: the
risk is wildly asymmetric. This PR is the low-risk foundation + cross-links; the glossary +
toggletip + doctrine gate
(where all the a11y/escaping/doctrinal-review risk concentrates) is the
focused PR2b-ii that builds on this foundation.

Two load-bearing facts the design surfaced (and this PR proves)

  • The remark chain is Node-loadable .js, not .ts. svelte.config.js is imported by a raw Node
    import() that can't transpile TypeScript, so gate.js / catalog.js / remark-bosco.js are ESM
    .js with JSDoc types (checked via checkJs). schema.ts re-exports the gate primitive from
    gate.js (single source), so existing from './schema' imports are unchanged.
  • The gate crosses two module realms via globalThis. plugin.ts (esbuild-inlined into the Vite
    config) and remark-bosco.js (loaded on-disk by svelte.config.js) are different instances, so a
    module-level variable wouldn't be shared. The plugin's configResolved populates
    globalThis[Symbol.for('bosco.content.catalog')] (gate + shipping topic paths) before any Markdown
    is transformed; remark reads it, and requireGate() throws fail-closed if the catalog is unset.

What's in it

  • gate.js (single-source gate primitive), catalog.js (passive globalThis store), remark-bosco.js
    (validate + rewrite bosco:, throw on external URLs — defense-in-depth; guard:external stays
    authoritative), plugin.ts (populate the catalog in configResolved, re-populate on HMR), the
    mdsvex wiring, tokenised .art-body a styling (this PR introduces the first in-prose link), the demo
    cross-link, the CONTRIBUTING governance rule, and remark-bosco.test.ts.

Verified

  • Build positive (bosco: rewrites to /library/world/printing-press/, no raw bosco: link leaks)
    and negative (a dangling bosco: fails the build with a clear, file-anchored error).
  • The cross-realm gate works (build succeeds ⇒ remark read the plugin-populated catalog).
  • svelte-check 0/0/0, all four guards, 70 unit (+8 remark: rewrite, children preserved, dangling throw,
    malformed throw, external throw, fail-closed, base assertion), 18 e2e (+2 cross-link: standalone +
    in-window intercept), lint clean.
  • Browser: link renders --sel-deep + underline at 7.34:1 on --paper, opens in-window.
  • Adversarial multi-agent review (4 lenses → per-finding verify).
## The Library — inline cross-links (v0.3.0 PR2b-i) Authors can now link from one article's prose to another Library topic with a `bosco:` protocol: ```md Clever foxes even star in old fables … once the [printing press](bosco:world/printing-press) made books cheap and easy to copy. ``` A build-time remark plugin rewrites `bosco:category/slug` to the real prerendered route `/library/category/slug/` **after validating the target ships in this build** — the inline sibling of the frontmatter `related`/See-also `validateCrossLinks`. A dangling or (in production) unreviewed target fails the build. Rendered links are real `/library/**` anchors, so the desktop's delegated handler opens them in-window while deep-links/no-JS follow the route. ### Split from PR2b A design workshop (3 proposals → synthesis → 3 critics) recommended splitting the original PR2b: the risk is wildly asymmetric. This PR is the **low-risk foundation + cross-links**; the **glossary + toggletip + doctrine gate** (where all the a11y/escaping/doctrinal-review risk concentrates) is the focused **PR2b-ii** that builds on this foundation. ### Two load-bearing facts the design surfaced (and this PR proves) - **The remark chain is Node-loadable `.js`, not `.ts`.** `svelte.config.js` is imported by a raw Node `import()` that can't transpile TypeScript, so `gate.js` / `catalog.js` / `remark-bosco.js` are ESM `.js` with JSDoc types (checked via `checkJs`). `schema.ts` re-exports the gate primitive from `gate.js` (single source), so existing `from './schema'` imports are unchanged. - **The gate crosses two module realms via `globalThis`.** `plugin.ts` (esbuild-inlined into the Vite config) and `remark-bosco.js` (loaded on-disk by `svelte.config.js`) are *different* instances, so a module-level variable wouldn't be shared. The plugin's `configResolved` populates `globalThis[Symbol.for('bosco.content.catalog')]` (gate + shipping topic paths) before any Markdown is transformed; remark reads it, and `requireGate()` throws fail-closed if the catalog is unset. ### What's in it - `gate.js` (single-source gate primitive), `catalog.js` (passive globalThis store), `remark-bosco.js` (validate + rewrite `bosco:`, throw on external URLs — defense-in-depth; `guard:external` stays authoritative), `plugin.ts` (populate the catalog in `configResolved`, re-populate on HMR), the mdsvex wiring, tokenised `.art-body a` styling (this PR introduces the first in-prose link), the demo cross-link, the CONTRIBUTING governance rule, and `remark-bosco.test.ts`. ### Verified - Build **positive** (bosco: rewrites to `/library/world/printing-press/`, no raw `bosco:` link leaks) and **negative** (a dangling `bosco:` fails the build with a clear, file-anchored error). - The cross-realm gate works (build succeeds ⇒ remark read the plugin-populated catalog). - svelte-check 0/0/0, all four guards, 70 unit (+8 remark: rewrite, children preserved, dangling throw, malformed throw, external throw, fail-closed, base assertion), 18 e2e (+2 cross-link: standalone + in-window intercept), lint clean. - Browser: link renders `--sel-deep` + underline at **7.34:1** on `--paper`, opens in-window. - Adversarial multi-agent review (4 lenses → per-finding verify).
Sign in to join this conversation.
No reviewers
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Bosco/bosco!88
No description provided.