Version. 0.1
Date. 2026-07-31
Inspection by. Claude Code on DUNIN7-M4, reported inline. Written up by Claude.ai.
Operator. Marvin Percival.
Brief. inspection-briefs/loomworks-b25-sizing-sweeps-inspection-brief-v0_1.
Environment. Engine main a317051, working tree clean except an unstaged lockfile. Read-only throughout; no branch, no commit, no database connection.
Status. Sizes build-list item B-25. Four Operator rulings recorded at §6, all settled 2026-07-31.
Eleven sites can write a value into the permanent record that is plausible and wrong. The walk audit's framing was three. It found one of three instances of the same construction in one file, and missed a category of five entirely.
And eighty-three more, in a class neither sweep anticipated, which is a single structural defect in one field rather than eighty-three separate faults. It is now its own build-list item (B-29) rather than part of B-25 — ruling 2 at §6.
| # | Sweep | Site | Writes today | True value |
|---|---|---|---|---|
| 1 | A | api/routers/engagements.py:285 | Actor with a generated identifier, as the draft seed's author | The authenticated person, in scope and used two lines earlier for the created-by field, then discarded |
| 2 | A | api/routers/engagements.py:347 | Same construction, as the amend author | The principal the creator-assertion just resolved |
| 3 | A | api/routers/engagements.py:392 | Same construction, as the induction author | Same |
| 4 | A+B | api/routers/considerations.py:195 | Coalesces the client's agent identifier against a generated one, kind agent | The agent the client named. An explicit null yields a fresh agent identity per call, stamped onto the summary and the event |
| 5 | A | api/routers/seed_commit_from_brief.py:271 | Kind contributor, carrying the person identifier | Kind person — this is the session-cookie path |
| 6 | A | api/routers/me_create_engagement.py:393 | Same | Same |
| 7 | A | api/routers/me_create_engagement.py:728 | Same | Same |
| 8 | A | api/routers/seed_extraction.py:246 | Same | Same |
| 9 | A | api/routers/seed_extraction.py:283 | Same | Same |
| 10 | A (W-6) | orchestration/router.py:359, :3292, orchestration/routers/converse.py:1378 against api/deps.py:1176 | Spoken door writes kind companion with the companion name; typed door writes kind person with the person's own name. Same person identifier on both | One of the two, consistently |
| 11 | B | orchestration/routers/converse.py:690 | Coalesces the request's project field against the last-viewed engagement | Empty, when the client sent an explicit null |
None of the first nine is detectable from any surface. Site 10 is — the two records read differently, which is how the walk audit found it. Site 11 is not.
On sites 5 through 9. memory/base.py:69-81 is explicit: contributor means a human acting through a registered Contributor row on the bearer-token path; person means a Person acting via the session-cookie path, and the two are distinct so that the actor record carries the authentication path the action was taken through. All five are cookie-authenticated routes stamping contributor. On the engine's own terms the record asserts a bearer-token row that does not exist. Ruling 1 at §6 settles these as real findings rather than acceptable shorthand.
On site 11. The field is legitimately nullable. The engine's own comments describe a project-less creation scope in which an empty engagement identifier is the correct value. The distinguishing test passes.
On site 10. Compounded at engagement/assertions.py:404, which hardcodes the companion name rather than reading the per-person preference, with an in-code note explaining the round trip it was avoiding.
compositions.py:73 is not a record write. It sits inside the response shaper. The record keeps the true triggering kind and the projector writes it verbatim (memory/projector.py:264). The response schema admits only contributor and agent, so a Companion-triggered composition is relabelled on the way out. The same coercion appears again at :289.
The record is honest and the surface lies about it. That is the governing rule's subject, not B-25's. Ruling 3 at §6 moves it to the engine-side rider (CR-B) in the completion arc.
Corrections preserved. Build list v0.7 named this as one of three record-write sites — "work the Companion triggers is recorded as a contributor's". That position is superseded: it is displayed as a contributor's, not recorded as one. Manifest v0.76 §5 had it more accurately, filing it under the surface class as active wrongness rather than silence, which is what it turns out to be. Where the two documents diverged, the manifest was right.
api/routers/considerations.py:111, called at :534. The escalation recipient's actor is taken wholesale from the request body — kind, identifier and version all client-supplied — and written through without validation that the actor exists or that the kind matches the identifier. Turns on: is the escalation recipient an assertion about a party, which is the client's to make, or a reference to a party, which is the engine's to resolve?
api/routers/seed_conversation.py:116. The seed-conversation Companion writes as kind agent under a stable sentinel rather than kind companion. Turns on: whether this Companion is person-bound. Kind companion requires the identifier to carry the person's own value; this identity is not person-bound, so agent may be correct rather than a mislabel.
Both belong to B-25's change request as open questions at its Step 0, not to this sizing.
provenance.wasGeneratedBy is typed at memory/base.py:147 with its meaning stated in a trailing comment: the memory event id that produced this version. append_event mints its own event identifier internally at memory/events.py:171 and never back-patches the object; the payload is serialised from the object as the caller built it.
Every caller therefore stamps an unrelated generated value.
This is not a convention. persons/personal_engagement.py does it correctly at three sites, threading the real seed, cycle and engagement event identifiers into the field. Three sites prove the field means what its comment says; eighty-three ignore it.
One correction to the inspection's own framing. The report headed this section as gating B-9 and then, in its body, stated the conditional accurately: a walk that follows this field dead-ends. The audit's proven five-hop walk does not touch it — it runs render to shape reference, shape to Manifestation reference and version, to selected memory references, to assertion at version, to attributed contributor. So this does not block the walk that was demonstrated to work. What it does is place a fabricated value in every record, which any provenance surface exposing the field would render with the same confidence as a true one. A design question for the provenance-walk change request, not a hard dependency. Ruling 4 at §6.
Cheap relative to its size. The true value does not exist until the event is appended, so the repair is not eighty-three corrections. It is one seam: either the append accepts the identifier from its caller, or it stamps the field itself before serialising. One change, eighty-three sites healed.
compositions.py:73 moves to the engine-side rider, CR-B in the completion arc. It is a surface defect, and B-25 is about the record.
Actor construction. 65 direct constructions in the source tree, two of them inside the Stele actor module itself, plus 20 call sites of the two Stele constructors. 63 write paths construct an actor without going through actor_from_person or actor_from_companion. Of those: 46 write-safe (documented sentinel system actors, resolver-derived actors, the contributor-helper family across a dozen modules, agent actors bound to real registered identities, and one site that correctly derives kind from the contributor it was given), 5 read-only, 11 write-false, 2 unclear.
Falsy coalescing. Genuinely small: 6 body-attribute coalesces, 6 identifier-variable coalesces, 6 dictionary-lookup coalesces on identifier-shaped keys, 17 attribute-access coalesces. All but two are token counters, carry-forward defaults, or guarded by an explicit empty check immediately after. 33 write-safe, 0 read-only, 2 write-false.
No database was connected to, so this says nothing about how many live records already carry a fabricated author or a turn written into the wrong engagement. That question is real and unanswerable without querying the serving perimeter.
For B-29 the damage is structurally knowable without a query, and the arithmetic runs the other way: every memory object this engine has written outside three sites carries a fabricated value in that field. That makes remediation cheaper, not worse — there is no per-record marking story, because the honest correction is one recorded statement that all objects written before the fix carry a fabricated value there. One marker, not tens of thousands.
For authorship the damage remains per-record and unquantified. It stays surfaced, not folded in.
DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — B-25 sizing sweeps — findings — v0.1 — 2026-07-31 Eleven sites in B-25; eighty-three in B-29; one reclassification out of both.