DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path change-requests/loomworks-source-identification-scoping-note-v0_2.md

Loomworks Source Identification — Scoping Note v0.2

Version. 0.2 Date. 2026-05-29 Status. Scoping note, decisions resolved. Orientation-first. Frames the source-identification work (Memory-completion item C), states what is settled, and records the Operator's resolution of the five open decisions (D1–D5, §8). The next artifact is the Change Request. Construction detail (build steps, exact migrations) is deferred to the CR. Provenance. Claude.ai session 2026-05-29, grounded in: the roles design documents (person-layer discovery, Phase 14 CR), live substrate code read by Claude Code (ActorRef, conversation_turns write path, append_event), and loomworks-foray-integration-grounding-investigation-v0_1 (the live dunin7-foray SDK contract). Operator: Marvin Percival. Companion to. loomworks-foray-integration-grounding-investigation-v0_1 (the FORAY facts this note references rather than re-derives); the architecture specification v0.4; the Loomworks candidate seed v0.9; queued-directions §15.3. Format note. Markdown-primary; HTML companion pending (no Markdown-to-HTML render specialist yet — queued-directions §3.3).


Plain-language summary

What this document does. It scopes source identification — making Loomworks Memory reliably record who or what asserted each piece of knowledge, and under what authority — as the first piece of the Memory-completion arc. It frames the problem against the real current code, names the one structural decision already made (unify provenance onto the existing ActorRef model), and surfaces the decisions still open for the Operator.

Why it matters. Memory is the foundation; everything derived from it (Manifestation, Shaping, Rendering, and any downstream AI or external use) inherits whatever Memory records. Today Memory records source two different ways — richly for assertions, crudely for conversation — and the surface discards what the substrate knows. If Memory cannot give one honest answer to "who asserted this," every derived artifact carries that ambiguity. This work closes that gap and lays the data foundation for FORAY attestation.

What changed in understanding since the work was named. Reading the live code (not summaries) established that the unification is smaller and safer than expected: the conversation-turn provenance path is one table, one writer, two call sites, and references no actor model today — so the change is additive (introduce an actor representation where none exists), not a refactor of competing logic.

What the Operator decided. All five decisions (D1–D5, §8) are resolved on the defaults: honest name+designation labels; first pass covers conversation_turns only (seed-conversation surface deferred); domain_expert gets a recognized-expertise marker but no workflow; FORAY-completeness at option (a) (data complete + seam-marked, no SDK dependency); the conversation path adopts the companion ActorRef kind. In and out of scope are stated. No construction is committed by this note — the Change Request is next.


1. The problem, in plain terms

Every piece of knowledge in Loomworks came from someone or something. Memory should always be able to answer: who put this here, and under what authority. Four source-kinds matter: Operator (the principal, governance authority), Contributor (invited participant), Domain Expert (recognized expertise), and AI (the Companion, or an automated agent).

Memory records source in two different places, two different ways:

Three consequences, all confirmed in live code:

  1. The AI has no distinct identity in conversation. A companion (AI) turn is written with the Operator's own person_id and distinguished only by role="companion". The substrate's ActorRef already has a companion kind built for exactly this (declared Phase 41) — the conversation path simply never adopted it.
  2. The surface discards what the substrate knows. Both the Operator Layer composer surfaces (CenterPane, ChatView) build the author label only from role. A Contributor's turn renders under the signed-in person's name with the "(Operator)" suffix. There is no code path by which a Contributor-vs-Operator distinction reaches the label — the architecture spec §13 names this exactly.
  3. domain_expert is built but inert. It is a valid designation, placeable as a membership row, but no code derives authority or behavior from it.

2. What is already settled (do not relitigate)

These are established by the roles design documents and confirmed in live code; the work builds on them, it does not revisit them.

3. The decision already made: unify onto ActorRef

The Operator chose, after weighing the alternative, to unify the conversation-turn provenance scheme onto ActorRef rather than apply a surface-only label fix. The reasoning, preserved per discovery-record discipline:

4. What unification actually takes (grounded in live code)

The conversation-turn provenance path is small, self-contained, and references no actor model today — so unification is additive, not a refactor:

