Skip to content

Fix: _parseFields accepts natural-English heading variants (#201)#217

Merged
Jason-Vaughan merged 1 commit into
mainfrom
fix/parsefields-normalize-headings-201
May 23, 2026
Merged

Fix: _parseFields accepts natural-English heading variants (#201)#217
Jason-Vaughan merged 1 commit into
mainfrom
fix/parsefields-normalize-headings-201

Conversation

@Jason-Vaughan
Copy link
Copy Markdown
Owner

Summary

lib/wrap-steps/ai-content.js:_parseFields previously required exact-string equality (after .toLowerCase()) between ## Heading text and the declared captureField name. This silently rejected the most natural Markdown a human or AI would write — ## Next Steps (space-separated) vs captureFields: ['nextSteps'] — and halted the wrap pipeline with Required captureField "nextSteps" missing or empty in AI response. Surfaced as Critic n1 on PR #200.

Closes #201.

What changed

  • lib/wrap-steps/ai-content.js — new _normalizeFieldKey(s) helper that lowercases and strips every non-[a-z0-9] character. Applied symmetrically to both sides of the comparison. After normalization, Next Steps, next-steps, next_steps, NEXT.STEPS, and nextSteps all collapse to the same match key nextsteps. Output map keys remain the DECLARED captureField name (camelCase), not the normalized form, so downstream consumers (the summary deriver at lib/sessions.js:_completeV2Wrap, the prawduct lockstep + inverse-drift pins at test/prawduct-aicontent-prompts.test.js:117-159) need no changes.
  • test/wrap-pipeline.test.js — 11 new tests:
    • 6 in _parseFields describe: natural-English variants (space, kebab, screaming snake, dotted), canonical form still works (regression pin against over-correction), mixed-style multi-heading, output-key contract pin (declared name, not normalized form).
    • 5 in _normalizeFieldKey describe: non-alphanumeric stripping, case folding, digit preservation, defensive coercion (null / undefined / number).
  • CHANGELOG.md### Fixed entry under [Unreleased].

What was deliberately NOT changed

The prawduct lockstep and inverse-drift tests in test/prawduct-aicontent-prompts.test.js enforce a STRICTER convention than the parser: bundled prawduct prompts must use single-word PascalCase headings that match the captureFields literally. The looser parser is the safety net for community-authored methodologies and for AI responses that drift from canonical. Tightening the prawduct tests to also use _normalizeFieldKey would weaken the style guide they enforce — explicitly out of scope.

Why this is safe

Normalization is a strict superset of the prior equality contract. Every input the old parser matched still matches; only the previously-rejected variants now also match. Pinned by the still matches the exact canonical form '## nextSteps' test.

Test plan

  • node --test test/wrap-pipeline.test.js — 271/271 pass (11 new + 260 pre-existing).
  • node --test test/*.test.js — full suite 2360/2360 pass (net +11 from this fix).
  • CHANGELOG structure verified (grep -E "^## \[" CHANGELOG.md shows [Unreleased][3.17.0] adjacent — feedback_verify_changelog_structure_post_edit pin).
  • Independent Critic — GREEN, no MAJORs, no MINORs.
  • Lockstep / inverse-drift tests in test/prawduct-aicontent-prompts.test.js still pass — confirms the fix doesn't break the stricter bundled-prompt convention.

Refs

`lib/wrap-steps/ai-content.js:_parseFields` previously required exact-
string equality (after `.toLowerCase()`) between `## Heading` text and
the declared `captureField` name. This silently rejected natural
Markdown a human or AI would write — `## Next Steps` vs
`captureFields: ['nextSteps']` — and halted the wrap pipeline with
"Required captureField missing." Surfaced as Critic n1 on PR #200.

- lib/wrap-steps/ai-content.js: new `_normalizeFieldKey(s)` helper —
  lowercase + strip every non-`[a-z0-9]` — applied symmetrically to
  both sides of the heading-vs-captureField comparison. Output map
  keys remain the DECLARED captureField name (camelCase), not the
  normalized form, so downstream consumers (the summary deriver in
  `lib/sessions.js:_completeV2Wrap`, the prawduct lockstep pins) need
  no changes.
- test/wrap-pipeline.test.js: 11 new tests — natural-English
  variants (space, kebab, screaming snake, dotted), canonical form
  still matches (regression pin against over-correction), mixed-
  style multi-heading, output-key contract, plus a dedicated
  `_normalizeFieldKey` describe (stripping, case folding, digit
  preservation, defensive coercion).
- CHANGELOG.md: `### Fixed` entry under `[Unreleased]`.

Prawduct lockstep + inverse-drift tests in
`test/prawduct-aicontent-prompts.test.js` are intentionally left
untouched — they enforce a STRICTER convention (single-word
PascalCase headings) than the parser, as a style guide for bundled
methodology prompts. The looser parser is the safety net for
community-authored methodologies and for AI responses that drift
from canonical.

Normalization is a strict superset of the prior equality contract:
every input the old parser matched still matches; only the
previously-rejected variants now also match.

Critic verdict GREEN — no MAJORs, no MINORs.

Full suite 2360/2360 (net +11 from this fix).

Closes #201.
@Jason-Vaughan Jason-Vaughan added the bug Something isn't working label May 23, 2026
@Jason-Vaughan Jason-Vaughan merged commit 7e0f099 into main May 23, 2026
@Jason-Vaughan Jason-Vaughan deleted the fix/parsefields-normalize-headings-201 branch May 23, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[enhancement] _parseFields rejects '## Next Steps' (with whitespace) where captureField is 'nextSteps'

1 participant