@ai-matrx/content-ir 0.16.2 → 0.18.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,11 +1,105 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.0 — 2026-09-25
4
+
5
+ **`/source` `isSingleDollarMath`: `$FC$` is math.** (RC-B9 verifier, RC-B3.)
6
+ `where $FC$ is fixed costs.` drew literal dollars on screen and in every
7
+ export, because the rule wanted an operator, a lone variable or a TeX
8
+ command. It now follows Pandoc's `tex_math_dollars` delimiters (what
9
+ remark-math approximates, and how ChatGPT and Claude render): the opener is
10
+ followed by a non-space; the closer is preceded by a non-space and not
11
+ followed by a digit. `$5 and $10`, `$5-$10`, `$5/$10` stay currency. On top,
12
+ content that reads as something else is refused: an unescaped `%`; a closing
13
+ bracket or `/` first, an opening bracket last; a straight quote at either
14
+ end; `:` `;` `,` `/` last; a number glued to a following letter
15
+ (`$10$N9qo…`); a placeholder (`$...$`); and prose (two plain words, a
16
+ contraction, an abbreviation) unless a TeX command or operator is present.
17
+ Measured before choosing (matrx-frontend
18
+ `scripts/measure-single-dollar-rule.ts`, 85,102 assistant messages and 4,298
19
+ notes, read-only): 128 spans become math, each one a formula on review
20
+ (`$FC$`, `$VC$`, `$(0, 0)$`, `$2a$`, `$3x + 6 = 15$`, `$XY$`, `$p(doom)$`);
21
+ 22 spans the old rule drew as math stop (jQuery `$("#id")`, template literals
22
+ `${id}:${…}`, a printf `%1$s`, broken TeX); 0 currency spans become math.
23
+ Pure Pandoc would have added 36 more false positives (shell `$HOME/…:$PATH`,
24
+ `$\ge$20% …**$`, `[$X] … [$Y]`, bcrypt costs). Shared vectors:
25
+ `__tests__/fixtures/single-dollar-vectors.json` (red on 0.17.0). No other
26
+ implementation of this rule exists (the Python server has none).
27
+
28
+ **New: `looksLikeOpenInlineMath(partial)`** — whether an UNCLOSED `$…`
29
+ already reads as a formula while a stream is still arriving. It keeps the
30
+ old signal rule (a TeX command or operator, a lone variable, a single-letter
31
+ shape; a leading digit needs a TeX command), because without a closer there
32
+ are no delimiter facts yet: `$35 per stop` keeps showing mid-stream.
33
+
34
+ Also carries the committed RC-B10 code-range work in `source/code-ranges.ts`
35
+ and `source/tokenize.ts`. The print lane owns its entry.
36
+
37
+ **Consumer action:** a streaming healer that asks `isSingleDollarMath` about
38
+ an unclosed `$…` tail must ask `looksLikeOpenInlineMath` instead. With the
39
+ wider rule, a price like `$35 per stop` would otherwise be held back until
40
+ the line ends. matrx-frontend `stream-heal.ts` is the one known caller.
41
+
42
+ ## 0.17.0 — 2026-09-26
43
+
44
+ **`/source` streaming: what "settled" promises, pinned — and the one
45
+ documented exception** (verify-RC-B3 § Re-verification (0.16.0): G3, G6, H1,
46
+ H2). The verifier's mutations M1–M13 each turn
47
+ `__tests__/source-attack.test.ts` red ON ITS OWN — including the three
48
+ holdbacks the 0.16.0 suite could not see (M9 unclosed backtick, M10 open `{`
49
+ line, M12 pending `$$`), the `$$` open-tail rule (M11) and the held footnote
50
+ (M13). Unmutated: green in CI and in 10 consecutive long runs under 24 CPU
51
+ spinners.
52
+
53
+ - **G3** — the suite's bounds are counts, never the clock, so no test may be
54
+ failed by the clock either: an explicit suite-wide timeout (15 min CI, 1 h
55
+ long). 0.16.0's long mode died on vitest's default 5 s timeout while every
56
+ work assertion held.
57
+ - **G6** — each streaming holdback is pinned directly and by a flicker
58
+ message, and a new property checks, over random documents with and without
59
+ a final newline, that every island a stream shows as settled is the one-shot
60
+ island.
61
+ - **H1** — a footnote whose continuation is undecided (it ends the text, or
62
+ the next line is still arriving — even one that currently looks like a
63
+ block) is held open (`complete: false`), never shown settled.
64
+ - **H2 (chair ruling, 2026-09-26)** — a late orphan `</thinking>` /
65
+ `</think>` / `</reasoning>` closer is the ONE documented exception: it folds
66
+ the text before it into a thinking region retroactively. Consumers re-read
67
+ the finished text one-shot when a stream completes (README § streaming
68
+ mode); matrx-frontend's chat renderer does the same for its accumulator.
69
+ - The property found and fixed further settle-then-change classes, each now
70
+ held back in streaming mode: a lone allowed HTML tag at any block start on
71
+ the open line; an undecided single-`$` span (everything from its opener);
72
+ a code span the final paragraph may still close (`pendingCodeSpanStart`,
73
+ counting a single trailing newline as still-open) — held only for the `$$`
74
+ readings it can change; `$$` pairs that a completing backtick / tilde run
75
+ would re-pair. The paragraph's end is always computed exactly as one-shot
76
+ computes it; only what is reported stops at the provisional point.
77
+
78
+ **New (`/source` `findCodeRanges`, `CodeRange`): THE ONE code-range rule**
79
+ (RC-B10 one-canonical). Fenced blocks and inline code spans by CommonMark —
80
+ a fence opens only at line start (≤3 spaces) and closes by the one
81
+ fence-nesting rule; a code span pairs equal backtick runs within one
82
+ paragraph. Moved out of `math-pairs` (with `pendingCodeSpanStart`) so every
83
+ package asks one function: `@ai-matrx/kit` delimiter-guard and
84
+ `@ai-matrx/chat` speakable text now import it. Shared vectors:
85
+ `__tests__/fixtures/code-range-vectors.json` (read by content-ir and kit).
86
+ Guard: `__tests__/one-code-range-rule.test.ts` fails on any NEW fence/code-span
87
+ detection in `apps/shared` (shrink-only census of the existing walkers).
88
+
89
+ **Consumer action:** streaming consumers re-tokenize one-shot on completion
90
+ (the H2 contract). Stored text is unaffected.
91
+
3
92
  ## 0.16.2
