Conversation
…otocol get names Two levels with one meaning each. Protocol-governed collaboration is the umbrella: agents coordinate through a published protocol and the mechanics stay with the program. The Task-Unit Protocol is the sub-protocol this line builds - a task is declared as a unit and the protocol fixes how it is adopted into one run, claimed, delivered and independently judged, and which facts the runtime decides. The parts keep the names they already have: Task Board is the sub-protocol's surface, managed entry is what a governed entry is, run is the frozen object, adopt is the binding transition, and the caller that decides to adopt is called the adopter. The words that came to hand were already taken - fusion (units sharing one session), scheduler (which the task-unit semantics decision deliberately does not enable), governance (the board addressing line), ledger (three of them) and executor (the bounded context adapters) - so each is recorded as considered and rejected rather than reused. No identifier or file name changes, for the reason the check-runner renaming recorded: `ooo` and the existing paths are cited by dated measurement records and frozen run archives. The name lives in the concept map with its aliases, and docs/glossary.yaml is untouched because it owns the repository and process vocabulary, not product concepts.
The definitions were spread over the design, the obligations ledger and several decision records, so reading them meant opening four files at once. The naming record now carries an index section: one line of meaning and a pointer per name, for both levels, the board verbs and the channel rules, the run and its facts, the legal action set and the dispatch loop. It ends with the two words deliberately not used for this protocol - scheduler and OoO - each with the owner of its real meaning, because reusing either is what made the discussion ambiguous in the first place. The section states its own status: an index, not a second specification, and where a row and its owner disagree the owner wins. Same content in the zh pair. Found while checking the links: the concept map's Task Board row points at an anchor that does not exist in memory-graphs.md, and docs:check does not catch it because it validates file existence rather than headings. The index uses the heading that is really there.
The row's anchor named "2.1 Task Board outside the three memory graphs", which is not a heading in memory-graphs.md: the section there is "Shared Task Board (cross-Agent coordination, not a memory graph)". Clicking the old link still opened the file, so it read as working. docs:check validates that a link's file exists rather than its anchor, which is why this survived; the row now names the heading that is really there, in both languages.
…bout speculation The naming record now carries the conceptual history the names only make sense inside: the board becoming a protocol on 2026-08-13 (identity and discovery that wake no LLM, directed delivery, serial admission decided by claim/resolve/expiry), governance and addressing on 09-06, out-of-order execution borrowed from the CPU with its limits written down on 09-09..09-11, the task unit's semantics on 09-13, the paid arms measuring both borrowed halves on 09-18..09-19, and the board absorbing the execution half through 09-20. The OoO step is stated as the CPU correspondence rather than as "parallelism": out-of-order execution with in-order commit, where the plan and its tickets are the reorder buffer, the coordinator is the only retire stage, and the acceptance rules define what counts as commit. Its two limits are recorded with it, because the second one is the point the fusion and speculation arms then measured: the CPU's premise that a wrong guess wastes resources already committed or free does not transfer to agents, where a wrong guess spends tokens and wall time (a worker call measured at 40-56 s). Hence the decision adopts only the class whose wrong guess costs no tokens and refuses the class that hides a wait by guessing it, and the arms record "cost with no gain" at the shape tried: 43k tokens over six units, one false fact wasting 20 332 tokens, 0 of 3 prepared candidates publishable, and 175 ms of verification against 6.2 s of work once the fact holds. Commit-level lineage stays where it already lives (implementation-lineage.md, from its Task Board row) rather than being copied into the record. Also corrected: the bootstrap design still said the speculation decision was proposed and that the no-speculation rule therefore stayed in force until it was implemented. The decision has been implemented since 2026-09-11, so the sentence now states what is actually in force - the host-side free class may be done, hiding a wait by guessing stays forbidden.
Adds a proposed record for the question the naming decision unblocked: the primitives have names and the shared layer can already compute the legal set (an ordered legal set, that set cut to the declared slot budget, and a refusal reason per unit), but no document states whose decision each step is. The proposal splits the work three ways and gives the program exactly one share. The protocol owns what the primitives are, the definition and criteria of legality, the named constraint list, and the two structural rules that cannot be negotiated because they are what "legal" means here: a claim (lease plus attempt fence) is the only arbiter of who holds a unit, and a deliverer never judges its own delivery. The accompanying program computes the ordered legal set from the declared plan and current facts, cuts it to the declared slot budget, and states for each unit why it is legal or not - it chooses nobody, adopts nothing, judges nothing, wakes nobody. Agents own the arrangement: the plan's content, the order they agree on, who takes which unit, who adopts a run, who judges - all of it as board facts, so the arrangement is readable instead of being implied by a program's choice. Constraints are named by the protocol and enabled by the plan, so a preference such as repair-first is neither program policy nor advice; and legality is asked rather than published, because a published handoff occupies a serial slot by the board's own protocol, so fusing the two would make a question cost a slot. The plan is three steps and only the first lands here: this record, then a readable answer through an existing board action, then promoting the preferences that still live as shared planning policy (repair-first first) into constraints a plan declares - which is what makes the "not enabled means absent from the answer" criterion true. The record names that third step as the one place the proposal is not yet true. Deliberately not done here: no product surface change, no driver, no wake, no new tool or channel.
The proposed record now relates to board governance and capability addressing (2026-09-06), and its
Problem says what that record does not cover: the board's correctness line - reviewable finalize,
authentic content, scope isolation, capability addressing, and the deliver/judge/attempt-fencing slice -
governs how an entry is treated once it exists, not who decides what happens next.
The two records are two halves of one protocol, and reading them together is what makes the
distributed-systems half visible: claimTaskBoardEntry is a single atomic compare-and-set ("lease-based
claiming ... on a losing CAS the failure is diagnosed against a fresh read"), lease expiry is enforced
lazily with no background sweeper - that is a suspecting failure detector, not a death certificate -
attempt fencing exists precisely because a lapsed lease cannot be trusted ("without this, work
reassigned to another agent could still be read through a stale artifact"), and the deliverable/verdict
pair binds an acceptance to an artifact identity. Idempotent acknowledgements and the never-recycled
monotonic identity counter are the other two primitives already in place.
No prose in either record names this, so every discussion of the boundary re-derives it.
…istributed concepts behind them Your read was that part of this is a distributed-systems problem, and reading the legality record together with board governance showed the framing has no home: the governance record is an implemented decision with a fixed format, and the 2026-08-13 document is board mechanics. This adds the inventory as a design document, and the naming record now points at it from its history section. It lists fifteen parts with owner and state: entries and addressing, identity and authenticity, ownership and time, termination integrity, attention and wake, scope and visibility, truth versus coordination state, the task unit, legality and admission, ordering and constraints, budget and accounting, cancellation and fencing, recovery and replay, handoff, and evidence. The task-unit protocol is the complete one, and no single part completes a task: a unit's declaration, ownership and time, termination integrity, attention, legality, budget, truth separation and handoff have to hold at once. It then names seven gaps, each with the concept that fits it rather than a new vocabulary: the adopter has no clause (a commit boundary, and orphan reaping for the restart responsibility), legality has no readable answer (admission control with a read-only precondition check), constraints have no declaration (declarative policy, plus deterministic replay for comparability), read guarantees are unwritten (monotonic reads, read-your-writes, causal consistency across one agent's sessions), disagreement has no arbiter beyond veto and racing a claim (optimistic concurrency with conflict detection, or a plain single-writer decision since one arbiter already exists), cross-run resources have no mutual exclusion (a fenced mutex, not only the slot budget and the throwaway-worktree practice), and in-doubt work has no resolution (an in-doubt transaction: the fact is known, the outcome is not). It also records what is deliberately not needed - consensus, leader election, quorum, two-phase commit, exactly-once delivery, distributed transactions, because truth lives in one store written by one daemon - and three analogies that mislead: a lease expiry is a failure detector's suspicion and not a death certificate, which is why attempt fencing must stay; the board is not a message queue, so re-reading is normal and re-doing is the problem; and agents are not replicas, their independent judgement being exactly why a delivery is recorded with a judge instead of a self-report trusted.
The primitives have names and the program's job is proposed, but the frame itself was undefined: which fields exist, how values are encoded, where they live in the store, and how a peer protocol sits beside the Task-Unit Protocol. Researching the finished specifications changed the shape of the problem - every layer but one is already defined by somebody - so this record chooses and names rather than invents. What it borrows, per layer: CloudEvents 1.0 for the envelope (only id/source/specversion/type required, context attributes inspected without deserializing the event data, lowercase names of at most 20 characters, data reserved); A2A 1.0.0 for the task model (terminal states, contextId, cursor paging chosen explicitly over offsets, historyLength, includeArtifacts false by default); NLIP/ECMA-430 for the payload discriminator and the progressive shape (messagetype/format/subformat/content/submessages/label, the first submessage inlined because most messages carry none, structured with subformat uri carrying a URI instead of bytes); MCP 2025-06-18 for LLM-facing results (content blocks with annotations, structured content beside text, isError so a failure is data); RFC 8941 for a one-line text type system; FIPA-ACL for the act and conversation fields; RFC 6709 for the unknown-field choice; ECMA-434 for the security layer. The one layer nobody defines is ownership, lease, fencing and legality, because every agent protocol assumes a task belongs to one agent. Decisions it records: the frame is a state record and not a message, so FIPA's performative is a rendering of existing columns rather than a column; the header stays in columns because the claim is one atomic compare-and-set UPDATE and a header inside JSON would turn that into read-modify-write; the payload is one opaque document, with the invariant that every payload can be NULL and T0/T1 still render while claim, wake, expiry and compact read still work (verified on the store's SQLite 3.53.3); a payload field a protocol wants to query is indexed by a generated column plus an expression index rather than a new board column, which is what keeps the schema from growing with the number of protocols; the protocol is a value with a version, a peer protocol supplies declaration validation, legality, projection and acceptance, and it plugs into the existing DispatchBoard and RoundQueryPort rather than into the board; unknown protocol means readable and not actionable, and unknown fields are decided by the protocol's own version rule, stated rather than assumed. Data format, in three separate questions: JSON on the existing RPC wire (protobuf-as-normative-source is not worth it with one binding); flat key/value for T0/T1 and natural language for negotiation, because format restrictions measurably degrade reasoning and escaping is a failure source, with tool schemas shaped for strict mode (additionalProperties false, every property required, absence as nullable); typed columns plus one JSON payload document in the store. TOON and CBOR are deliberately not adopted: TOON's saving applies to flat uniform data pushed into context, which is what pointer-first avoids, and CBOR waits for a transport with a bandwidth constraint. Security is the layer that is empty. ECMA-434 is mandatory for NLIP conformance and its companion guidelines score fifteen threats with prompt injection highest; two rules are adopted as text now (an in-band session token is a session credential and must not reach the model, and a caller's token is never forwarded), and a threat list of our own is owed. The scope ceiling is stated so the change cannot grow: one group of nullable columns, one boundary adapter, one rendering rule, one test. Anything needing a new table, a new tool or a new channel is outside this decision.
…o retractions Four review points, all accepted, plus the code checks behind them. 1. The field mapping was missing, and it changes what the invariant means. The record now carries an existing-to-proposed table: content stays the single source of the entry body (readTaskBoardPreviews projects taskBoardPreview(entry.content) - whitespace collapsed, 200 characters, a memory=<id> body returned verbatim), so "payload NULL still renders T1" is a property of the board's read path and not something the storage format produces by itself; the frozen declaration was never a body, it lives in task_run_manifest and task_run_tasks reached by run_id and task_id, with task_run_facts' own payload column as the precedent; and the proposed payload carries nothing the Task-Unit Protocol needs, so it stays NULL for Task-Unit entries. A rule follows from it: a payload may not restate a field that already has a column or a table, which is how the second task body would appear. 2. "The insertion points already exist" was not true. RoundQueryPort carries two typed reads, cancelled() and accepted(); the dispatch loop fails a claim whose ticket has no patch, so patch work is the only work shape today and a peer protocol must bring its own. The record now says what is reusable material and what is still a plan step, and adds that step: widen the query port or add one beside DispatchBoard. 3. Two storage arguments are withdrawn. Atomicity does not require columns: measured on the store's SQLite 3.53.3, a conditional UPDATE over a JSON payload (WHERE json_extract(payload,'$.state')='open') succeeded once and changed zero rows on the second claim, identical to the column form - so the reason is clarity, direct indexing, CHECK constraints and PRAGMA table_info migration guards. And a generated column is a column, an index is a schema object: peer protocols are not schema-free. What is bought is narrower and still worth it - the added schema is purely additive, belongs to the protocol rather than the board, and no field is stored twice. 4. Three borrowings were applied too widely. source_session_id is provenance, not a credential, so the security rule is now stated as a constraint on what may be added rather than a defence of what exists. The refusal rule now keeps MCP's split: a domain refusal becomes data, a request-level error stays an error - which the dispatch loop already does by separating refused from failure. And the CloudEvents naming constraint is stated as borrowing (lowercase letters and digits; twenty characters recommended), with protocol_version's underscore recorded as a deviation rather than as compliance.
…eded The legality record and the frame record each needed the same sentence and neither stated it: the legality record says what the program does and what it refuses to decide, the frame record says what the core knows and what it never parses. Those are one division seen from the side of the decision and from the side of the data. Because nothing named it, it had to be re-argued every time a field or a rule appeared, and the cost was already visible: "work means a patch" had reached six places, one of them a legality rule written in the kernel's own vocabulary (refuseWidening decides permission closure by reading parent.patch.editable). This record takes Hydra's principle - a kernel provides mechanisms and refuses policy - and states it as two contracts. Mechanism: one claim (compare-and-set, lease, attempt fence), an opaque declaration with a digest, an opaque artifact with a digest, a verdict from someone else, the lifecycle, and the legal set (which units are legal now, in order, cut to the declared slot budget, with a reason per unit). Policy: what a unit's inputs are, the artifact class, how the artifact is judged, how the work runs, its concurrency preconditions, the wording and enablement of legality rules, and who is chosen, who adopts, who judges. It also supplies the two things the slogan lacked. A decision procedure - for each field, type and code path, ask mechanism or policy, with a rule's check counting as mechanism while its name, wording and enablement count as policy. And a mechanically checkable rule: no policy word may appear in the mechanism layer's code, type declarations or schema paths, from a maintained list (patch, editable, files, instruction, checks, repair-first), with the path carried because a word can be policy in one place and mechanism in another. The consequence for work shapes is stated: a work shape is not a core concept, it is the policy layer's name for the declaration-and-artifact pair the core carries opaquely. The six leak sites are classified in a table, and the legality rule found today is the refinement the record adds - its check belongs to the program while permission closure's name and enablement belong to a declaration, so the fix is not to move the check out of the program but to stop hard-wiring the rule in the kernel's vocabulary. That is the same shape as plan step 3 of the legality record, where repair-first becomes a declared constraint instead of shared planning policy; two independent fixes taking the same shape is the evidence that the classification is right. Three rows are deliberately left undecided so that they are not settled by preference: task_run_tasks.effect is mechanism only if the mechanism must enforce write-set disjointness, the granularity of input and dependencies is a separate question from whether dependencies are mechanism, and operation may be policy. Alternatives rejected: keeping the slogan and deciding case by case, putting the principle in either record (it is wider than both), a plugin registry above the core with no second policy to justify it, and deciding the undecided rows now. Risks named: gutting the core (so the practical form is one default policy the core may carry but must not require), an ossifying word list, an undecided row becoming permanent, a policy word legitimately remaining for a release, and grep being gameable by synonyms. The legality record and the frame record now point here, so the division has one home.
… earns a place Records the model that came out of the last exchange as a draft rather than as a record, because it was reached by stacking analogies and nothing about it has been measured. The model: a drawing pipeline has four stages and so does ours - producer (a work-shape adapter), surface (the board entry: payload plus a discriminator and a digest, delivery as commit, resolve and expiry as release, wake as the frame callback), compositor (the board and the program: claim, lease, fence, serial and wake, expiry and reaping, the legal set), and display (the presentation end: tiers, flat lines, compact read, the tool descriptions an agent reads). From it come three ownership classes: content and semantics belong to the owner and are semantically opaque to the middle (a compositor reads pixels but cannot read what a button means, so it asks the owner; our board reads declared structure and never payload semantics); description is the owner's obligation (geometry, level, shape, dirty regions, terminal state, identity, a snapshot able to stand in for the owner - ours is the discriminator, digest, dependencies, scope, and the protocol's projection); and arbitration is only the middle's, because stacking, occlusion, visibility, focus, capture, timing and reaping are global properties. The boundary test that replaces a slogan: no reasoning needed means the object stays opaque; structure needed means the owner supplies a description and the middle reads the description but not the semantics; a global judgement means only the middle can make it, which is why the description must be cheap and fresh and why staleness needs a meaning. The document also carries its own case against itself: the analogies did the reasoning and were each partly overruled by a fuller view, one of the four stages is a name with no seam or owner or test, the only measurable claim in this arc (that the seam was narrow) was falsified by a grep within a minute, and nothing got smaller - no code changed, no concept removed, three prose records added. So it states an eligibility rule - an analogy earns a place in a record only when a check can falsify it - and records its predictions before measuring: (a) policy words in the middle, predicted at fifteen or more hits concentrated in the board and the legality module; (b) the two ends, predicted to be concentrated and separable at the producer end and scattered with no seam at the presentation end; (c) a second shape through the dispatch loop, predicted to change five or more files. The reduction test is named in advance too: less code (the middle must lose a type and a freeze method, or the model failed), fewer concepts (the three classes must absorb the two lists they replace rather than sit beside them), fewer change points (measured by how many places a new shape touches), and better maintainability (a new shape adds files under one owner and changes no test in the middle).
…he counting exposed Both checks were run against the prediction recorded before them. (a) Policy words in the middle: predicted fifteen or more hits, measured 195 raw - patch 106, files 39, checks 23, editable 14, instruction 12, repair-first 1 - concentrated exactly where predicted, in src/integration/ooo-board.ts (53 patch hits), src/integration/task-semantics.ts (27 patch, 9 editable) and src/core/store/base.ts (13 patch). Two corrections forced by the measurement. The raw count overstates the case, which is the caveat the check was written with: files in src/core/store/writes.ts and retrieval.ts is a mechanism word (a path inside a store) and checks in src/integration/ooo-candidate.ts names the check runner, also mechanism, so the word list drops files and checks and keeps patch, editable and instruction. What is left is still about 120 hits, so "the middle is policy-free" is false as a description of today, an order of magnitude past the prediction, and the model's support is directional: the leak is real, large and concentrated in three files. (b) The two ends: the producer end was predicted concentrated and separable and measured four to six functions over three files (preparePatchWork, patchPrompt, patchCandidate, patchSubmission, snapshotText, runTestFile); the presentation end was predicted scattered with no seam and measured six sites (the preview text, the entry and preview types, the wire shape, the service, the agent-facing renderer, and the generated tool descriptions). Both held. The measurement also corrected this document: the display row claimed T0-T3 tiers, and no such thing exists for a board entry - tieredDisclosure and tier belong to memory retrieval, and a board entry has exactly one presentation, the 200-character preview plus raw fields. That row now says what exists, so the second borrowed vocabulary is recorded rather than left in the table. (c) A second shape is not run yet, and the reduction test is unchanged: nothing has got smaller, the middle's three files hold the available reduction, and whether it pays is what (c) measures. The counting earned its keep twice - it produced the word-and-path rule the earlier prose could not state, and it caught this document borrowing the memory side's vocabulary as if it were the board's.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
A naming decision, so the main line can be discussed without re-deriving what it means each time.
Two levels, one meaning each:
protocol, while the mechanics of that coordination stay with the program rather than the model's
discussion.
dependencies, acceptance, capability, budget), and the protocol fixes how it is adopted into one
run, claimed, delivered and independently judged, and which facts the runtime decides and owns.
The parts keep the names they already have: Task Board is the sub-protocol's surface, managed
entry is what a governed entry is, run is the frozen object, adopt is the binding
transition, and the caller that decides to adopt is called the adopter.
Why these words
Everything that came to hand was already taken, and each collision is recorded as considered and
rejected rather than quietly reused: fusion already names one mechanism (several units sharing a
session), a scheduler is what the task-unit semantics decision deliberately does not enable,
governance is the board addressing and readability line, ledger already names three things
(assumptions, budget, disclosure), and executor names the bounded context adapters and the Pi SDK
execution path.
What it deliberately does not do
run,adopt,managed,dispatch, theooo-prefix andevery path stay as they are, because the term and the paths are cited by dated measurement records
and frozen run archives.
docs/glossary.yamlis untouched: it owns the repository and process vocabulary, and these areproduct concepts, which live in the concept map.
the shared dispatch loop); the product path still has no adopter, which is the next piece of work
rather than a consequence of the name.
Verification
npm run docs:check: 278 files, 0 errors, 0 warnings (58 implemented decisions).npm run glossary:check: 14 terms, 0 errors (unchanged).Follow-up to #70 (already merged). This branch was cut from
mainata9f56759, so it carries onecommit.
Added in the same branch
The naming record now carries an index section: one line of meaning and a pointer per name,
covering both levels, the board verbs and the channel rules, the run and its facts, the legal action
set and the dispatch loop, plus the two words deliberately not used (scheduler, OoO) with the owner
of their real meaning. It says of itself that it is an index rather than a second specification and
that the owner wins on any disagreement; the definitions were previously only reachable by opening
the design, the obligations ledger and several decision records at once.
The concept map's Task Board row pointed at an anchor that does not exist in
memory-graphs.md(
#21-task-board-outside-the-three-memory-graphs).docs:checkvalidates that a link's fileexists, not its anchor, so the link read as working; it now names the heading that is really there,
in both languages.
The naming record also carries the conceptual history now, because the names only make sense in
order: the board becoming a protocol (2026-08-13), governance and addressing (09-06), out-of-order
execution borrowed from the CPU with its limits written down (09-09..09-11), the task unit's
semantics (09-13), the paid arms measuring both borrowed halves (09-18..09-19), and the board
absorbing the execution half (through 09-20). Commit-level lineage stays in
implementation-lineage.md.Corrected while writing it:
ooo-execution-bootstrap.mdstill said the speculation decision wasproposed and that the no-speculation rule held until it was implemented. It has been implemented
since 2026-09-11; the sentence now states what is actually in force.
Adds a proposed record for the question the naming decision unblocked:
docs/decisions/proposed/2026-09-20-the-program-answers-legality.md(+ zh). The primitives have names andthe shared layer already computes the legal set, but nothing stated whose decision each step is. The record
gives the program exactly one share (answer legality: the ordered legal set, cut to the declared slot budget,
with a reason per unit - choosing nobody, adopting nothing, judging nothing, waking nobody), leaves the plan,
the order, the adopter and the judge to the agents as board facts, makes constraints named by the protocol and
enabled by the plan, and keeps the query free of state because a published handoff occupies a serial slot. It
is proposed, not implemented: the readable answer and the promotion of repair-first out of shared planning
policy are its plan steps 2 and 3.
Adds the umbrella's parts inventory as a design document:
docs/design/protocol-governed-collaboration.md(+ zh), and points the naming record's history section atit. Fifteen parts with owner and state (entries/addressing, identity, ownership/time, termination integrity,
attention, scope, truth vs coordination state, the task unit, legality, ordering, budget, cancellation,
recovery, handoff, evidence), seven gaps with the distributed-systems concept that fits each (commit boundary,
orphan reaping, admission control, declarative policy, monotonic reads, conflict detection, fenced mutex,
in-doubt transaction), what is deliberately not needed (consensus, leader election, quorum, 2PC, exactly-once,
distributed transactions), and three analogies that mislead (a lease is a suspicion, not a death certificate;
the board is not a queue; agents are not replicas).
Adds a second proposed record, the frame itself:
docs/decisions/proposed/2026-09-21-the-frame-and-its-storage.md(+ zh). The primitives have names and theprogram's job is proposed, but nothing said which fields the frame has, how values are encoded, where they
live in the store, or how a peer protocol sits beside the Task-Unit Protocol. Researching the finished
specifications changed the shape of the problem: every layer but one is already defined by somebody, so the
record chooses and names instead of inventing. It borrows per layer (CloudEvents for the envelope, A2A for the
task model and paging, NLIP/ECMA-430 for the payload discriminator and the progressive shape, MCP for
LLM-facing results and errors, RFC 8941 for a one-line text type system, FIPA-ACL for the act and threading
fields, RFC 6709 for the unknown-field choice, ECMA-434 for security) and states that the one layer nobody
defines is ownership, lease, fencing and legality, because every agent protocol assumes a task belongs to one
agent. Three decisions carry it: the frame is a state record rather than a message, so FIPA's
performativeis a rendering of existing columns; the header stays in columns because the claim is one atomic
compare-and-set
UPDATEand a header inside JSON would turn that into read-modify-write; and the payload isone opaque document whose invariant is that every payload can be NULL while T0/T1 still render and claim,
wake, expiry and compact read still work. A payload field a protocol wants to query is indexed by a generated
column plus an expression index instead of a new board column, which is what keeps the schema from growing
with the number of protocols; the protocol is a versioned value and a peer protocol supplies declaration
validation, legality, projection and acceptance through the existing
DispatchBoardandRoundQueryPortseams. Data format is answered as three separate questions (existing JSON RPC wire; flat key/value for T0/T1
with natural language for negotiation, since format restrictions measurably degrade reasoning; typed columns
plus one JSON payload document), and TOON and CBOR are deliberately not adopted. Security is named as the
empty layer, with two rules adopted as text from ECMA-434 and a threat list owed. The record ends with an
explicit scope ceiling so the change cannot grow: one group of nullable columns, one boundary adapter, one
rendering rule, one test - anything needing a new table, tool or channel is outside it.
The frame record answered its first review in a second commit. Four points, all accepted. (1) The field
mapping was missing and it changes what the invariant means: the record now maps every existing field to
its place in the frame, records that
contentstays the single source of the entry body(
readTaskBoardPreviewsprojectstaskBoardPreview(entry.content)), that the frozen declaration wasnever a body (it lives in
task_run_manifest/task_run_tasks), thattask_run_facts.payloadis theprecedent for the payload shape, and that a payload may not restate a field that already has a column -
which is how the second task body would appear. (2) "The insertion points already exist" was false:
RoundQueryPortcarries two typed reads and the dispatch loop requires apatch, so the four-role seamis a plan step, not a fact. (3) Two storage arguments are withdrawn with the measurement that kills them
UPDATEclaims over a JSON payload exactly once, and a generated column is a column, sopeer protocols are not schema-free; what remains is clarity, indexing,
CHECKconstraints, additiveprotocol-owned schema, and no field stored twice. (4) Three borrowings were too wide:
source_session_idis provenance rather than a credential, the refusal rule keeps MCP's protocol-error/execution-error
split (which the dispatch loop already makes as
refusedversusfailure), and the CloudEvents namingconstraint is stated as borrowing with
protocol_version's underscore recorded as a deviation.Adds a third proposed record that names the division the other two each assumed:
docs/decisions/proposed/2026-09-21-mechanism-not-policy.md(+ zh). The legality record says what the programdoes and refuses to decide; the frame record says what the core knows and never parses; they are one division
seen from the decision side and the data side. The record states it as two contracts (mechanism: one claim with
its lease and fence, an opaque declaration with a digest, an opaque artifact with a digest, a verdict from
someone else, the lifecycle, and the legal set with a reason per unit; policy: inputs, artifact class,
judgement, how the work runs, concurrency preconditions, the wording and enablement of legality rules, and who
is chosen, adopts or judges), adds a decision procedure that settles arguments rather than serving as a slogan
(a rule's check is mechanism, its name and enablement are policy), and adds a mechanically checkable rule: no
policy word may appear in the mechanism layer's code, types or schema paths, from a maintained list, with the
path carried because a word can be policy in one place and mechanism in another. It also states what this makes
of work shapes - a work shape is not a core concept but the policy layer's name for the declaration-and-artifact
pair the core carries opaquely - classifies the six sites where the patch assumption lives, and keeps three rows
deliberately undecided so they are not settled by preference. The legality and frame records now point here.