mesh/merge-gate head 6be8f6eada67 merged into trunk b7e22be7f55f — pass: [release feat/57-config-and-provisioning, judged by its controller cf897e89fe31] t…
mesh/repo-check head 6be8f6eada67 merged into trunk b7e22be7f55f — pass: [release feat/57-config-and-provisioning, judged by its controller cf897e89fe31] i…
mesh/delivery delivered
219 lines
15 KiB
Markdown
219 lines
15 KiB
Markdown
---
|
|
layer: to-be
|
|
status: designed
|
|
code: []
|
|
updated: 2026-10-12
|
|
decisions:
|
|
- "ADR 0290"
|
|
- "ADR 0321"
|
|
---
|
|
|
|
# 55 — The knowledge base
|
|
|
|
**The mesh keeps its decision records and research efforts whole in a module of its own, `mesh-knowledge`, one
|
|
instance on the control-node, holding the seat `knowledge-base`: each record's number, status, topic, typed links,
|
|
its clauses with their own status, and its reasoning, with every version kept. A record is proposed, checked when it
|
|
is written, reviewed by the knowledge base's own judgement and accepted there; the operator's Approve is asked when a record needs
|
|
it. Agents ask what holds, and why, in one bounded call.**
|
|
(ADR 0290,
|
|
from research 045.)
|
|
|
|
A **clause** is one numbered statement a decision record makes, with its own status. The **knowledge base** is the
|
|
module that holds the records; the seat it holds is `knowledge-base`. The glossary holds both words.
|
|
|
|
**Acceptance.** A session started in any folder on any node asks "what holds about the merge window, and why" and
|
|
gets, in one call under 4 KiB, the clauses in force, the records they come from, what changed them since, and how to
|
|
read the reasoning behind each.
|
|
|
|
This document designs the first slice in detail, tracked by issue 425. The slices after it are in
|
|
[§ 9](#9-the-slices-after-the-first).
|
|
|
|
## 1. The parts
|
|
|
|
```
|
|
control-node
|
|
|
|
mesh-knowledge (seat knowledge-base, held once for the mesh)
|
|
├ its process, launched by the node runtime
|
|
├ a database in the store records, versions, clauses, links; ranked full-text search
|
|
├ verbs ask, get, holds, links, history, reserve, propose, import, return
|
|
│ served by the control-node's tool runner
|
|
├ events proposed, reviewed, accepted, changed, imported, drafted, confirmed, returned
|
|
└ consumes the router's warrants: the operator's Approve for a record that needs it (§ 5)
|
|
|
|
mesh-issues (control-node) the counters for decision and research numbers (§ 6)
|
|
claude-code (same node) claude_code_judge: review a proposal (§ 5), draft and confirm clauses (§ 7)
|
|
records (any node) records_read at a commit: the import's source (§ 8)
|
|
messenger (control-node) the router: the operator's ask and its warrant
|
|
|
|
any agent session, on any node
|
|
mesh MCP server ── mesh_search, mesh_describe, mesh_call ──▶ the verbs, over the bus
|
|
```
|
|
|
|
The module is written in Go against the SDK. It holds no checkout of this repository; the import reads it through
|
|
the records module, as the issue tracker's import does.
|
|
|
|
## 2. What one record holds
|
|
|
|
- `number` and `kind` (decision or research), its key together; `title`, `topic`, `status`, `date`, `deciders`;
|
|
- its **reasoning**, in sections: for a decision, context, the options weighed, consequences, how it is checked,
|
|
references; for a research effort, its overview and each of its documents by name; markdown, as written;
|
|
- for a decision, its **clauses** (§ 3);
|
|
- its **links**, typed, each stored once and read from both ends;
|
|
- its **versions**: every change is a new version with who made it, when, and why in one line; `history` lists them
|
|
and gives the difference between any two. A progressive insight is a version marked as one, dated, saying what stood
|
|
before.
|
|
|
|
| Link | From → to |
|
|
|---|---|
|
|
| `supersedes` | a record → a record it replaces whole |
|
|
| `changes` | a clause or a record → a clause it replaces part of |
|
|
| `extends` | a record → a record it builds on |
|
|
| `became` | a research effort → a decision record or design |
|
|
| `rests-on` | a decision → a decision it stands on |
|
|
| `touches` | a research effort → a record, issue or design it bears on (by link), or an area (as text) |
|
|
| `cites` | any record → any record or issue it names |
|
|
|
|
## 3. Clauses
|
|
|
|
A clause holds its record's number and its own (`0276 §4`), its wording, a `status` and a `source`:
|
|
|
|
| Status | Meaning |
|
|
|---|---|
|
|
| `proposed` | its record is not accepted yet |
|
|
| `in force` | holds, and nothing later changes it |
|
|
| `changed` | a later clause replaces part of it; the `changes` link names which |
|
|
| `superseded` | its record is superseded, or a later clause replaces it whole |
|
|
|
|
| Source | Meaning |
|
|
|---|---|
|
|
| `written` | written as a clause by the record's author |
|
|
| `drafted` | written by the judgement from a prose `Decision` section at the import; never served as in force |
|
|
| `confirmed` | drafted, then confirmed by a second, independent judgement (§ 7) |
|
|
|
|
## 4. Writing a record
|
|
|
|
`reserve` gives a number (§ 6). `propose` takes the record whole: its fields, its clauses, its reasoning in sections,
|
|
its links, and for each `changes` the clauses it changes. It is refused, with every reason at once, when one of the
|
|
29 rules of the hq checks that judge one record or its prose fails, among them:
|
|
|
|
- a link names a record or clause that does not exist;
|
|
- a decision has no clause, or a clause has no bold lead;
|
|
- a record it supersedes or changes is not accepted, or one it cites as live is superseded without naming the record
|
|
that replaced it;
|
|
- its topic is not one of the reading order's;
|
|
- a research effort graduates without naming what it became;
|
|
- its text uses a retired word of the glossary, or a daemon's command line.
|
|
|
|
A proposed record can be revised by its author as new versions until it is accepted. Nothing proposed is ever served
|
|
as in force.
|
|
|
|
## 5. Review and acceptance
|
|
|
|
When `propose` takes a record (or a new version of a proposed one), the knowledge base reviews it itself: it asks for
|
|
a judgement in a separate call, with no tools, that sees only the record, the records it links and the rules, and
|
|
answers `approve` or `changes` with its findings, the way the issue tracker's triage judges an issue. The judgement
|
|
goes through the agent module's judge (`claude_code_judge`) today, and through the mesh's inference layer once one
|
|
exists; nothing in this design depends on which. On `changes`, the record stays proposed, the findings are kept with
|
|
that version, and its author revises it with a new version, which is reviewed again. A judgement that cannot be had
|
|
(the judge unreachable, or its answer unreadable) leaves the record proposed and says so; it is never taken as an
|
|
approval. On `approve`:
|
|
|
|
1. a record that does not need the operator is accepted at once;
|
|
2. a record whose author marked it `needs operator` gets an ask on the router with Approve and Decline, shown on a
|
|
channel that proves who answered (ADR 0274);
|
|
the knowledge base accepts it only on the warrant for Approve, which it keeps with the record.
|
|
|
|
On acceptance the record and its clauses move to `accepted` and `in force`, every clause its `changes` and
|
|
`supersedes` name moves to `changed` or `superseded`, and `accepted` and `changed` events are emitted. Then the 4
|
|
rules that judge the whole record set run (an accepted decision cited by nothing, and the like). A failure does not
|
|
undo the acceptance. It is a fault of the records, which their authors repair, not of the module: it is told to the
|
|
operator once, as a warning naming the rule and the records, and cleared once the rule holds again. The module's
|
|
health names it and stays healthy, because health says only whether the module works, and a finding never holds a
|
|
rollout at the module's first-node gate (the operator's decision of 2026-10-12 on issue 504, as issue 508 decided for a proposal never
|
|
reviewed).
|
|
|
|
The rule `cited` is also judged ahead, in the review, before the judgement: a decision that names no home and that no
|
|
accepted record links is not accepted. Its review, by the knowledge base itself, asks changes naming the rule (issue
|
|
504). It is not refused at `propose`, because no record can link a number only reserved: a record that cites a new
|
|
decision is proposed after it and accepted, and the new decision is proposed again.
|
|
|
|
An accepted record is changed only by a new record, or by a progressive insight: a new version marked as one, which
|
|
is reviewed like a proposal.
|
|
|
|
## 6. Numbers
|
|
|
|
`reserve` takes a kind and asks the issue tracker for the next number of that sequence (issue 424, ADR 0275 rule 8).
|
|
The number is spent: a record that is never accepted keeps it as `withdrawn`, with who reserved it and when. The
|
|
knowledge base keeps no counter.
|
|
|
|
## 7. Drafting and confirming clauses at the import
|
|
|
|
For a decision whose `Decision` section is prose, the import asks the agent's judgement
|
|
(ADR 0278)
|
|
for its clauses: the section in, numbered statements out, each one sentence, each saying nothing the section does not.
|
|
They are stored `drafted`. A second judgement, in a separate call that sees only the record and the drafts, answers
|
|
per clause whether the record says exactly that; an accepted clause becomes `confirmed`, a rejected one stays
|
|
`drafted` with the reason. Which clause of an older record a `supersedes-in-part` changes is judged and confirmed the
|
|
same way. When every record of a topic has been through both, the operator is told once per topic, with the counts
|
|
confirmed and still drafted. `return` with a record's number and a reason sends it back to be drafted again.
|
|
|
|
**A drafted clause may be changed, and a linked clause keeps its number** (ADR 0321, issue 494). A later record's
|
|
`changes` may name a drafted clause, confirmed or not, as it may one in force or changed; only a superseded or proposed
|
|
clause is refused. On that record's acceptance the drafted clause is marked `changed`, naming the clause that changed
|
|
it, keeps its number and stays `drafted`: it is still never served as in force, and `get` and `ask` say both. Because
|
|
a redraft numbers a record's clauses anew, `return` refuses a record any of whose clauses another record changed or
|
|
links by number, in a version served or proposed, naming each such link; a record that changes the drafted clause is
|
|
the way to correct it. A record no other record links by clause is returned as before.
|
|
|
|
## 8. The import
|
|
|
|
`import` takes a commit of this repository (and `dry-run`) and writes every decision record and research effort
|
|
whole, at its own number, as its first version, naming the commit. It creates what is absent, never overwrites, never
|
|
advances a counter; a second run changes nothing and says so. Records written in this repository after the import,
|
|
while the first slice does not take writes yet, are taken in by running it again.
|
|
|
|
**Refresh.** `import` with `refresh` re-reads, at the commit given, every record whose versions were all written by
|
|
the import, a refresh, or the knowledge base's own drafting and confirming of clauses, with nothing waiting over
|
|
it, and writes the corrected record as a new version naming why; a record anyone else wrote a version of is
|
|
never touched. Clauses already drafted and confirmed are kept when the Decision section's text is unchanged, and
|
|
drafted again when it changed. It repairs what an earlier import misread (issue 487) and is idempotent: a second run changes
|
|
nothing. `dry-run` lists what it would change. Once this repository holds no records, `import` refuses rather than
|
|
reporting nothing created (issue 488).
|
|
|
|
Before the records leave this repository (issue 426), every record is compared with its file at the import's commit,
|
|
field by field and section by section, and the result is written on issue 426.
|
|
|
|
## 9. The slices after the first
|
|
|
|
| Slice | Delivers | Done when the operator sees | Tracked by |
|
|
|---|---|---|---|
|
|
| 1 | this document: the module, the import, clauses, answers, `propose`, its own review and acceptance | the acceptance sentence above, live, and a record proposed, reviewed and accepted without a pull request | issue 425 |
|
|
| 2 | the decision records and research efforts leave this repository; path mentions become "ADR NNNN" and "research NNN"; playbooks 01 and 02 changed | this repository holds no decision record, and `get` answers every one | issue 426 |
|
|
| 3 | designs, playbooks and glossary entries as kinds | `holds` answers for a design's decisions and a glossary word | issue 428 |
|
|
| 4 | meeting notes, drawings and blog posts | not decided; needs its own decision | issue 429 |
|
|
|
|
Numbers from the issue tracker, which `reserve` needs, are the tracker's own slice, tracked by issue 424. This
|
|
repository keeps no copy of the records, generated or otherwise (issue 435, answered by the operator).
|
|
|
|
## 10. How it is checked
|
|
|
|
| Rule | Checked by |
|
|
|---|---|
|
|
| A proposal that breaks a per-record rule is refused, naming every reason | the module's table test, one case per rule of § 4 |
|
|
| A record is accepted only after the knowledge base's own judgement approves it, and, when it needs the operator, only on the warrant | the module's tests: a proposal whose judgement answers changes, or cannot be had, stays proposed; a `needs operator` record unaccepted without the warrant, accepted with it |
|
|
| A decision is not accepted cited by nothing | the module's test: a decision with no home and no record linking it gets changes from the review, with no judgement asked; with a home, or once a record citing it is accepted, it is accepted |
|
|
| A whole-set rule that fails is loud, and leaves the module healthy | the module's test: a correction that leaves a decision cited by nothing tells the operator once, as a warning naming the rule and the record, not again after a restart, and clears it once a record cites it; the module's health stays healthy throughout |
|
|
| Every version is kept and comparable | the module's test: three versions, `history` lists them, the difference of the first and third is exact |
|
|
| The import changes nothing on a second run, and loses nothing | the module's test over a fixture repository; and the comparison of § 8 on issue 426 |
|
|
| A drafted clause is never served as in force | the module's test: `holds` over a record with only drafted clauses answers none, and `ask` marks them |
|
|
| A drafted clause may be changed, and a linked clause is never renumbered | the module's tests: a record changing a drafted clause is accepted, and the clause is then `changed`, keeps its number, stays drafted and is not served; `return` of a record whose clause another record changed or links by number is refused naming the link, and writes nothing |
|
|
| An answer stays within its bound | the module's test over the full import of `main` at a recorded commit: every `ask`, `get` and `holds` of a fixed question list |
|
|
| A record written in this repository meanwhile writes its clauses | `records.py`, check `clauses`, on every hq pull request, until the records left this repository (issue 426); since then `records.py`, check `no-records`, refuses any record written here |
|
|
| Live | the acceptance sentence, asked from a session outside this repository |
|
|
|
|
## What it leaves out
|
|
|
|
Semantic or vector search; a browser view; line comments on a proposal (the judgement's findings name the section and
|
|
clause instead); and the rules of how-we-build, which are not decision records. Each needs a decision of its own.
|