Deferred items: a register column nothing fills - #509
Merged
Conversation
The deferred-items register holds a Follow-up column for the issue each row is raised as. Completion now fills it: the open rows are collected, each is put to the run at its own gate, and an approved row is raised against the tracker the package's own issue lives in, with the new issue's link written into that row. A row the run leaves unraised keeps its dash and stays open for a later package. The gate flag is set by both options, so each pass through the loop decides on its own row. The register states the mechanism that fills the column, and names the technique that does it. Closes #491 finding 4. Co-Authored-By: Claude Opus 5 (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
While a work package runs, it keeps meeting things that need doing and do not belong in this piece of work. Each is written into a single table — the deferred items register — one row per item, with what it was and why it was out of scope. The last column of each row is for the tracker issue that will carry the item forward, and until one is raised it holds a dash.
Nothing raises the issue, so the dash stays. This adds the step that fills it.
What happens today
The register is written faithfully and read once. At the end of the package a closing document counts the rows and writes a line saying how many are open and how many became issues, and the second number is always zero. The package then finishes, the worktree is removed, and the register sits in a planning folder nobody opens again.
The register's own instructions claim the opposite. One of its rules states that issue creation reads the register and that deferred-item issues are raised from its rows carrying the row ID. There is no such reader anywhere in any workflow, so someone reading the rule would believe a mechanism exists that does not.
This is the finding that caused #491 to be written. Three of that issue's four findings were set aside on the understanding they would be filed, and there was no way to file them.
The fix
Completion gains three things, placed before the closing document is written so its count is true when it is taken.
The register is read for rows whose Follow-up cell holds a dash. A run that deferred nothing has no register at all, and that is reported as having deferred nothing rather than as a missing file.
Each unraised row is then put to the run at its own gate, showing the item and the reason it was set aside. Raising creates something other people see, and every other outward-facing action in this workflow asks first — the package's own issue is created behind exactly such a gate.
An approved row is raised against whichever tracker the package's own issue lives in, and the new issue's link is written into that row, leaving the ID, item and reason as the deferring activity wrote them. A row the run leaves alone keeps its dash and stays open for a later package.
The register's rule now describes the mechanism that exists and names the technique that performs it.
A note on the gate flag
The gate sets a flag that the raise step reads, and both of its options set it — approving sets it true, declining sets it false. A flag only ever set true would survive into the next pass of the loop and raise an issue for a row the run had just declined.
That is the defect #491 reports as its second finding, in a different activity: an exit gated on a flag no step can clear. It would have been easy to reproduce here.
Verification
The full corpus sweep passes, 27 of 27, measured against a code branch carrying the loop-consumer fix this depends on.
Depends on
The guard that reports a declared output nothing consumes does not count a loop's collection as a consumer, so the technique that collects the open rows reads as producing something dead. That is a gap in the guard rather than in this change, and it is fixed separately on the code branch. Until that merges, the corpus check here reports one finding against
open_deferred_items.Scope
Reading the register, gating each open row, raising the approved ones, and linking each row to its issue. The register's rule updated to describe it.
Acceptance criteria
Non-goals
This does not change what may be deferred, who may defer it, or the shape of a row. The register keeps having no owning activity, because any activity may be the first to defer something.
This does not raise anything in review mode, where the package is reviewing someone else's change and its deferrals are not its own to file.