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
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>
This commit is contained in:
@@ -4,7 +4,8 @@ The accounting model (note 2786): the snippet library records CANON (small);
|
||||
the ledger accounts for EVERY extracted shape (total). These tools are how
|
||||
agents move shapes out of `unclassified` — the todo state — and how they read
|
||||
what still needs judgment. The ledger rows themselves are fed by the coverage
|
||||
refresh; these tools only ever judge what the sync has seen.
|
||||
refresh; a judgment given with `repo` may also land on a shape written this
|
||||
turn that the sync has not seen yet (milestone 439).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -14,7 +15,7 @@ from scribe.services import shape_ledger as shape_ledger_svc
|
||||
|
||||
|
||||
async def classify_shapes(
|
||||
project_id: int, classifications: list[dict], via: str = "agent"
|
||||
project_id: int, classifications: list[dict], via: str = "agent", repo: str = ""
|
||||
) -> dict:
|
||||
"""Record judgments for a project's code shapes — in batch, as rows.
|
||||
|
||||
@@ -52,15 +53,22 @@ async def classify_shapes(
|
||||
and get_snippet's `uses` read them.
|
||||
via: Who is judging — "agent" (default), "audit" (a sweep), or
|
||||
"import" (carrying maps recorded elsewhere).
|
||||
repo: The repo the shapes live in (its remote URL or bound key), for
|
||||
judging what you wrote THIS turn — shapes the ledger has not
|
||||
synced yet. With it, a shape no row matches is recorded as a
|
||||
provisional row under that repo and judged; the next sync
|
||||
confirms it. Must be bound to the project. Omit it to judge only
|
||||
synced rows.
|
||||
|
||||
All-or-nothing: a structural error, a missing snippet target, or no write
|
||||
access applies NOTHING. Returns {"classified": N, "unmatched": [...]} —
|
||||
unmatched names shapes no live ledger row matches (the tree may have
|
||||
moved since you listed; re-run the project's coverage refresh to re-sync).
|
||||
All-or-nothing: a structural error, a missing snippet target, an unbound
|
||||
repo, or no write access applies NOTHING. Returns {"classified": N,
|
||||
"unmatched": [...], "provisional": N?} — unmatched names shapes no live
|
||||
ledger row matches (the tree may have moved since you listed; pass `repo`
|
||||
for a shape you just wrote, or re-run the project's coverage refresh).
|
||||
"""
|
||||
uid = current_user_id()
|
||||
return await shape_ledger_svc.classify_shapes(
|
||||
uid, project_id, classifications, via=via
|
||||
uid, project_id, classifications, via=via, repo=repo
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user