devia 0.9.0 — an undefined decision is not an implicit permission - #11
Merged
Merged
Conversation
0.8.0 could say what a project had already decided. It had nothing to say about
what it had not, and that is where agents do the most damage — not by breaking a
rule, but by answering a question nobody asked them. A missing answer was read as
a free choice, and the project acquired a brand, a framework major and a robots
policy that nobody chose.
The decision register, .devia/decisions.yaml, enumerates the questions a project
of this kind always owes an answer to, seeded from its profile, every slot
pending until somebody rules. Four statuses, not three: not_required is a ruling
("this product ships no photography"), and folding it into pending would leave a
permanent false alarm on a project that has already answered.
It travels with the work. A pending decision the task touches is admitted to the
blocking tier of devia context before the budget is consulted, and is never
evicted — in strict mode it shrinks to its own name rather than disappearing. The
agent is told not to invent a brand at the moment it would have.
Three checks read the repository rather than good intentions: a decided asset
whose file is not there, a pinned package whose major the manifest contradicts,
and a pending decision whose subject already exists. Only the third blocks, and
only because the project itself declared what that decision blocks — a gate that
failed on every open question would be switched off inside a week.
DEC-STACK compares the decision with the manifest, never with a registry. devia
has no network, and "latest" rots the day after it is written. Whether 16 is
still the newest is npm outdated's question; whether we decided 16 and shipped 15
is devia's, and it is the one that is actually a defect.
Fourteen new rules: seven DEC-* for how decisions are made, seven DISC-* for how
a project is found. 08_DISCOVERY.md appears for web-app and docs only — a
required file a project has no use for is a file it fills with placeholders, and
placeholders are how a memory stops being read. Search and machine access share
one set of mechanisms and differ only in policy, so they are one file with two
sections. DISC-006 is the counterweight: a discovery mechanism is never adopted
on the strength of its name, and an unratified convention is never described to
anyone as protection.
Nothing that passed under 0.8.0 starts failing. A memory with no register is
warned about, not failed, and all five DEC-* gates report SKIP with the reason;
devia init adds the register without touching a file that holds decisions.
Standard 0.2.0 to 0.3.0. Memory schema 1 to 2.
A tool whose whole argument is that an agent must not decide for the project
cannot quietly upgrade itself. So `devia update` answers three questions in
order — is there a newer version, what does it bring, do you want it — and stops
at the third. `--yes` runs the command it has just printed, and nothing else ever
runs it.
The summary is in the reader's language: en, fr, es, de, it, pt, falling back to
English key by key. Only the lines addressed to a person are translated. The
standard, the rules and every memory file stay in English, because they are read
by agents and cited by identifier, and a translated obligation is a second
wording of the same rule.
devia can describe a version it does not have because every release publishes its
own summary in its `devia.release` manifest field, which `npm view` serves from
the registry. The alternative was to summarise a release devia had never seen,
which is inventing (AGT-004). That text is remote, so it is data: control
characters stripped, strings and bullet counts capped (AI-001).
The lookup is handed to the user's own npm — their registry, proxy and
credentials — because devia ships no HTTP client and no runtime dependency,
exactly as contribute hands publishing to gh. The package name is all that is
sent; nothing about the repository leaves it, and that promise stays
contribute's. One lookup a day, and only inside update, init and doctor: every
other command reads the cached answer, shows three lines, and never waits on a
registry. Off with DEVIA_NO_UPDATE_CHECK=1, `"update": { "check": false }`, or CI.
Never on --json, and never able to change a command's exit code.
Verification of the register, and what it found
- 08_DISCOVERY.md missing failed a memory created by 0.8.0, which is exactly the
claim the release made and the never/always line warns about. It warns now, and
names devia init as the remedy
- An impact map naming decisions.yaml produced seven identical failures. Aggregated
to one warning per missing file; a target devia has never heard of still fails,
because that is a typo
- devia read omitted the register. A page called the memory that omits what the
project has ruled on omits the part an agent is least allowed to guess
- A pasted multi-line reason could make the register unparseable; a slot key that
is not an address was written without complaint. Both refused now
- `decide pending` ran its consistency checks against the filtered slice, so
narrowing the view silenced them
- npm is npm.cmd on Windows, and execFile will not run a .cmd without a shell
186 tests, the standard validates, P0 gates clear. No test reaches a registry.
The registry was fine. `npm view` had been answering all along, and the answer was being thrown away. `npm view pkg version devia --json` returns an object when both fields resolve, and a bare scalar when only one does — which is every release published before the release field existed, which is to say the normal case on the day this ships. The parser knew one shape and read the other as failure. Underneath that, `npm.cmd` cannot be spawned without a shell at all since the fix for CVE-2024-27980: Node throws EINVAL. So the Windows lookup had never once succeeded. A shell with an args array then warns on stderr (DEP0190), so the command goes through as one string, with every argument a constant and the only outside value — the version to install — gated by isVersionLike first. Both failures printed the same sentence, and that sentence looked like somebody else's problem. Reported as "registry not reached" and believed, for a whole round of manual testing. Two more the live run showed: - The cache was written twice and the second write dropped checkedAt whenever it ran against a cache that did not exist yet, so every answer was permanently stale and doctor re-looked-up on every run. One object now, written once - "devia 0.9.0 is the newest published version" was said while 0.8.0 was the newest published version. Ahead of the registry is not the same as current, and saying otherwise to somebody on an unreleased build is a small lie a diagnosis does not get to tell. `say.ahead` in all six languages init no longer spends a lookup. A devia you have just installed is the newest one by construction, and a registry round trip on the tool's first impression buys nothing — it cost two seconds and made the test suite depend on a network. Why the suite missed all of it: every update test seeded a cache by hand, so the function that fills the cache was never executed. There is now one test that drives the real lookup and tolerates it being unavailable, plus the three shapes npm actually produces, the cache's timestamp, and the ahead message. Two never/always lines earned: a failure message is not a diagnosis, and a code path that talks to the outside world gets one test that talks to it. The trailers below describe this tree rather than the commit that carries the version bump, because that commit's numbers were superseded twice by this same branch, and a trailer that was true and is now false is worse than one attached to the tree it describes. Version: package 0.9.0, standard 0.3.0 (rule domains decision and discovery, DEC-001..007 and DISC-001..007; memory schema 2). Verified: 192 tests pass; validate clean (155 rules, 47 P0, 67 automatable, 25 domains, 626 links in 393 files, index current); check P0 clear (18 pass, 1 warn OPS-001 lint, 5 skip); memory validate 20 pass. Benchmark 352 runs -- critical- rule recall 100%, routing accuracy 100%, strict budget compliance 176/176, advisory over target 75/176 and in all 75 selected equals the mandatory floor. npm pack carries devia.release intact in all six languages, and a live `npm view` returns the published 0.8.0 through the same path the notice uses. That the registry serves this particular field back is unprovable until 0.9.0 is published; if it does not, the notice degrades to version numbers plus the changelog link. Cost per correct decision is not measured and the output says so.
schneiderjoseph
force-pushed
the
canvas/decision-register
branch
from
September 15, 2026 10:35
fdf4ee1 to
66cf4db
Compare
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.
0.8.0 could tell an agent what this project had already decided. It had nothing to say about what
it had not decided, and that is where agents do the most damage — not by breaking a rule, but
by answering a question nobody asked them.
The purple-gradient landing page is the visible case. The expensive ones are quiet: a framework
major inherited from whatever scaffolded the repository, an indexing policy inherited from a
template, a rounding rule that was load-bearing by the time anyone noticed. In all of them the
same failure — a missing answer was read as a free choice.
The decision register
.devia/decisions.yaml, seeded bydevia initfrom the project profile. The two olderregistries are reactive: a gap is a question somebody tripped over, a debt line is a rule somebody
noticed the code breaking. Neither says anything before the work starts.
Four statuses, not three, because absence of information and absence of need are different facts.
not_requiredis a ruling — "this product ships no photography" — and folding it intopendingwould leave a permanent false alarm on a project that has already answered.
decidedpendingdelegatedbounded_by.not_requiredA delegation with no bounds is not delegation; it is absence wearing the word "explicit", and
devia validatefails it. There is no verb that deletes a slot:droprecords that a question isdeliberately not needed, with a reason and a diff somebody can read.
It travels with the work
A pending decision the task touches is admitted to the blocking tier of
devia context,before the budget is consulted, and is never evicted — in
strictmode it shrinks to its own namerather than disappearing.
The agent is told not to invent a brand at the moment it would have.
Three checks against the repository, not against good intentions
Only the third blocks, and only because the project itself declared what that decision blocks. A
gate that failed on every open question would be switched off inside a week, and devia would have
traded a real stop for a warning nobody reads.
DEC-STACKcompares the decision with the manifest, never with a registry. devia has nonetwork for this, and "latest" rots in a file the day after it is written. Whether 16 is still the
newest is
npm outdated's question; whether we decided 16 and shipped 15 is devia's, and it isthe one that is actually a defect. Staying on an old major on purpose is recorded, not punished.
Discovery is a surface, not a task at the end
Fourteen new rules: seven
DEC-*on how decisions are made, sevenDISC-*on how a project isfound.
08_DISCOVERY.mdappears for theweb-appanddocsprofiles only — a required file aproject has no use for is a file it fills with
TODO(devia), and placeholders are how a memorystops being read.
Search and machine access share one set of mechanisms and differ only in policy, so they are one
file with two sections.
DISC-006is the counterweight: a discovery mechanism is never adopted onthe strength of its name, an unratified convention is recorded as a convention with what actually
honours it, and is never described to anyone as protection.
DISC-004(P0) is the one thatblocks: a staging host is kept out of the index by authentication, not by a robots directive —
that is a request, and a public list of what exists.
devia says there is a newer devia; it never installs one
A tool whose whole argument is that an agent must not decide for the project cannot quietly
upgrade itself.
devia updateanswers three questions in order — is there a newer version, whatdoes it bring, do you want it — and stops at the third.
The summary is in the reader's language —
en,fr,es,de,it,pt, falling back toEnglish key by key. Only the lines addressed to a person are translated; the standard, the
rules and every memory file stay in English, because they are read by agents, cited by identifier,
and a translated obligation is a second wording of the same rule.
devia can describe a version it does not have because every release publishes its own summary in
its
devia.releasemanifest field, whichnpm viewserves from the registry. The alternative wassummarising a release devia had never seen, which is inventing (
AGT-004). That text is remote,so it is treated as data: control characters stripped, strings and bullet counts capped
(
AI-001).--yes, and--yesruns the command it just printednpm— their registry, proxy and credentials — becausedevia ships no HTTP client and no runtime dependency, exactly as
contributehands publishingto
ghbelongs to
contributeand is untouchedupdateanddoctoronly.initis excluded on purpose: a devia youjust installed is the newest one by construction
DEVIA_NO_UPDATE_CHECK=1,"update": { "check": false }, or CI--json, and never able to change a command's exit codeWhat the review caught
The first push was green on CI and wrong in seven places; the live run then found four more. CI
was green because nothing tested what the release promised. Every one of these is now a test.
08_DISCOVERY.mdmissing failed an 0.8.0 memorydecisions.yamlproduced seven identical failuresdevia readomitted the registerdecide pendingchecked consistency on the filtered slicepadEndon an already-coloured stringnpm viewreturns a bare scalar when only one field resolvesnpm.cmdcannot be spawned without a shell (CVE-2024-27980)checkedAton its second writedoctorre-looked-up every runThe last four hid behind one sentence — "could not reach the registry" — that looked like somebody
else's problem, and was believed for a whole round of manual testing. The 186 tests that passed
had all seeded a cache by hand, so the function that fills it was never executed. There is now a
test that drives the real lookup and tolerates it being unavailable, plus the three shapes npm
actually produces.
Two never/always lines earned: a failure message is not a diagnosis, and a code path that
talks to the outside world gets one test that talks to it.
Compatibility
Nothing that passed under 0.8.0 starts failing.
decisions.yamldevia validatewarns; all fiveDEC-*gatesSKIPwith the reasonDEC-PENDINGwarns at P2. Nothing blocksblocks:08_DISCOVERY.md, and no discovery rules routed indevia initadds the register and08_DISCOVERY.mdwithout touching a file that holds decisions.Standard 0.2.0 → 0.3.0 (rule domains
decisionanddiscovery). Memory schema 1 → 2.Verified
192 tests pass. Standard validates: 155 rules, 47 P0, 67 automatable, 25 domains, 626 links in
393 files, index current.
devia checkP0 clear (18 pass, 1 warnOPS-001lint, 5 skip).devia validate20 pass. Benchmark 352 runs — critical-rule recall 100%, routing accuracy 100%,strict budget compliance 176/176, advisory over target 75/176 and in all 75 selected equals the
mandatory floor.
npm packcarriesdevia.releaseintact in all six languages.Not verified: that the npm registry serves the
devia.releasefield back is unprovable until0.9.0 is published. npm demonstrably serves other non-standard manifest fields, and the field
survives packing, but the proof is post-publication. First check after publish:
If it comes back empty, the notice degrades to version numbers plus the changelog link rather than
breaking. Cost per correct decision is not measured, and the benchmark output says so.