Skip to content

model-v2: anchor — land the v2 engine as the crates/n0 family#5

Merged
softmarshmallow merged 48 commits into
mainfrom
model-v2-anchor
Jul 19, 2026
Merged

model-v2: anchor — land the v2 engine as the crates/n0 family#5
softmarshmallow merged 48 commits into
mainfrom
model-v2-anchor

Conversation

@softmarshmallow

@softmarshmallow softmarshmallow commented Jul 17, 2026

Copy link
Copy Markdown
Member

Lands the v2 anchor stack as workspace crates. This PR carries the research branch's full 33-commit history (relocated from gridaco/grida#970 at the engine split) plus the landing commits, and merges --no-ff — never squash.

Tracking: #9 (anchor — the v2 node model). Sequencing per the legacy seam program (#27), which completed first: with the v2 engine in-tree, the extraction rule — a module becomes a workspace crate when its second consumer appears in the workspace — is now armed for every seam M4 reviewed.

The move map

was (branch) now crate
model-v2/a/lab crates/n0-model the skia-free anchor model (node records, ops, resolve, pick, n0_xml, textir)
model-v2/engine crates/n0 the engine: resolve → drawlist → paint, query, journal/replay, damage — takes the reserved public name
model-v2/a/spike-canvas crates/n0_dev the winit/egui dev shell (feel spike), re-hosted on the engine
model-v2/ (rest) stays the frozen workbench archive: phase papers, experiment verdicts, demo pages, format drafts — tombstoned README with the map

Promotion is a git mv, not a rewrite — the engine's own contract (ENGINE.md S-1, archived). The dependency-direction law survives as cargo boundaries: model (no skia) ← engine (skia in paint.rs only) ← host.

Nobody absorbs anybody at landing. This PR is topology-only. Absorption runs afterward in the promotion program: n0 consumes crates extracted from crates/grida (cg vocabulary first — M4 ruled it extraction-ready); grida is decomposed, not absorbed, and remains the executable conformance bar until the v1-vs-n0 scoreboard says otherwise. The freeze contract (@grida/canvas-wasm@0.91.0-canary.22) is untouched.

Landing commits (on top of the research history)

  1. Merge main — pre-landing sync; all 20 conflicts were docs/wg files superseded by the docs(wg): land the model-v2 spec overlay from model-v2-anchor #26 overlay; resolved to main's copies after a patrol audit proved zero branch-only substance (every delta a link-fix or main-addition).
  2. Pure move — byte-identical git mv of the three trees (the reserved crates/n0 stub retires).
  3. Workspace wiring — package renames (anchor-*n0 family), manifests rewritten against a patrol ledger (every caveat comment kept/rewritten, named-obsolete, or re-homed; nothing silently dropped), standalone locks/.cargo shims removed, include paths fixed, 15 forbidden grida.co/docs/wg links converted to same-repo relative.
  4. Shed workbench binse1/e3/edge/fork retired; their unrecorded essence (e3's group-AABB exclusion, edge's flipzero stand-in provenance, fork's escape/overlap metric definitions) was captured into the archive docs before deletion.
  5. Lint conformance — n0 + n0-model opt into the workspace lint table; rustfmt after the renames; n0_dev's opt-in deferred (46 unreachable_pub in a binary crate = follow-up hygiene).
  6. Tombstone + docs — archive README as decision-record surface (frozen papers keep pre-promotion paths, declared convention); both RFDs' v2 citations flip to real in-tree links as their footnotes promised; AGENTS/README de-reserve n0.
  7. Golden re-bless — see gate evidence below.
  8. Canonical naming, no plan codes (owner directive): live artifacts drop the experiment-ledger codes — bins e4resolve_bench, e5scansvg_transform_scan; "historical E3 TextIr" → "the historical TextIr dialect"; window/HUD titles and crate docs describe things instead of citing ledger ids. The archive canonicalizes too: models/{a,b,c,d}.md{anchor,sheet,bake,wire}.md, model-v2/a/model-v2/anchor/, experiment dirs drop eN- prefixes, the spike's frozen read-out moves to the archive. Registry citations (R-E1, E-A*, DEC-*, V-*, ENG-*) are deliberately kept — they cite the archived conformance/decision registers; the E1–E10 ids remain the ledger's register keys, with the old→new map in model-v2/anchor/README.md.
  9. Grida XML → n0 XML (owner directive — the format is v2-native, and v2 is n0): extension .grida.xml.n0.xml, modules/APIs grida_xmln0_xml, the RFD family docs/wg/format/grida-xml*.mdn0-xml*.md (with a "Formerly" continuity note), the term swapped repo-wide, and issue anchor — the v2 node model #9's body updated in kind (including its stale pre-split gridaco/grida links → landed in-tree paths). The Draft-0 wire grammar — the <grida version="0"> root element — is deliberately NOT renamed; that's flagged as an open RFD item, not smuggled through a sweep. Legacy crates: zero references, zero touch.
  10. Fixtures to repo root (owner directive, per the fixtures convention): rig/corpusfixtures/n0-replay/, rig/examples + rig/fixturesfixtures/test-n0-xml/{examples,cases}/, and all 14 SVG animation profile sources → fixtures/test-svg/animation/ — dissolving the cross-crate include (n0-model tests no longer reach into n0's tree). crates/n0/rig/ keeps only the machine-local gate baselines. Authored resource paths inside the moved documents rebased; the gate re-verified green from the new corpus.

Gates (all run at the head commit)

  • cargo test --workspace --exclude grida-canvas-wasm — green (legacy + v2 suites).
  • cargo clippy --no-deps --workspace --exclude grida-canvas-wasm -- -D warnings and cargo fmt --all --check — green (the exact CI commands).
  • Legacy untouched, proven twice: git diff main...HEAD over crates/grida*, math2, csscascade, fonts, grida-canvas-wasm, format/, packages/ is empty; the root Cargo.lock diff is additions-only (no existing dep version moved).
  • v2 gate: replay determinism and the oracle-law differential pass. The four shot goldens diffed by ≤50 bytes/4.9M at max channel delta 1; an A/B rebuild of the pre-promotion standalone stack (original manifests + standalone locks, worktree at the merge commit) produced byte-identical output to the promoted build — the promotion is pixel-exact; the goldens were stale against this machine's current rendering stack and were re-blessed from the SHA-verified-identical output. Bench budgets deliberately not re-blessed: the same A/B showed today's shell measures both builds uniformly ~1.7–2.5× over the recorded baselines (old build slower than new) — environmental variance, not regression; CI-hosted gate baselines are a filed follow-up.
  • Legacy pixel sweeps byte-identical: iosvg over the resvg suite — 0 byte diffs across all 4351 baseline PNGs (consensus 703/1425 @ 0.95 unchanged); wpt L0.exact — 0 byte diffs, 65/65. just build (the wasm package) succeeds off the shared lock.

Deferred (filed as follow-ups)

WG graduation of the anchor spec (normative rewrite of models/anchor.md); the extraction cascade (cg first); n0_xml extraction at its second consumer; math2 vs n0-model/math convergence; fonts-backed text oracle; the v1-vs-n0 reftest scoreboard; CI-hosted gate with CI-blessed baselines; ENGINE.md contract graduation; n0_dev pub-hygiene + workspace-lints opt-in; edition-2024 bump.

The full redesign workbench for node geometry/layout/transform, scoped to
the Rust engine (crates/grida) and the format spec (format/grida.fbs):

- phase 1-2 research corpus: problems, harnesses, peer study, candidate
  models (anchor / sheet / bake / wire) — anchor decided by survey
- the 114-test Rust lab (model-v2/a/lab): four-phase resolver (Taffy flex,
  oriented envelopes), typed ops incl. cross-zero flip resize (E-A14),
  canonical text IR, node-arena + SOA storage (11.5x resolver speedup)
- the decision register (a/DECISIONS.md) with DEC-0 LOCKED: visual-only
  rotation (the CSS framing), CSS-pure sizing (a/dec0-visual-only.md)
- peer-compat matrix (COMPAT), ship-readiness census (LIMITS), report
- demo pages (a/.preview): proof, model walkthrough, edge cases, DEC-0
  fork A/B, free editing
- E10: the native skia interactive spike (a/spike-canvas) — feel pass +
  TEXTBOOK.md, the reference for the legacy migration

Isolated: nothing outside model-v2/ is touched; no production code paths.
…nce the snapshot)

The lab's accumulated evolution on the anchor branch since the textbook
snapshot, across two threads — the seams anchor-engine consumes and the DEC-0
visual-only feel study — plus a crate-wide rustfmt pass. 121-test suite green.

Engine seams (additive; serde stays out of default deps):
- ops.rs: typed `Op` + pure-dispatch `apply` (journal/replay/dirty land on it;
  free fns kept, `apply ≡ free_fn` differential per variant) + `DirtyClass`
  parameterized on rotation-in-flow [ENG-1.2].
- model.rs: per-slot `generations` column + `gen_of` (semantic PartialEq
  ignores it — a storage artifact) [ENG-2.3].
- resolve.rs: non-panicking `box_opt`/`local_opt`/`aabb_opt`/`slot_count`.
- serde feature (default OFF) — the op-log wire; new tests accessors,
  generations, op_apply.

Visual-only exploration: rotation scenes added to the edge/fork probes (grow ×
rotation, rotated text/frame/group) and expanded edge_census + visual_only
corpora anchoring DEC-0.
…spike re-hosted

anchor-engine: document → resolve → drawlist → paint, plus the read tier
(query), time-as-data (journal/replay), and the sockets every future
optimization plugs into (damage, ident, oracle). It consumes anchor-lab as a
library — the relationship the crates/grida migration will have with the model
crate. Every ENG-0…ENG-5 contract has a code socket and a guarding test;
skia is confined to paint.rs so a later core/paint split is mechanical.

The spike is re-hosted onto it (proof, not just scaffolding): the scene painter
is deleted → drawlist::build + paint::execute (4 goldens byte-identical, incl.
the rotated and cross-zero-flip scenes); pick/hover via query; gesture ops via
apply, recorded in the journal (undo stays document snapshots — ENG-5.5);
`--record` writes .replay corpus. The scene-cache compositor (ENG-2) rasters
once into a backend-matched offscreen and blits camera pans O(1), re-rastering
only on doc-change / zoom / pan-beyond-margin. Live per-stage frame
instrumentation (a glFinish GPU-vs-vsync split) plus render-on-demand (draw only
on real input) land the felt-latency fix.

gate (ENG-0.2 oracle law): shots 4/4 IDENTICAL · replays deterministic ·
scene-cache differential MATCHES fresh (integer pan) · bench within budgets.

Docs: ENGINE.md SETUP ground contracts (S-1…S-7), engine README (contract →
module → guarding-test map), model-v2 + a/README phase-4 status.
Performance is not one question, so it is not one tool — it splits on a hard
line between what a machine can measure alone and what needs a human. This is
the doctrine that stops us measuring the wrong axis (as a session's detour did:
render *work* was green while the felt lag lived in the *present path*).

MEASURE.md — the four axes and which tool owns each:
- work + correctness are automated & headless (probe / probe_gpu / gate) — the
  default loop, no human.
- feel & pacing need a real window: the opt-in ANCHOR_FRAMELOG channel (human
  runs + interacts + kills; the reviewer reads the per-frame gap/stage log). An
  on-demand bridge, not the iteration loop.
- input→photon latency is NOT software-measurable — the lag accrues in the OS
  compositor/display after swap_buffers returns; measuring it needs a photodiode
  rig or a human glance. Named so a green gate is never mistaken for good feel.

The automated work axis it documents:
- bin/probe — deterministic CPU raster, per-stage distributions, JSON baselines,
  panicking audit-guards. The always-on regression detector.
- bin/probe_gpu — headless surfaceless-GL, real flush_and_submit timing, for the
  wins whose value is a persistent GPU texture (CPU raster reports the wrong
  sign there).

Worked example folded in: render-on-demand (idle frames 466 → 2, throughput
125fps median — the symptom was pacing/latency, not work).
…L doctrine

Two gate-verified data-layout moves aligned to browser prior art, plus the
decisions doc that grounds them:

- Color: fill `Option<String>` → `model::Color(u32)` (0xAARRGGBB), read
  straight by the drawlist. No per-node heap String, no per-build hex parse;
  text-IR/SVG convert at the boundary via from_hex/to_hex. Parse byte-identical
  to the old resolve_color (pixels unchanged, gate 4/4 IDENTICAL); build −31% at
  100k nodes.
- Resolve caches: HashMap<NodeId,_> → Vec<Option<_>> (union_cache, ops_cache).
  NodeId is a dense arena index — hashing it is the cc anti-pattern. Correctness
  preserved (gate PASS, 121 lab tests).
- spike-canvas: `pages` stress scene (realistic nested flex cards, ANCHOR_SCENE
  selected) + --bench rows; goldens still use starter().
- engine/DATA-MODEL.md: six data-layout details decided against cc/Blink/Stylo/
  Skia prior art, validity-tagged (ALIGNED/ADOPTED/SOCKET), with honesty
  corrections to the record.
Package renames (anchor-engine -> n0, anchor-lab -> n0-model,
anchor-spike -> n0_dev) with mechanical use-path renames across the
three crates; root workspace members += n0-model, n0_dev; path deps
rewired; compile-checked include fixes (lab tests' engine/rig includes
-> ../../n0/rig, spike font fixture depth); gate.rs re-pointed at the
n0_dev binary and ../n0_dev/shots goldens.

Patrol ledger (patrol-before-drop) — deliberately dropped as obsolete:
- the three [workspace] breakouts and "standalone on purpose" rationale
  comments (workspace membership is what promotion IS),
- [profile.release] debug=true x3 (ignored in a workspace; profiling
  uses CARGO_PROFILE_RELEASE_DEBUG=true),
- both .cargo/config.toml target-dir shims and every "shared target dir
  reuse" comment clause (automatic in-workspace),
- the three standalone Cargo.locks (the root lock takes over; its diff
  is additions-only — no existing dep version moved),
- the engine's phase-4 description (replaced by the stub's
  "A 2D graphics engine." + categories/keywords/readme metadata).

