@ai-matrx/content-ir 0.11.7 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,99 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.0 — 2026-09-25
4
+
5
+ **`/source` — fixes from the RC-B3 independent verification**
6
+ (common-docs `projects/rich-content-unification/evidence/verify-RC-B3.md`).
7
+ Every finding got a failing test first (`__tests__/source-verify-findings.test.ts`,
8
+ 14 of the 17 non-timing tests red on 0.12.0), then the fix:
9
+
10
+ - **THE nested-fence rule now lives here** (`source/fence-nesting.ts`, moved from
11
+ matrx-frontend `components/markdown-core/fence-nesting.ts`): inside a
12
+ ```` ```markdown ```` / `md` / `mdx` fence, ```` ```lang ```` opens a nested
13
+ fence and a bare ```` ``` ```` closes the innermost one; a nested fence still
14
+ open at the end of the text retries strict CommonMark. The tokenizer uses it,
15
+ so it ends a nested markdown fence exactly where the renderer does (real row:
16
+ note `f9b7e9a2-…`). Generated cross-language vectors
17
+ `__tests__/fence-nesting-vectors.json`; aidream matrx-ai's Python twin runs a
18
+ byte-identical copy and fails on drift.
19
+ - **Islands change only through `islandEdit(island, text)`.** A plain edit must
20
+ carry every island inside its range back byte-identical and in order —
21
+ otherwise `SourceSpliceError("island_edit")` names the island. Edits are
22
+ diffed segment by segment between islands, so anchors inside an edited
23
+ paragraph map exactly.
24
+ - **Integrity is refused by default.** `requireIntegrity` defaults to `true`;
25
+ `false` is documented as tooling-only.
26
+ - **Linear time on pathological input.** Every closer search goes through an
27
+ occurrence index; code spans use a per-paragraph run table; the single-`$`
28
+ scan stops at the rule's 400-character limit; embedded `__kind` probing has a
29
+ per-paragraph budget; `readXmlTag` takes a finder. 2 MB of `{{`: 21 s → 41 ms.
30
+ - **A tree's root label belongs to the tree island** (the renderer splitter's
31
+ `findTreeBlockStart`).
32
+ - **`$$` follows the core's pairing rule** (`source/math-pairs.ts`, ported from
33
+ `@ai-matrx/kit/delimiter-guard`): tokens outside code pair in order, prose
34
+ pairs are not math, an unpaired `$$` is literal. `$$` at the end of a line
35
+ pairs with a later closer, and a lone `$$` never locks the rest of a document.
36
+
37
+ ### Consumer action
38
+
39
+ - `spliceSave` now THROWS on an island change (`island_edit`) and on disturbed
40
+ integrity (`integrity`). Editors change islands with `islandEdit`; tooling
41
+ that wants the report passes `requireIntegrity: false`.
42
+ - matrx-frontend: import the fence rule from `@ai-matrx/content-ir/source`; the
43
+ local `components/markdown-core/fence-nesting.ts` is deleted.
44
+
45
+ ## 0.12.1
46
+
47
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
48
+ `git diff npm/content-ir-core/v0.12.0..npm/content-ir-core/v0.12.1 -- apps/shared/content-ir-core`).
49
+ No source changes intended and no consumer action required.
50
+
51
+ ## 0.12.0 — 2026-09-23
52
+
53
+ **`/source` — the stored text is the truth, block by block** (rich-content
54
+ unification PLAN decision 6, register row RC-B3). New subpath
55
+ `@ai-matrx/content-ir/source` (also re-exported from the root):
56
+
57
+ - `tokenizeSource(text)` — the offset-preserving tokenizer. Blocks
58
+ `{ kind: "prose" | "island" | "gap", islandType, start, end, startCp, endCp,
59
+ raw, complete, meta, inlines }` cover the text exactly (the concatenation of
60
+ `raw` IS the input — nothing trimmed or normalized). Every protected
61
+ construct is an island: code fences (incl. special languages, the ```json
62
+ string-aware close), bare typed / `__kind` / directive JSON, known XML
63
+ regions, attribute XML (line-leading and mid-line), unknown XML containers
64
+ (the renderer splitter's own balance tracker, ported), raw HTML blocks and
65
+ tags, HTML comments and pinned anchors `<!--@a:id-->`, `$$` / `\(` / `\[`
66
+ math and THE single-dollar rule, `{{variables}}`, `<matrxcite/>`, embedded
67
+ `__kind` JSON, `[Image URL: …]` media refs, front matter, box-drawing trees.
68
+ Islands inside a paragraph stay in that prose block as `inlines`.
69
+ Streaming-tolerant: an unclosed construct is an island to the end of the
70
+ text with `complete: false`; never throws. Offsets in UTF-16 and code points.
71
+ - `spliceSave(original, edits)` — save = splice. Block-aligned replacements;
72
+ bytes outside the edits are copied, never rebuilt; no-op edits return the
73
+ original string. Returns a change set narrowed to the bytes that differ
74
+ (UTF-16 + code points) for anchor mapping (`mapPosition`, `mapRange`,
75
+ ProseMirror StepMap semantics — STORE-DESIGN §3.19) and an integrity
76
+ report naming any island outside the edit that the edit disturbed
77
+ (`requireIntegrity: true` throws instead).
78
+ - `isSingleDollarMath` / `singleDollarMathEnd` — THE single-dollar math rule,
79
+ moved here from matrx-frontend's math normalizer so the renderer and the
80
+ tokenizer can never disagree.
81
+ - `readXmlTag`, `XmlContainerTracker`, `buildCodePointIndex`,
82
+ `toCodePointOffset`, `toUtf16Offset`, `joinSource`, `listIslands`,
83
+ `blockAt`, `blockEdit`, `blockRangeEdit`.
84
+
85
+ Proof: 39 tests (fixture corpus of every construct, 2,000 adversarial random
86
+ documents, every prefix of every fixture, 1,000 random single-block edits;
87
+ two planted mutations turned the suite red). matrx-frontend's read-only
88
+ `pnpm check:source-roundtrip` ran every stored row — notes, chat text parts,
89
+ agent and template messages, message templates, skills — 135,302 rows, all
90
+ byte-identical, all edit-local.
91
+
92
+ ### Consumer action
93
+
94
+ None required — additive. matrx-frontend adopts `isSingleDollarMath` from
95
+ `/source` in its math normalizer.
96
+
3
97
  ## 0.11.7
4
98
 
5
99
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/README.md CHANGED
@@ -18,6 +18,8 @@ The root export is the full surface and always will be. Since 0.10.0 each intern
18
18
  | `@ai-matrx/content-ir/registry` | kind registry types, storage transform, the dual gate |
19
19
  | `@ai-matrx/content-ir/convert` | kind ⇄ JSON Schema, the OpenAI structured-output converter |
20
20
  | `@ai-matrx/content-ir/wire` | partial-kind events, runtime wrapper readers, emit payload |
21
+ | `@ai-matrx/content-ir/directives` | Kind Directives: slug grammar, the ONE decoder |
22
+ | `@ai-matrx/content-ir/source` | offset-preserving source tokenizer, splice save + anchor-mapping change set, the single-dollar math rule |
21
23
 
22
24
  ```ts
23
25
  import { createKindStreamParser, envelopeFromCompleteValue } from "@ai-matrx/content-ir/core";