Cycle 6 of ~15: adds fenced-block stripping pass to
stripMarkdownInjection. Docs-and-examples inside code fences
no longer pollute the item roster.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cycle 5 of ~15: introduces stripMarkdownInjection helper.
First pass strips the YAML frontmatter region so injected
'### N. item' patterns inside frontmatter literal blocks
cannot be mistaken for real UAT items.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cycle 4 of ~15: phase dir present but no *-HUMAN-UAT.md files
now returns a typed NO_UAT_FILES reason instead of an empty
reasons array (which prior cycles used as a 'shouldn't happen'
fallback).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cycle 3 of ~15: when resolvePhaseDir returns null, predicate
returns a typed NO_PHASE_DIR reason. Previously the empty
reasons array was indistinguishable from other failure modes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cycle 2 of ~15: introduces REASON_CODE frozen enum and UatReason
typed shape. Non-pass items (result not literally 'pass') now
contribute a typed reason instead of being invisible to callers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cycle 1 of ~15: minimal end-to-end predicate. One phase dir, one
UAT file, one pass result. No injection stripping, no orphan
detection, no CLI registration yet — those follow in subsequent
commits per TDD discipline.
Also exports resolvePhaseDir from phase-list-queries.ts (was
private) so the new predicate can reuse it without duplication.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>