Kept/rewritten per the same ledger: the serde op-log-wire rationale,
the trace zero-cost-observability rationale, the native-gl-context
GL-free-default rationale, the skia-confined-to-paint.rs invariant,
and the shell-dep version-parity constraint (reason updated from
target-dir reuse to workspace type unification). Crate-doc (//!) and
README framing updated from phase-4/standalone future tense to the
landed topology; archived-workbench references repointed to model-v2/
paths; 15 forbidden grida.co/docs/wg links converted to same-repo
relative per the links discipline.

Part of landing #5; tracking #9.
git rm src/bin/{e1,e3,edge,fork}.rs — the archive-coupled experiment
harnesses whose outputs are frozen under model-v2/a/
(e1-rotation-in-flow/, e3-text-ir/, edge-cases/, dec0-fork/). The
arg-driven e4 (resolver benchmarks) and e5scan (SVG corpus scan) stay.

Patrol ledger (patrol-before-drop) — essence captured into the archive
BEFORE deletion, in this commit:
- e3's truth protocol emits a world-AABB line only for rotated
  NON-GROUP nodes — the group exclusion was undocumented (inert on the
  frozen corpus); now stated in model-v2/a/e3-text-ir/README.md.
- edge's flipzero scene: only the flip arm is real resize_drag output;
  wall and slide are analytic stand-ins — now stated in
  model-v2/a/DECISIONS.md DEC-9 (was recoverable from nowhere else).
- fork's demo-meter definitions (escape = max sibling world-AABB
  overrun past the container's ORIENTED painted rect, 0 = contained;
  overlap = max pairwise sibling world-AABB intersection area) — now
  stated alongside rule V-3 in model-v2/a/dec0-visual-only.md; escape
  was defined nowhere else.
- e1 carries no at-risk essence (fully covered by
  model-v2/a/e1-rotation-in-flow/ README + verdict).

Deliberately dropped: edge.rs's stale s_flipzero doc comment
(v=80/anchor-95 parameterization) — it contradicts the shipped
code and frozen frames.json (v=60/anchor-75); wrong, not essence.

Part of landing #5; tracking #9.
The anchor_lab -> n0_model / anchor_engine -> n0 renames shortened
import paths past rustfmt wrap thresholds. No semantic change.

Part of landing #5.
Opt n0 and n0-model into [lints] workspace = true — the workspace
table's too_many_arguments allow covers all 9 findings (the documented
house pattern: geometry/cache passes many scalar params). Fence
e5scan's ASCII decision table as a text block so its '+' rows stop
parsing as markdown list items.

n0_dev's opt-in is deferred (manifest comment): unreachable_pub flags
46 internal pub items in the binary crate; demoting them to pub(crate)
is follow-up hygiene, not landing scope.

cargo clippy --no-deps --workspace --exclude grida-canvas-wasm
-- -D warnings and cargo fmt --all --check both green.

Part of landing #5.
model-v2/README.md and a/README.md become the archive's navigational
surfaces: archive banner with the promotion map (a/lab -> crates/
n0-model, engine/ -> crates/n0, a/spike-canvas -> crates/n0_dev), the
declared convention that frozen papers' relative paths refer to the
pre-promotion layout, the stale gridaco/grida#957 tracking note fixed
to #9, run commands updated to workspace form, and the
bare "PR #437" reference fixed to gridaco/grida#437 per cross-repo
link discipline.

Both RFDs' v2 evidence citations flip from cited-by-branch-in-prose to
real in-tree links, as their own footnotes promised at landing:
paint-model.md -> crates/n0-model/src/model.rs,
display-list-contract.md -> crates/n0/src/drawlist.rs (the
branch-links footnotes retire).

AGENTS.md and README.md: crates/n0 is no longer "reserved" — the
project-structure table and workspace list gain the n0 family and the
model-v2 archive rows; check/test commands extended with the new
crates.

Part of landing #5; tracking #9.
… code)

All four shots (default, crosszero, rot45, ungroup) diffed against
their goldens by 11-50 bytes out of 4.9M pixels with max channel
delta 1 — sub-LSB antialiasing drift on edge pixels.

Etiology, established by A/B experiment: the PRE-promotion standalone
build (worktree at the merge commit 80c60ad, original manifests and
standalone Cargo.locks) produces byte-identical output to the promoted
workspace build in today's environment — all four shot SHA1s equal
across the two builds. The promotion is therefore pixel-exact; the
goldens were stale against this machine's current rendering stack
(recorded in an earlier environment). A stale always-red byte gate
catches nothing; re-blessed from the verified-identical output.

The bench budgets (rig/baselines.json) are deliberately NOT re-blessed:
the same A/B showed today's shell measures both builds uniformly
~1.7-2.5x over the recorded baselines (the old build even slower than
the new), i.e. environmental timing variance, not a promotion
regression. Loosening budgets from a slow context would blind the
gate. CI-hosted gate baselines remain the filed follow-up.

Part of landing #5.
@softmarshmallow softmarshmallow changed the title model-v2: anchor — the v2 node model (research branch) model-v2: anchor — land the v2 engine as the crates/n0 family Jul 19, 2026
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nothing Ready Ready Preview, Comment Jul 19, 2026 11:16am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 244 files, which is 144 over the limit of 100.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a022fb5-863b-49ab-8372-f3e791a49a1e

📥 Commits

Reviewing files that changed from the base of the PR and between 4e2e33b and 979d43d.

