Skip to content

refactor: route all markdown parsing through mdq() (plan 022)#93

Open
DavertMik wants to merge 1 commit into
mainfrom
refactor/mdq-compliance
Open

refactor: route all markdown parsing through mdq() (plan 022)#93
DavertMik wants to merge 1 commit into
mainfrom
refactor/mdq-compliance

Conversation

@DavertMik

Copy link
Copy Markdown
Contributor

Plan 022 — Route all markdown manipulation through mdq()

The project rule (CLAUDE.md, twice) is absolute: all markdown manipulation goes through mdq() — never regex, .includes(), or line-splitting. This fixes 8 violations, including 4 hand-rolled marked.lexer walks that re-implemented mdq's own section logic with subtly different semantics.

New mdq API (additive only)

MarkdownQuery.meta()Array<{type, depth, text}> — exposes token type, heading depth, and unwrapped text. This is the gap that forced the lexer walks. 6 new unit cases in markdown-query.test.ts.

Migrated

  • researcher.ts ## Summary regex + researcher/parser.ts .includes('Extended Research') → mdq queries.
  • planner.ts cleanExperienceFlows + table swap → positional .replace() with re-query-after-each-mutation (offsets go stale after a replace). Removed all String.replace(section.text(), …) and /^---/gm.
  • experience-tracker.ts: whole-section truncation (never cuts mid-code-fence), writeAction/writeFlow dedup via mdq, and listTocHeadings/extractHeadingSection/renderAsHowTo rebuilt on meta().
  • experience-compactor.ts: listSections on section2+meta(); the re-hardcoded clickXY regex → isNonReusableCode().
  • knowledge-tracker.ts firstLine → mdq().meta().
  • marked import removed from experience-tracker and experience-compactor.

Two deviations (both improvements, verified)

  1. renderAsHowTo uses startsWith via meta(), not the plan's literal h2(~"marker"). That contains-matcher would infinite-loop on a title containing the marker (## FLOW: undo FLOW: steps) and diverges from the old startsWith. The implemented version provably terminates and matches the old output (whitespace-only diff — the old code accidentally doubled blank lines).
  2. cleanExperienceFlows' > ... and N more discoveries note was dead code — the old .replace() no-op'd because the tail blockquotes were already removed from the string. The new code correctly appends it, as the plan specifies.

STOP-candidates cleared

  • Step 5 mixed-depth section indexing — verified byte-identical to the old lexer walk across all indices (h1–h4, out-of-range).
  • Step 7 clickXY → isNonReusableCode broadening — no test pins the narrow behavior; the #ember123 case yields the same final result (dropped at strip stage). All 43 compactor tests pass.

Verification

  • bun test tests/unit772 pass / 0 fail (+8 new tests; no existing assertions modified).
  • bun test tests/integration/63 pass / 0 fail.
  • bun run lint → clean; tsc total neutral (639 = 639).
  • grep marked in both files → empty; ## Summary regex gone; meta() present.

🤖 Generated with Claude Code

Enforce the "no regex/includes/line-splitting on markdown" rule across 8
violation sites. Adds one additive accessor — MarkdownQuery.meta() returning
{type, depth, text} — which removes the need for hand-rolled marked.lexer
walks. The `marked` import is now gone from experience-tracker and
experience-compactor.

- researcher Summary regex + parser `.includes('Extended Research')` -> mdq queries
- planner cleanExperienceFlows + table swap -> positional replaces with
  re-query-after-each-mutation (no more String.replace on section raw text /
  /^---/gm regex)
- experience-tracker: whole-section truncation (never cuts mid-fence),
  writeAction/writeFlow dedup via mdq, listTocHeadings/extractHeadingSection/
  renderAsHowTo rebuilt on meta()
- experience-compactor: listSections on mdq; clickXY regex -> isNonReusableCode
- knowledge-tracker firstLine via mdq().meta()

Deviations (both improvements, verified): renderAsHowTo matches with startsWith
via meta() (the plan's contains-matcher would infinite-loop on titles
containing the marker); planner's "and N more discoveries" note-append was
previously dead code (no-op after the tail blockquotes were removed) and now
correctly appends. Step 5 verified byte-identical to the old lexer walk;
Step 7's clickXY->isNonReusableCode broadening pinned by no test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Explorbot Self-Regression

Commit e7e0e2b · run

Scenario Result Attempts Duration
basic (native) FAIL 3/3 27m

Attempt details

  • basic (native) attempt 1 — FAIL: login evidence: PASS (post-login plan=true, post-login research=true); research: PASS (files=8, wellFormed=true, keywords=7/3); scenarios: PASS (tests=5/5, features=4/3); tests passed: FAIL (3 passed, 2 failed (reporter: 3 passed, 2 failed))
  • basic (native) attempt 2 — FAIL: login evidence: PASS (post-login plan=true, post-login research=true); research: PASS (files=8, wellFormed=true, keywords=7/3); scenarios: PASS (tests=5/5, features=4/3); tests passed: FAIL (4 passed, 1 failed (reporter: 4 passed, 1 failed))
  • basic (native) attempt 3 — FAIL: login evidence: PASS (post-login plan=true, post-login research=true); research: PASS (files=6, wellFormed=true, keywords=7/3); scenarios: PASS (tests=5/5, features=4/3); tests passed: FAIL (4 passed, 1 failed (reporter: 4 passed, 1 failed))

Session analysis — basic (native):

Session Analysis

The Issues list page was tested for core functionality: creation, filtering, search, and navigation. Four of five flows work correctly. The label filter feature fails to display a visual indicator of the active filter state, which is a required UX expectation.

Coverage

  • Pages: /issues, /issues/6
  • Features: Issue creation, label filtering, search filtering, status filtering, issue detail navigation

What works

  • Issue creationET-1 Create a new issue with title and description
  • Search filteringET-3 Search for issues using the search input
  • Status filteringET-4 Filter issues by status using the status selector
  • Issue detail navigationET-5 Navigate to issue detail page by clicking an issue row

Defects

[Medium] Label filter lacks visual active state indicator

Affects: ET-2 Filter issues by label using the label dropdown
Reproduce:

  1. Open label filter dropdown
  2. Click 'bug' label to apply filter
  3. Reopen the dropdown
    Evidence: Filter correctly shows only bug-labeled issues, but the dropdown does not highlight or indicate which label is currently active. Test stopped with "UI does not provide a visible indicator."

UX issues

  • Label filter — Users cannot determine which label filter is currently active because the dropdown provides no visual indicator (bold, highlight, or selected state) for the active filter.

Execution Issues

  • (none)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants