Skip to content

fix(verify): stop treating ledger/spec-only stories as "no changes since baseline"#79

Merged
pbean merged 2 commits into
mainfrom
fix/ledger-only-proof-of-work-exclude
Jul 7, 2026
Merged

fix(verify): stop treating ledger/spec-only stories as "no changes since baseline"#79
pbean merged 2 commits into
mainfrom
fix/ledger-only-proof-of-work-exclude

Conversation

@Pawel-N-pl

@Pawel-N-pl Pawel-N-pl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What

verify_dev/verify_dev_bundle's proof-of-work gate now excludes only the session's own spec file and the sprint-status ledger from has_changes_since, via a new verify_dev_exclude_relpaths(paths, spec_path), instead of the whole implementation_artifacts/planning_artifacts folders.

Why

The old exclusion existed so a session couldn't fake completion by only flipping its own spec's status: field, but it hid everything under those folders, including sibling content like the deferred-work ledger. A story whose entire authorized scope is ledger/spec reconciliation (no src/tests touched, by design) therefore always false-negatived "no changes since baseline" and got rolled back or deferred, no matter how much real, reviewed work landed.

How

  • New verify_dev_exclude_relpaths: excludes paths.sprint_status and the claimed spec_path only (file, not folder, granularity).
  • Wired into both has_changes_since call sites, replacing artifact_relpaths(paths) (which stays as-is for Engine's rollback-protection use, a different job).
  • output_folder deliberately stays out of the new exclude set: it's the parent dir of implementation_artifacts in the standard layout, so excluding it as a prefix would swallow that folder's content right back out of view.

Testing

Seven new tests in tests/test_verify.py: exclude-helper granularity plus a ..-segment normalization guard on the helper, a direct has_changes_since repro (ledger content counts, own-spec + sprint bookkeeping alone doesn't), both the verify_dev and verify_dev_bundle gates passing end-to-end on a ledger-only diff, and regression guards that a bare own-spec status flip still retries as "no changes" — both directly and when the spec is claimed via a ..-laden path. Full suite: 1412 passed, 7 skipped; ruff clean.

Related

Independent of the other pending PR (fix/resolve-baseline-advance); different files, either can land first.

Summary by CodeRabbit

  • Bug Fixes

    • Tightened the “no changes since baseline” check so it only ignores specific bookkeeping files instead of whole artifact folders.
    • Prevents false positives/negatives when validating work that includes ledger updates or status changes.
    • Improved path handling so claimed files are recognized consistently even when referenced through different relative paths.
  • Tests

    • Added coverage for ledger-only work, file-level exclusions, and status-only changes to verify the new behavior.

…nce baseline"

verify_dev/verify_dev_bundle's proof-of-work gate blanket-excluded the whole
implementation_artifacts/planning_artifacts folders from has_changes_since, so
a story whose entire authorized scope is ledger/spec reconciliation (e.g.
deferred-work.md sync) always produced a false "no changes" verdict and got
rolled back/deferred, no matter how much real, reviewed work landed.

Add verify_dev_exclude_relpaths(paths, spec_path): excludes only the session's
own claimed spec file and the sprint-status ledger (the two things every
session rewrites regardless of real work), not the whole artifact folders.
Sibling content (deferred-work.md, other stories' specs) now counts. Wired
into both has_changes_since call sites in place of artifact_relpaths, which
stays as-is for Engine's rollback-protection use (a different job).

output_folder is deliberately excluded from the new helper: in the standard
layout it's the parent dir of implementation_artifacts, so excluding it as a
prefix would swallow that folder's content right back out of view.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds verify_dev_exclude_relpaths to compute a narrow, file-granular exclusion set (sprint-status file and claimed spec path) for the has_changes_since baseline check, replacing the prior whole-folder artifact_relpaths exclusion in both verify_dev and verify_dev_bundle. Adds corresponding regression tests.

Changes

Verify Exclude Gating

Layer / File(s) Summary
File-granular exclude helper
src/bmad_loop/verify.py
Adds verify_dev_exclude_relpaths(paths, spec_path) which excludes only paths.sprint_status and the resolved spec_path relative to paths.project, no longer excluding whole artifact directories.
Wiring into gating checks
src/bmad_loop/verify.py
verify_dev and verify_dev_bundle now pass verify_dev_exclude_relpaths(paths, spec_path) instead of artifact_relpaths(paths) to has_changes_since.
Exclude helper unit tests
tests/test_verify.py
Tests assert the exclude set is file-specific and normalizes ..-laden spec paths to canonical exclude entries.
End-to-end gating regression tests
tests/test_verify.py
Tests cover dotdot-path spec claims, ledger sibling content counting as real changes, ledger-only stories passing verification, and own-spec-status-only flips remaining non-real-work.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dev as verify_dev/verify_dev_bundle
  participant Exclude as verify_dev_exclude_relpaths
  participant Git as has_changes_since

  Dev->>Exclude: compute exclude(paths, spec_path)
  Exclude-->>Dev: (sprint_status, spec_path) relpaths
  Dev->>Git: has_changes_since(baseline_commit, exclude=relpaths)
  Git-->>Dev: changed files outside exclude set
  alt real work detected
    Dev-->>Dev: proof-of-work gate passes
  else no changes since baseline
    Dev-->>Dev: proof-of-work gate fails
  end
Loading

Poem

A rabbit hopped through code with glee,
Trimming excludes down to just two and three.
No more whole folders hidden from sight,
Just sprint-status and spec, exact and tight.
Ledger work counted, gates now precise —
Thump-thump! Verified twice. 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: narrowing verify gating so ledger/spec-only stories are no longer treated as unchanged.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ledger-only-proof-of-work-exclude

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@augmentcode

augmentcode Bot commented Jul 6, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: Tightens the dev/bundle proof-of-work check so ledger/spec-only stories aren’t falsely treated as “no changes since baseline”.
Changes:

  • Adds verify_dev_exclude_relpaths to exclude only sprint-status and the session’s own spec file (file-level granularity)
  • Wires the new exclude list into verify_dev and verify_dev_bundle baseline change detection
  • Adds tests covering ledger-only diffs counting as work and guarding the spec-status-flip loophole

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/bmad_loop/verify.py Outdated
out: list[str] = []
for path in (paths.sprint_status, spec_path):
try:
rel = path.relative_to(paths.project).as_posix()

@augmentcode augmentcode Bot Jul 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verify_dev_exclude_relpaths: because spec_path isn’t normalized before relative_to(...).as_posix(), a spec_file containing .. segments could yield an exclude string that doesn’t match git’s normalized path, letting a spec-only status flip be counted as “real work”. Consider normalizing (resolve()) before deriving rel so the exclude set is stable and reliable.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

verify_dev_exclude_relpaths compared spec_path against paths.project via a
lexical relative_to(), but spec_path is derived from a session-reported
(untrusted) spec_file string. An un-normalized '..'/'.' segment in that
string still resolves to the real on-disk file (the OS resolves it when
checking spec_path.is_file()), but as a raw string it would not match git's
own normalized path output — silently defeating the exclude and letting a
bare status flip on the session's own spec count as real work.

Resolve both spec_path and paths.project before deriving the relpath, same
as spec_within_roots already does for the same session-controlled-path
reason. Two new tests: the exclude helper normalizes a '..'-laden path to
the same entry as the plain one, and an end-to-end verify_dev regression
confirming the bare status flip still retries as "no changes" when claimed
through such a path.

Addresses review feedback from PR #79 (Augment).
@Pawel-N-pl

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@pbean pbean merged commit 10e8168 into main Jul 7, 2026
9 checks passed
@pbean pbean deleted the fix/ledger-only-proof-of-work-exclude branch July 7, 2026 02:47
pbean added a commit that referenced this pull request Jul 7, 2026
…ular #79 contract (T3)

verify_dev_stories excluded the whole implementation_artifacts/planning_artifacts
folders from its proof-of-work gate (the pre-#79 artifact_relpaths blanket). After
#79 narrowed verify_dev/verify_dev_bundle to a file-granular exclude
(verify_dev_exclude_relpaths: only the session's own spec + the sprint-status
ledger), stories mode kept the exact false-negative #79 fixed: a story whose entire
authorized scope is ledger/spec reconciliation (e.g. deferred-work.md under
implementation_artifacts) always read as "no changes since baseline" and got rolled
back/deferred.

Swap artifact_relpaths for verify_dev_exclude_relpaths in verify_dev_stories, keeping
_stories_relpaths (the spec folder's stories/ subdir + stories.yaml hold only specs
and the human-authored manifest, never implementation work). Test: a stories-mode
story whose only diff is the deferred-work ledger now passes proof-of-work.

Co-Authored-By: Claude Opus 4.8 (1M context) <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.

2 participants