This means the change is bounded: introduce an actor representation on the conversation-turn write path (so a companion turn is recorded as the companion kind with its own identity, an Operator turn as person, a Contributor turn as person/contributor with the contributing membership's designation available), and carry it through to the read view and the surface label. The risk is the ordinary risk of touching a Memory write path (treat it as such — stepped, tested against production-session behavior), not the larger risk of unwinding entangled logic.

5. FORAY-completeness — the data requirement (not an integration)

This work makes the source record FORAY-complete and seam-marked, per the grounding note's option (a). It does not integrate FORAY, take a dependency on dunin7-foray, or construct FORAY JSON. The principle: Loomworks is the system of record; the data a future FORAY reflection needs must be present and durable at every source-and-commit point, derivable at any time including retroactively.

Against the real dunin7-foray SDK contract (grounding note §3), "complete" means modest: the SDK's actor surface is a single triggeredBy string and an opaque payload. So Loomworks must hold, natively and durably, enough to derive at emit time: (a) a canonical actor string, and (b) a structured actor object for the payload. The ActorRef already carries most of this; the gap to check during the CR is per-field — for each thing a future attestation would want (actor identity and kind; the authority/mandate, including model version and system-prompt hash for AI; the act — contribute vs commit; the subject — which assertion; the timestamp), name where the Loomworks-native datum lives or flag it as a capture gap.

Two structural facts from the grounding note shape this:

The reserved-location seam already exists on the memory_events path (_foray_reserved_emit). The conversation-turn path, once unified, should carry the equivalent seam so both Memory-population paths are seam-marked.

6. The four source-kinds — status and what this work does to each

| Source-kind | Substrate today | What this work does | |---|---|---| | Operator | Built; operator designation gates authority; written as person ActorRef kind on the assertion path. | Carry through to conversation-turn provenance and surface label honestly. | | Contributor | Built; contributor designation; distinguished from Operator at the membership level. | Close the surface gap — a Contributor's turn must not render as the Operator. This is the heart of the spec §13 fix. | | Domain Expert | Designation exists; inert (no code derives meaning). | Give it a provenance meaning at minimum (a recognized-expertise marker on the source record). The full recognition flow is out of scope (§7). | | AI | Two ActorRef kinds — agent (bearer-token agents) and companion (the conversational AI). companion is declared but unused on the conversation path. | Adopt companion on the conversation-turn path so AI turns carry distinct identity, not the Operator's. Respect and surface AI-cannot-commit. |

7. In scope / out of scope

In scope (this work):

Out of scope (named, deferred):

8. Resolved decisions (D1–D5)

All five resolved on the defaults (Operator, 2026-05-29). Each records the resolution and the reasoning, so the CR proceeds on settled answers and the trajectory is preserved.

D1 — Surface labeling depth. RESOLVED: honest name + designation. When a Contributor's turn renders, show the contributor's name and designation (e.g. "Jane (Contributor)" / "Jane (Domain Expert)"); AI turns marked as the Companion. Minimal, honest, matches "only show what is available."

D2 — Does unification cover the seed-conversation turn surface? RESOLVED: no. First pass covers conversation_turns only. seed_conversation.py (the candidate-engagement event-log turn path, _append_operator_turn/_append_companion_turn) is a separate mechanism; bringing it into the unified model is a later, separate step. (The Operator was explicitly offered the wider scope — both turn surfaces at once — and chose the tighter first pass.)

D3 — What does domain_expert mean in the source record (first pass)? RESOLVED: recognized-expertise marker, no workflow. A marker carried on the source record / surface label when the contributing membership holds the domain_expert designation — no authority change, no new workflow. The recognition flow stays deferred.

D4 — FORAY-completeness depth. RESOLVED: option (a). Data complete and seam-marked, no dunin7-foray dependency, verified per-field against the grounding note's SDK contract. (Option (b), a thin mapping stub, was set aside to avoid touching dunin7-foray before the integration phase.)

D5 — AI source-kind granularity. RESOLVED: conversation path uses companion. The conversational AI is recorded as the companion ActorRef kind; agent remains the bearer-token path on the assertion side. Surface labels show both as the Companion to the Operator (plain-terms), with the kind distinction preserved in the substrate.

9. What this work does not provide (honest boundary)

Source identification plus FORAY-completeness gives accountability and tamper-evidence — who asserted what, under what authority, unaltered, with a chain through to commit. It does not give correctness (that a claim is true) or competence (that the source was qualified). This boundary should be stated wherever the foundation's value is described, so it is not overclaimed.

10. Next step

The decisions are resolved; the next artifact is the source-identification Change Request: the construction decisions, the migration shape for the conversation-turn actor representation (matching append_event's pattern — three denormalized actor columns plus provenance JSONB, not a column per ActorRef field), the surface-label wiring, the per-field FORAY-completeness checklist against the SDK contract, the reserved-location seam on the conversation path (mirroring _foray_reserved_emit on memory_events), the held-then-commit chain representation, and the stepped build plan with the conversation-turn write path treated as a Memory write path (production-session-mirroring tests, not just green suite).


Changelog

v0.1 (2026-05-29). Initial scoping note for source identification (Memory-completion item C). Frames the problem against live code, records the unify-onto-ActorRef decision and the set-aside surface-fix alternative, states in/out of scope, and surfaces D1–D5 for the Operator. Grounded in the roles design documents, live substrate reads, and the FORAY integration grounding note.

v0.2 (2026-05-29). Records the Operator's resolution of D1–D5 (all on the defaults; the wider D2 scope was explicitly offered and the tighter first pass chosen). Updates the summary, §8, and the next-step section accordingly. Adds two CR-level construction pointers confirmed by live-code reading (the partial-denormalization pattern; the _foray_reserved_emit seam precedent). No change to problem framing, the unification decision, or scope boundaries.


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks Source Identification — Scoping Note — v0.2 — 2026-05-29