Skip to content

feat(help): retire the 13 phantom help entries + HelpCorpusSpec corpus-walk anti-drift guard - #263

Merged
fupelaqu merged 1 commit into
mainfrom
feature/20.7
Sep 2, 2026
Merged

feat(help): retire the 13 phantom help entries + HelpCorpusSpec corpus-walk anti-drift guard#263
fupelaqu merged 1 commit into
mainfrom
feature/20.7

Conversation

@fupelaqu

@fupelaqu fupelaqu commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Closes #261

What

Story 20.7 (Epic 20, BI venue enablement — Layer 0). Retires the thirteen phantom help documents (help entries for functions the SQL parser rejects) and adds HelpCorpusSpec, a corpus-walk anti-drift guard that makes a fourteenth phantom — or the arming of an existing one — a red build.

  • Retired (deleted, never committed — the files were untracked): the whole core/src/main/resources/help/functions/json/ directory (json_extract, json_object, json_array + _index.json — indexed but dead: HelpJsonLoader.loadFunctions never enumerated json, and the roadmap item fixing that skip would have armed all three), plus the ten unwired legacy phantoms conditional/{if,ifnull,nvl}, numeric/{ln,mod,truncate}, string/{lpad,rpad,space,regexp_replace}. The deletions produce no git diff; the red/green evidence below is the record (all fourteen files are archived locally before deletion).
  • NEW core test HelpCorpusSpec — 8 assertions, zero allow-lists: corpus locatable (never assume-cancelled); tree exactly two levels deep; every function doc topic ∈ SQLKeywords.functionWords or one of four recorded non-function parser words (CASE, INTERVAL, PI, RANDOM); topic uniqueness (.toMap keeps the last pair silently); escape-hatch integrity (checked against canonical clause/literal sql spellings — IF/TRUNCATE/JSON_ARRAY (statementWords) and the compound fragment OUTER are all rejected, so the hatch cannot launder a phantom); command topics word-checked against allWords; index↔disk equality in both directions (a dangling _index.json entry is skipped silently today); loader category lists ≡ directories present.
  • SQLKeywords.functionWords (sql): one new public lazy val — the derived function-word set (canonical + 54 aliases via the private[sql] wordsOf, single owner of the \s+-before-uppercase normalisation). Deliberately not allWords (which would falsely clear IF, JSON_ARRAY, TRUNCATE) and not functionTokens.map(_.sql) (which would reject alias help pages like SAFE_CAST).
  • HelpJsonLoader: the two hard-coded category lists hoisted to object-level private[help] val functionCategories / commandCategories — behaviour-neutral (same members, same order), so the spec can assert them against the directory tree. The roadmap Epic 31 item "fix HelpJsonLoader silently skipping help/functions/json" is resolved by removal + guarded — the loader still enumerates a hard-coded list; what changed is that the list is now checked against reality.

Red → green demonstration

RED (phantoms present, before any deletion) — exactly the three predicted failures, other five green:

- should publish only syntax the parser accepts *** FAILED ***
    (names all 13: IF, IFNULL, NVL, JSON_ARRAY, JSON_EXTRACT, JSON_OBJECT, LN, MOD, TRUNCATE, LPAD, REGEXP_REPLACE, RPAD, SPACE)
- should name exactly the documents present beside it *** FAILED ***
    [.../help/functions/conditional] present but unindexed - ...: HashSet(if.json, ifnull.json, nvl.json)
- should enumerate every category directory that exists *** FAILED ***
    [functions] category directories the loader never reads - silently invisible: HashSet(json)
Tests: succeeded 5, failed 3

GREEN (after archive + retirement; one sbt core/clean needed — sbt's cached resource Sync pruned the deleted files but left the empty target/.../json directory, and the union walk correctly went RED on it, never green-and-wrong):

Tests: succeeded 8, failed 0 — All tests passed.

Corpus size, reproducibly

git ls-files core/src/main/resources/help/functions | wc -l           # 105 before AND after (tracked — the phantoms were never committed)
find core/src/main/resources/help/functions -name '*.json' | wc -l    # 119 before → 105 after

No release note, no downstream sweep

Zero references to any of the thirteen in documentation/, README.md, or the website sources; the trio was never loaded, the ten were never indexed. Nothing customer-visible changes; the REPL .help output for every surviving topic is unchanged.

Honest statement of the guarantee

Every help document reachable by HelpJsonLoader is checked: a function document must name a parser-accepted function spelling or one of four recorded clause/literal words; a command document must be built from words the parser knows; every document must be indexed, unique, and two levels deep. Still possible, but only as review-visible source changes: a doc whose name is real while its syntax body advertises a rejected form (exactly what JSON_ARRAY was), or a deliberate addition to NonFunctionTopics.

Verification

  • RED → GREEN as above (verbatim outputs in the story's Dev Agent Record).
  • sbt "+ sql/compile" "+ core/compile" green (2.12.20 + 2.13.16).
  • sbt "+ core/test" "+ sql/test" green — both Scala legs. The 2.12 leg earned its keep: the spec's original clue string used \" inside an s-interpolated string, which the 2.12 lexer rejects (2.13-only tolerance) — caught only by + core/test, reworded without inner quotes.
  • sbt scalafmtAll (new file staged first — .scalafmt.conf has project.git = true; the formatter demonstrably rewrote it) and sbt headerCheck green. core/Test/headerCheck flags 21 pre-existing header-less test sources; HelpCorpusSpec.scala is not among them (it carries the Apache-2.0 header).
  • Adversarial review (3 layers): 0 decision-needed, 2 patch findings both applied (both-legs suites; an explicit negative assertion making AC-6's IF/TRUNCATE/JSON_ARRAY/OUTER rejection machine-demonstrated), 2 LOW deferred (cosmetic message relabel; hypothetical whitespace split — both loud-RED failure modes, never false green).

Story: 20.7 — spec _bmad-output/implementation-artifacts/20-7-phantom-help-entries.md (local).

🤖 Generated with Claude Code

…Spec corpus-walk guard (Story 20.7)

- delete all thirteen phantom help docs + json/_index.json (untracked, archived
  first - no diff shows; the RED/GREEN record in the story spec is the evidence)
- NEW core test HelpCorpusSpec: 8-assertion corpus walk, zero allow-lists
- NEW SQLKeywords.functionWords (canonical + alias function spellings via wordsOf)
- HelpJsonLoader: category lists hoisted to private[help] object vals
  (behaviour-neutral), asserted equal to the directories present - roadmap
  Epic 31's silent json-category skip is resolved by removal + guarded

Closes #261

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

Help corpus ships phantom function entries the parser rejects; add a corpus-walk anti-drift guard

1 participant