feat(coverage): the line names standing work with 0 unclassified + derive_new, copies that joined a family since the previous refresh (#2899, milestone 299 step 1)
CI & Build / TypeScript typecheck (push) Successful in 40s
CI & Build / Python lint (push) Successful in 6s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 33s
CI & Build / Python tests (push) Successful in 1m7s
CI & Build / Build & push image (push) Successful in 24s

Since the scoped bucket (#2869) the ledger reads 100% accounted while 439
derive rows stand; the standing block was gated on unclassified > 0 and so
went silent. Build it whatever the todo count ("; standing: ..."), and add
derive_new — derive-grouped rows first seen after the previous refresh
stamp — so entering a project names the drift ("+2 new copies since last
refresh: .error-msg in InceptionCard.vue") instead of waiting for an audit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 13:27:29 -04:00
co-authored by Claude Fable 5
parent c0caf7d23a
commit bb242ca566
6 changed files with 180 additions and 21 deletions
+37
View File
@@ -276,6 +276,8 @@ async def test_coverage_measures_the_tree_exactly_and_caches(seeded):
assert coverage["largest_gaps"] == [
{"dir": "src", "unclassified": 2, "total": 3}
]
# #2899: a first computation has no previous stamp — nothing is "new".
assert coverage["derive_new"] == {"count": 0, "examples": []}
# The walk fed the LEDGER (#2788): every extracted shape has a row, the
# snippet reference locations are mechanically stamped canonical WITH
@@ -512,6 +514,41 @@ def test_coverage_line_names_the_proposers_standing():
assert "top canon #2844 ×78" in line and "top copy closed-msg (identical body) ×3 files" in line
def test_coverage_line_shows_standing_work_even_with_nothing_unclassified():
"""#2899: since the scoped bucket a ledger can be fully accounted and
still carry derive groups / proposals / divergence — the line names
them as `standing:` instead of hiding them behind the todo count, and
names the drift since the previous refresh first-copy-first."""
from scribe.services.coverage import coverage_line
base = {
"total": 4693, "accounted": 4693, "unclassified": 0,
"counts": {"canonical": 37, "instance": 977, "variant": 73, "exempt": 1797, "scoped": 1809},
"computed_at": "2026-08-22T00:00:00+00:00", "largest_gaps": [],
}
quiet = coverage_line(base)
assert "unclassified" not in quiet and "standing" not in quiet
line = coverage_line({
**base,
"derive_groups": [{"group": "dup:abc", "label": "log-empty (identical body)", "files": 4}],
"derive_new": {"count": 2, "examples": [
{"label": ".error-msg", "path": "frontend/src/components/InceptionCard.vue", "group": "dup:9f0"},
{"label": ".error-msg", "path": "frontend/src/components/Other.vue", "group": "dup:9f0"},
]},
"divergent": 1,
})
assert "; standing: 1 derive group, +2 new copies since last refresh: .error-msg in " \
"frontend/src/components/InceptionCard.vue, 1 DIVERGENT, top copy log-empty (identical body) ×4 files" in line
assert "unclassified" not in line
# One copy reads singular; with a todo the block keeps its old place.
one = coverage_line({**base, "derive_new": {"count": 1, "examples": []}})
assert one.endswith("; standing: +1 new copy since last refresh")
todo = coverage_line({**base, "unclassified": 3, "accounted": 4690, "proposed": 2,
"derive_new": {"count": 1, "examples": [{"label": "x", "path": "a.py"}]},
"largest_gaps": [{"dir": "src", "unclassified": 3, "total": 9}]})
assert "; 3 unclassified (2 proposed, +1 new copy since last refresh: x in a.py), largest: src" in todo
def test_coverage_line_names_divergence_and_recheck():
from scribe.services.coverage import coverage_line