feat(ledger): derive readout ranks body-identical groups first; CSS fingerprints are declarations, not selectors (#2872, milestone 294)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Failing after 25s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 57s
CI & Build / Build & push image (push) Successful in 32s

The 2026-08 audit consolidated identical bodies under different names and
files (five auth views' CSS, two Workspace formatDate()s, four modal blocks)
while the derive readout led with name groups (to_dict ×25, main ×5, load ×6)
that were convention or coincidence.

- proposal_summary ranks dup:<sha> groups above name groups, wider file spread
  first, and carries `files`; scoped rows (#2869) are in the readout, since
  that is where view-level copies live.
- extract_definitions fingerprints a CSS rule by its declarations — the row
  identity already carries the selector — so .closed-msg / .error-block /
  .success-msg with one body are one dup group. One-time effect: judged css
  rows whose stored fingerprint predates this may show a recheck on the next
  refresh (the judgment stands; re-confirm).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 15:08:57 -04:00
co-authored by Claude Fable 5
parent 1126bbe84f
commit 57d68c9355
4 changed files with 56 additions and 7 deletions
+8 -1
View File
@@ -185,8 +185,15 @@ def extract_definitions(text: str) -> list[Definition]:
end = j
break
block = lines[i:end]
# A CSS rule's fingerprint is its DECLARATIONS, not its selector
# (#2872): the row's identity already carries the selector, and the
# question the fingerprint answers for derive grouping is "is this the
# same rule under another name?" — .closed-msg / .error-block /
# .success-msg with identical bodies are one dup group, not three
# lonely rows. Sym blocks keep their signature line in the hash.
hashed = block[1:] if kind == "css" and len(block) > 1 else block
out.append(Definition(
kind, name, lines[i].strip()[:_SIGNATURE_CAP], _block_sha(block),
kind, name, lines[i].strip()[:_SIGNATURE_CAP], _block_sha(hashed),
"\n".join(block), i,
))
return out
+17 -6
View File
@@ -1215,25 +1215,36 @@ def proposal_summary(rows: Iterable[CodeShape], *, top: int = 8) -> dict:
proposals await confirmation, and the largest derive-first groups."""
proposed = 0
groups: dict[str, dict] = {}
files: dict[str, set[str]] = {}
for row in rows:
if row.status != "unclassified":
if row.status not in _MECHANICAL_TODO:
continue
if row.proposed_snippet_id is not None:
proposed += 1
elif row.proposal_group:
dup = not row.proposal_group.startswith("name:")
g = groups.setdefault(row.proposal_group, {
"group": row.proposal_group, "kind": row.kind,
"label": (
("." if row.kind == "css" else "") + row.symbol
if row.proposal_group.startswith("name:")
else f"{row.symbol} (identical body)"
f"{row.symbol} (identical body)" if dup
else ("." if row.kind == "css" else "") + row.symbol
),
"size": 0, "paths": [],
"size": 0, "files": 0, "paths": [],
})
g["size"] += 1
files.setdefault(row.proposal_group, set()).add(row.path)
if len(g["paths"]) < 3:
g["paths"].append(row.path)
ranked = sorted(groups.values(), key=lambda g: (-g["size"], g["group"]))
for key, g in groups.items():
g["files"] = len(files[key])
# Body-identical groups first (#2872): the things an audit actually
# consolidated were identical bodies under different names/files; a
# name repeated across modules is usually convention. Within a tier,
# the group spread over more files is the bigger copy.
ranked = sorted(
groups.values(),
key=lambda g: (g["group"].startswith("name:"), -g["files"], -g["size"], g["group"]),
)
return {"proposed": proposed, "derive_groups": ranked[:top]}