feat(ledger): coverage self-seeds — enter_project background refresh + refresh_pattern_coverage tool + shape-accounting skill (#2802, milestone 294)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 23s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Failing after 33s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 23s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Failing after 33s
CI & Build / Build & push image (push) Skipped
The UI Refresh button must not be the only seed path (operator directive, hit live: the P7 backfill stalled waiting for a click). Three parts: - enter_project fire-and-forgets refresh_if_stale on the project OWNER — absent or day-old readouts recompute in the background (same spawn the webhook path uses), the enter stays fast, forge-less owners exit quietly (rule #115 baseline), and an in-flight guard keeps concurrent enters from fetching the same tarball N times. - refresh_pattern_coverage(project_id): the synchronous agent-facing form — write-gated, owner-keyring resolution, and ValueError messages that name the fix (add a connection / bind_repo) instead of measuring nothing silently. - plugin 0.1.33 ships the shape-accounting skill: the five statuses, the seed/todo/judge loop, and the derive-first rule, triggered by the coverage line or any proved code-to-canon relationship. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ refresh; these tools only ever judge what the sync has seen.
|
||||
from __future__ import annotations
|
||||
|
||||
from scribe.mcp._context import current_user_id
|
||||
from scribe.services import coverage as coverage_svc
|
||||
from scribe.services import shape_ledger as shape_ledger_svc
|
||||
|
||||
|
||||
@@ -90,6 +91,34 @@ async def list_shapes(
|
||||
return {"shapes": [r.to_dict() for r in rows], "total": total}
|
||||
|
||||
|
||||
async def refresh_pattern_coverage(project_id: int) -> dict:
|
||||
"""Seed or refresh the project's shape ledger NOW, and return the readout.
|
||||
|
||||
The synchronous form of the arrival-moment background seed (#2802):
|
||||
downloads the bound repos through the OWNER's forge connections, upserts
|
||||
every extracted shape into the ledger (new shapes arrive `unclassified`),
|
||||
re-stamps snippet reference locations as canonical, and recomputes the
|
||||
accounting. Reach for it when the ledger must be current before you act —
|
||||
a classification batch about to run, a coverage question asked directly —
|
||||
rather than waiting on the background seed an enter_project triggers.
|
||||
|
||||
Takes seconds, not milliseconds (it moves repo archives). Requires write
|
||||
access to the project. Errors name the fix: no forge connection → the
|
||||
owner adds one (Settings → Integrations → Git Forges); no served repo →
|
||||
bind_repo on a host a connection serves.
|
||||
|
||||
Returns the accounting payload — total, accounted, counts by status,
|
||||
unclassified, repos, largest_gaps — plus `pattern_coverage`, the same
|
||||
one-line summary enter_project carries.
|
||||
"""
|
||||
uid = current_user_id()
|
||||
coverage = await coverage_svc.refresh_for_caller(uid, project_id)
|
||||
return {
|
||||
"pattern_coverage": coverage_svc.coverage_line(coverage),
|
||||
**coverage,
|
||||
}
|
||||
|
||||
|
||||
def register(mcp) -> None:
|
||||
for fn in (classify_shapes, list_shapes):
|
||||
for fn in (classify_shapes, list_shapes, refresh_pattern_coverage):
|
||||
mcp.tool(name=fn.__name__)(fn)
|
||||
|
||||
Reference in New Issue
Block a user