The UI Refresh button must not be the only seed path (operator directive, hit live: the P7 backfill stalled waiting for a click). Three parts: - enter_project fire-and-forgets refresh_if_stale on the project OWNER — absent or day-old readouts recompute in the background (same spawn the webhook path uses), the enter stays fast, forge-less owners exit quietly (rule #115 baseline), and an in-flight guard keeps concurrent enters from fetching the same tarball N times. - refresh_pattern_coverage(project_id): the synchronous agent-facing form — write-gated, owner-keyring resolution, and ValueError messages that name the fix (add a connection / bind_repo) instead of measuring nothing silently. - plugin 0.1.33 ships the shape-accounting skill: the five statuses, the seed/todo/judge loop, and the derive-first rule, triggered by the coverage line or any proved code-to-canon relationship. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2.9 KiB
name, description
| name | description |
|---|---|
| shape-accounting | Use when a project's shape accounting needs attention — the pattern_coverage line from enter_project shows unclassified shapes or is missing on a forge-served project, the operator asks about coverage/accounting/canon, or you just proved a code-to-canon relationship (an audit enumerated call sites, a consolidation repointed consumers, a verify pass confirmed a helper's users). Triggers on "coverage", "accounted", "unclassified", "classify shapes", "what uses this", or finishing any consolidation. |
Shape accounting — every shape classified against canon
The snippet library records canon (small); the shape ledger accounts for every extracted definition in a project's bound repos (total). Each ledger row carries a status:
canonical— IS a snippet's reference (the coverage sync stamps these mechanically; you rarely set it).instanceof snippet N — conforms to recorded canon. Canon in another project counts (a family-level button shape fully accounts for a local use).variantof snippet N — a deliberate, named departure. Reason required — the why IS the record.exempt— judged genuinely one-off. Reason required. A recorded judgment, not silence — it stops the next pass re-litigating it.unclassified— nobody has judged it yet. This is the todo list.
The loop
- Seed / refresh — the ledger fills from coverage computation. Entering a
project triggers a background seed automatically; when you need it current
now (before a classification batch, or when the line is missing on a
forge-served project), call
refresh_pattern_coverage(project_id)— it returns the fresh accounting line. Takes seconds; it moves repo archives. - Read the todo —
list_shapes(project_id, status="unclassified"), optionally scoped bypathto the directories the coverage line names as largest.snippet_id=Nreads a consumer map. - Judge in batches —
classify_shapes(project_id, [{path, symbol, status, snippet_id?, reason?}]). All-or-nothing: a bad item applies nothing. Rows, never prose — a consumer list in a note or verification detail cannot be sorted, queried, or diffed.
The derive-first rule
N same-shaped occurrences matching no recorded canon is never N loose
classifications — it is a consolidation candidate: derive one reference from
the dominant form, create_snippet it, migrate the outliers, then classify
the rest as instances. Canon is determined from the code; consistency comes
from the derivation, not from asking permission.
What this buys
Divergence becomes mechanical: when button B appears where button A is canon,
the ledger says unintended divergence or justified variant with its
reason — nobody re-derives the history. get_snippet shows each snippet's
instances and variants, so "what uses this?" is answered from rows before
any contract change lands on its consumers.