diff --git a/00-META/glossary.md b/00-META/glossary.md index 5c8a0cfd..80694757 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -995,6 +995,11 @@ Not a domain of the mesh but of the way it is built, listed because its words me **author**, until it is submitted as a version or dropped; another session may **take it over** with a reason, as a proposal (ADR 0592). Not a **drafted** clause, which the import's judgement wrote from prose (see [Homonyms](#homonyms)). +- **opened** — of a draft: begun by `open` on a reserved or existing record, with its author, and said by the event + `opened` (ADR 0592). Not **drafted**. +- **drafted** — of a clause: written by the import's judgement from a prose Decision section, and never served as in + force until a second judgement confirms it; the event `drafted` says so (ADR 0290, ADR 0321). Never said of a + draft, which is **opened**. - **form-only version** — of a record: a version that changes only its sections' titles and the targets of its links, proved by a check rather than judged, and marked `form`; never a change of meaning (ADR 0592). - **search index** — the knowledge base's full-text index of the records, built in the module's memory from the bus diff --git a/03-DESIGN/01-to-be/55-the-knowledge-base.md b/03-DESIGN/01-to-be/55-the-knowledge-base.md index faa65222..89356a2f 100644 --- a/03-DESIGN/01-to-be/55-the-knowledge-base.md +++ b/03-DESIGN/01-to-be/55-the-knowledge-base.md @@ -55,7 +55,9 @@ and the knowledge base works out each design's state (ADR 0423, ADR 0424). ├ on the bus, written by it alone (§ 2) │ state heads one key per record: its fields, clauses, links, sections as title and digest │ state drafts one key per record being written: its author and its sections as title and digest - │ state findings the whole-set findings standing now, and when each was told + │ state asked one key per part asked of the judge and not yet answered: ticket, node, when + │ state names per digest: how many versions and drafts name it, and since when none has + │ state findings the whole-set findings standing now, and the told marks (told.) │ stream versions one message per version: who, when, why, its mark, the head as it stood │ stream reviews one message per part reviewed: the digest judged, the verdict, the findings │ objects sections every section's body, once, named by its sha256 digest @@ -65,14 +67,17 @@ and the knowledge base works out each design's state (ADR 0423, ADR 0424). │ withdraw, retract, import, return │ served by the control-node's tool runner ├ events reserved, opened, written, removed, ordered, submitted, dropped, taken-over, proposed, - │ reviewed, accepted, changed, imported, drafted, confirmed, returned, moved, formed + │ part-reviewed, reviewed, accepted, changed, swept, moved, checked, formed, + │ imported, drafted, confirmed, returned ├ consumes the router's warrants: the operator's Approve for a record that needs it (§ 5) + ├ consumes claude-code's judged: the judge's answer to a part (§ 5) └ consumes the delivery module's delivery-done announcement: a design's state (§ 9) mesh-issues (control-node) the counters for decision and research numbers (§ 6); the issues' design links, read for a design's state (§ 9) mesh-delivery (its seat) announces each delivery done, on the bus (§ 9) - claude-code (same node) claude_code_judge: review a section or a head (§ 5), draft and confirm clauses (§ 7) + claude-code (same node) claude_code_judge: review a section or a head (§ 5), draft and confirm clauses (§ 7); + emits judged with the answer of each ticket (§ 5, a dependency of the fifth slice) 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 @@ -84,35 +89,67 @@ The module is written in Go against the SDK. It holds no checkout of this reposi the records module, as the issue tracker's import does. Until the move of § 8.1, its records are in a database in the store; from the move on, it requires no database (ADR 0592 §1, changing ADR 0290 §7). +**A write is whole or refused** (ADR 0592 §9). Every change to `heads`, `drafts`, `asked`, `names` and `findings` is a +compare-and-set on the key's revision, retried at most three times and then refused with the reason. `submit` +writes the message on `versions` first, then the head against its revision, then the event; a failed step refuses +the call. At start the module rebuilds any head behind its last version. A reservation is a head created only if +the key is absent, so two sessions reserving at once get two numbers or one refusal. + **The search index** is a full-text index in the module's own memory, written with the pure Go library bleve. At -start the module reads every head and the bodies of every current version into it, and says it is not ready until it -holds as many records as `heads`; then it keeps the index current by watching `heads`. `ask` and `holds` answer from -it, ranked by title, clauses and sections as before. Nothing but the module writes it, and nothing outside it reads it. +start the module reads every head and the bodies of every current version into it, then keeps it current by watching +`heads`, noting the last revision of `heads` it took in. `ask` and `holds` answer from it, ranked by title, clauses +and sections as before, and refuse with "index not built" while it is built; `get`, `list` and `propose` answer from +`heads` at once (ADR 0592 §10). The integration test measures the start; the estimate is 20 to 40 seconds and about +100 MB of memory for today's 736 records. Nothing but the module writes it, and nothing outside it reads it. ### 1.1 Its tools, health and events Every piece of state has a tool that reads it, and every act the module does by itself can be done by hand -(ADR 0592 §20): +(ADR 0592 §26): | Tool | Reads or does | |---|---| | read a head | one key of `heads`, whole | -| read a version | one message of `versions`, with its sections' titles and digests | -| read a section | one object of `sections`, by its digest | -| read a draft | one key of `drafts`, with who holds it and since when | -| read a review | the part reviews of one version, from `reviews` | +| read a version | one message of `versions`, with its sections' titles, digests and authors | +| read a section | one object of `sections`, by its digest, checked against it | +| read a draft | one key of `drafts`, with its author and since when | +| read a review | the part verdicts of one version, from `reviews` | +| in-flight parts | the keys of `asked`: each part waiting on the judge, its ticket and since when; ask one again | +| told marks | the `told.` keys; clear one, so it is told again | | fill | each bucket's and stream's size and count against its cap | | rebuild the index | the search index, built again from the bus | | review again | asks one part's review again, for a version still proposed | +| sweep | lists the objects no version or draft names and since when; sweeps them now; dry run | +| integrity | checks every named digest has its object; restores a body from given text once its digest matches | +| form-only | lists, dry-runs and runs the form-only versions of § 2.2 | | move, and check the move | § 8.1, each with a dry run | -**Health** says whether every bucket and stream answers, and whether the search index is built and holds as many -records as `heads`. A stream that keeps its history raises its condition past 75 percent of its cap. A review waiting more than 30 minutes is named in the health and told to the operator once; the -module stays healthy, because a record waiting on its review is not the module failing (issue 508). +**Health** (ADR 0592 §27) is unhealthy, naming the cause, when a bucket or stream does not answer, when the index is +behind the latest revision of `heads`, when a digest some version names has no object (counted, each named), and +when a bucket or stream is at its cap. It names the source it serves from (the database or the bus) and the result +of the move's last check, and counts drafts idle more than a week, records the form-only check refused, and parts +waiting more than 30 minutes. A part waiting more than 30 minutes is asked of the operator once through the operator +channel, and the ask clears when the part is judged; the module stays healthy meanwhile, because a record waiting on +its review is not the module failing (issue 508). The condition at 75 percent of a cap is the controller's (§ 2.1). -**Events** say each step: `opened`, `written`, `removed`, `ordered`, `submitted`, `dropped` and `taken-over` for a -draft; `moved` for each record the move copies; `formed` for each form-only version (§ 2.2); beside the events the -module emits for reserving, proposing, reviewing, accepting, changing and the import. +**Events** (ADR 0592 §28) are kept 30 days; what a later reader needs is also in the version message. Each carries: + +| Event | Carries | +|---|---| +| `opened` | the record, the version it starts from, the author | +| `written`, `removed` | the record, the section's title and digest, the author | +| `ordered` | the record, the titles in order, the author | +| `submitted` | the record, the new version, its section digests, the author | +| `dropped` | the record, the author, the reason (asked, or idle 14 days) | +| `taken-over` | the record, the previous author, the new author, the reason | +| `part-reviewed` | the record, the version, the part, its digest, the verdict | +| `reviewed` | the record, the version, every part's verdict: one event per version, as before | +| `swept` | the digest removed, since when nothing named it | +| `moved` | the record, its counts on the bus | +| `checked` | the move's check: records compared, every difference | +| `formed` | the record, the version, the names changed | + +None is named `drafted`, which stays the event of a clause the import's judgement wrote. ## 2. What one record holds @@ -158,23 +195,40 @@ A record is kept in three of the bus's own forms, so that a new version costs on - **The head** is one key in the state `heads`, `.`: the record's fields, its clauses with their status and source, its links, the operator's ask and warrant, its current and pending version, the latest verdict of each part's review (§ 5), and its sections in order, each a title and a digest. A key's value stays under 256 KiB - (ADR 0201). + (ADR 0201). A reserved number is a head at `reserved`, with who reserved it, when, for what and when it expires. - **A version** is one message on the stream `versions`: who wrote it (the caller the bus proved), when, why, its - mark, and the head as it stood. It never copies a section's body. The stream keeps its history: every message, + mark, who wrote each section, the reason of any take-over since the version before, and the head as it stood. It never copies a section's body. The stream keeps its history: every message, with no age limit, and when it reaches its cap it refuses a new message rather than dropping its oldest, with a condition raised at 75 percent of the cap. A module's stream may declare that retention; before, a stream was kept at - most 30 days (ADR 0592 §6, changing ADR 0363 §1). The stream `reviews` keeps its history the same way. + most 30 days (ADR 0592 §6, changing ADR 0363 §1). The stream `reviews` keeps its history the same way. The + condition at 75 percent is raised by the controller, in one place, for every history stream and object bucket of + every module. - **A section's body** is one object in the bucket `sections`, named by the sha256 digest of the body: a section - unchanged in a new version costs nothing. An object no version and no draft names is removed a day after the last - stopped naming it. The bucket is storage of the bus, as the controller's object bucket of ADR 0486 is. Any module + unchanged in a new version costs nothing. The module checks that a body hashes to its name each time it reads one. + The state `names` keeps, per digest, how many versions and drafts name it and since when none has; an object no + version and no draft names is removed a day after the last stopped naming it, each removal the event `swept`. The bucket is storage of the bus, as the controller's object bucket of ADR 0486 is. Any module may declare an object bucket of its own in its manifest, with a local name and a cap, created as its state buckets are, kept with no age limit and refusing a new object when full (ADR 0592 §5). -- **A draft** is a key in the state `drafts` (§ 4). **A part's review** is a message on the stream `reviews` (§ 5). - **The whole-set findings** standing now, and when each was told to the operator, are keys in the state `findings`. +- **A draft** is a key in the state `drafts` (§ 4). **A part's verdict** is a message on the stream `reviews`, and a + part asked of the judge and not yet answered a key in the state `asked` (§ 5). **The whole-set findings** standing + now are keys in the state `findings`, and what was told to the operator once is a key `told.` there. + +**Caps** (ADR 0592 §21). Each is set from the move's dry run, within ADR 0363's 8192 MiB; the starting figures, from +today's 83 MB for 736 records with every version copying every section, are: + +| Bucket or stream | Cap | +|---|---| +| `versions` (stream) | 1 GiB | +| `reviews` (stream) | 512 MiB | +| `sections` (object bucket) | 1 GiB | +| `drafts` (state) | 64 MiB | +| `heads`, `asked`, `names`, `findings` (state) | ADR 0201's 64 MiB | + +A write refused at a cap names the cap, and the module's health turns unhealthy naming it. **Who may read each** is announced in the manifest. `heads`, `versions`, `sections` and `reviews` may be read by a -module the manifest names, such as the web page that shows records once it exists; `drafts` and `findings` by -mesh-knowledge alone. No secret is kept in any of them. A grant cannot limit a reader to some objects of a bucket +module the manifest names, such as the web page that shows records once it exists, and every such grant is read-only; +`drafts`, `asked`, `names` and `findings` by mesh-knowledge alone. No secret is kept in any of them. A grant cannot limit a reader to some objects of a bucket (ADR 0488), which is why reading is announced per bucket and never per record. ### 2.2 A section is a part with a title @@ -182,17 +236,21 @@ mesh-knowledge alone. No secret is kept in any of them. A grant cannot limit a r A section's name is a plain title, unique in its record: "Context", "Direction", "The move". It is never a file's name: a name with an extension, a number prefix such as `00-`, or a slash is refused, and so is a text that holds a local path (in a person's home folder or the temporary folder), a reference to a file and line, or a link whose -target is a relative path or a file (ADR 0592 §17). +target is a relative path or a file (ADR 0592 §23). -**A reference to a part has one form**, which `get` resolves and a web page links: the record, then each title down -to the part, joined by ›, such as "research 081 › Direction › D3"; a clause as its record and number, "ADR 0290 §7". +**A reference has one form** (ADR 0592 §24): the record, a section's title, then a row or clause inside that +section's text, joined by ›, such as "research 081 › Direction › D3"; a clause as its record and number, +"ADR 0290 §7". Sections never nest: `get` resolves a record and a section's title, and the row is an anchor in the +section's text, which a web page links. **The records imported with file-named sections** (the research efforts' `00-overview.md` and the like) get titles in -one form-only version per record, written by the module after the move. It changes only section names and the +one form-only version per record, written after the move by the move's tool alone; no verb writes one. It changes only section names and the targets of links, each link to a record's file becoming a reference in the form above. It is marked `form`, lists the names it changed, and is accepted without a judgement because a check proves only form changed: each section's text, -with every link replaced by its label, is the same before and after. It is not a change of meaning; `history` shows -it as a change of form (ADR 0592 §19). +with every link replaced by its label, is the same before and after, and each new link target resolves to the record +the old name named. `get` accepts the old section names as aliases, recorded in that version. A part's review carries +over to it, its meaning being unchanged. It is not a change of meaning; `history` shows it as a change of form +(ADR 0592 §25). ## 3. Clauses @@ -214,7 +272,7 @@ A clause holds its record's number and its own (`0276 §4`), its wording, a `sta ## 4. Writing a record `reserve` gives a number (§ 6). A record is then written in a **draft**, one section per call, and submitted as a -version (ADR 0592 §11): +version (ADR 0592 §14): | Verb | Does | |---|---| @@ -238,13 +296,19 @@ version (ADR 0592 §11): A draft is a key in the state `drafts`: its author, when it was opened, the version it starts from, the record's fields and clauses, and its sections in order as title and digest. Each `write` stores the section's body in the object bucket `sections` and its digest in the draft, so the knowledge base holds the only copy of a draft and a -session on any node can read it. A draft is kept until it is submitted or dropped; `list` names one untouched for a -week. +session on any node can read it. A draft holds at most 64 sections and 1 MiB; one untouched for a week is counted in +the health, and one idle for 14 days is dropped and its author told by `dropped`. -**A draft and a proposal have one author** (ADR 0592 §13). Only the author writes a draft or revises a proposal; +**A draft and a proposal have one author** (ADR 0592 §16). Only the author writes a draft or revises a proposal; another caller is refused, naming the author. `take-over` makes the caller the author, keeps the reason on the record, and tells the previous author by the event `taken-over`. It answers a proposal that only the machine that wrote it could revise (issue 1102) and one left proposed for ever by a version from an unproven writer (issue 465). +A proposal waiting for the operator's Approve cannot be taken over: its author withdraws it first. The reason of a +take-over is carried in the next version's message. + +**Only a proven caller writes** (ADR 0592 §17): `open`, `write`, `submit`, `propose` and `take-over` refuse a caller +the runtime could not prove. The operator's Approve binds the section digests of the version shown; a version with +any other section is asked again. `submit` and `propose` are refused, with every reason at once, when one of the rules that judge one record or its prose fails, among them: @@ -268,17 +332,21 @@ as in force. ## 5. Review and acceptance When a version is submitted (by `submit` or `propose`, a new version of a proposed record included), the knowledge -base reviews it itself, **in parts** (ADR 0592 §14 to §16, changing ADR 0290 §4): one judgement per part, each in a +base reviews it itself, **in parts** (ADR 0592 §18 to §22, changing ADR 0290 §4): one judgement per part, each in a separate call, with no tools, that 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. - **The head** is one part: the title, the brief, the clauses (at most 40 KiB together) and the links, judged against the clauses of the records it links, in what room is left, those not shown named. -- **Each changed section** is a part of its own, judged with **the frame** of at most 16 KiB, filled in this order - until full: the title and the links, every clause's bold lead, in full each clause the section names, then the - Context section (the Overview, for a research effort). What does not fit is cut, and the question says what was cut. - A section is at most 40 KiB, so each question stays under the judge's 60 KiB. +- **Each changed section** is a part of its own, judged with **the frame** of at most 16 KiB: the title, the links, + and only what the section names (rows of other sections, clauses, the clauses of linked records), with the digest + of the Context section (the Overview, for a research effort) it is read beside. What does not fit is cut, and the + question says what was cut. A section is at most 40 KiB, so each question stays under the judge's 60 KiB. +- **What is judged again.** A section is judged again only when its own text or what it names changes; the Context + only when it changes. So a usual revision judges only the sections it changed. +- **At most two judge calls of one version run at once.** A revision of eight sections takes a few minutes, and + about four times the tokens of one whole judgement. - **The rules on the whole record** (§ 4) stay code, run at `submit`; no judgement is asked to find a link to nothing. ``` @@ -290,13 +358,23 @@ the mesh's inference layer once one exists; nothing in this design depends on wh version 3 stays proposed, with the findings of Direction ``` -A part's review is a message on the stream `reviews`: the record, its version, the part, the digest judged, the -verdict, the findings, who judged and when; the head keeps the latest verdict of each part. A part's review is kept -for a new version when its digest and its frame's digest are both unchanged; any other part is judged again. **A -version is accepted when every part's review approves.** On `changes`, the record stays proposed, the findings are -kept with that version and the part they name, and its author revises it with a new version. A part that cannot be -judged (the judge unreachable, or its answer unreadable) leaves the version proposed and says which; it is never -taken as an approval. When every part approves: +**The parts wait on the bus** (ADR 0592 §19). Each part asked of the judge is a key in the state `asked` (the part, +the judge's ticket, the node, when it was asked), collected again at start, so a restart loses no review. The judge's +answer comes as the event `judged`, which the claude-code module emits for each ticket and the knowledge base +consumes; until claude-code emits it, the knowledge base polls the ticket, which is not NATS-native and is tracked by +issue 1956. The judge is a tool of the claude-code module, not a seat's verb: a seat for judgements (held by the +mesh's inference layer once one exists) is a note on that issue. A part waiting more than 30 minutes asks the +operator once through the operator channel, and the ask clears when the part is judged. + +**A part's verdict** is the event `part-reviewed` and a message on the stream `reviews`: the record, its version, the +part, the digest judged, the verdict, the findings, who judged and when; the head keeps the latest verdict of each +part. **`reviewed` keeps its meaning**: one event per version, once every part is judged, carrying each part's +verdict, so every wait on it keeps working. A part's review is kept for a new version when what it was judged with is +unchanged, and for a form-only version (§ 2.2); any other part is judged again. **A version is accepted when every +part's review approves.** On `changes`, the record stays proposed, the findings are kept with that version and the +part they name, and its author revises it with a new version. A part that cannot be judged (the judge unreachable, +or its answer unreadable) leaves the version proposed and says which; it is never taken as an approval. When every +part approves: 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 @@ -366,23 +444,36 @@ field by field and section by section, and the result is written on issue 426. ### 8.1 The move off the store The records leave the store once, and the database is dropped only after a check and the operator's yes -(ADR 0592 §10): +(ADR 0592 §11 to §13): -1. **Copy.** The move copies everything the database holds onto the bus, every record, version, clause, link, - review, finding, ask with its warrant, reservation and record of what was told: each version's sections into `sections` by digest, each version as a message on `versions`, each record's - head into `heads`, each standing finding into `findings`. A clause keeps its number, status and source as the - database holds them (ADR 0321). It emits `moved` per record, writes nothing twice, and a second run changes - nothing and says so. A dry run lists what it would write. -2. **Check.** A tool compares the database and the bus record by record: for each record the count of each of +1. **Order.** Three deliveries, in order: mesh-sdk (the manifest's field types for `objects` and + `retention: history`, and the catalog's check of them); then the controller (it creates the object buckets and + history streams, grants their readers read-only, and raises the condition at 75 percent for every such bucket and + stream in one place); then mesh-knowledge. An older controller refuses a manifest with these keys through the + catalog's check, so mesh-knowledge cannot be delivered before them. The claude-code module's `judged` event is + delivered beside, and is not needed for the move (§ 5). +2. **Copy.** The move copies everything the database holds onto the bus, every record, version, clause, link, + review, finding, ask with its warrant, reservation and told mark: each version's sections into `sections` by + digest, each version as a message on `versions`, each record's head into `heads`, each standing finding into + `findings`, each told mark as `told.`. A clause keeps its number, status and source as the database holds + them (ADR 0321). It emits `moved` per record, writes nothing twice, and a second run changes nothing and says so. + A dry run lists what it would write and the size each bucket and stream will need, from which the caps are set. +3. **The window.** From the move's final copy through the check to the switch, every writing verb is refused with + its reason ("the knowledge base is moving"). Reading verbs answer throughout. +4. **Check.** A tool compares the database and the bus record by record: for each record the count of each of those, the digest of every section of every version, computed from the database's text and read from the bus, - and a digest of every review's, finding's and ask's content. Its result names every difference. -3. **Switch.** The module answers from the bus only once the check shows no difference; until then it answers from - the database, and a difference is told to the operator. -4. **Tell and ask.** The operator is told the check's result and asked whether the database may be dropped, because - dropping it removes data. -5. **Drop.** On the operator's yes, the delivery after it removes the module's requirement of a database, and the + that each body hashes to its name, and a digest of every review's, finding's and ask's content. It emits + `checked` with every difference, and the health shows its last result. +5. **Switch.** Only once the check shows no difference, the module answers from the bus. The switch is a key on the + bus, so a restart never falls back to the database. A difference is told to the operator, and the module stays on + the database. +6. **Rollback.** Until the database is dropped, the module writes each change to the database too, so a rollback of + the delivery reads a current database. A rollback is safe only until the drop. +7. **Tell and ask.** Once the check is clean, the operator is told its result and asked, once, whether the database + may be dropped, because dropping it removes data. +8. **Drop.** On the operator's yes, the delivery after it removes the module's requirement of a database, and the database is dropped by the store's module, through its tool for it, which is built there first if it has none. -6. **Titles.** The module then writes the form-only versions of § 2.2, one per record with file-named sections. +9. **Titles.** The move's tool then writes the form-only versions of § 2.2, one per record with file-named sections. ## 9. The slices after the first @@ -392,7 +483,7 @@ The records leave the store once, and the database is dropped only after a check | 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 and the glossary's entries as records, moved in one delivery, and each design's state worked out by the knowledge base (§ 9.1 to § 9.3; ADR 0423, ADR 0424) | `get` answers design 47 with its sections and links, a word's entry answers from the knowledge base, and a design's state follows its issues' deliveries without anyone writing it | issue 428 | | 4 | meeting notes, drawings and blog posts | not decided; needs its own decision | issue 429 | -| 5 | the records on the bus, written and reviewed by section, the move off the store and the titles (§ 1, § 2, § 4, § 5, § 8.1; ADR 0592) | the acceptance tests of the fifth slice in § 10, live; the knowledge base requires no database | the issues its hand-off opens (playbook 04) | +| 5 | the records on the bus, written and reviewed by section, the move off the store and the titles (§ 1, § 2, § 4, § 5, § 8.1; ADR 0592), delivered as mesh-sdk, then the controller, then mesh-knowledge, with claude-code's `judged` event beside | the acceptance tests of the fifth slice in § 10, live; the knowledge base requires no database | the issues its hand-off opens (playbook 04) | 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). Playbooks @@ -495,6 +586,34 @@ milestones and nothing of how a delivery runs; it only listens for the announcem | A draft is written by section and has one author, and a take-over tells the previous one | unit tests of each verb of § 4, of a refusal naming the author, and of `take-over` emitting `taken-over` | | A stream that keeps its history, and an object bucket of a module's own | in the integration test: a history stream at its cap refuses a new message and keeps its oldest, its condition raised at 75 percent and cleared below; an object no version or draft names is removed after a day, one still named is kept; unit tests of registration refusing a name already taken | | A long record is judged whole, one part at a time | unit tests: the frame never passes 16 KiB and says what it cut, with twenty clauses of 2000 bytes and a 40 KiB Context; every question stays under 60 KiB with a 40 KiB section and that frame, and the head part with 40 KiB of clauses; a section over 40 KiB is refused saying split it; an unchanged section keeps its review, a changed frame asks it again | + +**The fifth slice's tests, one per failure path** (ADR 0592; the review by aspect's testing ruling). Unit tests are +table-driven; one integration test starts the module whole against the real bus server. The module's count today is +1 integration and 104 unit tests; these add about 20 table cases and stay within the budget of 50 and 500. + +| Failure path | Test | +|---|---| +| two writes race on one draft | unit: the second compare-and-set loses, is retried, and is refused with the reason past its tries | +| `submit` races `take-over` | unit: one wins; the other is refused naming the new author or the new version | +| two reservations race | unit: two numbers, or one refused; never one number twice | +| a write cut between the stream and the head | unit: a start rebuilds the head from its last version | +| a named digest has no object | unit: health unhealthy, naming it; the integrity tool restores it from given text | +| a body does not hash to its name | unit: the read refuses it, naming the digest | +| a full object bucket | integration: a write refused naming the cap; health unhealthy | +| a full history stream | integration: `submit` refused with the head unchanged; the condition at 75 percent raised and cleared | +| a judge timeout for one part | unit: that part stays asked and the version proposed, saying which; the others keep their verdicts | +| a restart with parts asked | integration: the parts in `asked` are collected again and judged | +| `reviewed` once per version | unit: one `reviewed` after the last `part-reviewed`, carrying every verdict | +| told once | unit: a whole-set finding told once across a restart, again only after its mark is cleared | +| a second run of the move | unit: changes nothing and says so | +| the move's check | unit: a changed review, a missing finding and a missing ask, each named | +| writes during the switch | unit: every writing verb refused with its reason; reading verbs answer | +| an older controller | the controller's test: a manifest with `objects` or `retention: history` refused through the catalog's check | +| a reference | unit: "record › title › row" resolves to the section; a nested title is refused | +| a form-only version | unit: accepted when only names and links changed and each target resolves; refused otherwise | +| an unproven caller | unit: `open`, `write`, `submit`, `propose` and `take-over` refuse it | +| the index behind | unit: health unhealthy while the index's revision is behind `heads`; `ask` refuses "index not built" | +| the start | integration: the time to a built index measured and reported | | A section is a part with a title | a table test, one case per refused name and text of § 2.2; a form-only version whose text changed beyond its links is refused | | Every bucket has a tool, and health says the index | the manifest test compares tools and events with the code; a unit test of the health before and after the index is built | @@ -536,8 +655,32 @@ done: change of form, and `get` of "research 062 › Direction" answers that section. 7. The fill tool shows each bucket and stream against its cap; the second version of a record with one changed section adds one object, not one per section. +8. During the move's window a `write` is refused saying the knowledge base is moving; after the switch a restart + still serves from the bus; the health names the source and the check's result. +9. A part's review waiting on the judge survives a restart of the module, and one past 30 minutes reaches the + operator once. +10. Every test of the table above passes in the one check of the pull requests, within the test budget. ## What it leaves out Semantic or vector search; a browser view (its reading of the buckets is announced, ADR 0592); 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. + +## Reviewed by aspect + +The fifth slice was reviewed by aspect on 2026-11-02 (four reviewers, two aspects each; the knowledge base's own +review of ADR 0592's fourth version beside), and the lead ruled on every finding. What was found, and what answers it: + +| Aspect | Found | Answered by | +|---|---|---| +| security | unproven callers could write or take over; an Approve did not bind the sections shown; a proposal waiting on the operator could be taken over; readers' grants and a body's match with its name were unsaid; a draft had no bound | ADR 0592 §4, §8, §14, §16, §17; § 2.1, § 4 | +| seams | asked parts lived only in memory; told marks and reservations had no form on the bus; the judge's ticket is polled; who creates buckets and grants was unsaid; the judge is a module's tool, not a seat | ADR 0592 §2, §7, §13, §19; § 1, § 5 (the judge's seat a note on issue 1956), § 8.1 | +| running qualities | three writes could stop halfway; caps had no figures; a usual revision judged every section again, with no limit on parallel calls; start time unknown | ADR 0592 §9, §18, §21; § 1, § 2.1 (caps), § 5 | +| health | a stale index, a missing body, a full bucket and the move's state were not visible; waiting reviews and idle drafts were not counted | ADR 0592 §21, §27; § 1.1 | +| events and logs | per-part verdicts would have broken every wait on `reviewed`; events did not say what they touched; a take-over's reason and each section's author were lost after 30 days | ADR 0592 §3, §22, §28; § 1.1 (the events table) | +| testing | each failure path lacked a test; the budget was not counted | ADR 0592's How it is checked; § 10 (the failure-path table) | +| upgrade | writes during the switch, a rollback after it, and the order of the three deliveries were unsaid; the form-only check did not prove new link targets | ADR 0592 §12, §13, §25; § 8.1, § 2.2 | +| tools | unnamed objects, missing bodies, form-only versions, asked parts and told marks had no tool | ADR 0592 §26; § 1.1 (the tools table) | + +The knowledge base's review of the fourth version found that the reference form read as nested sections: ADR 0592 +§24 and § 2.2 say sections never nest.