DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path substrate/cleanup/loomworks-substrate-hygiene-scoping-note-v0_1.md

Loomworks Substrate Hygiene Scoping Note — v0.1

Version: 0.1 Date: 2026-05-24 Author: Marvin Percival (DUNIN7), prepared via Claude.ai Audience: The Operator (Marvin). For review before any CR drafting or build work begins.


What this document is for

This is a scoping document, not a Change Request. Its job is to describe the cleanup work that comes next in plain English, with examples wherever they help you and me confirm we're reading from the same play card.

The cleanup is about getting things out of Loomworks that don't belong, and reserving clean locations for things that will eventually belong but aren't ready yet (FORAY). Once cleanup is done, we look at the current-status manifest together and identify the next core function to work on — which you've indicated will likely focus on Memory construction and maintenance, since memory is what Loomworks is fundamentally about.

If anywhere in this document you read something and think "no, that's not what I meant," that's the value of having this scoping note before any code work. Tell me, and v0.2 absorbs the correction.


What's getting cleaned up, in plain English

There are three things in Loomworks today that are wrong-shaped relative to what we now understand:

1. Tables that pretend to be FORAY internally. Three of them. They were built when we thought Loomworks needed its own FORAY-shaped data structures. We now know Loomworks doesn't need that — FORAY is a separate thing Loomworks will eventually call, like calling a library. The tables exist; they capture data; but the data they capture is in the wrong shape, in the wrong place.

2. Wiring on the memory_events table that was prepared for a FORAY integration that never happened in the form anticipated. Specifically, the readiness columns added in Phase 25. They were preparing for Loomworks to do FORAY's job internally. With the new understanding, that preparation isn't needed.

3. Possibly: anything else that's no longer necessary to support core Loomworks functionality. You said "cleanup anything that is no longer necessary" — so beyond the FORAY-related items, the work includes a sweep for other dead weight. Examples might include the Contributor concept (if it's residual from earlier architecture and no longer used), unused KV stores, orphaned tables, dead code paths. This document scopes the FORAY-specific cleanup precisely and names the sweep as a parallel concern.


The three FORAY-shaped tables — what they are today

Here's a plain-English description of each so we're aligned before any removal happens.

Table 1: credit.foray_action_flows

What it does today: Records every credit transaction — token consumption when a Companion runs, credit grants when an Operator signs up, credit debits at every API call. It's append-only and structured in a FORAY-like shape (events, parties, values).

Why it was built: When the credit substrate (Phase 47/48) shipped, it was designed with FORAY-anchoring in mind. The table tried to be FORAY-correct internally.

What's wrong with it: It's Loomworks pretending to be FORAY. The right pattern is: Loomworks records credit events in its own simple credit-event table, and also calls FORAY when the integration phase opens. Today this table is doing both jobs — Loomworks operational data AND a pretend-FORAY shape — and doing neither cleanly.

What replaces it (after cleanup): A simple Loomworks credit-event table that records what Loomworks actually needs for its own operation (who owes what, balance computation, audit display for the Operator). At the locations where credit events happen, a reserved code location holds the spot where the FORAY call will eventually go.

Example, plain English:

Today, when a Companion turn happens:

After cleanup:

The Operator's experience doesn't change. The credit ledger works. The balance updates. The audit display (when Phase 63 lands) shows the credit history. The FORAY anchoring of those events is deferred until the FORAY integration phase opens.

Table 2: audit.foray_events

What it does today: Records narrative events — primarily setting changes the Operator makes through the Companion. The most recent meaningful work added Companion-setting-changes here (backdrop blur tuning, Companion name changes, etc.).

Why it was built: It was meant to be the catch-all for FORAY-attestable events outside the credit substrate. The naming with foray_ in the schema reflects the original intent.

What's wrong with it: Same pattern as Table 1 — Loomworks pretending to be FORAY internally. The events captured here are real and valuable; the shape and naming are wrong.

What replaces it (after cleanup): A simple Loomworks audit.events table (or similar — drop the foray_ prefix from the name; the table itself isn't FORAY, it's Loomworks audit). It captures the same events with the same fields, just without pretending to be a FORAY substrate. Reserved FORAY locations sit alongside, marking where the eventual FORAY call goes.

Example, plain English:

Today, when an Operator changes the Companion's backdrop blur:

After cleanup:

