docs(planning): migrate deferred items to GitHub Issues and retire the deferred concept - #439
Merged
Merged
Conversation
…e concept Four of the five `planning/deferred/` items become GitHub issues labelled `needs-triage` (#434, #435, #436, #437), each carrying its full reasoning and its `## Revisit trigger` section verbatim, with relative links rewritten to absolute ones. The fifth, `2026-07-29-upstream-lean-convention`, is closed as resolved: #430 deleted `planning/.convention-version` and the vendored `planning/index.py`, which answers its question outright. #438 records that `ROADMAP.md`'s `## Under consideration` duplicates the queue; resolving it is not part of this change. `planning/scripts/perf-readability-audit.workflow.mjs` read `planning/deferred/` at run time, so its discovery step is repointed at open issues and its `deferred_items` bucket renamed `open_issues`. The `revisit_trigger` field goes with it: an issue carries no such section, and requiring one would install the convention this change retires. The repo now has two places for what outlives a PR: an open GitHub issue, or an ADR in `docs/adr/` recording a refusal. There is no third state, no `deferred` label, and no directory inviting new files in the retired format. Closes #431 Claude-Session: https://claude.ai/code/session_01FBic7HFGR6sdRfSW3cGEv2
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: a5b76f2 | Previous: fa0c1f2 | Ratio |
|---|---|---|---|
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type |
3027361.8106920146 iter/sec (stddev: 2.2883241128982294e-8) |
3058955.9930034317 iter/sec (stddev: 1.2044041425843978e-8) |
1.01 |
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry |
2885191.53517097 iter/sec (stddev: 2.3618048887534786e-8) |
3027749.719790808 iter/sec (stddev: 8.538688796421868e-9) |
1.05 |
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve |
25987.617902963448 iter/sec (stddev: 0.0000072761047265233606) |
26610.154146642257 iter/sec (stddev: 0.00000355802809936304) |
1.02 |
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached |
20851.43171155234 iter/sec (stddev: 0.000002696039870856156) |
20716.99406452999 iter/sec (stddev: 0.0000028564809603351236) |
0.99 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] |
431.70764262307534 iter/sec (stddev: 0.00002611991439477973) |
416.31016791682 iter/sec (stddev: 0.00013309029441131804) |
0.96 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] |
408.5483811179409 iter/sec (stddev: 0.00002238787107689653) |
393.9977086417439 iter/sec (stddev: 0.0002283727550580883) |
0.96 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] |
370.6284042074782 iter/sec (stddev: 0.00002862482881002619) |
370.04946265632594 iter/sec (stddev: 0.00004198169908252088) |
1.00 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] |
2450.608946711713 iter/sec (stddev: 0.000026574601264019737) |
2413.386087274012 iter/sec (stddev: 0.00002643190172770029) |
0.98 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] |
1788.6415359944801 iter/sec (stddev: 0.00018400220692895992) |
1794.5449422847682 iter/sec (stddev: 0.00019220801195772157) |
1.00 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] |
1251.3311034606247 iter/sec (stddev: 0.00003222095494540229) |
1231.880993890625 iter/sec (stddev: 0.0000310308519760051) |
0.98 |
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container |
761337.369791606 iter/sec (stddev: 9.317253594653207e-8) |
762484.3807458347 iter/sec (stddev: 6.677094612925152e-8) |
1.00 |
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope |
691584.7534952442 iter/sec (stddev: 4.65827446596004e-8) |
678747.4320234375 iter/sec (stddev: 3.7794020157847575e-8) |
0.98 |
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch |
2333.162205485119 iter/sec (stddev: 0.000009612181160470277) |
2292.756864125991 iter/sec (stddev: 0.000026611728800167923) |
0.98 |
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control |
61920.866043688955 iter/sec (stddev: 0.0000012981258217468314) |
61118.423043514515 iter/sec (stddev: 0.000001944441079019775) |
0.99 |
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale |
43744.40502892593 iter/sec (stddev: 0.000001732463662495283) |
42727.74546523071 iter/sec (stddev: 0.000003809824100830296) |
0.98 |
benchmarks/test_guard_resolve.py::test_g1_transient_resolve |
2057864.262038706 iter/sec (stddev: 3.4735943138951956e-8) |
2048596.1840997688 iter/sec (stddev: 2.4708186902378356e-8) |
1.00 |
benchmarks/test_guard_resolve.py::test_g2_cached_resolve |
3290374.424202136 iter/sec (stddev: 9.39285355609106e-9) |
3254762.7105441685 iter/sec (stddev: 1.0784726599609547e-8) |
0.99 |
benchmarks/test_guard_resolve.py::test_g3_deep_chain |
743599.3293485536 iter/sec (stddev: 6.636574724639586e-8) |
773273.8763039825 iter/sec (stddev: 3.5075102273856135e-8) |
1.04 |
benchmarks/test_guard_resolve.py::test_g4_wide_resolve |
410483.14009247796 iter/sec (stddev: 1.2626589720684507e-7) |
406845.64172646345 iter/sec (stddev: 1.028770545042996e-7) |
0.99 |
benchmarks/test_guard_resolve.py::test_g5_cross_scope |
1659258.9741148208 iter/sec (stddev: 3.5980032376590047e-8) |
1687496.4193458415 iter/sec (stddev: 2.1687288415664223e-8) |
1.02 |
benchmarks/test_guard_resolve.py::test_g9_context_resolve |
853714.5589999612 iter/sec (stddev: 3.1504644889986453e-8) |
857306.7741972841 iter/sec (stddev: 4.249658783304315e-8) |
1.00 |
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve |
478116.03158875846 iter/sec (stddev: 5.065997055686185e-8) |
501696.0839503699 iter/sec (stddev: 5.866275205489772e-8) |
1.05 |
benchmarks/test_guard_resolve.py::test_g18_alias_hop |
2260938.380314786 iter/sec (stddev: 9.960765075982985e-9) |
2262349.464396402 iter/sec (stddev: 1.2098233484183741e-8) |
1.00 |
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain |
30795.857341216826 iter/sec (stddev: 0.0000019332540463980586) |
30367.325292441026 iter/sec (stddev: 0.000002720201505366594) |
0.99 |
benchmarks/test_guard_validate.py::test_g11_validate_wide |
18154.68605853794 iter/sec (stddev: 0.00000327965809197932) |
17840.89924933394 iter/sec (stddev: 0.000003247131866794469) |
0.98 |
This comment was automatically generated by workflow using github-action-benchmark.
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.
Why
planning/deferred/held five items of real, understood, deliberately-unscheduledwork that nothing surfaced: files in a directory no contributor reads, invisible to
anyone browsing the project. The queue was also duplicated —
ROADMAP.md's## Under considerationrestated at least one item, and each pointed at the otheras also recording it. GitHub Issues is exactly the thing the convention document
conceded was missing, and it was already enabled here with zero open issues.
Design
Four of the five items become GitHub issues, labelled
needs-triageand nothingelse, so each gets re-decided rather than inherited unexamined:
Bodies are the files verbatim, including
## Why it is openand## Revisit trigger. Thesummary:frontmatter becomes the opening sentence; relative linksbecome docs-site URLs or
blob/mainADR links, since a relative path does notresolve in an issue body. #434 and #438 cross-reference each other.
The fifth,
2026-07-29-upstream-lean-convention, is not migrated. It askedwhether this repo's deviation from
planning-conventionshould go upstream; #430answered it by deleting
planning/.convention-versionand the vendoredplanning/index.pyoutright. Resolution recorded as a comment on #431.#438 records the
ROADMAP.mdoverlap so it is tracked rather than forgotten.Backfills:
pyproject.toml'sSLF001per-file-ignore comment (→ #436), ADR 0017and
ROADMAP.md(→ #434),planning/README.md(now covers onlyreleases/,_templates/,scripts/,links.py),CLAUDE.md's## Workflow, and the PRtemplate's checklist item.
One deviation from #431's enumerated backfills:
planning/scripts/perf-readability-audit.workflow.mjsreadplanning/deferred/at run time, so leaving it would have broken the harness. Its discovery step is
repointed at
gh issue list --state open, thedeferred_itemsschema key renamedopen_issues, and therevisit_triggerfield dropped — an issue carries no suchsection, and requiring one would install the convention this PR retires. Review
also caught that the resulting bucket must not be called a settled corpus (an
open issue is unsettled by definition), so the guardrail prose now reads "known
ground: an ADR is a settled refusal, an open issue is work already recorded".
The point, not a side effect: after this the repo has no concept of deferred work.
An item is an open issue or an ADR recording why it will not be done. The four
surviving
## Revisit triggersections are prose carried along for the reader andestablish no convention.
Non-goals
needs-triage; several are strongwontfixcandidates on their own text, and awontfixwrites an ADR. That is atriage-time judgement, not a migration decision.
ROADMAP.mdoverlap. Only ROADMAP.md's "Under consideration" duplicates the issue queue #438 is filed.deferredlabel, an issue template, or any org-repo change. An issue formwas rejected twice over: forms fire only in the web UI and are bypassed by
gh issue create, and a repo-local.github/ISSUE_TEMPLATE/would suppress theorg's inherited templates.
deferredgoes intodocs/agents/issue-tracker.md.docs/adr/0020's "typer is the one fixable case, deferred" — plain English,pointing at no directory; editing a settled record's prose was outside the ask.
Verification
No new tests: this PR creates issues and edits Markdown, TOML comments, and a
workflow script's prompt strings.
just check-links— the gate here. Every reference that pointed intoplanning/deferred/either resolves or is gone; a missed backfill fails here.git grep planning/deferredreturns nothing outside immutable release notes.just lint-ci— green (eof-fixer,ruff format,ruff check,ty, links).just test-ci— 512 passed, 100% line coverage. Unaffected, as expected: notest read
planning/deferred/after Migrate planning/decisions/ to native ADRs in docs/adr/ (29 → 26) #430.including the
#the-thread-safety-boundaryanchor.Unverified: the audit harness edit could not be executed.
node --checkrejectsthe file over the top-level
returnthe Workflow runtime allows — onmaintoo —so the change was checked by identifier consistency (schema key,
requiredlist,both prompts, and the
logline) rather than by a run.Closes #431
https://claude.ai/code/session_01FBic7HFGR6sdRfSW3cGEv2