⛔ Files ignored due to path filters (27)
  • Cargo.lock is excluded by !**/*.lock
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_000.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_015.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_030.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_045.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_060.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_075.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/frames/theta_090.svg is excluded by !**/*.svg
  • archive/model-v2/anchor/rotation-in-flow/metrics.csv is excluded by !**/*.csv
  • crates/n0_dev/shots/crosszero.png is excluded by !**/*.png
  • crates/n0_dev/shots/default.png is excluded by !**/*.png
  • crates/n0_dev/shots/rot45.png is excluded by !**/*.png
  • crates/n0_dev/shots/ungroup.png is excluded by !**/*.png
  • fixtures/test-svg/animation/svg-animation-profile0-boundaries.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile0-demo.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile1-keyframe-boundaries.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile1-keyframes.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile2-replacement-sandwich.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile2-sandwich-boundaries.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile3-additive-boundaries.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile3-motion-mixer.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile4-effects-and-transforms.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile4-transform-showcase.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile5-solid-fill-boundaries.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile5-solid-fill-showcase.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile6-path-boundaries.svg is excluded by !**/*.svg
  • fixtures/test-svg/animation/svg-animation-profile6-path-morph-showcase.svg is excluded by !**/*.svg
📒 Files selected for processing (244)
  • .oxfmtrc.jsonc
  • AGENTS.md
  • Cargo.toml
  • README.md
  • archive/README.md
  • archive/model-v2/.gitignore
  • archive/model-v2/README.md
  • archive/model-v2/anchor/.preview/edge.html
  • archive/model-v2/anchor/.preview/fork.html
  • archive/model-v2/anchor/.preview/free.html
  • archive/model-v2/anchor/.preview/index.html
  • archive/model-v2/anchor/.preview/model.html
  • archive/model-v2/anchor/COMPAT.md
  • archive/model-v2/anchor/DECISIONS.md
  • archive/model-v2/anchor/ENGINE.md
  • archive/model-v2/anchor/GROUP.md
  • archive/model-v2/anchor/LIMITS.md
  • archive/model-v2/anchor/MODEL.md
  • archive/model-v2/anchor/README.md
  • archive/model-v2/anchor/REPORT.md
  • archive/model-v2/anchor/dec0-fork/fork.json
  • archive/model-v2/anchor/dec0-fork/index.html
  • archive/model-v2/anchor/dec0-visual-only.md
  • archive/model-v2/anchor/edge-cases/frames.json
  • archive/model-v2/anchor/edge-cases/index.html
  • archive/model-v2/anchor/format-roundtrip/README.md
  • archive/model-v2/anchor/format-roundtrip/anchor.fbs
  • archive/model-v2/anchor/format-roundtrip/anchor_v2.fbs
  • archive/model-v2/anchor/format-roundtrip/quartet.json
  • archive/model-v2/anchor/format-roundtrip/quartet_v2.json
  • archive/model-v2/anchor/format-roundtrip/run.sh
  • archive/model-v2/anchor/free-editing/index.html
  • archive/model-v2/anchor/model-demo.html
  • archive/model-v2/anchor/pedantic-review.md
  • archive/model-v2/anchor/pluggable-layout/SKETCH.md
  • archive/model-v2/anchor/proof.html
  • archive/model-v2/anchor/resolver-spike/README.md
  • archive/model-v2/anchor/resolver-spike/verdict.md
  • archive/model-v2/anchor/rotation-in-flow/README.md
  • archive/model-v2/anchor/rotation-in-flow/demo.html
  • archive/model-v2/anchor/rotation-in-flow/verdict.md
  • archive/model-v2/anchor/shape-points-scale/README.md
  • archive/model-v2/anchor/spike-readout.md
  • archive/model-v2/anchor/svg-corpus/README.md
  • archive/model-v2/anchor/svg-corpus/verdict.md
  • archive/model-v2/anchor/text-ir/README.md
  • archive/model-v2/anchor/text-ir/grammar.md
  • archive/model-v2/anchor/text-ir/predictions/fable-a.txt
  • archive/model-v2/anchor/text-ir/predictions/fable-b.txt
  • archive/model-v2/anchor/text-ir/predictions/haiku-c.txt
  • archive/model-v2/anchor/text-ir/probes/p1.xml
  • archive/model-v2/anchor/text-ir/probes/p2.xml
  • archive/model-v2/anchor/text-ir/probes/p3.xml
  • archive/model-v2/anchor/text-ir/probes/p4.xml
  • archive/model-v2/anchor/text-ir/probes/p5.xml
  • archive/model-v2/anchor/text-ir/probes/p6.xml
  • archive/model-v2/anchor/text-ir/truth.txt
  • archive/model-v2/anchor/text-ir/verdict.md
  • archive/model-v2/axes.md
  • archive/model-v2/conformance.md
  • archive/model-v2/editor.md
  • archive/model-v2/finale.md
  • archive/model-v2/harnesses.md
  • archive/model-v2/models/anchor.md
  • archive/model-v2/models/bake.md
  • archive/model-v2/models/sheet.md
  • archive/model-v2/models/wire.md
  • archive/model-v2/paradigm.md
  • archive/model-v2/problems.md
  • archive/model-v2/study.md
  • archive/model-v2/survey.md
  • archive/model-v2/triage.md
  • crates/n0-model/Cargo.toml
  • crates/n0-model/README.md
  • crates/n0-model/src/animation.rs
  • crates/n0-model/src/bin/resolve_bench.rs
  • crates/n0-model/src/bin/svg_transform_scan.rs
  • crates/n0-model/src/lib.rs
  • crates/n0-model/src/math.rs
  • crates/n0-model/src/measure.rs
  • crates/n0-model/src/model.rs
  • crates/n0-model/src/n0_xml.rs
  • crates/n0-model/src/n0_xml_source.rs
  • crates/n0-model/src/ops.rs
  • crates/n0-model/src/path.rs
  • crates/n0-model/src/pick.rs
  • crates/n0-model/src/properties.rs
  • crates/n0-model/src/renderability.rs
  • crates/n0-model/src/resolve.rs
  • crates/n0-model/src/rounded_box.rs
  • crates/n0-model/src/svg_animation.rs
  • crates/n0-model/src/svgout.rs
  • crates/n0-model/src/text_layout.rs
  • crates/n0-model/src/textir.rs
  • crates/n0-model/tests/accessors.rs
  • crates/n0-model/tests/animation.rs
  • crates/n0-model/tests/animation_path_curves.rs
  • crates/n0-model/tests/animation_profile5_paints.rs
  • crates/n0-model/tests/arena_pick.rs
  • crates/n0-model/tests/common/mod.rs
  • crates/n0-model/tests/composition.rs
  • crates/n0-model/tests/derived.rs
  • crates/n0-model/tests/draft0_resolution.rs
  • crates/n0-model/tests/edge_census.rs
  • crates/n0-model/tests/escape.rs
  • crates/n0-model/tests/flip.rs
  • crates/n0-model/tests/generations.rs
  • crates/n0-model/tests/geometry.rs
  • crates/n0-model/tests/layout.rs
  • crates/n0-model/tests/lens_ops_properties.rs
  • crates/n0-model/tests/mm_laws.rs
  • crates/n0-model/tests/n0_xml_attributed_text.rs
  • crates/n0-model/tests/n0_xml_corners.rs
  • crates/n0-model/tests/n0_xml_paints.rs
  • crates/n0-model/tests/n0_xml_paths.rs
  • crates/n0-model/tests/n0_xml_properties.rs
  • crates/n0-model/tests/n0_xml_source.rs
  • crates/n0-model/tests/n0_xml_source_v2.rs
  • crates/n0-model/tests/n0_xml_source_v3.rs
  • crates/n0-model/tests/n0_xml_source_v4.rs
  • crates/n0-model/tests/n0_xml_stroke_widths.rs
  • crates/n0-model/tests/n0_xml_strokes.rs
  • crates/n0-model/tests/n0_xml_suite.rs
  • crates/n0-model/tests/op_apply.rs
  • crates/n0-model/tests/ops_suite.rs
  • crates/n0-model/tests/path_geometry_properties.rs
  • crates/n0-model/tests/properties.rs
  • crates/n0-model/tests/rotation.rs
  • crates/n0-model/tests/svg_animation.rs
  • crates/n0-model/tests/svg_animation_profile4.rs
  • crates/n0-model/tests/svg_animation_profile5.rs
  • crates/n0-model/tests/svg_animation_profile6.rs
  • crates/n0-model/tests/svgout_paints.rs
  • crates/n0-model/tests/text_layout.rs
  • crates/n0-model/tests/textir_suite.rs
  • crates/n0-model/tests/visual_only.rs
  • crates/n0/ANIMATION.md
  • crates/n0/Cargo.toml
  • crates/n0/DATA-MODEL.md
  • crates/n0/EFFECTIVE-VALUES.md
  • crates/n0/MEASURE.md
  • crates/n0/README.md
  • crates/n0/rig/baselines.json
  • crates/n0/rig/probe-baseline.json
  • crates/n0/src/bin/effective_values_demo.rs
  • crates/n0/src/bin/gate.rs
  • crates/n0/src/bin/n0_xml_render.rs
  • crates/n0/src/bin/probe.rs
  • crates/n0/src/bin/probe_gpu.rs
  • crates/n0/src/bin/svg_animation_render.rs
  • crates/n0/src/cache.rs
  • crates/n0/src/damage.rs
  • crates/n0/src/drawlist.rs
  • crates/n0/src/frame.rs
  • crates/n0/src/ident.rs
  • crates/n0/src/journal.rs
  • crates/n0/src/lib.rs
  • crates/n0/src/oracle.rs
  • crates/n0/src/paint.rs
  • crates/n0/src/playback_clock.rs
  • crates/n0/src/query.rs
  • crates/n0/src/replay.rs
  • crates/n0/src/text_layout.rs
  • crates/n0/src/trace.rs
  • crates/n0/tests/animation.rs
  • crates/n0/tests/animation_profile5_paints.rs
  • crates/n0/tests/animation_profile6_paths.rs
  • crates/n0/tests/cache.rs
  • crates/n0/tests/corners.rs
  • crates/n0/tests/damage.rs
  • crates/n0/tests/drawlist.rs
  • crates/n0/tests/frame.rs
  • crates/n0/tests/ident.rs
  • crates/n0/tests/journal.rs
  • crates/n0/tests/n0_xml.rs
  • crates/n0/tests/n0_xml_examples.rs
  • crates/n0/tests/n0_xml_slots.rs
  • crates/n0/tests/n0_xml_social_feed.rs
  • crates/n0/tests/n0_xml_source.rs
  • crates/n0/tests/paints.rs
  • crates/n0/tests/paths.rs
  • crates/n0/tests/playback_clock.rs
  • crates/n0/tests/query.rs
  • crates/n0/tests/rectangular_strokes.rs
  • crates/n0/tests/replay.rs
  • crates/n0/tests/strokes.rs
  • crates/n0/tests/support/mod.rs
  • crates/n0/tests/text.rs
  • crates/n0/tests/text_layout.rs
  • crates/n0/tests/values.rs
  • crates/n0_dev/Cargo.toml
  • crates/n0_dev/README.md
  • crates/n0_dev/TEXTBOOK.md
  • crates/n0_dev/src/camera.rs
  • crates/n0_dev/src/interaction.rs
  • crates/n0_dev/src/main.rs
  • crates/n0_dev/src/paint.rs
  • crates/n0_dev/src/scene.rs
  • crates/n0_dev/src/shell/app.rs
  • crates/n0_dev/src/shell/hud.rs
  • crates/n0_dev/src/shell/mod.rs
  • crates/n0_dev/src/shell/player.rs
  • crates/n0_dev/src/shell/player_transport.rs
  • crates/n0_dev/src/shell/window.rs
  • docs/wg/consolidation.md
  • docs/wg/feat-2d/display-list-contract.md
  • docs/wg/feat-painting/paint-model.md
  • docs/wg/feat-paragraph/text-layout.md
  • docs/wg/format/index.md
  • docs/wg/format/n0-xml-addressing.md
  • docs/wg/format/n0-xml-animation.md
  • docs/wg/format/n0-xml-component-parameters.md
  • docs/wg/format/n0-xml-component-slots.md
  • docs/wg/format/n0-xml-modules.md
  • docs/wg/format/n0-xml-properties.md
  • docs/wg/format/n0-xml.md
  • docs/wg/index.md
  • fixtures/n0-replay/crosszero.replay
  • fixtures/n0-replay/rot45.replay
  • fixtures/n0-replay/ungroup.replay
  • fixtures/test-n0-xml/cases/component-program/entry.n0.xml
  • fixtures/test-n0-xml/cases/component-program/swatch.n0.xml
  • fixtures/test-n0-xml/cases/durable-addressing.n0.xml
  • fixtures/test-n0-xml/cases/nested-rects.n0.xml
  • fixtures/test-n0-xml/cases/slot-program/entry.n0.xml
  • fixtures/test-n0-xml/cases/slot-program/post-shell.n0.xml
  • fixtures/test-n0-xml/cases/unit-path.n0.xml
  • fixtures/test-n0-xml/examples/dynamic-slide.n0.xml
  • fixtures/test-n0-xml/examples/nocturne-transit.n0.xml
  • fixtures/test-n0-xml/examples/per-side-strokes.n0.xml
  • fixtures/test-n0-xml/examples/prism-launch.n0.xml
  • fixtures/test-n0-xml/examples/pulse-analytics.n0.xml
  • fixtures/test-n0-xml/examples/rfc-only-dashboard.n0.xml
  • fixtures/test-n0-xml/examples/rfc-only-keynote.n0.xml
  • fixtures/test-n0-xml/examples/rfc-only-transit.n0.xml
  • fixtures/test-n0-xml/examples/rich-fills.n0.xml
  • fixtures/test-n0-xml/examples/rich-strokes.n0.xml
  • fixtures/test-n0-xml/examples/rich-text.n0.xml
  • fixtures/test-n0-xml/examples/rounded-surfaces.n0.xml
  • fixtures/test-n0-xml/examples/social-feed/assets/post-coastal-cabin.webp
  • fixtures/test-n0-xml/examples/social-feed/assets/post-orange-studio.webp
  • fixtures/test-n0-xml/examples/social-feed/entry.n0.xml
  • fixtures/test-n0-xml/examples/social-feed/post-card.n0.xml
  • fixtures/test-n0-xml/examples/source-becomes-surface.n0.xml

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Review on demand using usage pricing
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch model-v2-anchor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

CI's first-ever linux run of the v2 suites exposed a pre-existing
platform sensitivity: paint::read_pixels requested native-N32
(RGBA on Apple Silicon, BGRA on x86 linux), so byte-order assertions
in animation_profile5_paints failed on ubuntu. Pin the readback to
explicit RGBA8888 premul — the same rule tests/grida_xml.rs already
applies ("so the assertions do not depend on native N32"). Byte
output on Apple Silicon is unchanged: n0 suites and the gate's four
shot goldens re-verified IDENTICAL after the fix.

oxfmt (node.yml fmt:check): the frozen model-v2/ archive joins the
formatter's ignore list (kept verbatim per its tombstone); the live
crates/n0 docs are formatted.

Part of landing #5.
@softmarshmallow
softmarshmallow marked this pull request as ready for review July 19, 2026 09:45
The experiment-ledger codes (E1/E3/E4/E5/E10) were plan-sequence
names, not names of things; live artifacts now carry names per their
end-state role:

- bins: e4 -> resolve_bench, e5scan -> svg_transform_scan
- the "historical E3 TextIr" dialect -> "the historical TextIr
  dialect" (doc comments, error strings, and the test asserting on
  them, in lockstep)
- window/HUD titles and bin headers drop "E10"/"E4" for descriptive
  names; crate docs describe the experiments instead of citing their
  ledger ids (the ledger id survives only as a parenthetical archive
  citation where provenance matters)

Deliberately KEPT: registry citations (R-E1, G-E2, L-E1, D-E1, E-A*,
DEC-*, V-*, ENG-*) — these cite the archived conformance edge
registries, spec-delta register, and decision/contract catalogues;
scrubbing them would sever rule-to-registry traceability. SVG
animation Profile 0-6 identifiers are spec profile ids, not plan
codes.

Part of landing #5.
…n-slots

Renames (63 tracked renames, content byte-identical):
- models/{a,b,c,d}.md -> models/{anchor,sheet,bake,wire}.md — the
  files now carry the working identifiers their own README declared
- model-v2/a/ -> model-v2/anchor/ — the winner's workbench named for
  what it is
- experiment dirs drop their eN- ledger prefixes: rotation-in-flow/,
  format-roundtrip/, text-ir/, resolver-spike/, svg-corpus/,
  pluggable-layout/, shape-points-scale/ (dec0-* keeps its decision-
  register id)
- crates/n0_dev/SPIKE.md -> model-v2/anchor/spike-readout.md — a
  frozen session read-out belongs in the archive, not a live crate
  (TEXTBOOK.md stays: living migration doctrine)

Every repo reference rewritten (live crates, archive papers, demo
pages); the E1-E10 ids remain the experiment ledger's register keys in
prose and in anchor/README.md's table, which now also carries the
old-name -> new-name map. The archive convention note is amended:
content verbatim, names canonicalized at landing, frozen papers'
relative paths still mean the pre-promotion layout. One frozen
historical command quote in proof.html deliberately keeps the old bin
name (it records what was run).

Part of landing #5.
The XML source format is v2-native, and v2 is n0 — the format now
carries the engine's name (owner directive):

- modules/APIs: grida_xml -> n0_xml, grida_xml_source -> n0_xml_source,
  Dialect::GridaXml -> N0Xml; bin grida_xml_render -> n0_xml_render;
  all n0/n0-model test files renamed in kind
- file extension: .grida.xml -> .n0.xml (rig examples + fixtures
  renamed; every reference updated)
- docs/wg RFD family: format/grida-xml*.md -> format/n0-xml*.md with
  repo-wide link updates; the main RFD gains a "Formerly" continuity
  note; frontmatter keeps "grida xml" as a search keyword
- the term "Grida XML" -> "n0 XML" repo-wide, including the archive
  (the archive convention note now records the term rename as one of
  the two canonicalizations applied at landing)

Deliberately unchanged: the Draft-0 wire grammar — the
<grida version="0"> root element is NOT renamed by this commit; a
grammar rename is a spec decision, flagged as an open item in the RFD
rather than smuggled through a term sweep. Legacy crates: zero
references, zero touch.

Part of landing #5; tracking #9.
…nvention

Per the fixtures doctrine (deterministic test inputs live under
fixtures/<domain>/), the engine's rig corpus moves out of the crate:

- crates/n0/rig/corpus/*.replay      -> fixtures/n0-replay/
- crates/n0/rig/examples/*.n0.xml    -> fixtures/test-n0-xml/examples/
  (incl. social-feed/ with its webp assets)
- crates/n0/rig/fixtures/*.n0.xml    -> fixtures/test-n0-xml/cases/
  (incl. component-program/, slot-program/)
- all 14 SVG animation profile sources (showcases + boundaries)
  -> fixtures/test-svg/animation/ — joining the existing SVG fixture
  domain, and dissolving the cross-crate include (n0-model tests no
  longer reach into n0's tree; both crates now include from
  fixtures/)

crates/n0/rig/ keeps only baselines.json + probe-baseline.json — gate
state (machine-local budget/probe records), not fixtures.

Authored relative resource paths inside the moved .n0.xml documents
are rebased to their new location (../../images/...); every code and
doc reference updated; the gate re-verified green from the new corpus
location (shots IDENTICAL, replays DETERMINISTIC, differential
MATCHES).

Part of landing #5.
The post-landing program (phases 0-6 with entry/exit gates, first
three PRs, the owner decision registry, known unknowns) — synthesized
from the three-lens panel + adversarial judge and ratified by the
owner's review. Git-persisted so it survives agent sessions (named
consolidation.md, not *.plan.md — that suffix is the repo's untracked
working-plan convention); the umbrella tracking issue mirrors it.

Part of landing #5; tracking #9.
The frozen v2 workbench record moves from the repo root
(model-v2/) to archive/model-v2/ — a dedicated home for
concluded-program records (owner directive: the workbench should not
sit at the repo root on main). archive/README.md declares the
convention; future concluded programs land as archive/<program>/.

Every live reference updated (crate docs, WG docs, AGENTS/README,
issue links follow separately); the oxfmt ignore generalizes from
model-v2/ to archive/. The tombstone banner records the relocation;
archive-internal relative links are unaffected (the tree moved
wholesale).

Part of landing #5.
@softmarshmallow
softmarshmallow merged commit a2d7c29 into main Jul 19, 2026
8 checks passed
softmarshmallow added a commit that referenced this pull request Jul 19, 2026
Adopt the complete review-only candidate from GitHub Actions run 29700301719, artifact 8446425713 (zip SHA-256 469e3fbf2a526611f61f1d43220dc966bcc414ba290595dd0e97d6b2f3fed978). The manifest records source ed0f310, ubuntu-24.04 x86_64, Rust 1.92.0, and skia-safe 0.93.1.

Captured essence: preserve all four named 1360x900 RGBA states, paired shot/timing ownership, same-host determinism, replay determinism, the ENG-0.2 differential, scene-cache equality, and the generous max(1.5x, +50us) timing rule. The candidate gate passed every portable check before installing and uploading exactly five files.

Etiology: the outgoing images came from 7c101b9 on aarch64-macos. Main commit abe0305 then deliberately changed the footer from the plan-code name anchor spike — E10 to n0_dev — anchor spike without updating the shots; that source change accounts for exactly 4,010 pixels in each current macOS render. Comparing current source across macOS and Ubuntu changes 2,627-3,992 pixels per shot (0.215-0.326%); visual diffs are confined to text rasterization, while geometry and colors align.

The timing numbers move from incomparable macOS measurements to CI-owned min-of-11 measurements: starter 15.639/1.654us and flat10k 1076.711/269.591us for resolve/build. This is an authority transfer, not a performance claim.

Deliberate drop: retire only aarch64-macos baseline authority and the stale E10 footer pixels. Preserve their provenance here and in #5/#44. format/grida.fbs, the published canvas-wasm freeze, probe-baseline.json, renderer behavior, and fixture content remain untouched.
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.

1 participant