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:
@@ -1158,6 +1158,31 @@ scribe_held_query() {
|
||||
# the tests read THIS string rather than a copy of it.
|
||||
SCRIBE_LEDGER_DIRS="scribe-priorart scribe-autoinject"
|
||||
|
||||
# THE WRITTEN-SHAPES LEDGER (milestone 439). Every definition a write names,
|
||||
# appended as `path<TAB>kind<TAB>name`, for the Stop hook to ask about at the
|
||||
# end of the turn (scribe_shape_check.sh). Its own file — one file, one
|
||||
# question (lesson #4226) — under the prior-art directory, so the session
|
||||
# clear above already sweeps it. Read `kind<TAB>name` lines on stdin (the
|
||||
# scribe_defs format). A NEW file adds one `file` line named by its stem: a
|
||||
# component, module or package file is a candidate in its own right, in any
|
||||
# language, without a framework rule saying so.
|
||||
# $1 session id (already made filename-safe) $2 repo-relative path
|
||||
# $3 "new" when the file did not exist before this write
|
||||
scribe_written_append() {
|
||||
local sid="$1" rel="$2" fresh="${3:-}" dir stem
|
||||
if [ -z "$sid" ] || [ -z "$rel" ]; then cat >/dev/null; return 0; fi
|
||||
dir="${TMPDIR:-/tmp}/scribe-priorart"
|
||||
mkdir -p "$dir" 2>/dev/null || true
|
||||
{
|
||||
if [ "$fresh" = "new" ]; then
|
||||
stem=${rel##*/}; stem=${stem%.*}
|
||||
[ -n "$stem" ] && printf '%s\tfile\t%s\n' "$rel" "$stem"
|
||||
fi
|
||||
awk -F'\t' -v p="$rel" 'NF >= 2 && ($1 == "sym" || $1 == "css") && $2 != "" { printf "%s\t%s\t%s\n", p, $1, $2 }'
|
||||
} >> "$dir/${sid}.written.ids" 2>/dev/null || true
|
||||
return 0
|
||||
}
|
||||
|
||||
scribe_clear_session_ledgers() {
|
||||
# SPARES `*.keep.ids`, which are evidence rather than exclusions — see
|
||||
# `scribe_rules_append`. Everything else still goes: the convention is
|
||||
|
||||
Reference in New Issue
Block a user