Repository navigation
Conversation
levifig
added a commit
that referenced
this pull request
Oct 22, 2026
…ssages Review of #424: Implement now lists blockers with --layer unresolved-blockers because the default digest only counts those older than 30 days; Ship resolves blockers independently of local reconciliation; the not-a-block and scope-less block messages read correctly; the stale count line says "list them". Adds tests for an id-shaped scope, a scope-less imported block, a historical duplicate id unblock and a truncated collapsed page.
Owner
Author
|
Ship: request changes on 89da3ba. An independent reviewer found no code defects. The write check and the digest agree in every case it traced. One Verification box on #420 isn't met as written, and the PR still has to move onto #422's new digest renderer.
Agent notes
|
An unblock can now name one block by its entry id, which resolves only that block; unblock by scope still resolves every open block with that scope. The unresolved-blockers layer lists each open block separately, led by its id. An unblock naming an unknown entry, a non-block entry or an already resolved block is refused with a clear message and writes nothing. The default digest lists blockers from the last 30 days and counts older ones with the command that lists every blocker. Ship and Implement now resolve, by id, the blockers that landed or resumed work cleared. Fixes #420
…ssages Review of #424: Implement now lists blockers with --layer unresolved-blockers because the default digest only counts those older than 30 days; Ship resolves blockers independently of local reconciliation; the not-a-block and scope-less block messages read correctly; the stale count line says "list them". Adds tests for an id-shaped scope, a scope-less imported block, a historical duplicate id unblock and a truncated collapsed page.
After #422 the default digest, every SessionStart hook and post-compaction resumption render through renderJournalContextDigest, so the 30-day blocker collapse moves there: aged-out blockers are counted next to the layer's list command instead of listed, and listed blockers carry the resolve-by-id hint. The --layer read lists every blocker in #422's [date] id order. A Runner clock lets a test age real blockers and drive the CLI and Claude Code hook paths end to end.
levifig
force-pushed
the
claude/gracious-cori-08ce27
branch
from
October 22, 2026 00:52
cbdbbce to
7d9ea21
Compare
Review nits on #424: the digest's resolve-by-id hint now appears only when packing lists at least one blocker; Ship and Implement read blockers with --limit 100 so older ones are not hidden behind the first page; the #345 changelog clause no longer contradicts #420's JSON additions; renderer tests cover a limit-truncated page and a budget cut with stale blockers present.
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
The continuity digest's unresolved-blockers list only grew. A blocker cleared only when someone logged an
unblockwith exactly the same scope, and scopes are often generic (ship,review), so that rarely happened. On 2026-10-22 this repository had 24 open blocks; 13 of them cite work that has since merged or closed, and blocks sharing a scope hid behind the newest one.loaf journal log "unblock(<block id>): <what cleared it>". Only that block is resolved; other blocks with the same scope stay open. The block itself is never edited.unblock(<scope>)still resolves every open block with that scope.--from-hookit warns instead, as unmatched unblocks already did.--layer unresolved-blockersstill lists every blocker in full.--jsonkeeps its fields and addsstale_countand a per-itemstaleflag.Native work
Implements #420.
Verification
Ran on c5276d8, which is #420 rebased onto main after #422 landed, with the 30-day collapse moved into #422's renderer and the re-review nits fixed. The first round on 89da3ba is superseded.
Fixture tests for unblock by id. An id unblock clears exactly that block and leaves another block with the same scope open. An exact-scope unblock still works, also after id unblocks. Refusals cover:
Refusals write nothing, and a block whose scope merely looks like an id is resolved by that scope. Tests:
TestJournalUnblockByEntryIDResolvesExactlyThatBlock,TestJournalUnblockByIDThenScopeLeavesNoStrayDiagnostics,TestJournalUnblockEdgeShapesAgreeWithTheDigest,TestJournalLogUnblockByEntryIDAndBlockerLayerIDs. The existing exact-scope tests pass unchanged.Fixture tests for the age limit. With a fixed clock, blocks more than 30 UTC calendar days old are flagged and counted, including past the shown page. The day boundary is exact: 30 days is still listed, 31 is not. Tests:
TestJournalContextFlagsBlockersOlderThanTheAgeLimitandTestJournalContextAgeDaysCountsUTCCalendarDays.TestJournalContextDefaultPathsAgeRealBlockersByTheReadClocklogs real blocks and moves the read clock forward. Through the plain CLI and the Claude Code SessionStart hook, the digest then showsshowing 0 of 2 (more: … --limit 2; 2 older than 30 days not listed)with no block ids, while--layer unresolved-blockerslists both.TestJournalContextDefaultDigestCountsStaleBlockersInsteadOfListingThemcovers the mixed and all-stale renders.Resolving this repository's stale blockers: not run live. The check ran on a byte copy of the live journal, which was kept read-only. On the copy, 13 blocks were resolved by id: 11 cite merged or closed work (Verify native work before entering implementation #267/chore: retire legacy Amp modes and forced delegation #314, Record harness provenance and local gateway outcomes (#286) #361, build: emit JavaScript adapters and require Node 24+ #308 ×3, Retire the inert Amp loaf-modes plugin #309, fix: label implementation threads as implementer #280, fix: isolate CI tests and prioritize local verification #253, feat: integrate the vNext Loaf baseline #225, docs: codify shippable Git history #212) and 2 record their own resolution. The digest then reads
unresolved-blockers: showing 0 of 11 (more: … --limit 11; 11 older than 30 days not listed), with no diagnostics, at 4,229 bytes. The live run waits for a decision; see the Ship comment.Skill changes pass the authoring checklist. Ship and Implement edits are body-only, use harness-neutral prose and the skill's own journal command form, and change no frontmatter, sidecars or references; the journal template's links are unchanged. The
dist/andplugins/copies are regenerated and committed.env -u LOAF_DB make verify-localpasses on c5276d8.Also ran:
unblock(<id>)("no matching block exists"), and its layer showed only the newestshipblock, without an id.LOAF_DB, unblock by id resolved one of twoshipblocks. The three bad cases were refused with their messages and exit 1.loaf check issue-changelogpasses for Let agents resolve journal blockers by entry and stop listing stale ones #420 againstorigin/main.Ship
Pending Ship review.
Migration / risks
unblockentry whose scope is the block's id.loafbefore resolving the live journal's blockers by id.previous_unblock_idnow names the unblock that last resolved a block with the same scope before this one opened.Out of scope
unblock(<id>)entries listed in the agent notes, to log once the installedloafincludes this change.Fixes #420
Agent notes
resolveJournalBlocksininternal/state/journal_blockers.goreplays block/unblock rows oldest first. An unblock whose key is an earlier block's id resolves that block; any other unblock resolves the open blocks with exactly its scope. The digest (queryBlockerCandidates) and the write check (validateJournalUnblockTx) both use it, and the write check tests the cases in the same order, so an accepted write always resolves something on replay.journal-unmatched-unblock(unchanged, scope),journal-unblock-already-resolved,journal-unblock-unknown-entry,journal-unblock-not-a-block. All useJournalUnmatchedUnblockError, so the human,--jsonand--from-hookpaths are unchanged.journal…:<24 hex>legacy ids. A key matching an open block's exact scope is treated as a scope before the unknown-id rejection.journalContextAgeDayscounts whole UTC calendar days, so output is stable within a read date. A block is stale pastJournalContextBlockerStaleDays(30), the project knowledge staleness default.JournalContextOptions.Nowis the clock; zero means now.writeJournalBlockerLayerHumanininternal/cli/journal.go. When Fit the continuity digest to each harness's injection budget #345 lands its default-digest renderer, the collapse moves there;TestJournalContextDefaultDigestCountsStaleBlockersInsteadOfListingThemguards it.01a135f2-ef67-7633-a0cd-76124843b02d(Verify native work before entering implementation #267 closed, chore: retire legacy Amp modes and forced delegation #314 merged)01a1339c-fe66-7421-9ea1-7592945316a3(Record harness provenance and local gateway outcomes (#286) #361 merged)01a0d363-135d-7f32-9b3f-7916db3332aa,01a0d34e-5cca-751e-884e-9806cf880cca,01a0d10a-f150-7bee-a6c4-de204986df0d(build: emit JavaScript adapters and require Node 24+ #308 merged)01a0ce89-5d21-719c-a7f7-f0624b9f5bef(chore: retire legacy Amp modes and forced delegation #314 merged)01a0cb50-a232-7936-b0b5-f7ef6f2d1fb2(Retire the inert Amp loaf-modes plugin #309 closed)01a09656-2c30-799c-b45e-57ffc3628cad(fix: label implementation threads as implementer #280 merged)01a08dcb-d2d9-79fd-a223-b37ec92dd577(fix: isolate CI tests and prioritize local verification #253 merged)01a06d11-afa7-7d68-a0f9-ff6cb12c07fb(feat: integrate the vNext Loaf baseline #225 merged)01a05ee8-01d8-7b29-a608-6f90152eba20(docs: codify shippable Git history #212 closed)journal:e7f33b7b5a173a4647f33f55,journal:4a96fb42dddb0cd52b2f5147(self-resolved)