DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path standing-notes/loomworks-scoping-the-roster-exception-v0_1.md

Loomworks — Scoping Note: The Roster Exception — v0.1

Version: v0.1 Date: 2026-08-24 Status: Scoping note. Names the ruling three notes converge on, and one hard dependency none of them mentions. Rules nothing. Markdown primary. The question: may an agent_identities row be created when an operator declares a Shaping or a render type — or does seeded-never-minted hold without exception? Grounded on: agents/native_agent_roster.py, agents/shaping.py, agents/shaping_bootstrap.py, agents/render_specialist_bootstrap.py, agents/grantability.py read at engine 7136e34; Test 8's trace, 2026-08-24. Converging on this: standing-notes/loomworks-scoping-per-binding-session-minting-v0_2; standing-notes/loomworks-scoping-finding-freeze-alert-v0_1 §6; SR-1 on the seed-ratification list.


Plain-language summary

Loomworks has two registries of agent identity and they do not know about each other.

The roster holds four roles, written into the database at install time. It is the thing sessions are granted against and the thing a freeze acts on.

The per-configuration registers hold an agent for each Shaping and each declared render type — created when an operator declares one, carrying its own id, name, instructions and version. These are the agents that actually do the work.

Test 8 showed what that costs: freezing the roster's rendering identity reported success and the render ran anyway, because the render path never consults the roster at all. The two registries share a word and nothing else.

Three separate pieces of work are now waiting on the same question, which is why this note exists rather than another restatement.

Three ways forward. Let operator-declared identities be created at runtime — one registry, one freeze, one grant path. Or leave the registries separate and teach the governance mechanisms to look in either — no exception needed, two id-spaces forever. Or accept that per-configuration agents are ungoverned and say so plainly.

The dependency nobody has named: runtime creation breaks the frozen startup cache the current design relies on, and that cache is what keeps a hot path synchronous. That is a real cost of the first option and it has not been on the table.


1. What the roster's own reasoning says

The module states its case precisely, and the case has two distinct legs that are worth separating because only one of them survives contact with the question.

Leg one — no runtime minting. A process minting its own governed identity record is authority-shaped and sits against human-only widening (O10, DR-02), so adding a role is a migration — a human act with a review.

Leg two — deterministic ids. A seeded row's UUID is a citation, and a citation that differs per database is not one.

Leg one is about authority. Leg two is about citability. They point the same way for roles and they come apart for per-configuration identities.

A role exists identically in every database, so its id must too — you cite …022701 in a CR and it means the same thing everywhere. An identity belonging to Aldous's coaching-summary Shaping does not exist in another database at all. Its id is already non-portable, because the Shaping is. Leg two does not reach it.

So the exception, if made, is narrower than it first appears: it does not weaken the citability argument, because that argument was never about these.

Leg one is the real question, and it turns on a distinction the module does not make: a process minting its own identity versus a person declaring a thing and the system recording that it exists. The first is authority-shaped. Whether the second is, is the ruling.

2. What the roster already says about this question

The module defers to it explicitly. From its own comment on render specialists:

> NOT on this roster, deliberately … that identity survives restarts, so acceptance 4 already holds for them; but it is per-binding, which a seeded per-role roster cannot express and should not flatten. Whether specialists take agent identities, and at what grain, is a later question.

This is that later question, and the module was right that forcing them onto the roster for tidiness would be wrong.

3. What Test 8 added

The registries are not merely separate — nothing bridges them. All 28 files in the render production path contain zero references to check_grantability, mint_session, require_live_session or resolve_agent_identity. The governance surface has three consumers and rendering is not among them.

And the freeze's success report is not a lie. It set the status and ended the zero sessions it had. It never claimed anything about rendering — the claim was supplied by a shared noun. Any option below has to make the noun mean something or stop implying it does.

One thing to verify before ruling (§7.1): the roster's rendering role, …022702, may have no consumer at all. shaping.py mints under shaping; the bootstrap resolves render_dispatch; seed induction resolves its own. If nothing resolves rendering, the roster contains a role seeded in anticipation of wiring that never happened — and Test 8 froze a row that governs nothing by construction rather than by omission.

4. The dependency nobody has named

The frozen startup cache depends on minting being forbidden.

The roster loads once at startup into an immutable role → UUID map. CC's own words when it landed: a frozen cache is sound only because the ruling forbids runtime minting — that's the concrete win. It is what kept ensure_render_dispatch_agent_for_engagement synchronous and left both call sites in engagement/render.py untouched; resolve-or-mint would have forced a database read into a sync path or made it async.

Option A breaks this. If identities are created when an operator declares something, the cache is stale the moment they are, and it must either be invalidated or abandoned.

And the invalidation problem is already documented. The roster cache is process-local. Test 8's finding: a freeze reloads the roster in the freezing process, not the server's. That is harmless today because nothing consults it — and it would become a correctness bug the moment anything did, one that passes in tests (one process) and fails in production (many).

So Option A's real cost is not a migration. It is that the cache must become correct across processes, which is a different and larger piece of work than creating rows.

5. The options

5a. Runtime creation — the exception is made

An agent_identities row is created when an operator declares a Shaping or a render type.

Gives: one registry. One freeze switch that reaches everything. Per-identity granularity, which is what finding/freeze/alert needs to mean anything. Sessions mintable for every working agent.

Costs: leg one of the roster's reasoning is amended — narrowly, to a person declaring a thing may cause an identity to exist, never a process may mint its own. §4's cache work. And the natural key stops being role alone, so the 2026-08-20 natural-key ruling needs revisiting rather than assuming it extends.

The narrowness is defensible and should be written into the amendment, not left implied: the creating act is a human declaration through a surface, with an actor and a timestamp; the identity is a record that the thing exists, not a grant. Nothing self-registers.

5b. Two registries, resolved in either — no exception

Governance mechanisms learn to resolve an identity in agent_identities or in the per-configuration registers. Freeze writes a status wherever the identity lives.

Gives: seeded-never-minted holds untouched. Per-identity granularity. No cache problem for the roster, which stays exactly as it is.

Costs: two id-spaces permanently, and every governance mechanism — grantability, freeze, sessions, lifecycle rows — must handle both. agent_lifecycle_events.agent_identity_id and agent_sessions.agent_identity_id are foreign keys to agent_identities; either they loosen or a second column appears in both.

Worth noticing: this is the same shape as the ruling already made for actors. CR-2026-234 stopped asking which table does this kind name and started asking does this id name a real one in either space. The consistency argument is real — and so is the caution, because that ruling's cost was that the check no longer verifies kind and id-space agree.

5c. No exception, and say so

Per-configuration agents are ungoverned. The roster governs roles, which today means shaping and seed induction.

Gives: nothing changes. The design stays coherent and small.

Costs: finding/freeze/alert cannot be built — freeze one and alert the class needs a freezable one. The render path stays outside governance permanently, not pending. And the roster's rendering role must be removed or renamed, because a seeded identity that governs nothing while sharing a word with the thing it appears to govern is the misleading part of Test 8, not the ungoverned render path.

5c is not the do-nothing option. Choosing it means deliberately removing an implication, which is work.

6. What any answer must also decide

  1. What does freeze mean? Under 5a and 5b it becomes per-configuration — stop Aldous's coaching-summary agent, leave Warwick's running. Under 5c it stays per-role and platform-wide. SR-1 asks this from the other side and should be answered in the same ruling.
  2. The two identities on one act. produce_shape mints against the shaping role and attributes work to the per-Shaping actor — two ids on the same act, in production, unlabelled. 5a and 5b can remove the ambiguity; 5c must name it instead.
  3. Does shaping's per-Shaping register count as a register at all? Render specialists have render_specialist_binding with a real column. Shaping's agent identity lives on the Shaping's executor block in Memory. 5b requires resolving in it, which means it has to be a place you can look things up — this note has not checked whether it is.
  4. What happens to rendering (§3, §7.1).

7. Before ruling — three things to establish

7.1 Does anything resolve the rendering role? If nothing does, the roster contains an orphan and Test 8 froze a row that governs nothing by construction. Cheap to check and it bears on 5c directly.

7.2 Is the per-Shaping agent identity queryable? §6.3. If the executor block is not indexed or addressable, 5b is more expensive than it looks.

7.3 What would the cache have to become under 5a? §4. Not a design — a size. If cross-process invalidation is large, that is a reason to weigh 5b more heavily, and it should be known before the ruling rather than discovered after it.

8. What this note does not do

It does not choose. It does not amend the SEED ruling or the natural-key ruling. It does not answer SR-1. It does not check §7.1–§7.3 — those are named as prerequisites this note has not met. It does not design the freeze semantics under any option. And it does not treat 5c as costless: removing an implication is work, and the note says which work.


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — Scoping Note: The Roster Exception — v0.1 — 2026-08-24