Repository navigation
fix(daemon): drop superseded review cycles from the attention list - #377
Merged
Merged
Conversation
`compute_attention()` added a "failed" row for each `.project/review/*.md` file with a negative verdict. The runtime keeps earlier review cycles on disk, so a wave that blocked at cycle 1 and passed at cycle 2 kept a permanent "failed" row and a red project until the milestone was archived. For wave review files (`wave-N.cycleC.md` and the deep-review lens files `wave-N.cycleC.<lens>.md`), only the highest cycle of each wave and lens now drives attention. The Reviews table still lists every cycle. Final, gap and other review files are unchanged. Item 1 of the issue (runtime validation on the pinned-runtime layout) was fixed by 84b97f4. Fixes #356 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rdict A newer wave review file with no verdict line (a review that is still being written) replaced an older blocked cycle of the same wave and lens. The failed row disappeared and health could turn green. Only a review with a verdict now replaces an older cycle. A cycle with no verdict replaces nothing and adds no row. Tests: a newer cycle with no verdict keeps the blocked row and red health; cycle 10 is newer than cycle 9. Refs #356 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ave verdict A review that is still being written can have `Wave verdict:` with no value. The verdict pattern then reads the first word of the next line (`Cycle`), so the unfinished cycle counted as a verdict, replaced the blocked cycle before it, and the failed row disappeared. A cycle now replaces an older one only when its verdict is `pass` or `blocked`, the two values the runtime accepts for a wave review. Refs #356 Co-Authored-By: Claude Opus 5.5 <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.
Part of #356 (item 2).
Intent
Fix item 2 of GitHub issue #356 in open-gsd/gsd-path (item 1 was already fixed by merged PR #355). The monitor daemon's compute_attention() added a 'failed' Needs-attention row for every .project/review wave file whose verdict is blocked. The runtime requires earlier review cycles to stay on disk, so a wave that blocked at cycle 1 and passed at cycle 2 kept a permanent failed row until the milestone was archived. Decisions made on purpose: only the highest cycle of each wave and lens drives the attention row; status.reviews still lists every cycle as history, and final, gap and other review files are unchanged. Follow-up after an independent review: a newer cycle file supersedes an older one only when it has a valid wave verdict (pass or blocked, the two values the runtime accepts; a 'Wave verdict:' line with no value does not count), so a review that is still being written cannot hide a blocked cycle and turn the project health green; cycle numbers compare as numbers. The daemon is a separate package and cannot import scripts/, so it reuses its own WAVE_REVIEW_FILE_RE with capture groups; the name rule matches the runtime's wave-N.cycleC[.lens].md pattern and no new naming rule was added.
What Changed
compute_attention()indaemon/gsd_daemon/probe.pynow skips a wave review file when a later cycle of the same wave and lens replaces it, so a wave that blocked at cycle 1 and passed at cycle 2 no longer keeps afailedrow.status.reviewsstill lists every cycle, and final, gap and other review files are not filtered.passorblocked(newWAVE_VERDICTSset). A cycle file with no verdict, or with an emptyWave verdict:line, does not hide a blocked cycle, and the project health stays red. Wave and cycle numbers compare as integers.WAVE_REVIEW_FILE_REgains capture groups for wave, cycle and lens; the file name rule itself is unchanged.tests/test_daemon_attention.pyadds six tests: superseded blocked cycle, blocked newest cycle per wave, per-lens supersession, missing verdict, empty verdict line, and numeric cycle order (9 against 10).Risk Assessment
✅ Low: The change is one small pure helper and one skip in compute_attention(); traced cases (blocked then pass, blocked then blocked, per-lens deep review, newer cycle with no verdict or an empty verdict line, cycle 9 against 10, panel files with no Wave verdict) all give the correct rows, and the runtime fixes review depth per wave, so the lens set is the same in every cycle and per-lens grouping cannot leave a permanent failed row.
Testing
I installed the daemon from the target commit and from the base commit into two disposable venvs, and ran
gsd-path-daemon servefor each with an isolated HOME, a temporary daemon.json and nine throwaway fixture projects. I read/statusfrom both daemons, drove a full review-cycle lifecycle on disk against the running target daemon, and captured headless Chrome screenshots of both dashboards. The focusedtests/test_daemon_attention.pyfile also passed. No baseline commands ran before this step. All scenarios passed; the temporary setup was removed and the worktree is clean. One note: the first lifecycle run used a fixed 4-second wait that was shorter than the daemon's 3 to 4 second change-detection time, so I re-drove it with a wait-until-seen check.Evidence: /status attention rows per project, target commit
Evidence: /status attention rows per project, base commit
Evidence: Live review-cycle lifecycle against the running target daemon
step 1: only wave-1.cycle1.md (blocked) health=red failed_rows=['wave-1.cycle1.md'] step 2: cycle2 started, no verdict line health=red failed_rows=['wave-1.cycle1.md'] step 3: cycle2 has 'Wave verdict:' with no value health=red failed_rows=['wave-1.cycle1.md'] step 4: cycle2 gets 'Wave verdict: pass' health=amber failed_rows=[] (history keeps cycle1=blocked, cycle2=pass) step 5: cycle3 is blocked health=red failed_rows=['wave-1.cycle3.md'] The amber health in step 4 comes from the separate 'Runtime validation is unavailable.' row: the fixture projects have no installed runtime.Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
gsd-path-daemon --config <tmp>/daemon.json serve --port 47811(target 0e75e8ac, isolated HOME) thenGET /statusfor 9 fixture projectsgsd-path-daemon --config <tmp>/daemon.json serve --port 47812(base a09754ff, same fixtures) thenGET /statusto reproduce the bugLive lifecycle on project i-live-transition: wrote wave-1.cycle2.md with no verdict, then an emptyWave verdict:line, thenWave verdict: pass, then a blocked wave-1.cycle3.md, and read/statusafter the daemon saw each changeHeadless Chrome screenshot ofhttp://127.0.0.1:47811/(target) andhttp://127.0.0.1:47812/(base)python3 -m unittest tests.test_daemon_attention✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.