Files

169 lines
9.6 KiB
Markdown

# C2-11a: an inert editor wikilink node
Base: aca16404c. Owner: Herb. Reviewer: Filbert. Issue: #1715.
Authority: sage-2794, Q220/mos-1301. The assignment permits authoring the
node and tests before the measurement slot. Runs, claim and pushes wait
for Sage's CLEAR. After row253 lands, a new branch will carry the change
onto its landing with every landed hunk retained.
## Measurement before choosing the explanation
Run agents/herb/work/queue-214/measure.mjs only on a granted slot. It loads
aca16404c's editor.js and markdown-preview.js directly from local Git
objects. It verifies the editor bundle hash against that base's BUILD.json.
It cannot accidentally measure a candidate rebuild. Its JSON records the
full baseline SHA, bundle hash, timestamp, input, output and equality for
each fixture. The first five are the brief's plain, labelled, heading,
list and front-matter cases; extra cases cover a heading block, combined
heading/label, Unicode/spacing, adjacency and an inert embed. No result is
available yet. Static reasoning is not a measurement.
Outcome A, every baseline round-trip is equal: record that wikilinks do
not trigger Source fallback for the measured inputs. Do not claim that
bug exists. The source's raw/sig cache explains why an unchanged block can
keep its bytes even when its canonical serializer escapes brackets. Add
the node for structured wikilinks and dirty-block preservation, as the
brief requests. A baseline structural/edit regression must fail even if
all unchanged-file checks pass.
Outcome B, one or more differ: record the exact differing bytes and affected
contexts. Keep the existing Source fallback fail-closed. The node restores
the required spellings where the block is structured. Retain the same
no-edit and dirty-block regressions. If the mismatch comes from a separate
block, line-ending or front-matter defect, report it before widening scope.
## Representation and conversion
The schema gains one inline atom, wikilink, with a single source attribute.
Its source is the complete spelling, not reconstructed target/label parts.
It has no href, navigation, fetch or click behavior. A span with data-source
and a text child displays the spelling. Heading content includes the new
atom; paragraphs, quotes and lists already accept inline content.
One markdown-it inline rule runs before ordinary links, after escapes and
backticks. A sticky match reads a complete single-line [[...]] or ![[...]]
without copying every suffix or crossing state.posMax. The node writer
writes its validated spelling without bracket escaping, so editing adjacent
text cannot rewrite a wikilink. Front matter remains a raw block. No new
file-read, save, routing, documentPath or target-resolution behavior is added.
The accepted atom grammar excludes brackets within the body, line breaks,
angle brackets and ampersands. This is an editor representation boundary,
not a library resolver or a refusal to open such a file. Malformed,
HTML/entity-like and code syntax stays under the existing text/raw rules.
This preserves the existing escaping of HTML/entities when a block changes.
DOM paste accepts only that same grammar. Invalid attributes constructed
programmatically are flattened to one line and escaped by the text writer.
No input string is parsed as HTML and embeds never load an image.
## Acceptance and review
The measurement JSON goes in BUILD.md and the final manifest packet.
Ten fixture round-trips run with and without a final newline. A browser
test inspects real ProseMirror atom types and attributes, edits the same
block and reparses it, for each fixture. Two more browser tests cover
code/escape/malformed/hostile syntax and DOM/programmatic-attribute safety.
Tests use the existing fixture and Chromium harness and the shipped bundle.
They do not export new production APIs just for testing.
Before rebuilding, run only the structural regression against the baseline
bundle and observe it fail. Rebuild the candidate with the exact pinned
esbuild0.28.2 binary, run the whole new test file, existing editor tests,
editor browser tests and provenance test. Remove only the wikilink serializer
handler for one mutant; the dirty-block assertion must fail. Restore, rebuild
and rerun the focused regression. All execution needs Sage's CLEAR, including
installation, checks, builds, browser tests and the measurement.
The checked-in bundle and editor/BUILD.json must be regenerated by the
existing build script. No hand edits of generated JavaScript or provenance.
The current shared esbuild is0.28.1 and the local webui install is absent.
A granted npm ci --ignore-scripts --no-audit --no-fund in packages/webui is
needed before building; the root node_modules remains its plain symlink.
No dependency or lockfile change is planned.
Final gate: Filbert approves the manifest, then the whole webui suite and
every scripts/test-*.sh on Sage's slot. Two failures stop a gate. A failure
outside this row is reported to Sage before any rerun. Source, generated
output, mode/hash manifest and raw granted logs identify the candidate.
## Static review follow-through (Filbert, 2026-10-22T16:43:35Z)
R1: the focused editor-provenance run and Sage's whole webui gate must set
MOSAIC_REQUIRE_EDITOR_BUILD=1. A missing, wrong-version or unpinned binary
then fails. Check every log for ^# skip, as well as TAP # SKIP directives
and the spec reporter's skipped-test lines; record each skipped name and
reason. A skipped rebuild is not proof of bundle reproducibility. The CSS
output must stay byte-identical and match BUILD.json.
R2: no-edit roundTrip checks are expected to pass on the baseline because
parse sets sig=canonical and an unchanged serialise returns lead+raw. Their
green result is compatibility evidence, never evidence that the atom was
needed or installed. The same-block edit/structural regression is the red
that proves the new node. The required measurement still runs and is kept.
N1: bus.js checks visual mode at949 on this base and also requires
MosaicMarkdown. The measurement uses the existing helper's bare-window VM
shape, markdown-preview.js first, then editor.js, both from pinned Git blobs.
N2: the exclusion of & and angle brackets is deliberate: the existing
text serializer escapes entities/HTML when it rewrites a block for another
renderer. An atom's verbatim writer must not bypass that rule, including
for pasted/programmatic values. This keeps those targets as ordinary text;
[[Q&A]] will still be escaped if its own block changes. It is a known
representation limit beyond the five brief cases, not a resolver change.
It is included among the text-only cases. Unedited bytes remain intact.
N3: the reference-definition fixture [[a]] with [a]: u deliberately becomes
one inert wikilink rather than a bracket around a reference link. Literal
spelling and the separate definition block remain intact.
N4: [x [[a]]](u) is an explicit fixture. The atom inherits the enclosing
ordinary link mark, whose existing target gate still applies. The atom
itself supplies no href or new click behavior; the fixture checks its
structure and spelling before/after a same-block edit.
N6: every granted browser/test process gets TMPDIR from
mktemp -d /mnt/storage/scratch/tmp/gXXX. Never /tmp. Sweep owned Chromium
and Node processes by cwd and the temp-root path after the mutant, after
any timeout, and before clearing the slot. Retain/report uncertain owners.
## R2 current-base check, sage-4164 (2026-10-24)
The execution base is now487500a16, on herb/row214-r2, not the historical
aca16404c above. The two accepted document commits were cherry-picked
cleanly. The model, build script, toolchain, BUILD.json, editor.js, view,
entry and editor test loader are byte-identical between those bases. The
current fixture's new configDirectory isolation is retained; it is not
copied from the old worktree. The visual-mode check is now bus.js:1054.
The current C2-11a brief section is unchanged. Row266's chat modules,
public/chat.js and public/chat.css are outside this row, with no overlap.
measure.mjs now pins487500a16's Git objects and BUILD.json. The baseline
bundle still lacks the atom, and the first executed structural regression
will use it before any rebuild. The required measurement, red/green, pinned
rebuild, mutant kill and full gate remain unrun and required. Runtime
validation is not inferred from the unchanged source or this static check.
Sage-4164 explicitly authorizes committing the preserved local node/tests
on the new branch before execution. The authored source commit is static
work, not a green candidate. No Node, npm, rebuild or browser starts until
Sage sends CLEAR. HASH-PINS.json records the test-tree audit and row266
intersection. The gate still requires MOSAIC_REQUIRE_EDITOR_BUILD=1, a
named skip list, whole webui and every scripts/test-*.sh.
## R2 static follow-up, Filbert B1/N1 (2026-10-24T17:14:55Z)
B1: state.text(..., true) escapes Markdown punctuation, not HTML/entities.
The invalid-atom writer now calls the same escapedText helper as ordinary
text nodes, including the <& step. Valid atoms still preserve their source
verbatim. The malformed-attribute regression now asserts both an escaped
<img and an escaped &copy;, plus flattened line breaks. A second mutant
will replace only the invalid atom's escapedText call with state.text,
leaving normal text escaping intact; this browser regression must kill it.
This additional mutant needs Sage's grant alongside the serializer-removal
mutant. No runtime result is claimed for either.
N1: backticks are excluded from the atom body, preserving code-span
precedence. The text-only fixture includes [[a`]]` and must produce no
wikilink atom. All other malformed/HTML/entity boundaries remain as before.