Shapes are judged when they are written (milestone 439 steps 1–6) + #4608 fixes #188
Merged
bvandeusen
merged 6 commits from 2026-10-01 08:55:10 -04:00
dev into main
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
582a5a4f48 |
feat(shapes): the practice is written where it is read, and the coverage line measures the slip (milestone 439 step 6)
CI & Build / integration (push) Successful in 47s
CI & Build / Python tests (push) Successful in 1m39s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / Build & push image (push) Successful in 29s
- reusing-code: "Before the turn ends — say what you built" — the four verdicts, the one classify_shapes(repo=…) call, and the component file as a shape. Description names the end-of-turn moment. - shape-accounting: the writer judges; audits are the check that it held. The write path SUGGESTS (no more hook instances); component file rows and whole-file canon described; scoped covers Svelte too. - _INSTRUCTIONS reuse line: "before the turn ends, say what you built (create_snippet the reusable, classify_shapes the rest)" — 1570/1600. - Coverage line: "written-shape check (7d): N turns checked, M asked, K left unjudged", from the Stop hook's recorded outcomes; silent until the question has been put. - test_guidance_ownership pins the new topic on reusing-code. - prior-art hook header no longer says it stamps instance rows. Plugin version minted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8b1567cf2c |
feat(shapes): a component file is a candidate shape in its own right (milestone 439 step 5)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 54s
CI & Build / Build & push image (push) Canceled after 0s
CI & Build / Python tests (push) Canceled after 1m42s
A single-file component defines `.card`, `.title` and a `Props`, never anything named after itself — so the ledger could not hold "StatusChip is canon" and could not say a new card was built where one already existed. - coverage.is_file_unit: a file that RENDERS (its markup names classes, or it opens a <script>/<template>/<style> block) and defines nothing named after its stem gets one `file` row. Structural, not a framework list: Svelte and Vue components qualify, a TSX component already has its function's row, a module is accounted for by its definitions. Emitting every file would have put every module of every project in the todo at once. - No body fingerprint on file rows, so an edit never re-asks a judgment. - `file` is its own form and family; derive grouping skips it (`index`, `+page` repeat by convention). Divergence buckets it on its own, so a new component where a component canon dominates is a fair question. - mark_canonicals: a snippet recorded at a path with no symbol makes that file row canonical; it still covers no definition inside. - The write hooks apply the same test before noting a new file for the end-of-turn question. Plugin version minted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4cf1c6f042 |
feat(shapes): the write-path hook suggests and no longer stamps (milestone 439 step 4)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 54s
CI & Build / Python tests (push) Successful in 1m49s
CI & Build / Build & push image (push) Successful in 27s
The hook used to land its evidence as `instance` rows, classified_by=hook — a permanent verdict nobody read, and the source of the weak stamps that poisoned two ledgers (#4608). Now the agent that wrote the code judges it at the end of the turn, and the hook's evidence is what it is shown. - shape_ledger.suggest_write_path_instances (was stamp_write_path_instances): same evidence and form gate, but it writes a PROPOSAL — proposed_snippet_id, basis "reference" (named) or "semantic" (resembles), score — and never a status. A judged row is left alone; a new shape gets an unclassified provisional row so the suggestion reaches the end-of-turn question as "looks like #N". By-name uses edges stay: a fact, not a verdict. - The prior-art line says "looks like #N … when you judge this turn's shapes, say whether it is", and the result key is `suggested`. - write_time_divergence takes `suggested`; _RESEMBLE_MIN re-documented as the suggestion bar and the weak-stamp line. - reusing-code skill no longer says the pull stamps an instance. - Tests moved to the new contract, plus a guard that nothing the hook does writes classified_by="hook". Plugin version minted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f1fbdf746a |
feat(shapes): the agent judges what it wrote, at the end of the turn (milestone 439 steps 1-3)
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 52s
CI & Build / Python tests (push) Successful in 1m38s
CI & Build / Build & push image (push) Successful in 33s
Recording used to be decided by machinery — the only "record it" prompt fired when a same-named copy already existed (#2664), so a first instance of a reusable piece was never asked about, and judgment arrived only through audits. Now the question is asked where the knowledge is: the end of the turn that wrote the code, of the agent that wrote it. - Write hooks keep `<sid>.written.ids` (path, kind, name) for every definition a write names; a new file adds a `file` line for its stem — a candidate in any language without a framework rule (scribe_written_append). - Stop hook scribe_shape_check.sh sends the ledger to GET /api/plugin/shape-check and blocks once, in the server's words, when anything is unjudged. Same discipline as the report check: never twice, never without a recorded check, another hook's loop left alone; the ledger is kept when the instance cannot be reached. - shape_ledger.unjudged_shapes: no row, unclassified, scoped and hook stamps are unjudged; an agent/audit/import verdict is not. A snippet recorded at the shape answers for it until the refresh stamps it canonical. - services/shape_check owns the reason text and records every outcome in app_logs (passed / blocked / judged_after_block / left_after_block). - classify_shapes(repo=…) judges a shape the ledger has not synced yet via a provisional row under a bound repo; the sync confirms it, or vanishes and revives it with the verdict intact. An unbound repo is refused. Plugin version minted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb5cc6d3a7 |
fix(shapes): weak stamps elect no canon; the arrival line names the review; Svelte scopes by default (#4608)
CI & Build / Python lint (push) Successful in 8s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m3s
CI & Build / Python tests (push) Successful in 1m44s
CI & Build / Build & push image (push) Successful in 1m5s
Librarian and Stash had 132 and 488 write-path stamps written at 0.68-0.72, before the 0.80 floor (#4204). Nothing re-judged them, and dominant_canon counted them, so a YAML CI snippet (#3410) "dominated" Librarian's web directory and every write there was told it diverged from it — 1408 flags on one project, 902 on the other, all skimmed past. - is_weak_stamp: one predicate for "hook-stamped below today's floor". dominant_canon and canon_form skip such rows; stamps_to_review lists them by the same predicate. No stored row changes — they stay for judgment. - flag_divergence withdraws a standing flag whose canon no longer dominates its directory. A flag is a mechanical prompt, not a judgment. - The coverage line ends "N weak stamps · M incoherent canons to judge — stamps_to_review" when either is nonzero, so a project's own session sees the queue on arrival. The shape-accounting skill says what to do with it. - scoped_definitions handles .svelte: every <style> is component-scoped unless <style global> or :global(...); instance-script syms are scoped, module-script ones stay ordinary. Plugin version minted for the skill change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3270fe90c1 |
refactor(settings): one bounded_float for every numeric bar read from settings
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / integration (push) Successful in 52s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 32s
The shape ledger's divergence readout flagged _gate_setting (#4385). Reading it turned up a family with no canon: floor_for, get_duplicate_threshold, get_plan_match_threshold and _gate_setting each parsed a stored string, fell back to the default (never 0) and clamped into [lo, 1]. - services/settings.bounded_float(raw, default, lo=0, hi=1) is the pure parse, fallback and clamp. Each caller keeps its own get_setting read, so tests patching get_setting per module still take effect, and _gate_setting still fails open on an unreadable setting. - SettingsView.saveKbInject: eleven inline Math.min/Math.max clamps and the local gateAt become one asBar(v, d, lo = 0), mirroring the server. No behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |