@ai-matrx/content-ir 0.12.0 → 0.14.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,124 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.14.0 — 2026-09-25
4
+
5
+ **`/source` — RC-B3 polish: the re-verification residuals, and the verifier's
6
+ attacks made permanent** (common-docs
7
+ `projects/rich-content-unification/evidence/verify-RC-B3.md` § Re-verification).
8
+ Each residual had a failing test first (R1–R3 red on 0.13.0; the new
9
+ cross-language vectors fail 10 cases on the old Python twin):
10
+
11
+ - **R1** — an insertion carrying an exact copy of the next island at its
12
+ expected offset no longer causes a false `integrity` refusal: an island's
13
+ candidate positions are scored by how much of the original text still
14
+ surrounds them.
15
+ - **R2** — `tokenizeSource(text, { streaming: true })`: the last,
16
+ still-unterminated line closes no fence (a bare ```` ``` ```` there may grow
17
+ into ```` ```bash ````). Stored text omits the option.
18
+ - **R3** — `listIslands` loops instead of spreading, so a block with 150k
19
+ inline islands saves without a `RangeError`.
20
+ - **R4** — the fence rule defines its whitespace: `FENCE_WHITESPACE`
21
+ (CommonMark ASCII whitespace) and `trimFenceLine`, which every caller uses
22
+ in place of a language's `trim()`. The vectors carry U+FEFF, U+0085,
23
+ U+00A0, U+001C–U+001F and U+2028 lines; aidream matrx-ai's Python twin
24
+ gained `FENCE_WHITESPACE` / `trim_fence_line` and passes them.
25
+ - **R5** — tilde and odd-whitespace fences: matrx-frontend's
26
+ `source-covers-renderer` property test proves the tokenizer locks at least
27
+ every fenced block the renderer draws (both now share `trimFenceLine`).
28
+ - **Permanent attack suite** — `__tests__/source-attack.test.ts`: seeded fuzz
29
+ of rejoin identity, offsets (independently counted), surrogate safety,
30
+ no-edit/identity saves, splice verdicts, island refusals, misaligned spans,
31
+ streaming prefixes (settled islands never move) and pathological timing
32
+ (budget + linear scaling), bounded in CI; `SOURCE_ATTACK=long` runs the
33
+ verifier-scale version.
34
+
35
+ **Consumer action:** fence-line classification callers trim with
36
+ `trimFenceLine(line)` (matrx-frontend's splitters do as of this release).
37
+
38
+ **`/source` — islands for the extended markdown syntax** (RC-B8, common-docs
39
+ `projects/rich-content-unification/REGISTER.md`). The renderer now draws
40
+ callouts, directives, front matter, footnotes and wikilinks; an editor must
41
+ never re-serialize their grammar, so each is now an island:
42
+
43
+ - `directive` (block) — a generic-directive container `:::name[label]{attrs}`
44
+ … `:::` with nesting counted (tabs, columns, details, figures, callouts,
45
+ TOC), a leaf `::name` line (`meta.leaf`), or a MkDocs admonition
46
+ `!!! type "Title"` / `??? type` with its indented body (`meta.syntax: "mkdocs"`).
47
+ An unclosed container runs to the end with `complete: false` (streaming).
48
+ - `callout` (block) — a blockquote opening `> [!TYPE]` (GitHub alert /
49
+ Obsidian callout; `meta.name`, `meta.fold`).
50
+ - `footnote_def` (block) — `[^id]: …` with its continuation lines (`meta.id`).
51
+ - `front_matter` now also recognizes TOML (`+++`); `meta.format` is `yaml` | `toml`.
52
+ - `wikilink` (inline) — `[[Page]]`, `[[Page|alias]]`, `![[Page]]`
53
+ (`meta.target`, `meta.embed`); never across a line, never inside code.
54
+
55
+ CSV/TSV fences were already `fence` islands (`meta.lang`). Guard:
56
+ `__tests__/source-markdown-syntax-islands.test.ts` (7 of 10 red on 0.13.0).
57
+
58
+ **Consumer action:** an exhaustive `switch` over `IslandType` /
59
+ `BlockIslandType` gains the new members; nothing else changes (joinSource is
60
+ still byte-identical, the corpus check stays green).
61
+
62
+ **Single-dollar math: single-letter math shapes are math** (RC-B2 verification,
63
+ common-docs `projects/rich-content-unification/evidence/verify-RC-B2.md`).
64
+ `isSingleDollarMath` now also accepts a shape built only from single-letter
65
+ identifiers (primes, standard function names), digits, parentheses, commas and
66
+ `- * /` that applies, primes or juxtaposes them — `$f(g(x))$`, `$u v$`,
67
+ `$f'(x)$`, `$(x, y)$`, `$ln(x)$`. Words keep it text (`$Tipping (fee)$`), and
68
+ the pandoc spacing / digit rules still keep currency (`$5 and $10`, `$5-$10`)
69
+ as text. Guard: `__tests__/single-dollar-math.test.ts` (5 of 12 red before).
70
+
71
+ **Consumer action:** none — adopt the release; matrx-frontend's math
72
+ normalizer and `/source` tokenizer pick the rule up through the import.
73
+
74
+ ## 0.13.0 — 2026-09-25
75
+
76
+ **`/source` — fixes from the RC-B3 independent verification**
77
+ (common-docs `projects/rich-content-unification/evidence/verify-RC-B3.md`).
78
+ Every finding got a failing test first (`__tests__/source-verify-findings.test.ts`,
79
+ 14 of the 17 non-timing tests red on 0.12.0), then the fix:
80
+
81
+ - **THE nested-fence rule now lives here** (`source/fence-nesting.ts`, moved from
82
+ matrx-frontend `components/markdown-core/fence-nesting.ts`): inside a
83
+ ```` ```markdown ```` / `md` / `mdx` fence, ```` ```lang ```` opens a nested
84
+ fence and a bare ```` ``` ```` closes the innermost one; a nested fence still
85
+ open at the end of the text retries strict CommonMark. The tokenizer uses it,
86
+ so it ends a nested markdown fence exactly where the renderer does (real row:
87
+ note `f9b7e9a2-…`). Generated cross-language vectors
88
+ `__tests__/fence-nesting-vectors.json`; aidream matrx-ai's Python twin runs a
89
+ byte-identical copy and fails on drift.
90
+ - **Islands change only through `islandEdit(island, text)`.** A plain edit must
91
+ carry every island inside its range back byte-identical and in order —
92
+ otherwise `SourceSpliceError("island_edit")` names the island. Edits are
93
+ diffed segment by segment between islands, so anchors inside an edited
94
+ paragraph map exactly.
95
+ - **Integrity is refused by default.** `requireIntegrity` defaults to `true`;
96
+ `false` is documented as tooling-only.
97
+ - **Linear time on pathological input.** Every closer search goes through an
98
+ occurrence index; code spans use a per-paragraph run table; the single-`$`
99
+ scan stops at the rule's 400-character limit; embedded `__kind` probing has a
100
+ per-paragraph budget; `readXmlTag` takes a finder. 2 MB of `{{`: 21 s → 41 ms.
101
+ - **A tree's root label belongs to the tree island** (the renderer splitter's
102
+ `findTreeBlockStart`).
103
+ - **`$$` follows the core's pairing rule** (`source/math-pairs.ts`, ported from
104
+ `@ai-matrx/kit/delimiter-guard`): tokens outside code pair in order, prose
105
+ pairs are not math, an unpaired `$$` is literal. `$$` at the end of a line
106
+ pairs with a later closer, and a lone `$$` never locks the rest of a document.
107
+
108
+ ### Consumer action
109
+
110
+ - `spliceSave` now THROWS on an island change (`island_edit`) and on disturbed
111
+ integrity (`integrity`). Editors change islands with `islandEdit`; tooling
112
+ that wants the report passes `requireIntegrity: false`.
113
+ - matrx-frontend: import the fence rule from `@ai-matrx/content-ir/source`; the
114
+ local `components/markdown-core/fence-nesting.ts` is deleted.
115
+
116
+ ## 0.12.1
117
+
118
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
119
+ `git diff npm/content-ir-core/v0.12.0..npm/content-ir-core/v0.12.1 -- apps/shared/content-ir-core`).
120
+ No source changes intended and no consumer action required.
121
+
3
122
  ## 0.12.0 — 2026-09-23
4
123
 
5
124
  **`/source` — the stored text is the truth, block by block** (rich-content