Skip to content

memory-router: drift.ts consumes the loader's frontmatter parse export - #99

Merged
LanNguyenSi merged 2 commits into
masterfrom
task/b2b135a8-drift-parse-dedup
Aug 16, 2026
Merged

memory-router: drift.ts consumes the loader's frontmatter parse export#99
LanNguyenSi merged 2 commits into
masterfrom
task/b2b135a8-drift-parse-dedup

Conversation

@LanNguyenSi

Copy link
Copy Markdown
Owner

Summary

  • src/lint/drift.ts no longer carries its own frontmatter regex + parseYaml copy; it consumes the new additive loader export parseFrontmatterYaml (shared FRONTMATTER_RE). Drift's field-requirement policy stays local by design: the loader accepts files without description that drift must keep flagging, and the byte-identical-report AC forbids changing that (divergence now pinned by a regression test).
  • Hot-path constraint honored: loadMemoriesFromDir, parseMemoryFileWithReason, loadMemoriesFromDirWithRejects, parseMemoryFile are byte-identical to master (verified by function extraction + diff, twice).
  • Fix round after independent review: CHANGELOG claim corrected (drift.ts is the last read-path consumer; src/tag/applier.ts still carries a write-path copy, follow-up to be filed), dead body field dropped from the new export, direct unit tests for the export's three outcomes, em dashes removed from new prose.

Verification

  • Suite 619/619, typecheck clean, coverage 98.11/89.79/92.41 vs gate 90/80/80.
  • Reference diff: drift report on a fixture corpus (reviewer used an own 18-file corpus covering all 7 DriftKinds + 9 adversarial frontmatter shapes) sha256-identical between master and this branch; negative control proved the instrument can fail.
  • Mutation probes: corrupting the shared regex fails loader AND drift tests (21 red); breaking parseFrontmatterYaml fails the new direct tests.
  • Independent reviewer subagent pass (accept_with_notes); notes fixed in the fix-round commit.

Refs: b2b135a8-80a9-4dfb-b68c-dce7f47c567b

Lan Nguyen Si and others added 2 commits August 16, 2026 12:50
lint/drift.ts was the last consumer carrying its own FRONTMATTER_RE +
parseYaml() call (PR #95 closed this duplicate class for
consolidate/schema-metrics.ts). loader.ts gains an additive
parseFrontmatterYaml() export that reuses the loader's own regex/parse
step; drift.ts's scanMemories now sources parse results from it and
keeps its own field-requirement checks (drift-specific policy the
loader's hot-path validation does not perform). loadMemoriesFromDir
and parseMemoryFileWithReason are untouched.

Refs: b2b135a8-80a9-4dfb-b68c-dce7f47c567b
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPmP28EwHconrJps6tvtw2
Fixes 5 reviewer findings on the frontmatter-regex dedup change:

- CHANGELOG: correct the "last consumer" claim. lint/drift.ts is the
  last READ-path consumer of the frontmatter-regex-plus-parseYaml
  duplicate class; src/tag/applier.ts still carries a byte-identical
  copy on the write path (follow-up task will fold it in), and
  src/migrate/transform.ts carries a deliberately different variant.
- Drop the dead `body` field from FrontmatterYamlResult and
  parseFrontmatterYaml's return value; drift.ts's only consumer never
  reads it. Updated the hand-copied type annotation in drift.ts to
  match.
- Add direct unit tests for parseFrontmatterYaml's three outcomes (ok,
  no-delimiter, yaml-error with non-empty detail) in loader.test.ts.
- Add a regression test pinning the deliberate loader-vs-drift
  validation divergence: a file with name+type but no description is
  accepted by parseMemoryFileWithReason and flagged
  invalid_frontmatter by the drift lint.
- Replace em dashes introduced by this change (drift.ts, loader.ts,
  CHANGELOG) with commas/semicolons/parens; pre-existing em dashes
  elsewhere are left untouched.

Refs: b2b135a8-80a9-4dfb-b68c-dce7f47c567b
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPmP28EwHconrJps6tvtw2
@LanNguyenSi
LanNguyenSi merged commit 830c759 into master Aug 16, 2026
3 of 5 checks passed
@LanNguyenSi
LanNguyenSi deleted the task/b2b135a8-drift-parse-dedup branch August 16, 2026 11:14
LanNguyenSi added a commit that referenced this pull request Aug 16, 2026
… centralized (#107)

* memory-router: applier.ts consumes the shared frontmatter parse export

applier.ts was the last write-path consumer carrying its own
byte-identical FRONTMATTER_RE + parseYaml() copy after lint/drift.ts
moved onto loader.ts's parseFrontmatterYaml export (#99). Its
planChange now sources delimiter-match-plus-YAML-parse from that
shared export.

parseFrontmatterYaml gains back an additive `body` field (the raw,
unprocessed capture group 2 that #99's fix round dropped as dead code)
and a new `error` field on its yaml-error outcome carrying the
original caught exception, not just its stringified message. Both
close a real fidelity gap: applier.ts's own body normalization differs
from the read path's (.trim() vs strip-one-leading-newline), and its
malformed-YAML handling used to be an uncaught throw that cli.ts's
per-file try/catch reports under "errored"; a naive re-wrap
(`new Error(detail)`) would have silently changed the reported
`${String(err)}` from "YAMLParseError: ..." to "Error: ...".

parseMemoryFileWithReason now delegates to parseFrontmatterYaml
instead of carrying its own duplicate parse step. loadMemoriesFromDir
stays byte-for-byte unchanged, reference-diffed against origin/master
across the existing loader fixtures plus a dedicated edge-case corpus.

New tests pin the no-delimiter skip path, the malformed-YAML rethrow
fidelity, the body-normalization edge case, and parseFrontmatterYaml's
new body/error fields directly.

Refs: e5428d12-f157-480f-8b04-749117aa99c7
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPmP28EwHconrJps6tvtw2

* memory-router: fix CRLF mutation-blind tests, centralize FrontmatterYamlResult

Fix round on applier.ts's frontmatter parse dedup, per reviewer findings:

- Harden the CRLF applier test and add a CRLF unit test for
  parseFrontmatterYaml directly: the prior CRLF test asserted only
  `change.eol`, which is computed independently of the frontmatter regex,
  so a CRLF-blind FRONTMATTER_RE mutant fell through to the no-delimiter
  skip path and left the whole suite green. Now assert change.skipped and
  the merged topics field, plus a rendered-output check.
- Pin the exact key set on parseFrontmatterYaml's yaml-error branch.
- Move the FrontmatterYamlResult type out of loader.ts's local scope into
  the shared ambient types file (types.d.ts), alongside the existing
  MemoryScanEntry precedent, and reference it by name from both
  loader.ts's function signature and drift.ts's require()d import
  annotation. drift.ts previously hand-copied a structural type that was
  already stale (missing body/error) and offered no real protection: a
  require() call resolves to `any`, so the annotation was never checked
  against loader.ts's real export, and a field rename could silently
  degrade drift's error reporting to "parse error: undefined". Add a
  drift-side test asserting the parse-error detail carries the YAML
  parser's own message, not the literal string "undefined".
- Drop the repeated "see loader.ts's parseFrontmatterYaml comment"
  cross-reference in applier.ts's import comment block.
- Split the CHANGELOG's single long paragraph on this dedup into a
  top-level bullet plus short sub-bullets for the body and error fields.

Refs: e5428d12-f157-480f-8b04-749117aa99c7
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPmP28EwHconrJps6tvtw2

---------

Co-authored-by: Lan Nguyen Si <contact@lan-nguyen-si.de>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@LanNguyenSi LanNguyenSi added review:tests-pass merge-approval gate prerequisite review:checklist-complete merge-approval gate prerequisite review:comments-resolved merge-approval gate prerequisite review:scope-matches-task merge-approval gate prerequisite review:evidence-logged merge-approval gate prerequisite labels Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:checklist-complete merge-approval gate prerequisite review:comments-resolved merge-approval gate prerequisite review:evidence-logged merge-approval gate prerequisite review:scope-matches-task merge-approval gate prerequisite review:tests-pass merge-approval gate prerequisite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant