Skip to content

feat: consolidate refract-docs and refract-ui into monorepo - #37

Merged
zz-plant merged 198 commits into
mainfrom
feat/consolidate-monorepo
Oct 12, 2026
Merged

zz-plant merged 198 commits into
mainfrom
feat/consolidate-monorepo

Conversation

@zz-plant

Copy link
Copy Markdown
Collaborator

Summary

Consolidates refract-docs into apps/docs and refract-ui into apps/ui preserving 100% git commit history, blames, and authors via git subtree.

Architecture

  • Added apps/docs (Astro/Vite docs platform)
  • Added apps/ui (standalone visualization engine)
  • Updated root package.json workspaces to include apps/*
  • Added TDD contract verification suite (tests/monorepo-contract.test.ts)
  • Verified architecture boundaries (bun run check:boundaries clean)

zz-plant added 30 commits May 14, 2026 13:12
… interface

- Updated cli.md with real positional args, flags, and option tables
- Rewrote 4 tutorials with correct command syntax and EvidenceEvent schema
- Removed all fictional --page, --input, --output, --limit, --wiki flags
…ts to DOM

- Added FactProvenance, DeterministicFact, PolicyDimension, DiscussionType types
- Wired 6 unused components (SourceChangeTable, WordingDiffCard, RevertClusterDisplay, EditVelocityChart, TalkPageTimeline, SchemaViewer) to DOM containers
- Added dashboard-row2 grid layout and component styles
- Set Vite base to /varia-ui/ for Pages asset paths
- Added GitHub Actions workflow for build + deploy on push to main
…o subpath imports)

- Replace PascalCase class constructors with lowercase singletons
- Replace @var-ia/interpreter/openai subpath with createAdapter factory
- Fix quickstart to use positional page arg instead of nonexistent --page flag
- Remove references to @var-ia/observable (does not exist)
- Document all 7 package exports accurately
…ers, talk spikes, public eval

- schema.md: 27→29 event types (edit_cluster_detected, talk_activity_spike)
- cli.md: add wikihistory explore command reference
- sdk.md: add wikidata entity mapping exports, detectEditClusters, detectTalkActivitySpikes, computeCalibration, getGroundTruthById/ForPage
- concepts.md: add new event types to event model
- tutorials/dispute-timeline.md: fix outdated user claim (Revision now has user field)
- README.md: mark @var-ia/eval as Published
…sing .gitignore

- build.mjs: fix rewriteLink to resolve relative links from subdirectories (sourceDir tracking)
- build.mjs: replace deprecated marked.setOptions() with marked.use()
- AGENTS.md: fix false 'No build step' claim
- docs/sdk.md: fix command count (9→10), add explore
- docs/concepts.md: remove duplicate event type group
- README.md: fix broken GitHub URL
- .gitignore: add .env, .env.local
…, description)

- Add repository, homepage, bugs URLs
- Add description and AGPL-3.0 license field
- Replace NextConsensus footer with ecosystem links
…/observable

- Add repository, homepage, bugs, license fields
- Fix packages table: add interpreter + observable, fix eval status, add npm badges
- Fix --page flag in quickstart example
… count, reconcile EvidenceLayer, fix claim_first_seen bug, add env var reference, add explore to quickstart, add observable to sdk
claude and others added 21 commits September 29, 2026 04:28
The homepage gave readers three ways to reach the same pages: the
sidebar, the "On this page" list, and a 46-link Contents section, 30 of
whose links were already in the sidebar. Delete the Contents section.

The other 16 pages it listed were not in the sidebar, and four of them
(Integrations overview, Common events, Compare to alternatives,
Non-English wikis) had no other link from the homepage or the sidebar.
Add all 16 to nav.json, so the sidebar now lists every page.

In "Further uses", drop the rows that repeated a link the use-case
cards above already give (model evaluation, RAG provenance,
BYO-inference), and fold the three rows that all pointed at Frontier
use cases into one. The "Streaming and Parquet" row among them sent
readers to a page that mentions neither.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EpGaiBuSk5nCSV2hKyD6PN
Each "By use case" card carried a badge that restated its title
("Evaluation" over "AI model evaluator", "Agents" over "AI agent
developer"). Remove the six badges and the now-unused .usecase-badge
rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EpGaiBuSk5nCSV2hKyD6PN
The first screen was spent on controls and an empty panel. This makes
the viewer lead with the timeline and a filled diff, and gives each
panel the room its content needs.

- Toolbar: the filter row wraps (flex-wrap on #toolbar > div), so a
  390px page is 390px wide, not 708px, and all nine type filters are on
  screen. The three export buttons become one Export button with a
  format select.
- Filters: All and None are actions, not states. They are no longer
  highlighted beside nine highlighted chips; each is disabled when it
  would change nothing. The chips are buttons with aria-pressed, so
  they can be reached and toggled from the keyboard.
- Diff: the timeline selects its first listed event on load, and again
  when a filter hides the selected one, so the diff panel shows a change
  instead of "Click an event". Selection is held by reference, since
  eventId is optional. The diff now reads as one run of text. Before,
  its word chunks were laid out in a two-column grid.
- Layout: diff, citation churn and model confidence stack beside the
  timeline, so the confidence chart is no longer in a 1398px panel.
  The second row has three equal columns, and no panel is stretched to
  a taller neighbour's height.
- Source changes: the Rev column moves to each row's tooltip. The short
  columns shrink to their content, so Detail gets the rest of the row:
  210px at 1440, up from 26px visible. The panel is 245px tall, not
  886px. Cells are built with textContent. They were built with
  innerHTML, which ran markup from an uploaded file.
- Event schema: "present in every event" is said once in the header,
  and only fields some events lack show a percentage, which never rounds
  up to 100%. The fields share one grid so their columns stay aligned.
- The "Timeline" and "Changes" labels above panels that say the same
  thing are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EpGaiBuSk5nCSV2hKyD6PN
…-g3mj8p

fix(ui): open the viewer on the timeline and the selected event's diff
…t-g3mj8p

fix(docs): render raw-pipe tables, contain wide tables on phones, cut homepage nav repeats
…nes, use --mono

- Timeline count: the filter path called timelineView.setData(filtered)
  through updateAll(), which made the filtered set the total. With one chip
  off, the count read "10 of 10 events"; after None it read "0 of 0". The
  timeline now takes the full set only on load, and a filter through
  applyFilter, so the count reads "10 of 12".
- Wording changes: a first-seen sentence has no "before" and a removed one
  has no "after", and each printed an empty − or + line. That was 2 of 10
  lines on the sample data; they are no longer printed.
- RevertClusterDisplay, DiffView and CertaintyTimeline asked for
  var(--font-mono), which is defined nowhere, so their labels fell back to
  the body face. The token is --mono.
- lint-staged: biome ignores Markdown and YAML and exits non-zero when
  every path it is handed is ignored, so any commit touching only a .md
  file failed the pre-commit hook. Both globs now pass
  --no-errors-on-unmatched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EpGaiBuSk5nCSV2hKyD6PN
…-g3mj8p

fix(ui): keep the timeline's total when filtering, drop empty diff lines, use --mono
* chore: bump dependencies and align biome schema

* fix(ci): regenerate package-lock.json for npm 10 compatibility and migrate biome schema
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 5 to 6.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](actions/configure-pages@v5...v6)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…xml (#29)

Every built page now carries a canonical URL at the trailing-slash address
GitHub Pages serves it from, Open Graph and twitter:card tags, and one
JSON-LD block: WebSite plus SoftwareSourceCode on the home page, TechArticle
plus BreadcrumbList on doc pages. The build also writes dist/sitemap.xml
listing every page. It has no <lastmod> because the deploy checkout is
shallow and cannot date pages from git history.

Titles and the meta description are unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(seo): emit canonical URLs, Open Graph tags, JSON-LD and sitemap.xml

Every built page now carries a canonical URL at the trailing-slash address
GitHub Pages serves it from, Open Graph and twitter:card tags, and one
JSON-LD block: WebSite plus SoftwareSourceCode on the home page, TechArticle
plus BreadcrumbList on doc pages. The build also writes dist/sitemap.xml
listing every page. It has no <lastmod> because the deploy checkout is
shallow and cannot date pages from git history.

Titles and the meta description are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(seo): derive per-page descriptions and strip markdown from titles

Each doc page's meta description, og:description and TechArticle
description now come from its first prose paragraph after the H1, trimmed
at a word boundary to 155 characters. Lists, tables, code, blockquotes,
images, lead-ins ending in a colon, bold-label callouts, asides and
"See ..." pointers are skipped. The home page keeps the site description,
as does any page with no usable paragraph; the build logs those (today:
glossary).

Titles in <title>, og:title, the JSON-LD headline and the search index use
the H1's visible text, so the cross-wiki-diff title loses its literal
backticks.

The search index excerpt now uses the same description, replacing the
regex-based getExcerpt(), which left list markers and ** in excerpts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: describe Refract as a deterministic observation engine everywhere

The site described Refract three ways: the home H1 said "observation
layer for model evaluation", the meta description and sidebar said "the
open claim-history layer for public knowledge", and AGENTS.md says to
describe it as a deterministic observation engine, which is what the
README leads with. The home H1, the site description, the sidebar
tagline and the opening sentences of Why Refract and Concepts now use
the README line. Those openings are the pages' meta descriptions now.

The home <title> no longer appends "— Refract" to an H1 that already
starts with the name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…les (#31)

* fix(links): give relative doc links their trailing slash

GitHub Pages serves dist/<slug>/index.html at <slug>/ and 301-redirects
the slash-less form. The markdown link resolver only added the slash when
a link ended in .md, so seven built links redirected: `(cli)` and `(./cli)`
in mcp, schema and sdk, `(schema#version-compatibility)` in downstream,
`(python-sdk)` and `(visualizer)` on the home page, and
`(tutorials/refract-ui)` in visualizer.

rewriteLink now resolves every relative link to a page (cli, ./cli, cli/,
cli.md, ../index.md) to the page's trailing-slash URL. A path whose last
segment has a file extension (.svg, .png, .ipynb) is an asset and keeps
its form. Links with any URL scheme, such as mailto:, are left alone;
before, only http(s) links were.

Tests:
- a built-site test fails if any internal link, including the canonical
  URL, points at a directory without the trailing slash;
- unit tests cover rewriteLink's page, asset and external cases. build.mjs
  now builds only when run as a script, so tests can import it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(seo): add a 1200x630 Open Graph card to every page

No page had an og:image, and the PNGs in docs/assets are placeholders.
The build now renders dist/social-card.png: the site icon and "Refract",
the positioning line, and the site address, in the colors from
assets/style.css. It is drawn from SITE_NAME and SITE_DESCRIPTION, so the
card changes when the positioning line does.

Every page's head gets og:image (absolute URL), og:image:width,
og:image:height, og:image:alt, and twitter:card summary_large_image.

social-card.mjs renders an SVG with @resvg/resvg-js. The site's font
stack starts with system-ui, which resolves to the reader's OS face (SF
Pro, Segoe UI) and cannot be redistributed in an image, so the card uses
Roboto, the stack's OFL-licensed face, from @expo-google-fonts/roboto.
System fonts are never loaded, so every machine renders the same PNG.
The description is word-wrapped by measuring it in that font; a
description too long for the card fails the build instead of clipping.

Tests cover the head tags on every page, the published PNG's size, line
wrapping, SVG escaping, and the overflow error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: run lint and tests on pull requests

CI only ran the build, so the link, SEO and docs tests ran only where a
contributor ran them by hand. It now runs `npm run lint` and `npm test`
before the build, which makes the redirect check a merge gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(deps): record every platform's native binaries in package-lock.json

The lockfile listed only the darwin-arm64 builds of @biomejs/biome,
rolldown (Vitest's bundler) and lightningcss. `npm ci` on Linux therefore
installed no Biome or Rolldown binary, and `npm run lint` and `npm test`
failed there. CI passed only because it ran nothing but the build.

The entries for those three packages were re-resolved with
`npm install --package-lock-only`. Biome (2.5.15) and Rolldown (1.0.2)
keep their versions and gain their other platform builds. lightningcss
moves from 1.32.0 to 1.33.0, within Vite's ^1.32.0 range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: retitle the MCP, Wikipedia tutorial and compare pages

Titles come from each page's H1, so these H1s now use the words people
search for:
- mcp: "MCP — Model Context Protocol" becomes "Wikipedia & MediaWiki
  revision-history MCP server". The server's tools analyze any MediaWiki
  page's revisions.
- tutorials/wikipedia-history: "Tutorial: Track changes on a Wikipedia
  page" becomes "Track changes to a Wikipedia article over time".
- compare: "Refract vs. Wikipedia's page history" becomes "Wikipedia
  history tools compared". The intro names the tools the page compares
  and the question each answers.

Each claim about another tool was checked against that tool's
documentation, and the page now links it:
- page history: the history page links WikiBlame for finding text;
  reverts are tagged; each revision has a permanent link and an API
  SHA-1; the watchlist can send email. The page had said "manual",
  "screenshots are the only record" and "no" for these;
- XTools and Who Wrote That? rows added;
- WikiBlame split from WhoColor: it searches revisions for the one that
  added or removed a text, not "visual diff highlighting";
- WikiWho is token-level provenance, including deletions and
  reinsertions;
- Wikimedia Enterprise sells access to a service, not a licence, and has
  free access.

The <title> element is now escaped like the other head values, since the
MCP title contains "&".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…laceholder images (#32)

* docs(mcp): say in the intro that the server reads Wikipedia and any MediaWiki API

The /mcp/ page is titled "Wikipedia & MediaWiki revision-history MCP
server", but its first paragraph, which build.mjs also uses as the meta
and og:description, named neither. The paragraph now says the server
analyzes page revision histories from Wikipedia or any MediaWiki API.
That matches the code: the analyze, claim and export tools take an `api`
parameter ("MediaWiki API base URL"), and the client defaults to
https://en.wikipedia.org/w/api.php.

The description is 150 characters, under the 155-character cut. The
`wikihistory mcp` alias moves to the Quick start sentence beside the
command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(assets): delete the unused placeholder images and their scripts

18 docs/assets/refract-docs-*.png scene renders (badge, og, favicon,
touch-icon and so on), their docs/assets/source.svg, and the two scripts
that generated and checked them (scripts/generate-scenes.ts,
scripts/check-assets.ts), with their package.json entries
(assets:generate, assets:check).

Nothing referenced them: no page, build.mjs (the Open Graph image is
social-card.png, rendered by social-card.mjs), test, CI workflow, hook or
package script outside the two being removed. The build now copies 5
assets instead of 24; lint, 103 tests and the build pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…lead (#33)

- compare: WikiBlame's "Searches a page's revisions, by binary or linear
  search, for the one…" split its verb from its object; it now reads
  "Uses binary or linear search over a page's revisions to find the
  one…". Who Wrote That?'s trailing ", using WikiWho" moves into the
  verb ("uses WikiWho to highlight…"). The edit-wars cell's ", and so
  are the edits they revert" becomes ", as are…".
- mcp: "a Model Context Protocol server over stdio that lets AI agents…"
  hung the relative clause on "stdio". It now says "a stdio Model
  Context Protocol server that lets…". The meta description is 145
  characters.
- tutorials/wikipedia-history: the Goal paragraph ended "— all
  deterministically, byte-for-byte reproducible", and its meta
  description was cut at "— all…". The goal is now its own paragraph
  and the description; determinism and reproducibility are the next.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
git-subtree-dir: apps/docs
git-subtree-mainline: f2227a1
git-subtree-split: 9ca0f93
git-subtree-dir: apps/ui
git-subtree-mainline: fff8825
git-subtree-split: 3a2d86e
Comment thread apps/docs/assets/docs.js
document.querySelectorAll(".search-result-item").forEach((item) => {
item.addEventListener("click", () => {
const href = item.getAttribute("data-href");
if (href) window.location.href = href;
href.startsWith("https://") ||
href.startsWith("mailto:") ||
href.startsWith("data:") ||
href.startsWith("javascript:")
// Visible text of an HTML fragment: tags dropped, entities decoded,
// whitespace collapsed.
function textOf(fragment: string): string {
return decodeEntities(fragment.replace(/<[^>]+>/g, ""))
Comment on lines +258 to +260
const head = html
.slice(0, html.indexOf("</head>"))
.replace(/<script[\s\S]*?<\/script>/g, "");
for (const { slug, html } of pages) {
const head = html
.slice(0, html.indexOf("</head>"))
.replace(/<script[\s\S]*?<\/script>/g, "");
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.

3 participants