feat(family): the shape ledger judges against family ideas, across languages (milestone 463 step 5, #4991)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 58s
CI & Build / integration (push) Successful in 1m26s
CI & Build / Python tests (push) Successful in 2m9s
CI & Build / Build & push image (push) Successful in 1m27s

- classify_shapes takes idea_id: the shape is judged against the idea's
  reference in its language, or its first.
- A shape classified against a canon idea's reference moves the project's
  adoption row (instance -> adopted, variant -> variant). Withdrawing the
  shapes that gave an answer returns it to unassessed. This runs on
  classify_shapes, the sweep, confirm_proposals and the coverage refresh.
- assess and undo refuse an answer the shapes contradict. A conflict
  resolution re-judges the variant shapes on both sides.
- The proposer's family arm offers a canon idea's reference on a shared
  platform, in any language. It proposes only when the reference is the top
  hit over every readable snippet and scores at least 0.70. The pairs this
  was measured on are recorded beside _FAMILY_FLOOR. The proposer is now v6.
- The matrix cell shows the code that answers it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 13:06:45 -04:00
co-authored by Claude Opus 5.5
parent 233fa3eea9
commit 5f41dbd283
10 changed files with 823 additions and 38 deletions
+2
View File
@@ -126,6 +126,8 @@ export interface AdoptionCell {
/** Answered against a canon version that is not the current one. */
needs_recheck: boolean;
owed_task: { id: number; title: string; status: string } | null;
/** Live shapes in the project classified against one of the idea's references. */
shapes: { path: string; symbol: string; status: "canonical" | "instance" | "variant" }[];
}
export interface MatrixIdea {
@@ -218,6 +218,15 @@ defineExpose({ load });
</router-link>
<span class="fam-muted">({{ selected.owed_task.status.replace("_", " ") }})</span>
</p>
<div v-if="selected.shapes.length" class="fam-detail-shapes">
<p>In this project's code — the shape ledger classifies:</p>
<ul>
<li v-for="s in selected.shapes" :key="`${s.path}::${s.symbol}`">
<code>{{ s.path }} · {{ s.symbol }}</code>
<span class="fam-muted">{{ s.status === "variant" ? "variant" : "instance" }}</span>
</li>
</ul>
</div>
<p v-if="selected.assessed_at" class="fam-muted">
Answered {{ fmtStamp(selected.assessed_at) }}
<template v-if="selected.decided_via">by the {{ selected.decided_via }}</template>
@@ -320,6 +329,9 @@ button.fam-cell:hover { background: var(--fs-surface-hover); }
.fam-detail p { margin: 0.4rem 0 0; font-size: 0.875rem; }
.fam-detail-reason { color: var(--fs-text-primary); }
.fam-detail-recheck { color: var(--fs-text-secondary); }
.fam-detail-shapes ul { margin: 0.25rem 0 0; padding-left: 1.1rem; font-size: 0.85rem; }
.fam-detail-shapes li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.5rem; overflow-wrap: anywhere; }
.fam-detail-shapes code { font-family: var(--fs-font-mono); }
.fam-outcomes { margin-top: 0.75rem; font-size: 0.85rem; color: var(--fs-text-secondary); }
.fam-outcomes summary { cursor: pointer; color: var(--fs-text-secondary); }
.fam-outcomes dl { margin: 0.5rem 0 0; }