R-292: share where a tag starts, not what it says
c0 asked whether tagsIn should return indices so beatLikeIn could take spans from it. No -- that widens this file's signature to serve another, and R-291 already fails when the two disagree. But detection is not prevention, and there is a third thing to share. The two patterns differ in their bodies for good reasons: tagsIn captures the whole tag for skillsIn to split, outcome-coverage stops at the em-dash because the outcome follows. What was copied into both files, and what drifted, is the opening -- the literal \[CUS:, widened by R-290 here and left behind there. TAG_OPEN is now exported as a string with tagRe(body) composing a fresh matcher onto it; fresh because a shared /g regex carries lastIndex between callers. 22 tags before and after, c0's body composed onto TAG_OPEN gives the same 22 its own pattern does, 19 guards green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8a051f7f2b
commit
3a31e0c9b0
@@ -6866,3 +6866,31 @@ silence — the build stops, which is the safe direction — but the message nam
|
||||
thing, and the fix is the one check-rollable already made for the cast: read through the other
|
||||
guard's function rather than a second regex. That file is c0's and the call is theirs; it is
|
||||
recorded here so it is a decision rather than something nobody wrote down.
|
||||
|
||||
## R-292 — share where a tag starts, not what it says
|
||||
|
||||
c0 asked whether `tagsIn` should return indices so `beatLikeIn` could take its spans from it,
|
||||
as check-rollable does with `castMarkersIn`. No — and c0 had already reasoned its way to the
|
||||
same answer. Returning indices widens this file's signature to serve another file, and
|
||||
R-291's cross-reader test already fails the moment the two disagree.
|
||||
|
||||
But detection is not prevention, and there is a third thing to share that neither of us
|
||||
proposed. The two patterns **differ in their bodies for good reasons**: `tagsIn` captures the
|
||||
whole tag and lets `skillsIn` split it, `outcome-coverage` stops at the em-dash because the
|
||||
outcome text follows. Sharing the whole pattern would be wrong. What was copied into both
|
||||
files, and what actually drifted, is the **opening** — the literal `\[CUS:`, widened here by
|
||||
R-290 and left behind there, after which three spellings had one guard reading a tag and the
|
||||
other calling it unparseable.
|
||||
|
||||
So `TAG_OPEN` is exported as a string and `tagRe(body)` composes a fresh matcher onto it —
|
||||
fresh because a shared `/g` regex carries `lastIndex` between callers, which is its own quiet
|
||||
defect. Each reader keeps its own body. The half that must agree is the only half shared.
|
||||
|
||||
Verified nothing moved: 22 tags before and after, c0's body composed onto `TAG_OPEN` gives the
|
||||
same 22 its own pattern does, the four tolerated spellings still read, `[CUS Spot]` still
|
||||
refused, 19 guards green.
|
||||
|
||||
**Also corrected here**: I told c0 the count had gone 21 → 22 because they were writing v0.18.
|
||||
Wrong. `beatsIn` returns every marker and `measure()` filters the quoted one — Anomaly Lore at
|
||||
line 758, Act Three's quotation of the format. 22 markers, 21 real beats. Both figures were
|
||||
right and the disagreement was mine.
|
||||
|
||||
@@ -62,9 +62,22 @@ export function skillsIn(body) {
|
||||
through. A beat spelled any of those four ways was checked by neither guard while both
|
||||
printed OK. Same fail-open as R-289's `<!-- cast : -->` and check-cited's three spellings of
|
||||
`cite:`; found the same way, by putting the spellings to the reader instead of to the tree. */
|
||||
/* THE OPENING OF A TAG, AS ONE STRING, because that is the half that drifted. Two guards read
|
||||
`[CUS: ...]` and their BODIES differ for good reasons — this one captures the whole tag and
|
||||
lets skillsIn split it, outcome-coverage stops at the em-dash because the outcome text
|
||||
follows. Sharing the whole pattern would be wrong. Sharing where a tag STARTS is not: the
|
||||
literal `\[CUS:` was copied into both files, R-290 widened this one, and for three spellings
|
||||
the two guards then disagreed about whether a tag existed at all — one reading it, the other
|
||||
calling it unparseable. Compose your own body onto this and that cannot happen again.
|
||||
R-291's cross-reader test still stands behind it; this is the prevention, that is the check. */
|
||||
export const TAG_OPEN = String.raw`\[\s*CUS\s*:\s*`;
|
||||
|
||||
/** A fresh matcher each call — a shared /g regex carries `lastIndex` between callers. */
|
||||
export const tagRe = (body = String.raw`([^\]]+)\]`) => new RegExp(TAG_OPEN + body, "gi");
|
||||
|
||||
export function tagsIn(text) {
|
||||
const out = [];
|
||||
for (const m of text.matchAll(/\[\s*CUS\s*:\s*([^\]]+)\]/gi)) out.push(m[1]);
|
||||
for (const m of text.matchAll(tagRe())) out.push(m[1]);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user