The Operator can still review setting changes (when there's a UI for it). The audit log works. FORAY anchoring waits.

Table 3: The memory_events Phase 25 readiness wiring

What it does today: Three columns on the memory_events table — _foray_* columns added in Phase 25 — plus an _ANCHOR_PRIORITY registry in code that tags each memory event kind with a priority value ("critical", "high", "standard"). The columns are populated when memory events fire; the _ANCHOR_PRIORITY registry decides which events get the FORAY-anchoring metadata.

Why it was built: Phase 25 was preparing memory_events to support FORAY anchoring of memory commits. The wiring was added in anticipation of an integration that never happened in the anticipated form.

What's wrong with it: The columns serve no current purpose. They consume row width on every memory event. The _ANCHOR_PRIORITY registry is a real design artifact (it captures which events Loomworks considers important enough to anchor) but it's currently feeding data into nowhere.

What replaces it (after cleanup): The _foray_* columns are removed. The _ANCHOR_PRIORITY registry stays — possibly renamed (_FORAY_INTEGRATION_PRIORITY or similar) — because it captures real design intent about which memory events deserve eventual FORAY anchoring. Reserved code locations replace the column-writes with markers for the eventual ForayClient.emit(...) call.

Example, plain English:

Today, when an assertion is committed:

After cleanup:

Memory continues to work exactly as today. The information about which events are FORAY-worthy is preserved. The mechanical wiring is cleaned up.


What "reserved code location" looks like

You said to use the most logical approach since CC and I will be responsible for both finding the locations and implementing FORAY eventually. I'll propose a structural pattern; this is the part where examples matter most because the pattern needs to be findable in six months when integration time arrives.

The proposal: Each reserved location is three things together, so it's both findable and useful:

  1. A clearly-named function call, even though the function does nothing today. Naming example: _foray_reserved_emit(event_kind, payload). The leading underscore says "this is internal plumbing." The _reserved says "this is a placeholder for future integration." The function exists in one place in the codebase and is called from every integration location.
  1. The function body is a no-op today. It accepts the arguments, does nothing with them, returns. When FORAY integration opens, this function becomes a real ForayClient.emit() call and every reserved location goes live in one wire-in.
  1. A consistent comment marker at every call site. Something like # FORAY_RESERVED_LOCATION: <event_kind>. This makes the locations grep-able. Anyone — me, you, CC, a future contributor — can find every FORAY integration point with one search.

Plain-English example of what code looks like at an integration location:

Today (wrong-pattern):


# In credit.flows or wherever the credit event happens
flow_row = ForayActionFlow(
    transaction_id=...,
    parties=...,
    arrangement_ref=...,
    # ... FORAY-shaped fields ...
)
session.add(flow_row)

After cleanup (reserved location):


# In credit.flows or wherever the credit event happens
event = CreditEvent(
    event_kind="token_consumption",
    person_id=person.id,
    amount_cents=cost_cents,
    asset_id=asset_id,
    occurred_at=now(),
    rationale="Companion turn",
)
session.add(event)

# FORAY_RESERVED_LOCATION: credit.token_consumption
_foray_reserved_emit("credit.token_consumption", {
    "person_id_hash": hash_person(person.id),
    "amount_cents": cost_cents,
    "asset_id": asset_id,
    "occurred_at": now().isoformat(),
})

The credit event is written to Loomworks' own data store in clean Loomworks shape. The reserved call is sitting right next to it, ready for the day FORAY integration opens. When that day arrives, _foray_reserved_emit becomes a real ForayClient.emit() and every location goes live together.

Why this shape:

If this pattern doesn't feel right to you, tell me. The alternatives are real (interface classes, decorator patterns, separate stub modules) and any of them could work. The proposed shape is what I think is most logical for finding-and-eventually-implementing, but you have visibility into Loomworks' actual code style that I don't.


The cleanup, end to end

Here's the work in plain order:

Step 1 — Identify every FORAY integration location. CC reads the engine code with the cleanup in mind, identifies every place where one of the three wrong-pattern tables is being written, and produces a list. Each location gets:

The output is an inventory document — call it loomworks-foray-integration-locations-v0_1.md. You review before any code changes.

Step 2 — Design the replacement tables. For each of the three wrong-pattern tables, design the simpler Loomworks-natural replacement. This is mostly about removing FORAY-shaped fields, renaming foray_* schemas/columns to honest names, and keeping the operational fields Loomworks actually uses.

Output: schema definitions for the replacement tables, with migration plans (how to move existing data from the old tables to the new ones without losing audit history).

Step 3 — Add the _foray_reserved_emit plumbing. One function, one module, no-op body. Used everywhere a reserved location is needed. This goes in first so the reserved locations have something to call when they're added.

Step 4 — Replace each table's writes with the reserved-location pattern. For each integration location identified in Step 1:

Step 5 — Drop the three wrong-pattern tables. Once nothing writes to them anymore, they get dropped (or renamed and archived if there's any reason to preserve them).

Step 6 — Sweep for other dead weight. Separate piece of work, depending on what surfaces. Examples to investigate:

This sweep produces its own list, you review, and we decide which items belong in the cleanup arc vs which belong as separate phases.


What this cleanup does NOT do

To be honest about scope, here's what's deliberately out of scope:


What I'm asking from you to proceed

Three things, lightweight:

1. Confirm the cleanup framing as-stated. If the three tables I've named are the three you'd name, and the reserved-location pattern is roughly what you'd want, then v0.1 of this scoping note is good and we proceed to Step 1.

2. Tell me if there's anything else you'd put on the cleanup list that I haven't named. You said "anything no longer necessary to support core Loomworks functionality." If you have specific items in mind beyond the three FORAY-shaped tables (the Contributor retirement is the obvious candidate; there may be others), name them and they fold into Step 6.

3. Confirm the sequencing. Cleanup first, then together-review of the current-status manifest, then memory work as the next focus. If you'd rather reorder — e.g., look at the manifest now and choose the next memory work before cleanup — say so.

After your answers, I produce the inventory document (Step 1 output) — most likely as a CC kickoff that reads the engine code, identifies all the FORAY-integration locations, and lands an inventory at /Users/dunin7/Downloads/ for your review.


A small note on what comes after

You've signalled that memory work is likely the next core focus once cleanup is done. I want to say back what I'm hearing so it's recorded as part of the discovery trajectory of this conversation:

You said "If we get memory right, everything else will work." That's a foundational principle, and it lands with the same weight as "FORAY is additive, not mandatory" did. Memory is what Loomworks is fundamentally for — the persistent, considered, Operator-owned knowledge substrate that makes engagement-with-the-agentic-era tractable. Everything in the four-room methodology, the Companion's role, the FORAY integration, the OVA authorization layer — all of it rides on Memory being the right shape.

When we get to that work, the discipline this conversation has established (immersion-first, questions before recommendations, look at everything during investigation, don't narrow scope on inference) is the discipline that should govern it. The memory work will be more important than the FORAY arc was; it deserves at least the same care.

Ready when you are.


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks Substrate Hygiene Scoping Note — v0.1 — 2026-05-24