4
93
 
5
94
  - **Fixed (`/source` `pairDisplayMath`, `pendingDisplayMathOpener`):** a
6
95
  `$$...$$` / `$$…$$` placeholder in prose was paired as display math. New
7
96
  `isMathPlaceholder(inner)`; such a pair is consumed whole as literal text.
8
97
  Same rule as `@ai-matrx/kit` `delimiter-guard`.
98
+ - **Fixed (`/source` `pairDisplayMath`): an inline triple backtick in prose
99
+ hid every later `$$` formula.** Code is now found the CommonMark way — a fence
100
+ opens only at line start (≤3 spaces), closes by the one fence-nesting rule
101
+ (`classifyInnerFenceLine`), and a code span pairs equal backtick runs inside
102
+ one paragraph. `tokenizeSource` math islands inherit it.
9
103
  - Consumer action: none — refresh to latest.
10
104
 
11
105
  ## 0.16.1
@@ -14,7 +108,7 @@ Automatic changed-only republish (docs/metadata drift since the last tag — see
14
108
  `git diff npm/content-ir-core/v0.16.0..npm/content-ir-core/v0.16.1 -- apps/shared/content-ir-core`).
15
109
  No source changes intended and no consumer action required.
16
110
 
17
- ## Unreleased
111
+ ## 0.16.2 (also shipped)
18
112
 
19
113
  **`/source` — a callout or `:::` directive nested in a list item stays in the
20
114
  list's prose block** (verify-RC-B8 round 2, SAFETY). Guard:
package/README.md CHANGED
@@ -43,6 +43,30 @@ import {
43
43
 
44
44
  The package has no browser, React runtime, application store, database client, routing, or renderer dependency. `ajv` is its only runtime dependency. Host-specific registry fetching, component compilation, rendering, and error capture remain adapters around this kernel.
45
45
 
46
+ ## `/source` streaming mode: what "settled" promises
47
+
48
+ `tokenizeSource(text)` reads stored text; `tokenizeSource(prefix, { streaming: true })`
49
+ reads a message still arriving. In streaming mode anything the next bytes could
50
+ still change is held back as plain prose (an open last line, an unclosed code
51
+ span, a `$$` that can still pair, a footnote whose continuation is undecided, …),
52
+ so **an island reported `complete` is the island the finished text has** — with
53
+ ONE documented exception:
54
+
55
+ - **A late orphan reasoning closer.** Models do emit closer-only reasoning (the
56
+ `<thinking>` opener lost upstream). When a `</thinking>` / `</think>` /
57
+ `</reasoning>` arrives with no opener, the one-shot reading folds everything
58
+ before it into a thinking region — retroactively. No streaming reader can
59
+ know that in advance short of holding ALL prose provisional until the stream
60
+ ends, which costs more than it saves (chair ruling, 2026-09-26; common-docs
61
+ `projects/rich-content-unification/REGISTER.md`, RC-B3 rulings).
62
+
63
+ **Consumer contract:** when a stream completes, re-read the finished text in
64
+ one-shot mode (`tokenizeSource(text)`, no `streaming`) and show THAT — the
65
+ final screen always equals the one-shot result, which is also what a reload
66
+ shows. Stored text never goes through streaming mode, so none of this can
67
+ change a stored byte. (matrx-frontend's chat renderer does the same for its
68
+ own live accumulator: `components/mardown-display/chat-markdown/settle-stream-blocks.ts`.)
69
+
46
70
  ## Release gate
47
71
 
48
72
  ```bash