Skip to content

Lessons: the agents' own are the supervisor's to keep; only one that changes what the owner set reaches the Inbox, in plain words - #222

Merged
hhff merged 5 commits into
mainfrom
lessons-agents-keep
Nov 14, 2026
Merged

hhff merged 5 commits into
mainfrom
lessons-agents-keep

Conversation

@hhff

@hhff hhff commented Nov 14, 2026 •

Copy link
Copy Markdown
Member

What

  • Docs (process/supervisor.md §4, governance/constitution.md, process/operator.md): a lesson about how the agents work is the supervisor's to accept itself once it cites plain evidence. That covers using the kit, the process, the tools, the workers' habits and the box. Only a lesson that would change something the owner set goes to the owner: the product's direction, a goal, a rule they gave, or an owner-only class. It is sent with a plain line that says what would change and why the owner should care. The owner can still retire any lesson. --kit lessons are also the operator's to harvest upstream. Accepting a lesson grants nothing.
  • Kit: knowledge add|set … --for-owner --plain "<words>" (schema: knowledge.for_owner (const true) and knowledge.plain, both supervisor-only).
    • The Inbox, the hub badge (hello), the tab title and the Loop count now include only for_owner candidates.
    • The supervisor's own candidates are listed in orient, along with the commands to accept, retire or send them.
    • --plain is refused if it contains backticks, --flags, kit words (devteam.mjs etc.), kit ids, file names, or hyphenated command, class or ticket names. It reuses ask's KIT_WORDS, KIT_ID and UNSAFE_TEXT and the COMMANDS table.
    • Once a lesson is sent, the supervisor can't accept it, reword it or re-scope it. It can only retire it, and the same words can't be added back as the agents' own.
    • A lesson scoped to an owner-only class, or a preference the supervisor inferred, must be --for-owner.
    • Both rules are enforced in the CLI, in integrity() and in the fold, so a hand-written line counts for nothing.
  • Dashboard:
    • The owner's Inbox card shows the plain line first, with the technical wording folded under it.
    • The Loop tab has a folded, read-only section, "The agents' own lessons, waiting for the supervisor", so nothing is hidden.
    • A lesson's drawer shows its plain line and has a Retire button, so the owner can retire any lesson.

Why

The owner asked: "why are the Lessons open in stacks so jargonny?" Stacks had three candidate lessons in the owner's Inbox, written for agents, e.g. "check-pr reads tickets from main's log: after ticket add or ticket set (touches, done-whens), run log-sync and merge --chore log before the ticket's PR is checked…". These are operating lessons for the agents, backed by incidents. The owner can't judge them and shouldn't have to; the owner has said repeatedly that over-asking is unacceptable. After this lands, Stacks' three open candidates move to the supervisor's orient list. They stay visible to the owner, read-only, under the folded Loop section.

Authority check: authorise() accepts --approved k-… only for knowledge the owner created (writerClass(created_by) === 'owner'), accepted, scoped class:<c>, and never for an owner-only class outside owner_rules. decide --on only records lineage. Trust promotion reads answered questions only. So a lesson the supervisor accepted approves nothing; a new test asserts decide --class <owner_only> --approved <supervisor-accepted k> is refused.

Tested

Node 24 locally: test/ooda-knowledge.test.mjs, test/kit.test.mjs (82 pass), test/dashboard.test.mjs (144 pass), plus kit-lessons, plain-questions, machine, ooda-learning, ooda-lineage, ooda-signals, log-tolerance, search, bounds, approvals (60 pass).

  • New test in ooda-knowledge:
    • a default lesson doesn't reach the owner's list or the Inbox count, and is in orient; the supervisor accepts it.
    • a --for-owner lesson reaches the owner with its plain line.
    • --for-owner without --plain is refused.
    • plain lines with backticks, a flag, devteam.mjs, check-pr, a kit id or a file are refused; "Node.js" and "sign-up" pass.
    • the supervisor can't accept, reword or re-scope a sent lesson; raw lines doing so are ignored by the fold.
    • a withdrawn lesson can't come back as the agents' own; a preference and an owner-only scope are refused without --for-owner.
    • a supervisor-accepted lesson is no standing rule.
  • The dashboard press test checks that the plain line comes first, the technical wording is folded, the agents' lesson is not in the Inbox, and it is in the Loop's folded section.
  • test/lib/chain.mjs: the hub badge count now covers only lessons sent to the owner.
  • test/next-step.test.mjs: the Inbox-order test's lesson is sent to the owner, since only such lessons are in the Inbox now. The first CI run caught this; next-step, links and recovery pass locally.

Fable's adversarial review

Fixed:

  • Must-fix: the supervisor could reword or re-scope a sent lesson after the owner kept it. The owner's Keep pinned only status. Now refused in the CLI and ignored in the fold.
  • Must-fix: chain.mjs's hub badge test still counted every candidate. Updated it, with a mix of sent and agent candidates.
  • Must-fix: the plain check refused "Node.js". The bare .js/.ts branch now matches only lowercase names.
  • The sent-lesson and owner-only-scope rules were CLI-only. They are now in integrity() and the fold.
  • Send, then withdraw, then re-file as the agents' own: refused on matching words.
  • A supervisor-inferred preference self-accepted contradicted operator.md. It must now be --for-owner.
  • Doc wording: the constitution said "knowledge authorises nothing", but a standing rule is knowledge. The schema said "never taken back", but it can be retired.
  • The drawer now shows the plain line after acceptance and labels the raw fields.
  • The drawer's Retire button shows "Retiring…".

Left as is (low priority, the refusal message explains itself): plain-check false positives on the hyphenated class name new-feature, -- used as a dash, and "rung".

Fable found that the authority paths, the counts that must agree (hub, Inbox, title, gateway push) and the doc consistency were sound.

🤖 Generated with Claude Code

hhff and others added 5 commits November 13, 2026 23:23
… one sent to the owner (--for-owner, with a plain line) reaches their Inbox

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t too); preferences and withdrawn lessons go to the owner; review fixes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Inbox

A set line clearing for_owner on a lesson sent to the owner is ignored, like
a rewording or an accept: otherwise the supervisor could unsend it, then keep
it itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hhff

hhff commented Nov 14, 2026

Copy link
Copy Markdown
Member Author

Reviewed at d0859e1:

  • The gap I found and fixed: a hand-written knowledge set line with for_owner: false on a lesson already sent to the owner was accepted by the fold. That took the lesson out of the owner's Inbox, after which the supervisor could accept it itself. The fold now ignores it, the same as a rewording or an accept (d0859e1). I added a test, and confirmed it fails without the fix.
  • The rest checks out: for_owner and plain are writable only by the supervisor. An owner-only scope or an inferred preference must be sent to the owner, and a withdrawn lesson can't be refiled under the same words. Accepted lessons still grant nothing.
  • Tests: on Node 24, merged with main, kit passes 82 of 82 and ooda-knowledge 5 of 5.
  • One flaky test: dashboard passed 143 of 144. The Loop sidepeek test timed out once with load around 30; on its own it then passed 4 of 5 runs on the branch and 4 of 4 on main, so it's load, not this change. Worth watching.

CI passes 9 of 9. Merging.

@hhff
hhff merged commit 60ad157 into main Nov 14, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant