Audit: Plan index¶
What we check¶
docs/plans/index.md is the one page that answers "what has this
repository planned, and what still wants attention". It is read by
people picking up work and by tooling deciding what to surface, and
neither can read it if every repository shapes it differently. Three
layouts had grown across the fleet -- a date-first table of plans, a
plan-first table of plans, and a plan-first table of phases -- so
a reader (or a script) had to work out which one it was looking at
before it could find the status column.
Repositories with a docs/plans/ directory must satisfy all of:
- An index exists.
docs/plans/index.mdis present wheneverdocs/plans/holds any plan at all. - Plans are listed in tables, not as prose or a bullet list.
- Every table leads with
DatethenPlan. Later columns are the repository's own business;Intent,StatusandPhasesare the common ones. AStatuscolumn is optional -- a standalone plan listing that tracks no status is registered, just not tracked. - Dates are
YYYY-MM-DD, and rows run oldest first. Ordering is checked within each table, not across them, so a repository may keep separate master, standalone and consolidation tables that each start over. - Every master plan is listed. A plan file in
docs/plans/that the index never links is invisible: it was drafted and then forgotten. Phase plans are exempt -- they are named after their master plan and tracked inside it. - Status cells come from the shared vocabulary, described below.
Repositories with no docs/plans/ directory are reported as N/A.
Whether every project should plan this way is a separate decision,
not smuggled in here.
The status vocabulary¶
A status cell holds exactly one of Proposed, Not started,
In progress, Blocked, Complete, Abandoned or Superseded,
and nothing else. Matching is case-insensitive, so In Progress
passes, but the canonical spelling is the one to write.
The rule is strict about the "nothing else" because that is the part that decayed. Status cells across the fleet had grown into whole paragraphs:
Complete (phases 1-5 and 2b, 2026-08-15): every merge to develop
installs a freshly built .deb/.rpm on...
That is useful writing in the wrong column. A status is read to decide
whether a plan still wants attention; when the answer is buried in a
paragraph, neither a person scanning the table nor a script can get
it out. Dates, phase arithmetic and summaries of what happened
belong in the plan file, and a one-line summary belongs in the
index's own Intent column.
The vocabulary itself is a versioned shared block,
plan-status-vocabulary, which every PLAN-TEMPLATE.md must carry
(see the plan-template audit) so that plans are written to it
rather than corrected afterwards. It governs the master plan's own
Execution phase table as well as the index row. A test in
scripts/test_audit_check.py asserts the block and the list the
audit enforces name the same terms, so the wording repositories are
handed cannot drift from the wording they are measured against.
Overlap with the session hook, which is deliberate¶
An unregistered plan is also reported by the local SessionStart plan-status hook, which lists incomplete and unregistered plans as candidate work when a session opens in the repository. The two are not redundant: the hook is a per-session nudge that disappears when the session ends, and the audit is what turns a persistent gap into a tracked issue. Format, ordering and vocabulary are the audit's alone -- the hook only reads the index, it does not police it.
Template¶
No template. templates/shared-blocks/plan-status-vocabulary.md
holds the canonical status vocabulary; copy it verbatim, markers
included, into the repository's PLAN-TEMPLATE.md.
To convert an index to the canonical layout, move the date to the
first column, sort each table oldest first, and move everything that
is not a vocabulary term out of the status column -- into Intent
if it is a one-line summary, into the plan file if it is longer. Add
a row for any plan the index does not list; consult the plan to work
out its real status rather than guessing from the file's existence.
Projects¶
This table is regenerated daily by the consistency audit
workflow from scripts/audit-check.py results; do not edit
it by hand.
Last regenerated: 2026-08-23T06:45:38.740880+00:00
| Project | Status | Issue |
|---|---|---|
| actions | N/A | - |
| agent-python | N/A | - |
| client-python | non-compliant | client-python#365 |
| client-python-k3s | non-compliant | client-python-k3s#32 |
| clingwrap | N/A | - |
| cloudgood | N/A | - |
| development | compliant | - |
| divergulent | non-compliant | divergulent#69 |
| instar | non-compliant | instar#506 |
| kerbside | compliant | - |
| kerbside-patches | N/A | - |
| library-utilities | non-compliant | library-utilities#42 |
| occystrap | non-compliant | occystrap#116 |
| private-ci | N/A | - |
| ryll | compliant | - |
| sfui | non-compliant | sfui#24 |
| shakenfist | compliant | - |
Details for non-compliant projects:
- client-python (Status): docs/plans/index.md is missing, so none of the 1 plan(s) in docs/plans/ are registered
- client-python-k3s (Status): docs/plans/index.md is missing, so none of the 2 plan(s) in docs/plans/ are registered
- divergulent (Status): 1 table(s) not led by Date then Plan columns: line 10 starts "Plan | Phases"
- instar (Status): 1 status cell(s) outside the shared vocabulary (Proposed, Not started, In progress, Blocked, Complete, Abandoned, Superseded): instar amend subcommand ("1.1 (qcow2 v2⇔v3 version transition, ...")
- library-utilities (Status): docs/plans/index.md is missing, so none of the 1 plan(s) in docs/plans/ are registered
- occystrap (Status): index has no plan table (it must list plans in a table led by Date and Plan columns, not as prose or a bullet list); 4 master plan(s) not listed in the index: PLAN-make-the-speed.md, PLAN-post-write-verification.md, PLAN-registry-proxy.md, PLAN-structured-logging.md
- sfui (Status): docs/plans/index.md is missing, so none of the 3 plan(s) in docs/plans/ are registered