refactor(#3309): extend planning-snapshot.cts with 8 more parsed fields
Phase 11 of epic #3180 (ADR-3180 §8.1 rule 2). PlanningSnapshot grows from 7 fields to 15: projectSections, statePhaseTokens, stateStatus, roadmapDeclaredPhases, roadmapPhaseCheckboxes, researchValidationStatus, milestoneArchiveStatus, planningRootFiles. Every field is a reused owner (buildRoadmapPhaseVariants/ buildNotStartedPhaseVariants from src/validate.cts, stateFieldValue) or a small relocation of already-working verify.cts logic (PHASE_NUMBER_TOKEN_SOURCE scanning, the checkMilestonePrefixMismatches sectionRx walk, W009/W018's file-existence checks) — never a new algorithm, and never raw document text: §8.1 rule 2 forbids exposing raw text, not exposing a parsed list or boolean derived from it once by the snapshot builder. roadmapPhaseCheckboxes deliberately reads the same ROADMAP checkbox isPhaseComplete (§7.4, disk-strict) refuses to consult — that owner decides completion and must not read it; this field only exposes what the checkbox says, for a diagnostic (W011) whose whole purpose is flagging disagreement. Not a re-derivation of §7.4, recorded explicitly to prevent that reading. Adds PROJECT_UNREADABLE to UNUSABLE_REASON (ninth #1879 site), closing a gap the implementing agent correctly flagged rather than silently leaving absent-vs-corrupt collapsed for PROJECT.md, matching the STATE_UNREADABLE/ CONFIG_UNREADABLE precedent from this same effort's prior commits. currentPhaseLabel/statePhaseTokens/stateStatus share one STATE.md read (buildStateFields) rather than three independent reads. Additive only — all prior fields and worstScope/buildPhaseSnapshot unchanged.
This commit is contained in:
@@ -71,6 +71,13 @@ const UNUSABLE_REASON = Object.freeze({
|
||||
* is corruption. (#3309, eighth #1879 site — planning-snapshot's config field)
|
||||
*/
|
||||
CONFIG_UNREADABLE: 'config_unreadable',
|
||||
/**
|
||||
* A PROJECT.md exists but could not be read (EACCES/EIO/…). Distinct from a project that has
|
||||
* not run any project-writing command yet: absence returns the same non-answer, silently —
|
||||
* only an exists-but-unreadable PROJECT.md is corruption. (#3309, ninth #1879 site —
|
||||
* planning-snapshot's projectSections field)
|
||||
*/
|
||||
PROJECT_UNREADABLE: 'project_unreadable',
|
||||
} as const);
|
||||
|
||||
type UnusableReason = (typeof UNUSABLE_REASON)[keyof typeof UNUSABLE_REASON];
|
||||
@@ -87,6 +94,8 @@ const REASON_PROSE: Readonly<Record<UnusableReason, string>> = Object.freeze({
|
||||
'STATE.md exists but could not be read; the current-phase label fell back to unavailable',
|
||||
[UNUSABLE_REASON.CONFIG_UNREADABLE]:
|
||||
'config.json exists but could not be read or parsed; the config field fell back to unavailable',
|
||||
[UNUSABLE_REASON.PROJECT_UNREADABLE]:
|
||||
'PROJECT.md exists but could not be read; the projectSections field fell back to unavailable',
|
||||
});
|
||||
|
||||
// ─── Dedup state ──────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user