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
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>
This commit is contained in:
@@ -908,11 +908,13 @@ async def snippet_consumers(user_id: int, note_id: int) -> dict:
|
||||
# semantic arm scored it above the write-path threshold for this
|
||||
# very payload. Either is evidence; the pull alone is not.
|
||||
# Both hold → every shape the hook named at that path, of the snippet's kind,
|
||||
# becomes instance-of-N with classified_by="hook" and the evidence as reason.
|
||||
# carries N as a PROPOSAL (milestone 439). Until then it became instance-of-N
|
||||
# with classified_by="hook" — a verdict nobody read, and the rows written that
|
||||
# way are what `stamps_to_review` still lists.
|
||||
#
|
||||
# A hook row is EVIDENCE, not judgment: it only ever lands on rows nobody has
|
||||
# judged (unclassified) or rows an earlier hook stamped, never on a canonical
|
||||
# row or an agent/audit/import judgment. Re-judge with classify_shapes.
|
||||
# A proposal is EVIDENCE, not judgment: it lands only on rows nobody has
|
||||
# judged, never touches a status, and is what the end-of-turn question shows
|
||||
# the agent as "looks like #N". The agent's classify_shapes is the verdict.
|
||||
|
||||
# "The write path actually pulled it": a working session's reach. The
|
||||
# precision comes from the in-play test above, not from this window.
|
||||
@@ -1354,7 +1356,7 @@ def _stamp_allowed(rank: int, mine: str, canon: str) -> bool:
|
||||
return forms_agree(mine, canon)
|
||||
|
||||
|
||||
async def stamp_write_path_instances(
|
||||
async def suggest_write_path_instances(
|
||||
user_id: int,
|
||||
project_id: int,
|
||||
*,
|
||||
@@ -1365,22 +1367,35 @@ async def stamp_write_path_instances(
|
||||
resembles: dict[int, float] | None = None,
|
||||
repo_key: str = "",
|
||||
) -> list[dict]:
|
||||
"""Land hook evidence as `instance` rows for the shapes being written.
|
||||
"""Offer hook evidence as a PROPOSAL on the shapes being written.
|
||||
|
||||
This used to land the evidence as `instance` rows, classified_by=hook —
|
||||
a permanent classification written with nobody reading it. That is what
|
||||
poisoned two ledgers (132 and 488 rows below today's floor, #4608), and
|
||||
what milestone 439 retires: the agent that wrote the code says what it is,
|
||||
at the end of the turn, and this evidence is what it is shown when it
|
||||
does. So the row keeps its status; the candidate canon goes into the
|
||||
proposal fields (`proposed_snippet_id`, `proposal_basis` "reference" for a
|
||||
by-name hit or "semantic" for a resemblance, `proposal_score`), where the
|
||||
end-of-turn question reads it as "looks like #N". A judged row is left
|
||||
alone entirely.
|
||||
|
||||
``shapes`` is the hook's (kind, name) list for ``path``; ``pulled`` is
|
||||
recent_pulls(); ``resembles`` maps snippet ids the semantic arm scored
|
||||
for this payload to their score. Returns the rows stamped, each
|
||||
for this payload to their score. Returns the suggestions, each
|
||||
{path, symbol, kind, snippet_id, reason} — empty in the common case.
|
||||
|
||||
A shape the ledger has no live row for yet (it is being written right
|
||||
now) gets a PROVISIONAL row under ``repo_key`` — first/last-seen empty —
|
||||
so the stamp is not lost to the next sync, which either confirms the
|
||||
shape (sets its seen marker) or stamps it vanished. No repo key → only
|
||||
existing rows are stamped.
|
||||
now) gets a PROVISIONAL unclassified row under ``repo_key`` — first/
|
||||
last-seen empty — so the suggestion survives to the end of the turn and
|
||||
the next sync either confirms the shape or stamps it vanished. No repo
|
||||
key → only existing rows carry a suggestion.
|
||||
|
||||
Every pulled canon the payload NAMES is still recorded as a `uses` edge:
|
||||
that is a fact about the code, not a verdict about what it is.
|
||||
|
||||
When more than one pulled snippet is in play for a shape, a by-name
|
||||
reference beats resemblance and the most recent pull breaks ties: a row
|
||||
holds one canon (the known model limit logged on #2790).
|
||||
reference beats resemblance and the most recent pull breaks ties.
|
||||
"""
|
||||
from scribe.services import access
|
||||
from scribe.services import snippets as snippets_svc
|
||||
@@ -1433,8 +1448,7 @@ async def stamp_write_path_instances(
|
||||
for bucket in in_play.values():
|
||||
bucket.sort(key=lambda t: (t[0], t[1]), reverse=True)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
stamped: list[dict] = []
|
||||
suggested: list[dict] = []
|
||||
async with async_session() as session:
|
||||
rows = (
|
||||
await session.execute(
|
||||
@@ -1486,9 +1500,12 @@ async def stamp_write_path_instances(
|
||||
by_key[(name, kind)] = row
|
||||
elif not (row.status in _MECHANICAL_TODO or row.classified_by == "hook"):
|
||||
continue # a judgment — or the canon itself — stands
|
||||
await _judge(session, row, status="instance", snippet_id=sid, by="hook",
|
||||
reason=why, at=now)
|
||||
stamped.append({
|
||||
# A proposal, never a status: the writer decides (milestone 439).
|
||||
row.proposed_snippet_id = sid
|
||||
row.proposal_basis = "reference" if _rank >= 2 else "semantic"
|
||||
row.proposal_score = resembles.get(sid) if _rank < 2 else 1.0
|
||||
row.proposal_group = None
|
||||
suggested.append({
|
||||
"path": path, "symbol": name, "kind": kind,
|
||||
"snippet_id": sid, "reason": why,
|
||||
})
|
||||
@@ -1504,9 +1521,9 @@ async def stamp_write_path_instances(
|
||||
[t[2] for t in bucket if t[0] == 2],
|
||||
basis="hook", evidence="write path: pulled the snippet, payload names its symbol",
|
||||
)
|
||||
if stamped:
|
||||
if suggested:
|
||||
await session.commit()
|
||||
return stamped
|
||||
return suggested
|
||||
|
||||
|
||||
# --- the mechanical proposer (#2792): the machine proposes, judgment classifies
|
||||
@@ -2210,8 +2227,11 @@ async def confirm_proposals(
|
||||
|
||||
# A canon dominates a directory+kind when at least this many siblings are
|
||||
# judged (canonical/instance) and this share of them answer to one snippet.
|
||||
# How much a payload must resemble a canon before the hook may assert, with
|
||||
# nobody watching, that a shape IS an instance of it.
|
||||
# How much a payload must resemble a canon before the hook SUGGESTS it as the
|
||||
# shape's canon — and, for the rows stamped before milestone 439, the bar below
|
||||
# which a stored stamp is weak (`is_weak_stamp`). Until milestone 439 this was
|
||||
# the bar for the hook to ASSERT, unattended, that a shape IS an instance; the
|
||||
# hook no longer asserts anything, and the history below is why.
|
||||
#
|
||||
# WHY A FLOOR AT ALL. There was none: any score the semantic arm produced
|
||||
# counted, so 0.69 asserted as confidently as 0.95, and the score went into
|
||||
@@ -2364,15 +2384,15 @@ async def canon_density(
|
||||
|
||||
|
||||
async def write_time_divergence(
|
||||
project_id: int, path: str, shapes: list[tuple[str, str]], stamped: list[dict],
|
||||
project_id: int, path: str, shapes: list[tuple[str, str]], suggested: list[dict],
|
||||
code: str = "",
|
||||
) -> list[dict]:
|
||||
"""The in-band check for the shapes the hook named at ``path``: for each
|
||||
kind whose directory has a dominant canon, the named shapes that are
|
||||
not (already or just now) that canon's instance/canonical — new or
|
||||
not that canon's instance/canonical (judged, or just suggested as it) — new or
|
||||
unclassified rows only; a judged shape is not re-litigated at every
|
||||
edit. Returns [{symbol, kind, canon_snippet_id, instances, judged}]."""
|
||||
just_stamped = {(s["symbol"], s["kind"]): s["snippet_id"] for s in stamped}
|
||||
just_stamped = {(s["symbol"], s["kind"]): s["snippet_id"] for s in suggested}
|
||||
out: list[dict] = []
|
||||
if not shapes:
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user