Merge pull request 'ADR 0290 rewritten: a decision record lives whole in the knowledge base' (#307) from decisions/0290-records-whole-in-the-knowledge-base into main

This commit was merged in pull request #307.
This commit is contained in:
2026-10-11 00:07:48 +00:00
9 changed files with 311 additions and 270 deletions
+5 -2
View File
@@ -27,7 +27,7 @@ indistinguishable from one that cannot.
| `live-citation` | a governing document citing a **superseded** record names its replacement in the same paragraph | `01-to-be/README.md` citing ADR 0022 as live guidance |
| `supersession` | if A says it was superseded by B, B says it supersedes A | ADR 0012 never declared that it superseded 0011 |
| `partial-supersession` | a record's `supersedes-in-part:` names records that exist, each carrying a dated *Superseded in part* note naming it under its heading; and every such note is named back by its superseder's field | 11 of 21 partial supersessions had no note on the record they change, and 6 more were said only in prose ([research 045](../../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md)) |
| `clauses` | an accepted record dated from 2026-10-11 writes its `## Decision` section as numbered clauses with a bold lead ([ADR 0290](../../02-DECISIONS/0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md) rule 3) | 226 of 263 decision records wrote their decision as prose, so the knowledge base must draft their clauses |
| `clauses` | an accepted record dated from 2026-10-11 writes its `## Decision` section as numbered clauses with a bold lead ([ADR 0290](../../02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md) rule 3) | 226 of 263 decision records wrote their decision as prose, so the knowledge base must draft their clauses |
| `numbering` | the number in the filename is the number in the heading | — |
| `topics` | every record names a topic of the reading order in `02-DECISIONS/README.md` | — |
| *(index.py)* | the reading order is written, every record's topic is one of it, and the README stores no list of records ([ADR 0248](../../02-DECISIONS/0248-the-decision-index-is-generated-when-it-is-read-and-never-stored.md)) | a stored list made every two open decisions conflict ([issue 297](../../04-ISSUES/297-two-open-decisions-always-conflict/00-report.md)); it failed on the README of `main` before the list was removed |
@@ -71,7 +71,10 @@ off — "until renamed", "left for later", "not decided here", "postponed", "fut
change" — names the issue that tracks it, as tracking it ("tracked by issue N", or "issue N tracks"), in that
paragraph or list item, or in a dated progressive insight that speaks about it: one in the same section, or one
that quotes it. An issue cited for another reason tracks nothing, and one insight does not excuse every deferral
in a record. A rejected option is not work put off and is not held, judged by its `##` section, so an option under a
in a record. The tracking issue counts when it has a folder in `04-ISSUES/`, or when its number is above every
folder's: since ADR 0275 an issue from 365 on lives only in the issue tracker, which a checkout cannot read, and the
tracker hands out numbers in order (issue 436). A made-up number above the folders therefore passes; the reviewer
checks that the issue exists, with `issue-tracker.get`. A rejected option is not work put off and is not held, judged by its `##` section, so an option under a
`###` subheading of "Considered Options" is skipped too
([issue 354](../../04-ISSUES/354-a-decided-rename-was-never-scheduled-and-the-operator-believed-it-live/00-report.md):
ADR 0244 deferred the code renames with no issue, and two days later the operator believed them done). Held to
+8 -1
View File
@@ -117,7 +117,14 @@ def covers(insight_section, insight_text, section, text):
def issue_refs(text, issues):
return {n for a, b in ISSUE_REF.findall(text) for n in (a, b) if n and n in issues}
"""The issues a text names as tracking it: one with a folder here, or one numbered above every folder.
Since ADR 0275 an issue from 365 on lives only in the issue tracker, and ADR 0291 removes the folders; a
checkout alone cannot see those, so a number above the highest folder counts as one the tracker holds
(issue 436). The tracker hands out numbers in order, so such a number was issued after the last folder.
"""
top = max((int(k) for k in issues if k.isdigit()), default=0)
return {n for a, b in ISSUE_REF.findall(text) for n in (a, b) if n and (n in issues or int(n) > top)}
def rel(path):
+7 -6
View File
@@ -577,12 +577,13 @@ Not a domain of the mesh but of the way it is built, listed because its words me
*record* has other meanings (see [Homonyms](#homonyms)).
- **clause** — one numbered statement a decision record makes, with its own status (`proposed`, `in force`,
`changed`, `superseded`): a later record may change one clause and leave the rest
([ADR 0290](../02-DECISIONS/0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md)). Not a *rule*, which is a line of
([ADR 0290](../02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md)). Not a *rule*, which is a line of
`00-META/how-we-build.md`.
- **knowledge base** — the role that holds the structure of the decision records and research efforts (number,
status, topic, typed links) and each decision's clauses, and answers what holds: the seat `knowledge-base`, held by
the module `mesh-knowledge` ([55 — The knowledge base](../03-DESIGN/01-to-be/55-the-knowledge-base.md)). This
repository keeps the reasoning. Not **the record**, the literal reader of this repository.
- **knowledge base** — the role that holds the decision records and research efforts whole (number, status, topic,
typed links, clauses and reasoning, with every version), takes them as proposals, has them reviewed and accepted,
and answers what holds: the seat `knowledge-base`, held by the module `mesh-knowledge`
([55 — The knowledge base](../03-DESIGN/01-to-be/55-the-knowledge-base.md)). Not **the record**, the literal reader
of this repository.
- **design** — a document in `03-DESIGN/`: **as-is** (what runs) or **to-be** (what is being built).
- **issue** — a question about the mesh that someone must answer, numbered and tracked by the issue tracker, which
holds it whole: its report, diagnosis and resolution included ([ADR 0291](../02-DECISIONS/0291-an-issue-lives-whole-in-the-issue-tracker.md));
@@ -644,7 +645,7 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| record | a numbered decision | **decision record** | The record |
| | the literal reader of this repository, searched first for a symptom | **the record** (the `records` module) | Operator and conversation |
| | the upgrade policy that sends nowhere | `record` | Module |
| knowledge base | the module holding records' structure and clauses | **knowledge base** | The record |
| knowledge base | the module holding the decision records and research efforts whole | **knowledge base** | The record |
| | the predecessor's operational memory, in older playbooks (issue 430) | none: it no longer exists | — |
| check | a pull request's two statuses | **merge check**, **merge gate**, **repository check** | Change and delivery |
| | a delivery group's verdict | **composed check** | Change and delivery |
@@ -14,7 +14,7 @@ touches:
- 00-META/glossary.md
- the records module's tools
became:
- 02-DECISIONS/0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md
- 02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md
- 02-DECISIONS/0291-an-issue-lives-whole-in-the-issue-tracker.md
- 03-DESIGN/01-to-be/55-the-knowledge-base.md
---
@@ -0,0 +1,183 @@
---
topic: how we work
status: accepted
date: 2026-10-11
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0153-the-record-is-read-by-a-module-and-the-console-lists-it.md
---
# 290. A decision record lives whole in the knowledge base, made of clauses
> **Rewritten — 2026-10-11, on the operator's word.** This record was merged an hour earlier as *The knowledge base
> holds each record's structure and clauses, and hq keeps its reasoning*: the store held the structure, and this
> repository the reasoning, reviewed in pull requests. The operator asked why one record should live in two places,
> and asked for this record to be updated in place rather than superseded. Nothing had been built on the earlier
> version. It is in this repository's history at commit `08b1077b`.
## Context
[Research 045](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md) measured, on 2026-10-11, how an
agent learns what the mesh decided ([findings](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/01-findings.md)).
The operator gave the purpose the same day: the decisions and research should become shared knowledge that agents
reach through tools, instead of reading markdown files, and a session should no longer have to start in this
repository's folder to know what was decided.
**An answer costs too much.** "What holds about the merge window" took 26 search hits in 11 documents and about 85 KB
of reading, some 21,000 tokens. The decision index, generated by the records module
([ADR 0248](0248-the-decision-index-is-generated-when-it-is-read-and-never-stored.md)), is 77 KB, more than one
tool answer may be. The records module matches a phrase literally and knows nothing of which record still holds
([ADR 0153](0153-the-record-is-read-by-a-module-and-the-console-lists-it.md)).
**What a decision decided is not data.** 226 of 263 decision records write their `Decision` section as prose; 37
write it as numbered statements with a bold lead (198 in all). A later record that changes one statement of an older
one could say so only in prose or by naming the whole record: 21 `supersedes-in-part` links had no reverse, and 6
more records said it in prose alone, until hq pull request 305 declared all of them in both records and added a check.
**The checks run after the fact.** Of the 33 rules the hq checks enforce, 25 judge one record and 4 judge its prose;
all 29 could refuse a bad record when it is written. Only 4 need the whole record set.
**Numbers collide.** 16 decision numbers were taken twice by sessions working at once between 2026-09-25 and
2026-10-10. [ADR 0275](0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md)
rule 8 already decided that the issue tracker hands out decision and research numbers; issue 424 tracks building it.
### Against GENESIS
- **The mesh owns the truth** ([mission](../00-META/mission.md)): a record lives in one place, written through one
module, not in a file every branch may edit.
- **The mesh brokers everything the work needs, knowledge included**: an agent asks the mesh what holds, by
capability, instead of knowing which folder to read.
- **The mesh remembers** ([effect](../00-META/effect.md)): what was decided, and why, is available to whoever needs it
next, on any node, in any folder, with every earlier version kept.
- **Failure must be loud**: a write that would leave the records inconsistent is refused when it is made.
## Considered Options
### Where a record lives
1. **hq stays the truth; a module indexes it** (the research's option A). Rejected: a link about one statement of a
decision stays prose, and every inconsistency is found after it is written.
2. **Divided: the knowledge base holds a record's structure and clauses; hq keeps its reasoning.** Rejected by the
operator on 2026-10-11: one record in two places, an agent sent to a file for the *why*, and the structure written
twice until the frontmatter left hq.
3. **The knowledge base holds a record whole: structure, clauses and reasoning, with every version.** Adopted. It is
the division the operator made for issues ([ADR 0291](0291-an-issue-lives-whole-in-the-issue-tracker.md)), applied
to decisions and research.
### The unit
1. **The record.** Rejected: a later record changes one statement of an older one far more often than the whole.
2. **The clause: one numbered statement a decision makes, with its own status.** Adopted. The research called it a
*rule*; *rule* already names a line of [how-we-build](../00-META/how-we-build.md), and one word names one thing
([ADR 0244](0244-the-mesh-is-described-in-domains-and-one-word-names-one-thing.md)).
### How a record is reviewed, once it is not a pull request
1. **The operator approves every record.** Rejected: records are reviewed today by an independent agent, and the
operator is asked only for real decisions; making every record wait for one person slows what works.
2. **An independent agent reviews it, the write-time checks pass, and a record that needs the operator waits for the
operator's Approve on a channel that proves who answered.** Adopted. It is how a pull request here is merged
today, and the operator's Approve already reaches the mesh that way
([ADR 0274](0274-an-agent-proposes-a-shared-instruction-section-and-every-node-takes-it-only-on-the-operators-warrant-which-it-proves-itself.md)).
### Who confirms the clauses drafted for the 226 prose decisions (the research's open question 1)
1. **The operator, topic by topic.** Rejected: 226 records is days of reading for one person, for statements already
decided and reviewed once.
2. **Nobody: drafted clauses are served as they are.** Rejected: a summary nobody checked would speak as the record's
word, which is the work-that-reports-success-and-did-nothing fault.
3. **A second judgement, independent of the one that drafted them, confirms each record's clauses against its text;
the operator is told per topic and may send any record back.** Adopted, and confirmed by the operator on
2026-10-11.
## Decision
1. **The knowledge base is a Go module, `mesh-knowledge`, with one instance on the control-node.** It declares and
claims one seat held once for the mesh, `knowledge-base`
([ADR 0126](0126-a-module-declares-its-own-seats.md)). Its first kinds are the **decision record** and the
**research effort**.
2. **The knowledge base is the truth for a record whole**: its number, kind, title, topic, status, date, deciders, its
typed links (held in both directions), its clauses, and its reasoning (context, options weighed, consequences,
how it is checked; a research effort's documents). **Every version is kept**, with who wrote it and when, and any
two versions can be compared. Once the import has run and been checked, no record is written in this repository.
3. **A decision record is made of clauses.** A clause is one numbered statement of what was decided, with a status:
`proposed`, `in force`, `changed` by a clause of a later record, or `superseded`. A link that is about a clause
names the clause, not only the record. A record is written as clauses from the start. Until the knowledge base
takes writes, a record written in this repository from 2026-10-11 on writes its `Decision` section as numbered
clauses with a bold lead, and `records.py` refuses an accepted one that does not.
4. **A record is proposed, reviewed and accepted in the knowledge base.** `propose` writes it with a number from
`reserve`, and refuses it outright when one of the 29 rules that judge one record or its prose fails. An
independent agent reviews it (`review`), and its approval moves the record and its clauses to `accepted` and
`in force`, and every clause it changes or supersedes accordingly. A record that says it needs the operator waits
for the operator's Approve, asked on a channel that proves who answered, and the warrant is kept with it
([ADR 0259](0259-an-ask-is-a-message-on-the-bus-any-channel-answers-it-and-the-asker-acts-on-a-warrant.md)).
An accepted record changes only by a new record, or by a dated correction of a fact, written as a new version and marked as one;
the 4 rules that judge the whole record set run over it after every acceptance and raise a condition when one
fails.
5. **Numbers come from the issue tracker's counters**, as ADR 0275 rule 8 decided: `reserve` asks the tracker for the
next decision or research number, and a reserved number is spent whether or not its record is accepted. Until the
tracker hands them out, tracked by issue 424, a session takes the highest number on `main` and on every open
branch, plus one, as the shared instruction section *writing-decision-records* says.
6. **An answer is the shape agents need, bounded.** The verbs are `ask` (records and clauses bearing on a question,
ranked, each saying whether it holds or what changed it), `get` (one record: clauses, links both ways, what changed
it since; its reasoning only when asked), `holds` (the clauses in force for a topic or a record), `links`,
`history` (a record's versions and the difference between two), `reserve`, `propose`, `review`, `import` and
`return` (send drafted clauses back to be drafted again). `ask`, `get` and `holds` stay under a size bound they
state; the default is 4 KiB.
7. **State is in a database in the store**, provided to the module, not in buckets: `ask` needs ranked full-text
search, and a record's versions are a record set to search, not current state to watch
([ADR 0201](0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md)
is not narrowed). **Every change is an event the module declares**
([ADR 0041](0041-events-are-a-relationship.md)), carrying what changed and who changed it.
8. **The import reads this repository at a commit and can run again.** It writes every decision record and research
effort whole, at its own number, with the commit as its first version's source; it creates what is absent, never
overwrites, never advances a counter, and a second run changes nothing and says so. A record whose clauses are
written as numbered statements gets them as `written`. A prose record gets them `drafted` by the agent's judgement
([ADR 0278](0278-the-issue-tracker-checks-every-new-issue-for-a-duplicate-through-a-judgement-the-agent-makes-without-tools.md)),
then `confirmed` by a second judgement that sees only the record and the drafts; the operator is told per topic and
may send a record back. An answer marks a drafted or confirmed clause as such, and never serves a drafted clause as
in force.
9. **This repository stops holding decision records and research efforts** once the import is checked against it,
record by record: one pull request removes them, rewrites the mentions of their paths to "ADR NNNN" and "research
NNN", and changes playbooks 01 and 02, tracked by issue 426. Whether this repository then carries a generated,
read-only public copy is not decided here, tracked by issue 435. The records module stays the literal reader of
what this repository still holds.
10. **It is built in slices, each tracked by an issue.** The first is the module for decisions and research: import,
clauses, answers, and proposing and reviewing a record, tracked by issue 425. The records leave this repository
under issue 426. Designs, playbooks and glossary entries follow the same way, tracked by issue 428. Meeting notes,
drawings and blog posts come last and are not decided here, tracked by issue 429. The design is
[to-be 55](../03-DESIGN/01-to-be/55-the-knowledge-base.md).
## Consequences
- An agent on any node asks what holds and why, and gets the clauses in force, the records they come from and what
changed them, in one call, instead of reading several records whole. No session needs this repository's folder to
read or write a decision.
- A later record that changes one statement of an older one says which, and the older clause's status changes when
the later record is accepted.
- Review moves from a pull request to the knowledge base's `review`, and the forge's line comments and diff are
replaced by the record's versions and `history`. A record is checked when it is written, not when it is merged.
- Until the first slice takes writes, records are still written here as pull requests, with numbered clauses, and the
import takes them in with the rest.
- What got harder: one more module the mesh's own process depends on. Reading or writing a decision needs the mesh to
be reachable; a node that cannot reach the control-node says so rather than guessing. The public repository stops
showing decisions as they are made, until issue 435 decides on a public copy.
## How it is checked
- **Clauses in a record written here** (rule 3): `records.py`, check `clauses`, on every pull request of this
repository, until the records leave it.
- **What the module does** (rules 2, 4, 6, 7, 8): the module's tests and its live acceptance, listed in
[to-be 55](../03-DESIGN/01-to-be/55-the-knowledge-base.md) §9, built under issue 425.
- **Nothing lost when the records leave** (rule 9): every record compared with its file at the import's commit before
the files are removed, the result written on issue 426.
- **Numbers** (rule 5): the issue tracker's tests of its counters, built under issue 424; until then the
`numbering` and duplicate checks of `records.py` and `cycle.py` find a collision on `main`.
## References
- [Research 045](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md) and its
[findings](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/01-findings.md).
- [To-be 55 — The knowledge base](../03-DESIGN/01-to-be/55-the-knowledge-base.md).
- hq pull request 305: every partial supersession declared in both records, and the `partial-supersession` check.
- Issues 424, 425, 426, 428, 429 and 435.
@@ -1,160 +0,0 @@
---
topic: how we work
status: accepted
date: 2026-10-11
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0153-the-record-is-read-by-a-module-and-the-console-lists-it.md
---
# 290. The knowledge base holds each record's structure and clauses, and hq keeps its reasoning
## Context
[Research 045](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md) measured, on 2026-10-11, how an
agent learns what the mesh decided ([findings](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/01-findings.md)).
The operator gave the purpose the same day: the decisions and research should become shared knowledge that agents
reach through tools, instead of reading markdown files, and a session should no longer have to start in this
repository's folder to know what was decided.
**An answer costs too much.** "What holds about the merge window" took 26 search hits in 11 documents and about 85 KB
of reading, some 21,000 tokens. The decision index, generated by the records module
([ADR 0248](0248-the-decision-index-is-generated-when-it-is-read-and-never-stored.md)), is 77 KB, more than one
tool answer may be. The records module matches a phrase literally and knows nothing of which record still holds
([ADR 0153](0153-the-record-is-read-by-a-module-and-the-console-lists-it.md)).
**What a decision decided is not data.** 226 of 263 decision records write their `Decision` section as prose; 37
write it as numbered statements with a bold lead (198 in all). A later record that changes one statement of an older
one could say so only in prose or by naming the whole record: 21 `supersedes-in-part` links had no reverse, and 6
more records said it in prose alone, until hq pull request 305 declared all of them in both records and added a check.
The older record's status still reads `accepted`, and a reader must read both to know what holds.
**The records change after they are written, and that is reviewed.** 189 of 271 decision records were edited after
the commit that created them, every edit through a pull request with a human approval and the repository's checks.
**Numbers collide.** 16 decision numbers were taken twice by sessions working at once between 2026-09-25 and
2026-10-10. [ADR 0275](0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md)
rule 8 already decided that the issue tracker hands out decision and research numbers; it is not built, and issue
424 tracks it.
### Against GENESIS
- **The mesh brokers everything the work needs, knowledge included** ([mission](../00-META/mission.md)): an agent asks
the mesh what holds, by capability, instead of knowing which folder to read.
- **The mesh remembers** ([effect](../00-META/effect.md)): what was decided, and why, is available to whoever needs it
next, on any node, in any folder.
- **Failure must be loud**: a write that would leave the records inconsistent is refused when it is made, not found by
a check afterwards.
## Considered Options
### Where the truth lives
1. **hq stays the truth; a module indexes it and opens pull requests for writes** (the research's option A).
Rejected: it keeps review, but a link about one statement of a decision stays prose, and every inconsistency is
found after it is written, which is the cause of what the research measured.
2. **A store is the truth for everything, and hq is its export** (option B). Rejected: it would rebuild review, line
comments, history and diff for prose, which git and the forge already give, for records that are edited after they
are written as often as these are.
3. **Divided by layer: the store holds each record's structure and its clauses; hq keeps its reasoning.** Adopted.
It is what the research recommended when the operator asked on 2026-10-11 what a clean start would pick, and the operator chose it, and the division ADR 0275
already made for issues, carried down to the statement a decision makes.
### The unit
1. **The record.** Rejected: a later record changes one statement of an older one far more often than the whole.
2. **The clause: one numbered statement a decision makes, with its own status.** Adopted. The research called it a
*rule*; *rule* already names a line of [how-we-build](../00-META/how-we-build.md), and one word names one thing
([ADR 0244](0244-the-mesh-is-described-in-domains-and-one-word-names-one-thing.md)).
### Who confirms the clauses drafted for the 226 prose decisions (the research's open question 1)
1. **The operator, topic by topic.** Rejected: 226 records is days of reading for one person, for statements already
decided and reviewed once.
2. **Nobody: drafted clauses are served as they are.** Rejected: a summary nobody checked would speak as the record's
word, which is the work-that-reports-success-and-did-nothing fault.
3. **A second judgement, independent of the one that drafted them, confirms each record's clauses against its text;
the operator is told per topic and may send any record back.** Adopted, and confirmed by the operator on 2026-10-11. A clause keeps its source, so an answer says
whether a clause was written by the record's author or drafted and confirmed.
## Decision
1. **The knowledge base is a Go module, `mesh-knowledge`, with one instance on the control-node.** It declares and
claims one seat held once for the mesh, `knowledge-base`
([ADR 0126](0126-a-module-declares-its-own-seats.md)). Its first kinds are the **decision record** and the
**research effort**.
2. **The knowledge base is the truth for each record's structure**: its number, kind, title, topic, status, date,
deciders, and its typed links, each held in both directions. **hq is the truth for each record's reasoning**:
context, options weighed, consequences, research documents, as markdown reviewed in pull requests. A record's file
keeps its number in its name and heading.
3. **A decision record is made of clauses.** A clause is one numbered statement of the `Decision` section, with a
status: `in force`, `changed` by a clause of a later record, or `superseded`. A link that is about a clause names
the clause, not only the record. A record written from 2026-10-11 on writes its `Decision` section as numbered
clauses with a bold lead, and the knowledge base reads them from the merged text, so a clause's wording is always
the reviewed one. `records.py` refuses an accepted record dated from 2026-10-11 whose `Decision` section has no
numbered clause.
4. **A record is accepted when its pull request merges.** The knowledge base hears the forge's merge on the bus,
reads the merged record through the records module, and moves the record and its clauses to `accepted` and
`in force`, and each clause it changes or supersedes accordingly. The merge, with its human approval and both
required checks, is the warrant; there is no second approval beside it. A structural write that would change what
an accepted record says, without a pull request, is refused.
5. **Numbers come from the issue tracker's counters**, as ADR 0275 rule 8 decided: the knowledge base's `reserve`
asks the tracker for the next decision or research number, and a reserved number is spent whether or not its
record lands. Until the tracker hands them out, tracked by issue 424, a session takes the highest number on `main`
and on every open branch, plus one, as the shared instruction section *writing-decision-records* says.
6. **An answer is the shape agents need, bounded.** The verbs are `ask` (records and clauses bearing on a question,
ranked, each saying whether it holds or what changed it), `get` (one record: clauses, links both ways, what changed
it since, its reasoning only when asked), `holds` (the clauses in force for a topic or a record), `links`,
`reserve`, `propose`, `import` and `return` (send a record's drafted clauses back to be drafted again). Every answer names the commit of this repository it was read at and stays under
a size bound that `ask`, `get` and `holds` state; the default is 4 KiB.
7. **State is in a database in the store**, provided to the module, not in buckets: `ask` needs ranked full-text
search, which the store's server does and a bucket does not. This narrows nothing in
[ADR 0201](0201-a-module-keeps-its-current-state-in-key-value-buckets-it-declares-and-reaches-through-the-runtime.md):
what the module keeps is a record set to search, not current state to watch. **Every change is an event the
module declares** ([ADR 0041](0041-events-are-a-relationship.md)), carrying what changed and who changed it.
8. **The import reads this repository at a commit and can run again.** It creates what is absent, never overwrites,
never advances a counter, and a second run changes nothing and says so. A record whose clauses are written as
numbered statements gets them as `written`. A prose record gets them `drafted` by the agent's judgement
([ADR 0278](0278-the-issue-tracker-checks-every-new-issue-for-a-duplicate-through-a-judgement-the-agent-makes-without-tools.md)),
then `confirmed` by a second judgement that sees only the record and the drafts. The operator is told per topic and
may send a record back. An answer marks a clause that is drafted or confirmed as such, and never serves a drafted
clause as in force.
9. **The records module stays the literal reader of this repository.** `records_search` for a symptom's literal text
is unchanged; the knowledge base answers what holds. Both reach every session through the mesh MCP server, and a
session needs this repository's folder only to write a record's reasoning.
10. **It is built in slices, each tracked by an issue.** The first is the module for decisions and research, its
import and its answers, tracked by issue 425. The structure's fields then leave hq's frontmatter, kind by kind,
once the import is proven to hold the same values, tracked by issue 426. Designs, playbooks and glossary entries
follow the same way, tracked by issue 428. Meeting notes, drawings and blog posts come last and are not decided
here, tracked by issue 429. The design is
[to-be 55](../03-DESIGN/01-to-be/55-the-knowledge-base.md).
## Consequences
- An agent on any node asks what holds and gets the clauses in force, the records they come from and what changed
them, in one call, instead of reading several records whole.
- A later record that changes one statement of an older one says which, and the older clause's status changes when
the later record merges; the dated note under the older record's heading stays, for a reader who follows a citation.
- Writing a decision changes in one way: its `Decision` section is numbered clauses, from this record on. This record
and [ADR 0291](0291-an-issue-lives-whole-in-the-issue-tracker.md) are written that way.
- Until issue 426 lands, a record's status and links are written in two places: hq's frontmatter, which the hq checks
read, and the knowledge base, which reads them from hq at every merge. hq stays the source until then, so the two
cannot disagree for longer than one merge.
- What got harder: one more module the mesh's own process depends on, and a reader of a decision needs the mesh to be
reachable to learn its clauses' status. The file in hq stays readable alone.
## How it is checked
- **Clauses in a new record** (rule 3): `records.py`, check `clauses`, on every pull request of this repository.
- **What the module does** (rules 2, 4, 6, 7, 8): the module's tests and its live acceptance, listed in
[to-be 55](../03-DESIGN/01-to-be/55-the-knowledge-base.md) §9, built under issue 425.
- **Numbers** (rule 5): the issue tracker's tests of its counters, built under issue 424; until then the
`numbering` and duplicate checks of `records.py` and `cycle.py` find a collision on `main`.
## References
- [Research 045](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md) and its
[findings](../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/01-findings.md).
- [To-be 55 — The knowledge base](../03-DESIGN/01-to-be/55-the-knowledge-base.md).
- hq pull request 305: every partial supersession declared in both records, and the `partial-supersession` check.
- Issues 424, 425, 426, 428 and 429.
@@ -33,10 +33,11 @@ tracker alone.
story from a file, by a path the tracker gives. Since ADR 0275 an issue with a folder and one without are read
differently, and which one has a folder is an author's judgement at the moment it was opened.
**What the public record keeps.** A design or governance question that matters ends in a decision record, and decision
records stay here, public, with their reasoning
([ADR 0290](0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md)). What
the public repository loses is the story of how a question was found, not the answer.
**What the record keeps.** A design or governance question that matters ends in a decision record, which the
knowledge base holds whole, with its reasoning
([ADR 0290](0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md)). What an issue's
content adds is the story of how a question was found, not the answer. Whether accepted decision records stay
readable in this public repository is issue 435.
### Against GENESIS
@@ -52,7 +53,7 @@ the public repository loses is the story of how a question was found, not the an
1. **Keep ADR 0275's split.** Rejected by the operator: one issue in two places, and a reader who must know which.
2. **Everything in the tracker; hq keeps no issue content.** Adopted.
3. **Everything in the tracker, and hq keeps a generated public copy of every resolved design or governance issue.**
Rejected for now: it keeps a second copy, and the public reader who needs the outcome has the decision record. This
Rejected for now: it keeps a second copy, and the reader who needs the outcome has the decision record. This
was the research's open question 2; the operator confirmed no export on 2026-10-11. An export, if it is wanted
later, is a decision of its own.
@@ -71,8 +72,8 @@ the public repository loses is the story of how a question was found, not the an
4. **A mention of an issue is its number.** The 765 path mentions become "issue N" in the same pull request that
removes the folders, and `records.py` then refuses a new path into `04-ISSUES/`. The knowledge base and the
tracker resolve a number.
5. **No issue content is exported to this repository.** The public record of a design question is the decision
record it led to.
5. **No issue content is exported to this repository.** The record of a design question is the decision record it
led to.
6. **The work is tracked by issue 427**: the documents in the tracker, the import, the mentions rewritten, the folders
removed, and playbook 03 changed to match. Until it lands, every folder stays and playbook 03 is followed as it is
written.
@@ -80,8 +81,8 @@ the public repository loses is the story of how a question was found, not the an
## Consequences
- One issue, one place: an agent reads an issue whole with `issue-tracker.get`.
- The public repository no longer shows how a design question was found. The question's answer, the decision record,
stays public.
- The public repository no longer shows how a design question was found. Whether it still shows the answer, the
decision record, is issue 435.
- The tracker's values grow from a few hundred bytes to some kilobytes each; the largest measured fits 10 times over.
- Reviewing an issue's diagnosis moves from a pull request to the tracker's history of that document. An issue's
content was never a decision; what is decided still goes through a pull request.
+96 -90
View File
@@ -4,28 +4,28 @@ status: designed
code: []
updated: 2026-10-11
decisions:
- 02-DECISIONS/0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md
- 02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md
---
# 55 — The knowledge base
**The mesh keeps the structure of its decision records and research efforts in a module of its own,
`mesh-knowledge`, one instance on the control-node, holding the seat `knowledge-base`. It holds each record's number,
status, topic and typed links, and each decision's clauses with their own status, and answers what holds in one
bounded call. This repository keeps each record's reasoning, reviewed in pull requests; a record is accepted when its
pull request merges.**
([ADR 0290](../../02-DECISIONS/0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md),
**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 an independent agent 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](../../02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md),
from [research 045](../../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/00-overview.md).)
A **clause** is one numbered statement a decision record makes, with its own status. The **knowledge base** is the
module that holds records' structure and clauses; the seat it holds is `knowledge-base`. The glossary holds both words.
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 the
commit of this repository it was read at.
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
[§ 8](#8-the-slices-after-the-first).
[§ 9](#9-the-slices-after-the-first).
## 1. The parts
@@ -34,30 +34,34 @@ This document designs the first slice in detail, tracked by issue 425. The slice
mesh-knowledge (seat knowledge-base, held once for the mesh)
├ its process, launched by the node runtime
├ a database in the store records, clauses, links, sources; ranked full-text search
├ verbs ask, get, holds, links, reserve, propose, import, return
├ a database in the store records, versions, clauses, links; ranked full-text search
├ verbs ask, get, holds, links, history, reserve, propose, review, import, return
│ served by the control-node's tool runner
├ events imported, proposed, accepted, changed, drafted, confirmed, returned
└ consumes the forge's merge event for hq: read the merged records (§ 4)
├ 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)
records (any node) records_read at a commit: the text of a record
mesh-issues (control-node) the counters for decision and research numbers (§ 5)
claude-code (same node) claude_code_judge: draft and confirm clauses (§ 6)
mesh-issues (control-node) the counters for decision and research numbers (§ 6)
claude-code (same node) claude_code_judge: 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 and holds no checkout: it reads this repository through the records
module's `records_read` and `records_list` at the commit a merge names, as the issue tracker's import does.
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`, and
the `path` of its file in this repository;
- `commit`: the commit of this repository the record was last read at;
- `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 **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 |
|---|---|
@@ -65,12 +69,7 @@ module's `records_read` and `records_list` at the commit a merge names, as the i
| `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 |
| `corrects` | a dated progressive insight → the record it stands in |
| `cites` | any record → any record or issue it links in its text |
`changes` at the level of a clause is new. A merged record that declares `supersedes-in-part` gives a `changes` link
to the older record; which of the older record's clauses it changes is read from the newer record's text by the
judgement of § 6 and held as `drafted` until confirmed, like a drafted clause.
| `cites` | any record → any record or issue it names |
## 3. Clauses
@@ -78,100 +77,107 @@ A clause holds its record's number and its own (`0276 §4`), its wording, a `sta
| 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 |
| `proposed` | its record's pull request is not merged |
| Source | Meaning |
|---|---|
| `written` | read from a `Decision` section written as numbered clauses with a bold lead |
| `drafted` | written by the judgement from a prose `Decision` section; never served as in force |
| `confirmed` | drafted, then confirmed by a second, independent judgement (§ 6) |
| `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) |
From 2026-10-11 every accepted record writes its clauses (`records.py`, check `clauses`). The 226 records written
before then in prose get theirs drafted and confirmed at the import.
## 4. Writing a record
## 4. Acceptance follows the merge
`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:
The knowledge base consumes the forge's merge event for this repository. For each decision record or research
overview the merge adds or changes, it reads the file at the merge's commit through the records module and:
- 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.
1. writes or updates the record's structure from its frontmatter, and its clauses from its `Decision` section;
2. moves a record from `proposed` to `accepted` when its frontmatter says `accepted`;
3. for each `supersedes` and `supersedes-in-part` the record declares, moves the older record or the drafted target
clauses to `superseded` or `changed`, and emits `changed` for each;
4. emits `accepted`, naming the commit.
A proposed record can be revised by its author as new versions until it is reviewed. Nothing proposed is ever served
as in force.
A merge that changes nothing the knowledge base holds changes nothing. A record read that fails is retried, and a merge
whose records could not be read after the retries raises a condition naming the commit: a merge the knowledge base did
not take is loud, not silent.
## 5. Review and acceptance
`propose` writes a new record's structure as `proposed` before its pull request exists, with the number `reserve`
gave; nothing proposed is ever served as in force. A structural change to an accepted record without a merge is
refused, with the reason that what an accepted record says changes only through a pull request.
`review` is called by an agent that did not write the record, with a verdict, `approve` or `changes`, and its
findings. The knowledge base refuses a review by the record's author. On `changes`, the record stays proposed and the
findings are kept with it. On `approve`:
## 5. Numbers
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](../../02-DECISIONS/0274-an-agent-proposes-a-shared-instruction-section-and-every-node-takes-it-only-on-the-operators-warrant-which-it-proves-itself.md));
the knowledge base accepts it only on the warrant for Approve, which it keeps with the record.
`reserve` takes a kind and asks the issue tracker for the next number of that sequence (issue 424, ADR 0275 rule 8),
and answers it. The number is spent: a record that never lands leaves it as a gap, and the knowledge base keeps who
reserved it and when, as `withdrawn` once its branch is closed unmerged. The knowledge base keeps no counter.
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 raises a
condition naming the rule and the records, and does not undo the acceptance.
## 6. Drafting and confirming clauses
An accepted record is changed only by a new record, or by a progressive insight: a new version marked as one, which
goes through `review` 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](../../02-DECISIONS/0278-the-issue-tracker-checks-every-new-issue-for-a-duplicate-through-a-judgement-the-agent-makes-without-tools.md))
for its clauses: the record's `Decision` section in, numbered statements out, each one sentence, each quoting nothing
the section does not say. They are stored `drafted`.
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 second judgement, made in a separate call that sees only the record's text and the drafts, answers per clause
whether the record says exactly that. A clause it accepts becomes `confirmed`; one it rejects stays `drafted` with
the reason. When every record of a topic has been through both, the operator is told once per topic, with the count
confirmed and the count still drafted, through the router. `return` with a record's number and a reason sends a
record back to be drafted again.
## 8. The import
## 7. Answers
`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.
| Verb | Takes | Answers |
|---|---|---|
| `ask` | a question in words; optionally a kind, a topic, a size bound | records and clauses bearing on it, ranked by the store's full-text search: number, kind, status, title, and each clause with its status and what changed it |
| `get` | a number and kind; optionally `reasoning` | one record: its clauses, its links both ways, what changed it since; the reasoning's text only with `reasoning` |
| `holds` | a topic or a record | the clauses in force, each with its record and the `changes` that led to its present wording |
| `links` | a number and kind | its typed links, both directions |
| `reserve` | a kind | the next number (§ 5) |
| `propose` | a kind, a number from `reserve`, a title, a topic, and its links | the structure written as `proposed` |
| `import` | optionally `dry-run`, a commit | every decision and research effort at that commit, as § 4 reads one, with prose decisions drafted (§ 6); create-if-absent, never an overwrite; run again, changes nothing and says so |
| `return` | a number and a reason | sends a record's drafted or confirmed clauses back to be drafted again |
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.
Every answer names the commit it was read at. `ask`, `get` and `holds` answer at most 4 KiB unless a larger bound is
given, and say when they cut and how to ask for the rest. A clause that is `drafted` is marked so in every answer and
never listed under `holds`.
## 8. The slices after the first
## 9. The slices after the first
| Slice | Delivers | Done when the operator sees | Tracked by |
|---|---|---|---|
| 1 | this document: the module, the import, the clauses, the answers, acceptance on merge | the acceptance sentence above, live | issue 425 |
| 2 | the frontmatter fields the knowledge base holds leave this repository, kind by kind, and the per-record rules of `records.py` and `cycle.py` move into its write verbs | a decision record's file carries no status or links, and the hq checks still pass | issue 426 |
| 1 | this document: the module, the import, clauses, answers, `propose`, `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 slice 1 needs for `reserve`, are the tracker's own slice, tracked by issue 424.
Numbers from the issue tracker, which `reserve` needs, are the tracker's own slice, tracked by issue 424. Whether this
repository keeps a generated public copy of accepted records is issue 435.
## 9. How it is checked
## 10. How it is checked
| Rule | Checked by |
|---|---|
| A record merged in hq is held, with its clauses, at the merge's commit | the module's test over a real bus and a fixture repository: a merge event, then `get` names that commit; and live, the first decision merged after the module is delivered |
| A merge the knowledge base could not take is loud | the module's test: records unreadable after the retries raise a condition naming the commit |
| The import changes nothing on a second run | the module's test: two imports at one commit, the second reports nothing created |
| 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 a review by someone else, and, when it needs the operator, only on the warrant | the module's tests: a review by the author refused; a `needs operator` record unaccepted without the warrant, accepted with it |
| A whole-set rule that fails is loud | the module's test: an acceptance that leaves a decision cited by nothing raises the condition |
| 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 structural change to an accepted record without a merge is refused | the module's test, one case per field |
| An answer stays within its bound and names its commit | 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 new record writes its clauses | `records.py`, check `clauses`, on every hq pull request |
| 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 |
| Live | the acceptance sentence, asked from a session outside this repository |
## What it leaves out
Semantic or vector search; a browser view; writing a record's reasoning (that stays a pull request in this
repository); and the rules of how-we-build, which are not decision records. Each needs a decision of its own.
Semantic or vector search; a browser view; line comments on a proposal (a review'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.
+1 -1
View File
@@ -54,7 +54,7 @@ document is written and this one's status becomes `implemented`.
| [`52-shares-and-mounts.md`](52-shares-and-mounts.md) | **In progress.** A node shares one folder at a time through `nfs-server`, which provides it as a provision to the private network only, mapping every client to the folder's owner; a node that asks mounts it through `mounts`, a mount unit and an automount per share, so nothing mounts or fails at boot; a device that comes and goes is an occasional source whose absence is a state | [ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md), [ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md), [ADR 0092](../../02-DECISIONS/0092-an-operator-delivers-a-pair-credential.md) |
| [`53-the-issue-tracker.md`](53-the-issue-tracker.md) | **Designed.** The mesh keeps its issues in one module, `issues`, on the control-node: every number from one counter advanced by compare-and-set, the cycle's issue rules refused at the write, an event per change; an issue lives whole in the tracker, hq keeping no issue content ([ADR 0291](../../02-DECISIONS/0291-an-issue-lives-whole-in-the-issue-tracker.md)) | [ADR 0275](../../02-DECISIONS/0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md), [ADR 0291](../../02-DECISIONS/0291-an-issue-lives-whole-in-the-issue-tracker.md) |
| [`54-the-controllers-records-on-the-bus.md`](54-the-controllers-records-on-the-bus.md) | **Designed.** The controller keeps five record mirrors on the bus (nodes, assignments, walks, builds, settings): each a bucket written from its store only when the record changed, with one event per write, and audited against the store every self-check run, a difference raised as `mirror-drifted` before the healer H6 repairs it | [ADR 0289](../../02-DECISIONS/0289-the-controller-mirrors-its-records-into-buckets-written-only-on-a-change-and-audited-against-its-store.md) |
| [`55-the-knowledge-base.md`](55-the-knowledge-base.md) | **Designed.** The mesh keeps its decision records' and research efforts' structure in one module, `mesh-knowledge`, on the control-node: number, status, topic, typed links both ways, and each decision's clauses with their own status; a record is accepted when its pull request merges; agents ask what holds in one bounded call, and hq keeps the reasoning | [ADR 0290](../../02-DECISIONS/0290-the-knowledge-base-holds-each-records-structure-and-clauses-and-hq-keeps-its-reasoning.md) |
| [`55-the-knowledge-base.md`](55-the-knowledge-base.md) | **Designed.** The mesh keeps its decision records and research efforts whole in one module, `mesh-knowledge`, on the control-node: number, status, topic, typed links both ways, each decision's clauses with their own status, and the reasoning, with every version; a record is proposed, checked at the write, reviewed by an independent agent and accepted there, with the operator's Approve when it needs it; agents ask what holds in one bounded call | [ADR 0290](../../02-DECISIONS/0290-a-decision-record-lives-whole-in-the-knowledge-base-made-of-clauses.md) |
## Not yet written