DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path phases/phase-15-loomworks-universal-commons/phase-15-cr-loomworks-universal-commons-v0_1.md

Phase 15 — Loomworks engagement as universal commons — CR v0.1

CR identifier. CR-2026-027 Version. 0.1 Date. 2026-04-26 Status. Draft for Operator review. Scoping note. loomworks-phase-15-scoping-note-v0_1.md — five settled decisions (S1–S5). Consumed; not relitigated here. Candidate seed. loomworks-candidate-seed-v0_4.md — thirteen declared render-types. This is what enters the database.


1. What Phase 15 delivers

A new person signs up, lands on the welcome page, proceeds to the dashboard, and sees the Loomworks engagement as their first engagement. They can open it and see its Memory. The product has stopped being empty.

Specifically:


2. Grounding

Phase 15 is grounded in three layers, consulted in order. Claims in this CR cite the layer they rest on.

Layer 1 — Methodology document v0.17. The Loomworks engagement's Memory is knowledge about the methodology. The five founding Memory assertions (Section 8) must be consistent with the methodology's vocabulary and concepts. The methodology names Memory as accumulated engagement knowledge; the engagement as the durable container; the seed as the commitment at creation; designations as per-engagement, stackable, independent. The commons purpose (Decision 9, Discovery record v0.2) names the Loomworks engagement as the universal commons — the engagement whose Memory is visible to every person in the system.

Layer 2 — Reference Design v0.1.2. The Reference Design's assertion model (content, provenance, state, non-erasure discipline) governs how the founding Memory enters. Assertions are held, then committed. The Operator is the confirming party per R-A3.

Layer 3 — Playground Spec v0.10. Specific requirements:


3. Settled decisions — consumed from the scoping note

| ID | Decision | Summary | |----|----------|---------| | S1 | Seed v0.4 | Commons purpose + build purpose. Thirteen render-types (eleven build, two commons). | | S2 | Silent at signup, visible on arrival | Automatic membership in signup transaction. No mention during signup ceremony. | | S3 | Static welcome page with engagement link | Living surface deferred. Static content stays; card added. | | S4 | Five authored topics as founding Memory | Deeper content accumulates organically through use. | | S5 | Induction + automatic membership only | No invitation flow, no Rendered content inline, no specialist registrations for commons render-types. |


4. Construction decisions

4.1 Induction path — migration, not API

Phase 2's engagement creation flow (draft_seed → induct_seed → commit_engagement) is the full ceremonial path with agent-driven seed examination and convergence. The three prior engagement inductions (PartsPilot, FieldPilot, Agricultural Engagement) used the seed induction driver script (scripts/seed_induction_driver.py), which calls the Phase 2 machinery programmatically with a live LLM.

Phase 15 uses a different path: an Alembic migration. The Loomworks engagement must exist before the signup flow can reference its engagement_id for automatic membership. This ordering constraint makes a migration the correct mechanism — the migration runs at alembic upgrade head and guarantees the engagement exists before any code that depends on it.

The migration creates the engagement row, records the Engagement and Seed memory objects in the event log, and sets visibility to 'automatic'. The seed content comes from loomworks-candidate-seed-v0_4.md. This is a direct database operation, consistent with Phase 2's patterns (engagement row in engagements table, memory objects in memory_events, materialized view updated via projector) but skipping the agent-driven examination loop. The Operator has reviewed and approved the seed through the scoping process; the induction agent's role (verifying seed completeness against R-A5–R-A11) is satisfied by that review.

R-A17 (walkable induction history) is satisfied by recording the migration as an event in the memory log with appropriate provenance. The migration records a single-cycle induction history: one SeedInductionLoopCycle with convergence_reached=True and zero findings, reflecting the Operator's pre-approval.

4.2 Loomworks engagement UUID — deterministic

The Loomworks engagement receives a deterministic UUID, stored as a constant alongside the existing ADMINISTRATIVE_ENGAGEMENT_ID:


LOOMWORKS_ENGAGEMENT_ID = UUID("00000000-0000-0000-0000-000000000002")

The signup flow references this constant when creating the automatic membership. A lookup-based approach (query the engagement by name at startup, cache the ID) would work but adds a failure mode (engagement not yet inducted) that a constant avoids.

4.3 Visibility column — 'automatic' value

The engagements.visibility column is TEXT with default 'private'. Phase 14 added it as schema preparation. No CHECK constraint exists on the column (TEXT columns in SQLite and PostgreSQL accept any string by default). Phase 15 inserts 'automatic' as the Loomworks engagement's visibility value. If a CHECK constraint is found during pre-flight, it must be updated to accept the three values: 'private', 'discoverable', 'automatic'.

'automatic' means: every person in the system is a member of this engagement from signup. This is distinct from 'discoverable' (visible and joinable by choice) and 'private' (invitation-only). The Loomworks engagement is the only engagement that will carry this value.

4.4 Founding Memory — migration-authored assertions

The five founding Memory topics (S4) are authored as assertions in a migration that runs after the engagement induction migration. The assertions go through the normal assertion pathway: each is recorded as a memory event with event_kind='assertion_added', then committed with event_kind='assertion_committed'. The Operator (Marvin Percival, person_id 6d867b23-655a-440a-b377-e6bf4fb3882b) is the confirming party per R-A3 / R-B20.

The migration inserts both the Add and Commit events for each assertion in the same migration. This is consistent with the prior induction pattern where seeds are drafted and committed in the same operation. The assertions are pre-approved by the Operator through the scoping process.

4.5 Automatic membership — signup transaction modification

The signup transaction currently creates: person record, WebAuthn credential, TOTP secret, recovery codes — all atomic. Phase 15 adds: one membership row (person_id, loomworks_engagement_id) and one membership_designations row ('contributor') in the same transaction.

The signup endpoint that completes the transaction is /auth/signup/totp-verify (Phase 14, Section 12.1, Step 3 — the TOTP verification step is where the person record is committed). The membership insert happens in the same database transaction, after the person record insert and before the session mint.

4.6 Test person — Loomworks membership via migration

The existing test person (Phase 14's second person, created via the signup flow for testing, with no memberships) receives a Loomworks membership via the same migration that inducts the engagement. This ensures the test person's state matches what new signups will get.

If CC finds that the test person does not exist in the dev database at execution time (e.g., database was reset), this step is a no-op — the migration handles the case gracefully.


5. Divergences from Phase 2 patterns

Phase 15 follows Phase 2's data model conventions (engagement row in engagements, memory objects in memory_events, materialized view via projector) but diverges in three ways:

| Aspect | Phase 2 pattern | Phase 15 divergence | Reason | |--------|----------------|---------------------|---------| | Induction path | Agent-driven loop via induct_seed | Direct migration | Ordering constraint: engagement must exist before signup can reference it. Operator pre-approved the seed. | | Visibility | Not set (column did not exist) | 'automatic' | Third visibility tier per Decision 9. Unique to the Loomworks engagement. | | Founding Memory | No Memory at induction; assertions arrive later via API | Five assertions authored in migration | S4: founding Memory is part of the induction — new Contributors need orientation content from the first moment. |


6. Prerequisites

6.1 Tag and baseline

Phase 14 is complete. Substrate at tag phase-14-person-layer, 1038 tests passed, 2 environment-gated skips. Frontend at tag phase-14-person-layer, lint + tsc + build clean. Phase 15 builds against main HEAD.

6.2 Pre-flight ground-truth checks (Step 0)

CC verifies the following before Step 1 runs:


7. Data model

7.1 Engagement row


engagements table:
  id: 00000000-0000-0000-0000-000000000002
  name: "Loomworks"
  engagement_version: <set by append_event>
  visibility: "automatic"
  created_at: <migration timestamp>
  updated_at: <migration timestamp>

7.2 Engagement constant


# src/loomworks/engagement/constants.py (or alongside ADMINISTRATIVE_ENGAGEMENT_ID)
LOOMWORKS_ENGAGEMENT_ID = UUID("00000000-0000-0000-0000-000000000002")

7.3 Seed memory object

The Seed is a MemoryObject in the event log, consistent with Phase 2's Seed type. The seed content fields are populated from loomworks-candidate-seed-v0_4.md:


Seed(
    object_type="seed",
    what_the_work_is=<from v0.4 "What the work is">,
    who_consumes_the_work=<from v0.4 — four consumers>,
    voice_of_the_work=<from v0.4 "Voice">,
    constraints=<from v0.4 — six constraints plus "Public Memory by default">,
    success_conditions=<from v0.4 "Success conditions">,
    initial_contributors=[MARVIN_PERSON_ID],
    initial_agents=[],
    additional_assertions={
        "the_universal_commons": <from v0.4 "The universal commons">,
        "authorisation": <from v0.4 "Authorisation">,
        "declared_render_types": <summary of thirteen render-types>,
    },
    is_divergent=False,
    divergence_rationale=None,
)

CC reads the full seed content from the v0.4 file at execution time and populates these fields. The seed content is not reproduced verbatim in this CR to avoid stale duplication — the v0.4 file is authoritative.

7.4 Founding Memory assertions

Five Assertion memory objects, each with content authored in Section 8 of this CR:


Assertion(
    object_type="assertion",
    content=<see Section 8>,
    state="committed",
    committed_at=<migration timestamp>,
    committed_by=ActorRef(kind="contributor", id=MARVIN_PERSON_ID),
)

Each assertion is recorded as two events: assertion_added (state "held") then assertion_committed (state "committed"). The confirming party is the Operator.

7.5 Automatic membership

On signup, the transaction inserts:


memberships table:
  id: <generated UUID>
  person_id: <new person's id>
  engagement_id: 00000000-0000-0000-0000-000000000002
  active: true
  created_at: <transaction timestamp>

membership_designations table:
  membership_id: <from above>
  designation: "contributor"

8. Founding Memory — assertion content

The five founding Memory assertions are authored below. Each assertion is a self-contained piece of knowledge that enters the Loomworks engagement's Memory through the normal Add/Commit pathway. The content is consistent with the methodology document v0.17's vocabulary and concepts.

8.1 What Memory is and how it accumulates

> Memory is the accumulated knowledge of an engagement. Every piece of knowledge enters Memory as an assertion — a statement contributed by a person or an agent, carrying provenance that records who contributed it, when, and in what context. > > Memory grows through contribution. Assertions can be added, committed, revised, and retracted, but never erased. A correction does not delete what came before; it adds a new assertion that supersedes the prior one, with the relationship between them preserved. This non-erasure discipline means the full history of what an engagement has learned — including what it learned was wrong — is always walkable. > > Memory is not a database dump or a file archive. It is considered, weighted, source-identified knowledge that compounds over time. The more an engagement accumulates, the richer its Memory becomes — not just in volume but in the relationships between what it knows.

8.2 What an engagement is and how it works

> An engagement is a persistent space where knowledge work happens. It has a name, a seed that defines its purpose and commitments, and Memory that accumulates as people and agents contribute knowledge. > > The engagement holds a pipeline of transformations. Memory is the raw accumulated knowledge. A Manifestation is a snapshot — a bookmark of Memory at a specific moment, against which downstream work runs. Shaping prepares material from a Manifestation for a particular consumer, selecting and recasting what that consumer needs. Rendering produces the final-form artifact a consumer reads — a document, a specification, a reference, a guide. > > Each engagement is independent. Its Memory, its Manifestations, its Shapings, and its Renders belong to it alone. A person can participate in many engagements, each with its own knowledge and its own pipeline.

8.3 What designations mean and how they stack

> A designation is a role flag on a membership — it describes what a person does within a specific engagement. The three current designations are Operator, Contributor, and Domain Expert. > > An Operator governs the engagement. They approve state transitions, confirm assertions, manage the seed, and make decisions about the engagement's direction. Every engagement has at least one Operator. > > A Contributor participates in the engagement's knowledge work. They can add assertions to Memory, contribute knowledge, and read the engagement's content. Every person in the Loomworks engagement is a Contributor. > > A Domain Expert carries recognised expertise in the engagement's subject matter. This designation is earned through demonstrated knowledge and is a persistent recognition — it stays unless explicitly removed. > > Designations are per-engagement and stackable. A person can be an Operator on one engagement and a Contributor on another. A person can hold multiple designations on the same engagement — an Operator who is also a Domain Expert, for instance.

8.4 What a seed is and why it matters

> A seed is the founding document of an engagement. It declares what the work is, who consumes it, what voice the work takes, what constraints it operates under, and what success looks like. The seed is written before the engagement exists and is the basis on which the engagement is created. > > The seed is not a plan that gets discarded after launch. It is a continuously-held commitment that the engagement carries throughout its life. It can be amended — through a deliberate, recorded process — but it is never abandoned. The seed constrains what the engagement does, what render-types it commits to producing, and what quality discipline it maintains. > > Every engagement has exactly one seed. The seed for the Loomworks engagement declares both a build purpose (the environment in which DUNIN7's own work runs) and a commons purpose (the educational and community space that every person in the system participates in).

8.5 How to contribute knowledge

> Contributing knowledge to an engagement means adding an assertion to its Memory. An assertion is a statement you believe to be true, relevant, and worth preserving. It might be a fact, an observation, a correction, a clarification, or a connection between existing knowledge. > > Every assertion carries provenance — your identity, the timestamp, and the context of the contribution are recorded and preserved. This provenance is permanent. It means your contributions are always attributable, always traceable, and always part of the engagement's history. > > Contributions are considered and deliberate. The engagement's Operator reviews and commits assertions, ensuring that what enters Memory meets the engagement's quality standards. A contribution that is revised or superseded is not lost — the original and its successor both remain in Memory, with their relationship recorded. > > The Loomworks engagement's Memory is visible to every person in the system. Contributions to this engagement are part of a shared knowledge base that helps everyone — from newcomers learning what an engagement is, to experienced Operators deepening the methodology.


9. Frontend changes

9.1 Welcome page update

The /welcome page (Phase 14, Section 14 — ceremonial surface, vertical lockup) retains all existing static content. A new section is added after the designations explanation and before the dashboard door:

Content. A card or section:

Brand compliance. Render against the brand guide HTML (loomworks-brand-guide-v0_15.html) side-by-side during development. The card uses the same visual language as the dashboard engagement cards. Ceremonial register (vertical lockup) is maintained.

9.2 Dashboard

No dashboard code changes are expected. The dashboard reads from /me/memberships (Phase 14, Step 13). The automatic membership makes the Loomworks engagement appear on the dashboard naturally. The engagement card shows "Contributor" as the role label.

If pre-flight reveals that the dashboard does not read from /me/memberships or that the Loomworks engagement does not appear, the CR step addresses whatever wiring is needed.


10. Test suite

10.1 Per-file test projections

| File | Tests (projected) | |------|-------------------| | test_loomworks_engagement_induction.py | 8 | | test_founding_memory.py | 6 | | test_automatic_membership.py | 8 | | test_loomworks_visibility.py | 4 | | Total (projected) | ~26 |

Per Phase 9 Finding F discipline: per-file projections are the authoritative shape; the aggregate may drift ~20% at execution.

10.2 Test descriptions

test_loomworks_engagement_induction.py

test_founding_memory.py

test_automatic_membership.py

test_loomworks_visibility.py

10.3 Construction-decision coverage

Each scoping decision has at least one test that would fail if the decision were reversed:


11. Order of operations (steps with checkpoints)

Auto-mode posture: Steps 0–3 auto, Checkpoint A. Steps 4–5 auto, Checkpoint B. Steps 6–8 auto, Checkpoint C (final).

Substrate steps

Step 0 — Pre-flight and CR archival.

Archive this CR to docs/phase-crs/phase-15-cr-loomworks-universal-commons-v0_1.md. Run pre-flight checks (Section 6.2). Confirm baseline: uv run pytest -v reports 1038 passed, 2 skipped. Create branch phase-15-loomworks-universal-commons.

Verification: all pre-flight checks pass. Baseline green.

Commit: Phase 15 step 0: CR archival and branch creation.

Step 1 — Seed v0.4 in repo.

If docs/seeds/loomworks-candidate-seed-v0_4.md does not exist, create it from the project knowledge copy of loomworks-candidate-seed-v0_4.md. If v0.3 exists, it remains alongside (not deleted — non-erasure discipline).

Verification: docs/seeds/loomworks-candidate-seed-v0_4.md exists and matches the project knowledge version.

Commit: Phase 15 step 1: seed v0.4 in repo.

Step 2 — Engagement constant and induction migration.

Add LOOMWORKS_ENGAGEMENT_ID constant alongside ADMINISTRATIVE_ENGAGEMENT_ID.

Write migration 0034_phase_15_loomworks_engagement_induction.py:

The migration reads the seed file content at migration time. The downgrade reverses: delete the Loomworks engagement row and its memory events.

Verification: uv run alembic upgrade head succeeds. The Loomworks engagement exists in the database with correct visibility. uv run pytest -v still green (1038 passed — no regressions).

Rollback: uv run alembic downgrade -1.

Commit: Phase 15 step 2: Loomworks engagement induction.

Step 3 — Founding Memory assertions migration.

Write migration 0035_phase_15_founding_memory.py:

Verification: uv run alembic upgrade head succeeds. Five committed assertions exist in the Loomworks engagement's Memory. uv run pytest -v still green.

Rollback: uv run alembic downgrade -1.

Commit: Phase 15 step 3: founding Memory assertions.

Checkpoint A — Loomworks engagement inducted. Seed recorded. Five assertions committed. Operator confirms before signup modification.

Step 4 — Automatic membership in signup.

Modify the signup endpoint handler (the function behind /auth/signup/totp-verify) to add a membership row and designation row for the Loomworks engagement in the same transaction that creates the person record. The LOOMWORKS_ENGAGEMENT_ID constant is imported and used directly.

Write migration 0036_phase_15_test_person_loomworks_membership.py:

Write test files per Section 10.2.

Verification: uv run pytest -v reports 1038 + ~26 = ~1064 passed, 2 skipped.

Rollback: git revert.

Commit: Phase 15 step 4: automatic membership and tests.

Step 5 — Iterate to green.

Run uv run pytest -v. For each failing test, diagnose and fix the implementation (not the test, unless the test is wrong against this CR). Continue until all tests pass.

Verification: uv run pytest -v reports all tests passing.

Rollback: if iteration cannot reach green within reasonable effort, surface to Operator with the failing tests' output.

Commit: Phase 15 step 5: acceptance suite green.

Checkpoint B — Substrate complete. All tests green. Operator confirms before frontend work begins.

Frontend steps

Step 6 — Welcome page update.

Update the /welcome page to add the Loomworks engagement card (Section 9.1). Render against the brand guide HTML side-by-side during development. The card links to /engagement/<LOOMWORKS_ENGAGEMENT_ID>.

Verification: lint + tsc + build clean. The welcome page shows the Loomworks engagement card.

Commit (frontend repo): Phase 15 step 6: welcome page Loomworks engagement card.

Step 7 — Dashboard verification.

Verify the Loomworks engagement appears on the dashboard for a person with a Loomworks membership. If the dashboard already reads from /me/memberships (Phase 14, Step 13), no code change is needed — confirm visually. If the engagement does not appear, diagnose and fix.

Verification: lint + tsc + build clean. Dashboard shows the Loomworks engagement card with "Contributor" label.

Commit (frontend repo, if changes needed): Phase 15 step 7: dashboard Loomworks engagement verification.

Step 8 — Implementation notes and tagging.

Create docs/phase-impl-notes/phase-15-implementation-notes-v0_1.md recording: what Phase 15 built, any findings surfaced during execution, any divergences from this CR.

Verification: file exists and is reviewable.

Commit: Phase 15 step 8: implementation notes.

Checkpoint C — Final. Both repos green. A new person can sign up and see the Loomworks engagement on their dashboard. The Loomworks engagement has five committed assertions in its Memory. Tag both repos as phase-15-loomworks-universal-commons.


12. Acceptance gate

Phase 15 is accepted when:

  1. Substrate: all tests pass (1038 existing + ~26 new ≈ 1064, ±20%). 2 environment-gated skips carried.
  2. Frontend: lint + tsc + build clean.
  3. The Loomworks engagement exists with visibility 'automatic' and five committed Memory assertions.
  4. The Operator can see the Loomworks engagement on the dashboard with "Operator" designation (via existing membership from prior phases — the Operator should also have a Loomworks membership; see Section 13).
  5. A new person can sign up, land on the welcome page (which now shows the Loomworks engagement card), proceed to the dashboard, and see the Loomworks engagement with "Contributor" designation.
  6. The Loomworks engagement's Memory is viewable on the engagement overview page.
  7. The four prior engagements are unchanged (visibility 'private', existing tests pass).
  8. Agent auth still works on engagement-scoped endpoints.

On acceptance: tag both repos as phase-15-loomworks-universal-commons. Write implementation notes.


13. Operator's Loomworks membership

The Operator (Marvin Percival) already has four memberships (one per existing engagement), each with the 'operator' designation. Phase 15's migration (Step 4, migration 0036) adds a Loomworks membership for all persons without one. The Operator's Loomworks membership should carry the 'operator' designation (not 'contributor') — the Operator governs this engagement per the seed's Authorisation section.

The migration logic: for Marvin Percival specifically (by person_id), create the membership with 'operator' designation. For all other persons (the test person, any future persons), create with 'contributor' designation.


14. Post-CR state

Residues carried forward


15. What this CR does not specify (deferred)


16. Dependencies and related changes

Depends on.

Enables.


17. CC operating instructions

> Read this CR from top to bottom before starting. > > Execute the eight steps in Section 11 in order. After each step, run the verification command named in that step, report the result, and commit the step's work to git with the named commit message. Proceed automatically through Steps 0–3, but stop and wait for explicit Operator confirmation at Checkpoints A, B, and C. > > If any verification fails, stop and report the failure with the full error output. Do not improvise around a CR deficiency. If you encounter a problem the CR's choices cannot solve cleanly, stop, report the problem, and wait for the CR to be amended. > > The construction decisions in Section 4 are closed; do not relitigate them. The assertion content in Section 8 is concrete; use it exactly. The test specifications in Section 10 are concrete; follow them. The order of operations in Section 11 is concrete; do not reorder steps without explicit direction. > > The seed content for the Seed memory object comes from docs/seeds/loomworks-candidate-seed-v0_4.md (committed in Step 1 or already present). Read the file at execution time; do not rely on inline snippets from this CR. > > The founding Memory assertion content comes from Section 8 of this CR. Use the text exactly as written. > > Begin with the pre-flight check when ready.


18. Changelog

v0.1 (2026-04-26). Initial draft. Full Phase 15 scope per scoping note v0.1: Loomworks engagement induction from seed v0.4, five founding Memory assertions, automatic membership at signup, welcome page update, dashboard verification. Three Alembic migrations (engagement induction, founding Memory, test person membership). Eight steps with three checkpoints.


DUNIN7 — Done In Seven LLC — Miami, Florida Phase 15: Loomworks engagement as universal commons — CR v0.1 — 2026-04-26