Decision 0081
0081. A partition that classifies files promises something about processes
Architecture decision record 0081: 0081. A partition that classifies files promises something about processes
Status: accepted. Corrects the boundary ADR-0014 drew and ADR-0010 depends on.
Context
tacid-propose splits this tree in two. Core is everything between the agent and the machine —
the brainstem, the keeper, the protocol, the policy engine, the journal, the health gate — and the
agent cannot file a proposal against it at all: not reviewed, not approved, refused before it is
written down. Mutable is everything else the agent runs, and a machine that has rewritten any of
it is marked, because it is no longer running the code its channel signed.
The list is explicit rather than a rule, and there is a test that every crate is on one side or the other, so a crate cannot become core by nobody noticing.
What there was no test for is the direction of the arrow. And the list did not only fail to check
something — it contradicted the record it implements. ADR-0014 names
core as “tacid-stem, tacid-keeper, tacid-protocol, the health gate”, and PLAN.md §3 says
the same words. The health gate is tacid-doctor. It was on the mutable list.
tacid-keeper is core. It depended on tacid-facts and tacid-doctor, both mutable.
tacid-update and tacid-install are core; both depended on tacid-facts. So three of the twelve
core crates were compiled out of code the agent may rewrite, and the most important of them was the
keeper: the health gate that decides whether an activation stands is tacid-doctor running over
tacid-facts, inside the keeper’s own process.
ADR-0010 says the health gate and automatic rollback cannot be disabled by the agent. Until now that sentence was not true. An agent could have proposed a change to a fact reader — mutable, allowed, and presented to an owner as an improvement to diagnostics — and what it would have changed is what the keeper believes about the machine it is judging. Three concrete consequences, none of which needed anything else to go wrong: the update system decides when a machine may change itself by asking whether this is a quiet moment, and a rewritten reader answers always; the installer lays out a disk from what it detected; and the health gate sees a healthy machine.
The reasoning that put them on the mutable side was about the wrong thing, and it is worth writing
down because it was not silly. tacid doctor is a report a person runs and the agent uses. Facts
are how the agent knows anything about the machine. Both look like the agent’s tools, and
ADR-0028 deliberately made the report and the gate read from one place,
because two implementations of one check is how a gate and a report come to disagree about the same
machine. That decision was right. What it did was carry one implementation across the partition, and
nothing was watching that direction.
Decision
tacid-facts and tacid-doctor are core. The keeper reads the machine through them to decide
whether what it just activated works. That is authority, whatever the code looks like from the
agent’s side.
A test asserts the arrow. No crate on the core list may name a crate on the mutable list in its manifest. A list cannot notice a dependency; this is what notices.
The cost is stated rather than absorbed. The agent can no longer propose a new fact reader or a new doctor check. Growing those is one of the ways hardware support grows, and this closes it. The answer is the one ADR-0073 already found for hardware modules — a door of fixed shape, through which a description passes rather than code — or the maintainer’s own hand. Neither is built, and until one is, a machine that learns something about its own body can say so and cannot teach the check that would find it.
Consequences
- Core is fourteen crates and mutable is nine.
- Three dependencies that crossed the line no longer do, because the line moved rather than the dependencies: duplicating the fact readers to keep the keeper away from them would have been two implementations of one question, which is the failure ADR-0076 is about.
- A proposal touching
crates/tacid-facts/orcrates/tacid-doctor/is now refused outright rather than queued. Any that were queued are refused on the next look, which is the correct outcome and will read as a regression to whoever queued one. - ADR-0010’s sentence about the health gate is true now. It should be read as having been aspirational before today.
Alternatives rejected
Leave it, and rely on the self-built mark. A machine that rebuilt itself is marked and cannot
claim stable, so the owner can see that something changed. That is a notice, not a boundary: it
tells the owner after the machine has been running the agent’s health gate, and it says “this
machine is self-built” rather than “the thing that judges your activations is no longer the thing
your channel signed”.
Give the keeper its own fact readers. Then facts stay mutable and the keeper reads the machine
itself. It is two implementations of one question — the one arrangement in which the report and the
gate quietly come to disagree — and it is a great deal of duplicated code that reads /proc and
/sys, each copy with its own edge cases.
Split each crate: a core half the keeper links and a mutable half the agent may improve. The honest version of this is where it will end up if the door below is built. Done today it would put the seam in the wrong place: the interesting checks are the ones the gate runs, so the core half would be nearly all of it, and the mutable half would be formatting.
A door of fixed shape now, so the agent may still add checks. The right answer and not this change. It wants its own design — what a check may express, what it may read, and how a machine proves a proposed one is not a way to make the gate say yes — and shipping a partition fix behind that design would leave the hole open while the design was argued about.