v0.8.47 — a domain is a registered section of one project, and the record that owns the scope names it
Added
-
A domain is now a registered SECTION of one project, with an identity of its
own.domainhad been a free-text metadata field with nothing to be unknown
against: a typo and a new section were the same event and both entered the
corpus silently. Migration 028 addsproject_domains— keyed on a surrogate
id, referencingprojects(id)and never a project name, with the section's
label unique only within its project becauseoperationsunder one project
andoperationsunder another are different sections that share a word. Its
alias junctiondomain_aliaseslands in the same migration rather than as a
follow-up, so a retired spelling resolves from the first day the axis exists.Ingress mirrors the project protocol exactly: an unregistered value is refused
400 domain_unknownwith proposals, and the second submission registers it —
behind the same two naming guards a new project faces, because the agent that
sets the flag is the agent that makes the typo. Proposals match a section's
description as well as its name, which is the one real difference from the
project axis: project names are short and typo-shaped, while an operator
reaching for a section may type a word that appears nowhere in its name.The graph gains
(:Fact|:Decision|:Retrospective)-[:DOMAIN_OF]->(:Domain)-[:PROJECT_OF]->(:Project),
written in the existing single outbox round-trip.:DomainandDOMAIN_OFare
spine, pinned in code — an amendment to the frozen-spine decision, made
because the fold gate is intended to read this axis, and a renameable label
would falsifyontology.yaml's own promise that consolidation touches only
spine identifiers. -
Who controls which axis, stated once and enforced. A fact asserts its
own project and domain and mints its own entities. A decision asserts its
own project and domain, and inherits its entities from the facts it grounds
in. A retrospective asserts neither axis — project and domain both come
from the decision it judges, so a verdict is always filed with what it judges
rather than with the later evidence that measured it; one that supplies a
domain is refused400.A decision that names no domain inherits its grounding facts' sections as a
default, never a ceiling. This is the load-bearing part: a decision reaches
further than the fact that prompted it. A fact may observe that agents write to
the graph directly — an infrastructure observation — while the decision it
provokes governs which agents are authorised to write, which is about access
and sits above the infrastructure that prompted it. Capping a decision at its
evidence's sections would file it away from the section that most needs to
surface it. The rule guards itself on the existing provenance stamp: a bare
edge is an assertion, a stamped one is a default, and inheritance declines
wherever an assertion exists. -
--domainon the CLI (repeatable) and onsave_decision, plus the MCP
equivalent. The value is stored verbatim and never split on a separator, since
a separator that can occur inside a value is not a delimiter. The skill
elicits a section only when the record's project already has registered
ones — a project with an empty registry is never prompted, so the first
section in any project stays a deliberate act. -
GET /health→domain_identity, besideproject_identity: registry
versus graph, plusunattached— a section with noPROJECT_OFedge. That
last number exists for a traversal that has not been built yet. Cross-project
and cross-domain synthesis will walk from a section to its project and from a
record to its grounding facts, and a section missing that edge would drop out
of the walk silently, presenting as a quiet corpus rather than an error. -
backfill_domain_of.pyenqueues the historical population through the
outbox, in two modes: a record's own sections, or a re-run of the gateway's own
inheritance query for a judgement that asserted none. The second mode exists so
the rule has a single implementation — a repair that re-derives a rule is a
repair that can disagree with the thing it repairs.
Notes
-
Migration 028 ships schema and nothing else — no seed, no data repair. A
seed on this axis cannot be derived from the data the way the project registry
seeded itself, because the values needing registration are exactly the ones
that must not be registered verbatim. An emptyproject_domainsis the correct
state for a new install: sections arrive through ingress, like projects. -
There is deliberately no name-keyed
:Domainfallback, unlike the project
axis. Losing aPROJECT_OFedge violates an axis that already gates folding,
so that write falls back to a name; nothing gates on domain yet and the value
survives in Postgres either way, so the honest answer to "no identity" is no
edge and a log line. -
Known, unchanged, and named so it is not mistaken for a defect: the
consolidation daemon's internaldomainvariable holds the project, and
community_summaries.metadata->>'domain'stores a project name. Nothing in the
fold path reads a record'smetadata->>'domain', which is why this release
cannot change fold behaviour. Untangling that naming belongs with the release
that moves the fold gate onto these axes.