Skip to content

chore: graduate the friction-log inbox to GitHub Issues (#54-#56) - #57

Merged
topij merged 2 commits into
mainfrom
chore/triage-2026-07-26
Jul 26, 2026
Merged

chore: graduate the friction-log inbox to GitHub Issues (#54-#56)#57
topij merged 2 commits into
mainfrom
chore/triage-2026-07-26

Conversation

@topij

@topij topij commented Jul 26, 2026

Copy link
Copy Markdown
Owner

The inbox was at its 150-line budget carrying an explicit "sweep required before the next entry" tripwire. Run inline in the skill's documented LLM-only modescripts/triage_friction_log.py and scripts/finalize_triage.py are not vendored yet (blocked on #6), so the parse / draft / sweep steps were done by hand against the doctrine.

Graduated (3)

#54 every verification claim must name the command that establishes it
#55 safety-critical-changes.md rule 1 should name a tightening threshold
#56 removing a mechanism requires enumerating what it was rejecting

#54 supersedes the inbox entry's own proposal. That entry suggested "wrap-up should fact-check the handoff". The pattern turned out to be broader than the handoff and broader than authorship: two instances this session (#51, #53) are generated by engines, so they reproduce identically in every adopter no matter who is writing. The filed version promotes panel contract item 8 — "state what was verified clean, and how" — from review time to authoring time, which is the form that binds engine output too.

Needed no ticket — their fixes had already shipped (3)

Checked rather than assumed, which is the part of triage most worth doing:

entry proposed fix already shipped as
"reading is not running" panel must require execute + mutation-test contract items 4–5
"a fix round is where the next bug comes from" rule 3 needs a stopping criterion rule 3 → blast-radius cross-ref
"concurrent lenses corrupt each other" isolated worktrees contract item 7

All three landed in #31. Filing them would have produced three issues that were already closed on arrival.

Everything else was already tagged with an issue id (#10, #18, #19, #33) or recorded a guard working correctly with "No change proposed".

The sweep

Moves the whole prior inbox verbatim into kit-friction-log-archive.md with headings demoted one level, matching finalize_triage.py's documented behaviour, and rewrites the active file as H1 + intro + the new graduation marker.

Verified rather than asserted (per #54, filed in this very PR):

# the whole original body, demoted, must appear as ONE CONTIGUOUS byte-identical
# block in the archive — this establishes verbatim AND in order, where a
# set-membership check ("every line appears somewhere") would not.
body    = '\n'.join(orig.split('\n')[13:]).rstrip('\n')
demoted = '\n'.join(('#'+l) if l.startswith('## ') else l for l in body.split('\n'))
assert demoted in open('docs/kit-friction-log-archive.md').read()
contiguous byte-identical block present in archive:  True
original body lines (non-blank):                      120
## headings demoted:                                  3 of 3
inbox: 150 -> 35 lines (budget 150)

An earlier revision of this section cited lines NOT found in archive: 0, which is
set membership and does not establish the verbatim-and-in-order claim the prose
made. Caught by review — and an instance of exactly what #54, filed in this PR, is
about. The check above is the one that establishes it.

Config drift found during pre-flight

Worth flagging separately: this repo's own config/dev-model.yaml still carries unstamped placeholderstracker.backend: linear, tracker.project_name: "My Project Dev", tracker.url: "", notify.backend: slack — while the actual tracker is GitHub Issues on this repo (19 issues filed today) and notify is unused.

The kit is the template repo, so it never ran ./init.sh against itself. Nothing reads those keys today, which is why it has gone unnoticed — but triage-friction-log is the first workflow that would have, and a vendored triage_friction_log.py would resolve tracker.backend: linear and try to file into Linear. Not fixed here to keep this PR to one concern.

https://claude.ai/code/session_01V27wAgECMEApqAvmJMFyqm

The inbox was AT its 150-line budget with an explicit "sweep required before
the next entry" tripwire. Run inline in the skill's documented LLM-only mode:
scripts/triage_friction_log.py and scripts/finalize_triage.py are not vendored
yet (blocked on #6), so the parse/draft/sweep steps were done by hand against
the doctrine.

Three entries graduated:

  #54  every verification claim must name the command that establishes it
  #55  safety-critical rule 1 should name a tightening threshold
  #56  removing a mechanism requires enumerating what it was rejecting

#54 supersedes the inbox entry's own narrower proposal ("wrap-up should
fact-check the handoff"): the pattern turned out to be broader than the
handoff, and two instances this session (#51, #53) are generated by ENGINES,
so they reproduce in every adopter regardless of who is authoring.

Three further entries needed no ticket — their proposed fixes had ALREADY
SHIPPED in #31, which the triage checked rather than assuming:

  "reading is not running"      -> panel contract items 4-5 (execute,
                                   mutation-test) exist
  "fix rounds introduce bugs"   -> rule 3 now carries the blast-radius
                                   stopping criterion
  "concurrent lenses corrupt"   -> contract item 7 mandates isolated worktrees

Everything else was already tagged with an issue id (#10, #18, #19, #33) or
recorded a guard working correctly with "No change proposed".

The sweep moves the whole prior inbox verbatim into kit-friction-log-archive.md
with headings demoted one level, matching finalize_triage.py's documented
behaviour. Verified: all 120 body lines present in the archive, all three
section headings demoted, nothing dropped. Inbox 150 -> 32 lines.

Claude-Session: https://claude.ai/code/session_01V27wAgECMEApqAvmJMFyqm
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@topij, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6df78d19-494b-4e43-afc0-3da7f708f596

📥 Commits

Reviewing files that changed from the base of the PR and between 3a9de44 and 9fa6fd3.

📒 Files selected for processing (3)
  • docs/kit-friction-log-archive.md
  • docs/kit-friction-log.md
  • docs/kit-handoff.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/triage-2026-07-26

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.

Review findings on #57. All LOW; the content-preservation core held.

  - the active file's intro still said "entries below are the ones that are
    not yet issue-shaped" — after the sweep there are no entries below. It is
    preserved verbatim per the doctrine's "H1 + intro", so an engine run would
    have left it too; reworded to describe the marker convention instead.
  - the archive header named TWO buckets for the un-graduated remainder; there
    are three. The 11th entry (a guard firing correctly, "No change proposed")
    is neither already-tagged nor already-shipped. Both files now give the full
    11-entry accounting: 3 graduated + 3 already shipped + 4 already tagged +
    1 no-change.
  - a line wrapped so it began `#31 —`. Not an ATX heading under CommonMark (no
    space after `#`) and no kit tooling mis-parses it — both `init.sh` and
    `archive_plan_sessions.py` match `"## "` with the space — but an unfortunate
    wrap in a file whose own sweep engine is heading-anchored. Reflowed.

Also updates the handoff, which this PR's own sweep had just falsified: it
said "the friction log is AT budget (150/150) and triage-friction-log is now
blocking". It is 32 lines and not blocking. Step 5 of the doctrine constrains
the finalize commit to the two doc paths, so this is a deliberate scope
deviation — `session-start` reads the handoff and would otherwise hand the
next session a false blocking signal, which is precisely the failure #54 (filed
in this PR) exists to stop.

Re-verified with the stronger check the reviewer used, rather than the
set-membership one the PR body originally cited: the entire original body,
demoted, appears as one CONTIGUOUS byte-identical block in the archive — which
establishes verbatim-and-in-order, not merely present.

Claude-Session: https://claude.ai/code/session_01V27wAgECMEApqAvmJMFyqm
@topij

topij commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

Review record — one correctness lens, not a panel

CodeRabbit is rate-limited on this head (detected on both the comment surface and the check description). One isolated fresh-context lens ran instead — deliberately one, not the panel, and the receipt says so. Blast radius here is records, and the one failure mode that matters — did the sweep lose anything — is a correctness question, not an adversarial one.

Verdict: content preservation clean, no HIGH or MEDIUM. Nine LOW findings; six fixed in 9fa6fd3, three answered below.

The verification that mattered

The lens re-derived the sweep integrity with a stronger method than the one I originally cited, and it holds: the entire original body, demoted, appears as one contiguous byte-identical block in the archive — which establishes verbatim and in order, where my lines NOT found in archive: 0 only established set membership. Fair hit, and an instance of the very thing #54 is about; the PR body now cites the stronger check.

It also independently verified the part I most wanted checked — all three "already shipped in #31" determinations are true (git blame7485512b for panel contract items 4–5, item 7, and rule 3's blast-radius cross-ref). No friction entry was dropped without a ticket. And all four "already tagged" entries carry their ids.

Fixed in 9fa6fd3

Answered, not changed

The PR is not a draft, and the doctrine says it should be. Deliberate. CLAUDE-sections.md — the always-on baseline — holds that a finished PR must never sit in draft, because ready-for-review is what triggers the review bots. That conflict is already resolved in this repo's favour: the handoff records that when parallel.md's kickoff and the lane contract disagreed on exactly this, the lane contract was the outlier, and pr_watch proves it ("PR is draft" is a merge blocker, so a draft PR can never satisfy the merge gate). A finalize_triage.py that opens a draft PR would inherit that bug — worth its own issue when the engine is vendored (#6).

Range spelled three ways#54–#56 (en dash) in the docs, #54-#56 (ASCII) in the commit subject and PR title. Cosmetic; the docs are the artifact readers see and they are internally consistent.

No reports/triage_2026-07-26.md and no frozen-inbox snapshot. Expected: both are written by the unvendored parser (#6). Nothing to snapshot against, since draft and finalize happened in one session with no window between them.

Receipt: fallback:correctness-lens, one lens, bound to 9fa6fd3.

@topij
topij merged commit 65553d2 into main Jul 26, 2026
3 checks passed
@topij
topij deleted the chore/triage-2026-07-26 branch July 26, 2026 13:47
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.

1 participant