Conversation
The README explained the loop in a paragraph and carried docs/oss.png, an image whose accuracy nothing verifies and whose drift no guard would notice. Mermaid rather than an image, deliberately: GitHub renders it natively, it is text so it diffs, and a wrong arrow shows up in review. An image drifts silently, which is the defect class this project is named after pointed at its own front page. The first draft added 33 lines and cut none, and tests/test_readme_trim_795.py correctly refused it at 99 lines against its 80-line ceiling (#795) -- the same append-dont-replace failure this repository rejects everywhere else. Paid for by cutting instead: the Type it once paragraph the diagram now states better, and the More link list, where nine of ten entries wrapped onto a second line. 79 lines with the diagram in. docs/oss.png stays: it is a banner carrying the tagline, not an architecture drawing, and removing it is a decision about the pages visual identity rather than about its accuracy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH
…1412) Maintainer review of the first version: /oss:doctor is one of the two verbs and did not appear at all, and -- worse -- the diagnose step was missing entirely. That step is the whole subject of #1390: /oss:run checks the install and the repo on every start, repairs what is ours, and carries on with a missing capability marked unavailable rather than being replaced by the diagnosis. Only a gap that makes the loop unsafe stops it, and each such gap names what would clear it. None of that was on the page. Both added, plus the unsafe-stop as its own terminal node so the refusal is visible rather than implied. Paid for inside the 80-line ceiling again rather than by raising it: the launcher section, which the diagram now shows; the Type it once paragraph, which restated the cadence-is-config rule docs/overview.md already carries; and the tagline, rewrapped onto one line. 79 lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH
…1412) The diagram showed the loop and hid the one property a reader needs before leaving it running unattended: each tick runs in a context that is thrown away after it, so hours of running cost what one tick costs rather than what all of them summed would. That was classified as internal vocabulary, following docs/overview.md rule that the mechanism is not the product. Half right: the NAME (sub-manager) is internal, the PROPERTY is the product. Someone deciding whether to run this unattended is deciding on exactly this, and it was nowhere on the page. Still 79 lines: the board node carries both facts on two lines instead of one, and the paragraph was rewrapped rather than the ceiling raised. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH
fdaviddpt
added a commit
that referenced
this pull request
Sep 11, 2026
… stop the /oss:run scheduler reading its own sub-steps (#1405, #1406, #1414) (#1418) * feat: rank next_action's sources instead of arbitrating, and show inbound work on the statusline (#1405, #1406) `scripts/next_action.py`'s `rank()` replaces `decide()`: every source (inbound, release, curate, triage) is composed every time and returned ordered, never stopped at the first fired/unresolved one. Every candidate carries its evidence; an unresolved reading is listed as `could-not-tell`, never dropped. `record_skip()` records a deliberate deviation from the top candidate via `oss_state.append`. `unsafe` and `due: setup` stay outside ranking, as refusals/preconditions rather than candidates. `inbound_reading()` in `scripts/statusline.py` is the "one module, two consumers" the design note on #1405 asked for: `refresh()` caches it on the board's own clock for the statusline's `inb NisNpr` field (#1406), and `next_action.py`'s `_fresh_inbound_reading` calls the same function fresh, since the loop is about to act on it. `unanswered_comments` is always `None` -- a per-thread comment walk is out of scope for this change and is left as a follow-up rather than guessed at. `commands/run.md` still reads the old four-state shape and needs a follow-up to consume the new one; not touched here since it is owned by a lane in flight on the same subsystem (fix/1389). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH * fix: two self-review findings on #1405/#1406 -- a repeat-suppression regression and a missing statusline doc/guard entry Explore reviewer found that `rank()`'s full composition (every source evaluated every call) armed the curate/triage repeat-suppression receipt the moment those candidates were merely evaluated, regardless of whether they were the one actually taken -- reintroducing the permanent-divert defect #1390/#1064/#1155 exist to close, one call later. Fixed: `_route_already_seen` gains `arm=False`, `_curate_candidate`/ `_triage_candidate` default to it, and `rank()` re-arms only `candidates[0]` once ranking is settled. Red repro and green fix both in `tests/test_next_action_1389.py::test_a_lower_ranked_curate_candidate_is_not_falsely_suppressed`. oss:auditor found `docs/status-line.md` and its own guard test (`tests/test_readme_statusline_fields_650.py`) were not updated for the new `inb` field -- the guard passed despite existing specifically to catch this. Fixed both. Three other findings (commands/run.md's stale shape, the new inbound source having no repeat-suppression of its own, and inbound_triage.py not actually being reused) and one auditor note (record_skip has no real caller yet) are non-blocking per the ranking table and logged to trap.d/ rather than fixed here or filed as issues. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH * fix: precision in rank()'s re-arm comment A follow-up lightweight review of the previous fix commit (855585f, required by fix_commit_scope.py's needs-second-pass verdict at 8 files touched) found the re-arm comment claiming "no extra forge call" was only precisely true for curate; triage's re-run also re-invokes triage_trigger.compute, which does its own local git/state-file reads. Read-only and deterministic either way -- no correctness issue, comment only. NO FINDINGS otherwise; both reviewer returns and this follow-up classify cleanly via scripts/review_return.py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH * feat: commands/run.md consumes rank() and stops reading its own sub-steps (#1405, #1414) Merged origin/main (the #1411/#1413 picker demotion, #1412's own fragment) -- clean merge, no conflicts. Two things in commands/run.md, as one coherent rewrite (#1414's own sequencing note): 1. Step 2 now consumes next_action.py's rank() shape (unsafe / due:setup / ranked / nothing-due) instead of the old four-state decide() this file used to parse. A new next_action.py --record-skip CLI lets a markdown procedure actually call record_skip() -- a plain Python function with no other caller reachable from a shell. 2. #1414: the scheduler no longer reads commands/run/setup.md, scaffold.md, install-audit.md, triage.md, curate.md, changelog.md or commands/release.md directly in its own long-lived session -- the erosion #695 built the sub-manager/releaser split to prevent, one layer over. A new agent, agents/scheduler-step.md, is the one generic wrapper the first six share (they differ only in which file to read); release spawns oss:releaser directly; dispatch is unchanged (commands/tick.md was already a thin spawn wrapper, not a document to follow). Budget tables updated: agents/scheduler-step.md and commands/run.md raised with the measurement and reasoning in CLAUDE.md, per this repo's own replace-or-raise convention. Context-size measurement (#1414's own scope item): not-measured. #695 is the precedent for measuring rather than reasoning, and this lane could not run a multi-tick session to take the before/after comparison itself; reported as not-measured rather than a reasoned-to number, per this repo's own rule that an unmeasured claim is trusted least. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH * fix: rank() must never write a receipt, only an explicit --take/--record-skip commitment may (#1405, #1414) A second self-review round on the #1414 commands/run.md rewrite found a real regression, independently corroborated by both spawns: rank()'s own curate/triage repeat-suppression receipt was armed on every call, including a plain read-only --json call, rather than only when a caller actually committed to acting on the top candidate. #1414's own --record-skip gave a caller a real reason to call rank() without taking candidates[0] at all, collapsing "surfaced" and "acted on" back into one event -- exactly the permanent-divert defect the earlier arm=False/ arm=True split (from the #1405 self-review round) was built to close. Fixed: rank() no longer writes anything, ever. A new _arm_route_source is the one place a receipt is persisted, called only from a new --take <source> CLI (the ordinary case: source must equal candidates[0]) and from --record-skip (arms the source actually taken, once the skip itself is recorded). record_skip() also gained a membership check on taken_source against the real ranked sources, closing a second finding both spawns raised independently: a typo used to sail through both checks and land in the state file's permanent decision log exactly as confidently as a real deviation. commands/run.md's step 2 documents --take alongside --record-skip, and each of the five remaining generic sub-steps (scaffold, install-audit, triage, curate, changelog) now gets its own literal Agent(...) line rather than one shared example a reader had to adapt by hand -- the Explore reviewer found the shared form gave four of the five nothing but the required path strings to notice a regression back to "read and follow" prose. One finding logged to trap.d/ rather than fixed here (non-blocking, reasoned not observed): _record_skip_cli/_take_cli reload .oss.json a second, independent time after rank()'s own internal load, a narrow TOCTOU seam whose honest fix is exposing rank()'s own loaded config rather than reloading -- a bigger change than its severity warrants in this lane. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH * fix: three docstrings still described rank()'s own removed arm mechanism A second lightweight follow-up review of 4533e7d (required by fix_commit_scope.py's needs-second-pass verdict at 6 files touched) found _curate_candidate, _triage_candidate and _route_already_seen still describing the pre-fix mechanism ("rank()'s own re-call... passes arm=True") that 4533e7d removed entirely. A reader of any of these three functions in isolation would come away believing rank() still arms candidates[0], which is exactly the bug that commit fixed. Corrected all three to name _arm_route_source/_take_cli/_record_skip_cli as the only remaining arm=True call sites. NO FINDINGS otherwise; all three reviewer returns (two on 6830151, one on 4533e7d) classify cleanly via scripts/review_return.py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH * fix(tests): scheduler-step.md joins NO_TEST_CONCERN in the delegated-test-run guard (#1414) All four pytest legs on PR #1418 failed on tests/test_delegated_test_run_877.py: a new Bash-granted agent definition must be placed in one of its three buckets, and agents/scheduler-step.md was in none. The guard is right -- it exists so a new agent cannot skip the question of whether it may run the test suite. The answer: NO_TEST_CONCERN, beside triager.md. scheduler-step reads exactly one of setup, scaffold, install-audit, triage, curate or changelog, none of which runs test_command, and its own description forbids the two sub-steps that could (dispatch and release have their own spawns). The reason is written beside the set, where the guard reads it. Found by CI, not by the lane: this guard was not in the set the lane ran. Worth a trap fragment -- a lane adding an agents/*.md has a fixed list of guards to run and this one was not on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- 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.
Closes #1412.
The README explained the loop in a paragraph and carried
docs/oss.png, an image whose accuracynothing verifies and whose drift no guard would notice. The loop is now explainable end to end, and
prose is the wrong medium for it.
Adds a mermaid
flowchartunder Type it once: one human action (oss-workspace, once), thequestion
/oss:runasks, the branches it takes -- no config, inbound, release, curate, triage, orotherwise dispatch -- the lane, the audit, the merge, and every arrow returning to
/oss:runratherthan stopping. That last part is the claim this project actually makes, and it was nowhere on the
page.
Mermaid rather than an image, deliberately. GitHub renders it natively so there is nothing to
build or host; it is text, so it diffs and a wrong arrow shows up in review like any other wrong
line. An image drifts silently -- the defect class this project is named after, pointed at its own
front page.
Replace, don't append. The first draft added 33 lines and cut none.
tests/test_readme_trim_795.pyrefused it at 99 lines against its 80-line ceiling (#795: read likea tool, not like a lab notebook), which is exactly the append-don't-replace failure this repository
rejects everywhere else. The ceiling was not raised. Paid for by cutting:
79 lines with the diagram in.
Not in scope:
docs/oss.pngstays. It is a banner carrying the tagline, not an architecturedrawing, and removing it is a decision about the page's visual identity rather than about accuracy.
Checks run
tests/test_readme_trim_795.py,tests/test_content_invariants.py,tests/test_freshness.py--254 passed.
assemble_changelog.py --check-- ok. Docs only, no code path changes.One thing I cannot verify from here: that the mermaid block renders as intended on GitHub. The syntax
is standard
flowchart TDwith an&fan-in on the last edge, which is the only construct worth asecond look.
🤖 Generated with Claude Code
https://claude.ai/code/session_012UYdzDHX3k3C2Eh7B5hRVH
[AI-generated]