feat(cc030): validate.sh closure-date + CHANGELOG drift (Index↔Section bidirectional)#65
Merged
Merged
Conversation
Extend pm/scripts/validate.sh with two new structural checks: - E-CLOSURE-DATE-MISMATCH: when index row is `✅ closed YYYY-MM-DD` (or `🚫 ...` dropped), require the body section to carry the same date — either as a heading marker (`## CC-XXX — title ✅ YYYY-MM-DD`) or as any YYYY-MM-DD token within the section when **Outcome**: is present. Catches the drift class where Index says closed but body has no closure metadata (or disagrees on date). - E-CHANGELOG-DRIFT: optional second pass that runs when CHANGELOG.md is given as third positional arg or auto-detected as sibling of BACKLOG.md. For each pr:#NN token under `## [Unreleased]`, require some backlog Index row to reference that PR; symmetric direction (closed but unmentioned) intentionally out of scope. CLI surface extended additively: validate.sh <BACKLOG.md> [DECISIONS.md] [CHANGELOG.md] 2-arg form unchanged; missing sibling CHANGELOG silently skips drift pass; explicit nonexistent path returns exit 2 (matches DECISIONS file behavior). Fixtures added: bad-closure-date-mismatch/ and bad-changelog-drift/ with explicit want_token entries in run-tests.sh. Existing fixtures unchanged; 13 passed / 0 failed. Repo BACKLOG.md continues to emit only the pre-existing 3 token set (E-INDEX-MISMATCH, E-AREA-ENUM, E-REFS-PREFIX) tracked separately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR-gate gate-20260516-195358 found two convergent issues: - CHANGELOG drift only checked PR token presence in Refs, not status: `[Unreleased]` could reference an `🔵 active` row and silently pass. Strengthen rule so `pr:#NN` MUST map to at least one backlog row with status `closed`. Missing / active / deferred / dropped / done all emit E-CHANGELOG-DRIFT (Branches A–E from proactive sweep). - Closure body date fallback scanned any YYYY-MM-DD in the section, including Source / Why / Note lines. Tighten to heading marker (`✅ YYYY-MM-DD` / `🚫 YYYY-MM-DD`) OR a date on a `**Outcome**:` line only. New fixture bad-changelog-drift-active-ref/ exercises Branch C (Unreleased ref → active row). Existing bad-changelog-drift remains the canonical Branch A (missing ref) case. Existing bad-closure-date-mismatch confirmed still emits exactly E-CLOSURE-DATE-MISMATCH under the tightened extraction scope. run-tests.sh: 14 passed / 0 failed. The strengthened closure-date rule exposes pre-existing data drift on the live BACKLOG (CC-027 / CC-028 / CC-034 Outcome lines lack YYYY-MM-DD; previously masked by Source-line dates). That data drift is intentionally left for a separate data-prep PR before merging this branch, per the established split between data and validator-code changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…gate r2) PR-gate r2 (gate-20260516-201444) found a real regression: callers using the legacy `validate.sh BACKLOG.md DECISIONS.md` form silently lost CHANGELOG drift detection. Root cause was line 41's overly strict guard `[ -z decisions ] && [ -z changelog ]` — sibling CHANGELOG auto-detect only ran when BOTH optional args were empty. Fix: condition relaxed to `[ -z changelog ]` only. DECISIONS arg presence no longer suppresses CHANGELOG auto-detection. Branch sweep across all CLI invocation forms (CLI-1..CLI-6): - 1 arg, auto-detect: unchanged (works) - 2 args (DECISIONS), auto-detect sibling: NOW works - 3 args explicit DECISIONS+CHANGELOG: unchanged (works) - 3 args empty DECISIONS + explicit CHANGELOG: unchanged (works) - 3 args explicit but nonexistent CHANGELOG: unchanged (exit 2) - 2 args, sibling CHANGELOG missing: unchanged (silent skip) Test coverage: - T1: explicit 3-arg drift via run_validate_case_multi helper - T2: legacy 2-arg + sibling CHANGELOG drift (regression-fix case) - T3: explicit nonexistent CHANGELOG -> exit 2 + E-SCHEMA-HEADER run-tests.sh: 17 passed / 0 failed. New minimal DECISIONS.md fixture under bad-changelog-drift/ enables T2 without disturbing the existing single-arg case. Architect-medium (status normalize dedup) and architect-low (flag-based CLI) deferred to follow-up backlog entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e (gate r3)
PR-gate r3 (gate-20260516-202620) found two regression boundaries:
- Body-marker date capture in note_body_closure_date silently
truncated trailing junk: `## CC-X ✅ 2026-05-15 garbage` was
accepted as exact date. Restore strict shape: heading marker
must terminate after the 10-char date (only trailing whitespace
permitted). Trailing non-whitespace content emits E-DATE-FORMAT.
- Outcome-line fallback scanned for any YYYY-MM-DD anywhere in
the line; mid-sentence dates accidentally satisfied closure
evidence. Tighten regex to require the date IMMEDIATELY after
the literal `**Outcome**: ` prefix. Mid-line dates no longer
count as closure evidence — they must be in the canonical
position or in the heading marker.
Coverage gaps closed:
- good-changelog-closed-ref/: [Unreleased] referencing a closed
backlog PR exits 0 cleanly (CL-B happy path).
- bad-closure-date-trailing-junk/: BD-3 boundary -> E-DATE-FORMAT.
- bad-outcome-date-misplaced/: BD-7 boundary
-> E-CLOSURE-DATE-MISMATCH.
run-tests.sh: 20 passed / 0 failed.
The tightened Outcome regex newly flags CC-029's Outcome line
("**Outcome**: PR #57 合併 2026-05-15;" — date is not at the
prefix position). That data drift is intentionally left for a
separate data-prep PR before merging this branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e (gate r4) PR-gate r4 (gate-20260516-204121) flagged two convergent gaps and one cleanup: - F1 (critic+qa high): schema permits pr:owner/repo#NNN (schema.md:96) but validator regex only matched pr:#NNN. Cross-repo refs in [Unreleased] silently passed when active row referenced them. Fix: unify PR-token regex `pr:([A-Za-z0-9._-]+/[A-Za-z0-9._-]+)?#[0-9]+` across both passes (backlog refs collection + [Unreleased] scan). Cross-repo and simple tokens kept as DISTINCT keys (pr:#100 != pr:owner/repo#100). - F2 (qa medium): bad-closure-date-dropped-mismatch/ fixture covers the 🚫 dropped branch of the closure-date check. - F3 (critic low): removed unused date_token() helper added in fix-r3. Schema audit table (delivered in dispatch final message) confirms no further divergence between schema.md and validator behavior: Refs prefixes, status enum, closure markers all aligned. Audit recorded for follow-up reviewers. Branch sweep XR-1..XR-6 (cross-repo refs) verified: - XR-2 (cross-repo closed-row match) PASS - XR-3 (no matching row) drift - XR-4 (cross-repo active row) drift - XR-5 (mixed simple+cross) drift per token - XR-6 (malformed pr:#owner/repo) ignored gracefully run-tests.sh: 22 passed / 0 failed (20 prior + 2 new). Repo BACKLOG.md validation token set unchanged (3 pre-existing). Deferred to follow-up backlog (architect-medium status-normalize dedup; qa-low docstring style) will be recorded by main-thread. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR-gate r5 (gate-20260516-205441) — only qa-tester blocked: the Outcome-date fallback branch had negative coverage (bad-outcome-date-misplaced rejects mid-sentence dates) but no positive fixture proving the canonical accepted shape. Add good-closure-outcome-date/ — closed row with no heading marker, Outcome line "**Outcome**: 2026-05-01 — ..." date right after the prefix → exit 0, empty stderr. Critic + qa low (docstring style) and critic + arch low (run_validate_case_multi duplicates run_validate_case) deferred to follow-up backlog; will be recorded by main-thread. run-tests.sh: 23 passed / 0 failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements CC-030 —
pm/scripts/validate.shIndex ↔ Section bidirectional consistency + CHANGELOG drift detection.New error tokens
✅ closed YYYY-MM-DD/🚫 dropped YYYY-MM-DD) must match either a heading marker (## CC-X — title ✅ YYYY-MM-DD, exact terminator) OR a**Outcome**: YYYY-MM-DD ...line where the date is immediately after the literal prefix. Mid-sentence dates ignored.pr:#NN(orpr:owner/repo#NN) inside CHANGELOG.md's## [Unreleased]section must correspond to a backlog row whose status isclosed. Active / deferred / dropped / missing all drift.CLI surface
validate.sh <BACKLOG.md> [DECISIONS.md] [CHANGELOG.md]— third arg optional; sibling CHANGELOG.md auto-detected when omitted, regardless of whether DECISIONS.md is supplied. Backwards compatible with all existing call sites.Why
Existing validator only enforced Index-row format. CC-030 strengthens it to catch:
[Unreleased]entries that reference PRs not actually shipped✅ 2026-05-15 garbageno longer silently truncated)Schema audit table delivered in commit
fix(cc030): cross-repo PR refscovers all Refs prefixes, status enum, and closure markers frompm/schema.md— no further divergence detected.Gate history
6 PR-gate rounds (r1 NO-GO → r6 GO). Sequence:
validate.sh BACKLOG DECISIONSskipped sibling CHANGELOG auto-detectpr:owner/repo#NNbut regex only matchedpr:#NN; needed dropped-row fixtureData prep PRs landed first to keep main's validator output stable: #60 (CC-029 close + See stubs), #62 (CC-027/028/034 Outcome dates), #63 (CC-029 Outcome reorder).
Follow-up
[[known-bug backlog rule]].Test plan
bash pm/scripts/test/run-tests.sh→ 23 passed / 0 failedbash pm/scripts/validate.sh BACKLOG.md→ only pre-existing 3-token baseline (CC-035 E-INDEX-MISMATCH, CC-038 E-AREA-ENUM + E-REFS-PREFIX; tracked separately)🤖 Generated with Claude Code