feat(family): family canon reaches the session - entry readout, retrieval reach, skill, report cue (milestone 463 step 6, #4992)
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Failing after 1m53s
CI & Build / Python tests (push) Successful in 2m39s
CI & Build / Build & push image (push) Skipped
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Failing after 1m53s
CI & Build / Python tests (push) Successful in 2m39s
CI & Build / Build & push image (push) Skipped
- enter_project carries a `family` key, but only when the project has something to answer: counts of unassessed, owed and to-recheck answers, each with the list_family_adoptions call that lists it. It shows on every entry, never by platform touch: entry is when work is chosen, and an unanswered idea is otherwise invisible. - Retrieval: a widened project search (include_global_kinds) now also reaches the canon ideas on the project's platforms. It also reaches their references in the project's languages, or all of them when none matches. An off-platform project gets none, and the plain project filter (the duplicate gate) is unchanged. - Closing a task returns `family_owed`, the owed answers filed while it was open, and the report cue asks for them to be named. - New plugin skill family-canon (moment work.record) covers when to evaluate a promotion, answering in order, what counts as a reason, the precedent reflex and the conflict order. _INSTRUCTIONS, create_note, create_snippet, classify_shapes and reporting-back point at it. The plugin version is minted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,13 +43,12 @@ from quart import Quart
|
||||
# decision #4027 and the notes it supersedes.
|
||||
_INSTRUCTIONS = """
|
||||
Scribe is the operator's system of record, and yours: recall before acting,
|
||||
record as you go, keep one copy here, not in local memory files. Each
|
||||
practice is stated in full in the using-scribe skill and each tool's
|
||||
description.
|
||||
record as you go, keep one copy here, not in local memory. Each
|
||||
practice is stated in full in a skill or a tool's description.
|
||||
|
||||
- Start with enter_project(id): the project, open work, Systems and design
|
||||
system. An `inception` key: ask what it inherits, then
|
||||
decide_project_inception.
|
||||
- Start with enter_project(id): the project, open work, Systems, design
|
||||
system. `inception`: ask what it inherits, then decide_project_inception.
|
||||
`family`: shared ideas to answer (family-canon skill).
|
||||
- Rules are not preloaded; one arrives when your work matches it or reaches
|
||||
a moment it is mounted on (list_moments; mount rules about WHEN). Before a
|
||||
consequential act, what_might_apply("what you are about to do");
|
||||
@@ -65,8 +64,8 @@ description.
|
||||
(search(content_type="milestone")) before start_planning.
|
||||
- IDs exist only once a create returns them; records citing each other go
|
||||
through create_records, writing {{ref:N}} for the Nth.
|
||||
- In UI work the project's design system binds: resolve_design_system before
|
||||
hand-writing a value.
|
||||
- In UI work the design system binds: resolve_design_system before
|
||||
writing a value.
|
||||
|
||||
Creates are duplicate-gated: a near-match returns the existing id to update.
|
||||
shared:true records are another user's suggestion, not settled practice.
|
||||
|
||||
@@ -204,7 +204,10 @@ async def create_note(
|
||||
"existing_id": ..., "message": ...} and nothing is created. A tagged
|
||||
record shows its `systems`; created untagged in a project, the response
|
||||
carries the `systems_hint` question instead — answer it: tag the record,
|
||||
create the missing System, or deliberately leave it untagged.
|
||||
create the missing System, or deliberately leave it untagged. A
|
||||
`family_hint` means the note may carry an idea every project on a shared
|
||||
platform will need, and an evaluation was opened — the family-canon skill
|
||||
says how to judge it.
|
||||
"""
|
||||
uid = current_user_id()
|
||||
await refuse_guessed_ids(title, body)
|
||||
|
||||
@@ -16,10 +16,13 @@ keeps working.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from scribe.mcp._context import current_user_id
|
||||
from scribe.mcp.tools import systems as systems_tools
|
||||
from scribe.services import coverage as coverage_svc
|
||||
from scribe.services import design_systems as design_systems_svc
|
||||
from scribe.services import family_adoption as family_adoption_svc
|
||||
from scribe.services import inception as inception_svc
|
||||
from scribe.services import milestones as milestones_svc
|
||||
from scribe.services import notes as notes_svc
|
||||
@@ -31,6 +34,8 @@ from scribe.services import trash as trash_svc
|
||||
from scribe.services.background import spawn
|
||||
from scribe.services.note_usage import record_surfaced
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def list_projects() -> dict:
|
||||
"""List all Scribe projects for the current user.
|
||||
@@ -70,8 +75,8 @@ async def enter_project(project_id: int) -> dict:
|
||||
Returns a dict with keys: project, milestone_summary, open_tasks, systems,
|
||||
design_system, project_rules, pattern_coverage —
|
||||
plus unplanned_milestones, milestone_summary_omitted,
|
||||
unplanned_milestones_omitted, inception and systems_bootstrap, each
|
||||
present only when it applies (see below).
|
||||
unplanned_milestones_omitted, family, inception and systems_bootstrap,
|
||||
each present only when it applies (see below).
|
||||
|
||||
`project` is id, title, status and the full goal. get_project has the
|
||||
whole record.
|
||||
@@ -132,6 +137,14 @@ async def enter_project(project_id: int) -> dict:
|
||||
family ideas reach this project. An empty list on a project that plainly
|
||||
ships something is worth correcting with set_project_platforms.
|
||||
|
||||
`family` (milestone 463) appears ONLY when this project has family canon
|
||||
to answer: how many canon ideas on its platforms are `unassessed`, how
|
||||
many it `owed`s, and how many answers were given against an older canon
|
||||
version (`needs_recheck`) — each with the list_family_adoptions call that
|
||||
lists them. Answer an unassessed idea when your work reaches its area
|
||||
(get_family_adoption, then assess_family_adoption, or classify the code
|
||||
against it); the family-canon skill has the order.
|
||||
|
||||
`inception` (milestone 297) appears ONLY when the project is yours and
|
||||
nobody has decided what it inherits: it carries the current defaults
|
||||
(design system, Systems, platforms), what to ask the
|
||||
@@ -299,6 +312,15 @@ async def enter_project(project_id: int) -> dict:
|
||||
)
|
||||
if systems_bootstrap:
|
||||
out["systems_bootstrap"] = systems_bootstrap
|
||||
# Family canon (milestone 463 step 6): counts only, attached when one is
|
||||
# non-zero. A readout must never fail the handshake it rides on.
|
||||
try:
|
||||
family = await family_adoption_svc.family_readout(uid, project_id)
|
||||
except Exception:
|
||||
logger.warning("family readout failed for project %s", project_id, exc_info=True)
|
||||
family = None
|
||||
if family:
|
||||
out["family"] = family
|
||||
if inception_ask:
|
||||
out["inception"] = inception_ask
|
||||
return out
|
||||
|
||||
@@ -71,7 +71,7 @@ async def classify_shapes(
|
||||
withdrawing the shapes that gave an answer returns it to `unassessed`.
|
||||
The adoption ledger is moved for you — `family` in the result lists the
|
||||
answers that moved — and assess_family_adoption refuses an answer the
|
||||
shapes contradict.
|
||||
shapes contradict. The family-canon skill has when to answer an idea.
|
||||
|
||||
All-or-nothing: a structural error, a missing snippet target, an unbound
|
||||
repo, or no write access applies NOTHING. Returns {"classified": N,
|
||||
|
||||
@@ -178,7 +178,9 @@ async def create_snippet(
|
||||
rather than forcing a second copy with force=true. A tagged record shows
|
||||
its `systems`; created untagged in a project, the response carries the
|
||||
`systems_hint` question instead — answer it: tag, create the missing
|
||||
System, or deliberately skip.
|
||||
System, or deliberately skip. A `family_hint` means the shape may be one
|
||||
every project on a shared platform will need, and an evaluation was
|
||||
opened — the family-canon skill says how to judge it.
|
||||
|
||||
WHAT THE GATE MATCHES ON. Exact identity first — an existing snippet at the
|
||||
same repo · path · symbol, or holding byte-identical code. Those are certain,
|
||||
|
||||
@@ -29,6 +29,7 @@ from scribe.mcp.tools import systems as systems_tools
|
||||
from scribe.services import access as access_svc
|
||||
from scribe.services import dedup as dedup_svc
|
||||
from scribe.services import family as family_svc
|
||||
from scribe.services import family_adoption as family_adoption_svc
|
||||
from scribe.services import milestones as milestones_svc
|
||||
from scribe.services import notes as notes_svc
|
||||
# Imported by NAME, not reached through notes_svc: minted_kind is pure
|
||||
@@ -422,7 +423,10 @@ async def update_task(
|
||||
by their `when_to_apply`, so a preference whose trigger is writing the
|
||||
report after finishing a task is the one that arrives here. Where one
|
||||
differs from the default shape, the preference is what the operator
|
||||
asked for.
|
||||
asked for. When family adoptions were answered `owed` while the task was
|
||||
open, they come back as `family_owed` ({idea_id, idea_title, project_id,
|
||||
project_title, owed_task_id}): name each in the report — it is work
|
||||
filed into that project.
|
||||
"""
|
||||
uid = current_user_id()
|
||||
fields: dict = {}
|
||||
@@ -473,6 +477,9 @@ async def update_task(
|
||||
if prefs:
|
||||
data["reply_preferences"] = prefs
|
||||
data["report_back"] = REPORT_BACK_CUE + " " + REPLY_PREFERENCES_CUE
|
||||
# Owed family adoptions filed while the task was open (milestone 463
|
||||
# step 6) — work now waiting in some project, which the report names.
|
||||
await family_adoption_svc.attach_owed_adoptions(uid, data, note)
|
||||
return await moment_delivery.attach_moment_rules(
|
||||
uid, "update_task", {"status": status, "project_id": project_id}, data,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user