feat(lessons): judged when written — a new lesson is offered its rules, and "no rule fits" is an answer (milestone 440 step 2, #4631)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 53s
CI & Build / Python tests (push) Failing after 1m15s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 53s
CI & Build / Python tests (push) Failing after 1m15s
CI & Build / Build & push image (push) Skipped
"Which rule is this lesson an instance of?" now has three recorded answers: a rule named (a confirmed link, #4630), no rule fits (new), or unjudged. - Model + migration 0112: lesson_no_rule (lesson_id PK, CASCADE from the note; why; judged_at). A table rather than a key in notes.data, because that mirror is re-composed from the body on every edit and would erase it. - Service (lesson_rules): set_no_rule rejects any confirmed link with the reason; a confirmation (set_lesson_rules or judge_link) deletes the answer; require_one_answer refuses both answers in one call before any write; judgments_for_lessons + attach_lesson_rules add rule_judgment (and no_rule) to every lesson payload; list_unjudged lists the open ones; rule_candidates searches rules with the lesson's claim + trigger at the explicit-search bar, None when the search could not run. - MCP: create_lesson/update_lesson take no_rule; an unanswered create returns rule_candidates, rule_judgment and a rule_hint; list_lessons(unjudged=true). - REST: the same on POST/PATCH /api/lessons and GET ?unjudged=1; create returns rule_candidates. - Backup v19: a lesson_no_rule section, export (full and per-user) and import. - Guidance: create_lesson docstring, writing-records.md in using-scribe (owner, pinned in test_guidance_ownership), create_rule docstring on linking the lessons a new rule governs. Plugin version minted. - Tests: door units, integration for the three states, the rejection reason, scoping, cascade; backup registries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "scribe",
|
||||
"description": "Scribe for Claude Code: connects the scribe MCP server, adds the hooks that deliver live project state and relevant records at the right moment, ships the shared client-neutral Scribe skills (using-scribe, writing-plans, reporting-back, systematic-debugging, verification, brainstorming, reusing-code, shape-accounting), and syncs your saved Scribe Processes as skills (/scribe:sync).",
|
||||
"version": "2026.10.01.1246",
|
||||
"version": "2026.10.01.1724",
|
||||
"author": {
|
||||
"name": "Bryan Van Deusen"
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@ arrives that names the situation you are actually in; and before filling
|
||||
## Contents
|
||||
- Where a new rule goes — its home, its trigger, what already covers the moment
|
||||
- A lesson grows each time it proves itself
|
||||
- A lesson names the rule it is an instance of
|
||||
- A note that asserts a fact can carry its own check
|
||||
|
||||
## Where a new rule goes
|
||||
@@ -76,6 +77,29 @@ waiting in a situation nobody is in. One claim that has met the same failure
|
||||
four times is worth more than four claims that each met it once, so when a
|
||||
near-duplicate create hands back an existing id, that is the record to grow.
|
||||
|
||||
## A lesson names the rule it is an instance of
|
||||
|
||||
A lesson records one situation; a rule records the binding choice for a class
|
||||
of them. Linking the two is what lets a rule be reached through the situations
|
||||
that keep proving it — moments that resemble why it was written more closely
|
||||
than its own wording does. A lesson never becomes a rule. It points at one.
|
||||
|
||||
The writer is best placed to say which rule, so answer while writing, in
|
||||
`create_lesson` itself or in the `update_lesson` right after it:
|
||||
|
||||
- **`rule_ids=[…]`** — the rule or preference whose situation this is an
|
||||
instance of.
|
||||
- **`no_rule="why"`** — no rule governs it, in a line. That is a full answer,
|
||||
not a gap: lessons that stand alone and keep landing in one situation are
|
||||
what a missing rule looks like, and the reason is what lets the answer be
|
||||
re-judged once a rule exists.
|
||||
|
||||
A lesson created with neither comes back with `rule_candidates`, the rules it
|
||||
most resembles, each with its trigger. Read them against the situation the
|
||||
lesson describes, not its topic — a rule about the same subsystem that governs
|
||||
a different moment is not its rule — and give one of the two answers.
|
||||
`list_lessons(unjudged=true)` gathers the ones still open.
|
||||
|
||||
## A note that asserts a fact can carry its own check
|
||||
|
||||
**A few notes assert a FACT, and those can carry their own check.**
|
||||
|
||||
Reference in New Issue
Block a user