DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path substrate/loomworks-substrate-inventory-v0_1.md

Loomworks Engine Substrate Inventory v0.1

Read-only inspection produced 2026-05-24 against loomworks-engine main at commit 2f04e7a (70 migrations, 00010070).

This inventory is organised by conceptual area, not by migration order. Each entity carries the introducing migration and a flat column list. The "Observations" line at the bottom of each entity is the load-bearing part of this document — they mark places where the structure feels evolved-rather-than-designed. They do not propose action.

The FORAY substrate (§4) is the explicit examination point per the kickoff. It is given a full section that describes all three FORAY-shaped surfaces, their relationships, what is shared, and what isn't.

A small number of cross-cutting findings (ORM/migration drift, polymorphism by string, code-only vs DB-level enumerations) are gathered at §15.


Table of contents

  1. Identity layer — persons, memberships, designations, credentials
  2. Engagement layer — engagements table, candidate/active lifecycle, display identifiers
  3. Memory canonical log and typed projections
  4. FORAY substrate (examination point)
  5. Credit and accounting
  6. Conversation and orchestration
  7. Companion notifications and approval cards
  8. Settings and tunables
  9. Audit (narrative events)
  10. Cross-engagement grouping — workspaces, tags, saved filters
  11. Operational job / queue tables
  12. Side-table metadata (titles, bindings, secrets, files)
  13. Bootstrap-seeded engagements (constants in code)
  14. Migration shape across phases
  15. Cross-cutting findings (drift, polymorphism, dead columns)

1. Identity layer

The identity layer was introduced in Phase 14 (mig 0029). It coexists with the older contributors table from Phase 3, which was the engagement-scoped bearer-token actor before persons existed. Persons are global; contributors are per-engagement; the two were not collapsed.

contributors (public.contributors)

What it is: Engagement-scoped operational row for the Phase 3 bearer-token actor model. Predates persons. Carries the commit_authority flag.

Introduced: 0005_phase_3_contributors.

Columns:

Observations:

persons (public.persons)

What it is: Global identity record. One row per natural person across the system.

Introduced: 0029_phase_14_person_layer. Heavily extended: companion_name + personal_engagement_id (0057), referred_by + license_tier + account_status + expires_at + previous_status_change_at (0062 Phase 47 credit lifecycle), exhaustion_preference + near_exhaustion_{20,10,5}pct_seen_at + previous_responder_model (0064 Phase 49).

Columns (current state):

Relationships:

Observations:

webauthn_credentials

Introduced: 0029. Columns: id, person_id (FK), credential_id (BYTEA unique), public_key (BYTEA), sign_count, transports (JSONB), display_name, created_at.

Observations:

memberships

What it is: Person <-> engagement join with stackable designations and a soft-delete flag.

Introduced: 0029. Extended with active (0031), operator_sequence_number (0065).

Columns:

Uniques: (person_id, engagement_id); (person_id, operator_sequence_number).

Observations:

membership_designations

What it is: Stackable role flags on a membership. Composite PK on (membership_id, designation).

Introduced: 0029. active flag added (0031).

Columns:

Designation values (code-only, in persons/memberships.py):


ALLOWED_DESIGNATIONS = frozenset({"operator", "contributor", "domain_expert"})

Observations:

recovery_codes

Introduced: 0029. Bcrypt-hashed single-use codes per person.

migration_events (public.migration_events)

What it is: Append-only audit log of the Phase 14 person-layer migration (and any future identity-layer data fixups). Distinct from the substrate's main event log because the main log is engagement-scoped.

Introduced: 0032.

Columns: id, event_type (TEXT discriminator), payload (JSONB), created_at.

Observations:

credentials (public.credentials)

What it is: Pre-Phase-16 generic credential store. Scoped to system/operator/engagement.

Introduced: 0004.

Columns: id, scope CHECK in ('system','operator','engagement'), scope_id, provider, encrypted_key, created_at, updated_at. UNIQUE(scope, scope_id, provider).

Observations:

contributors (Phase 3 — still here)

Already inventoried above; reiterated here to note that two actor-identity concepts (contributors + persons) coexist after Phase 14.


2. Engagement layer

The engagement is the spine of everything. The engagements table started life with four columns in Phase 1 and has accumulated columns through 10+ migrations.

engagements (public.engagements)

What it is: The root row for every engagement. Carries the version counter, the current state, the visibility flag, the display identifier, and a hodgepodge of denormalised label/lookup columns.

Introduced: 0001_phase_1_substrate_events. Extended by: 0007 (candidate_seed_id), 0030 (visibility), 0041 (next_display_number), 0047 (created_by_person_id), 0049 (title), 0065 (display_identifier).

Columns (current):

State values observed in code:

Visibility values observed:

Display identifier format:

Observations:

Candidate seed handle

engagements.candidate_seed_id was introduced at 0007 for the HTTP engagement-creation flow when the eid in the URL pre-dates instantiation. The migration docstring is explicit that this is "purely the HTTP-layer handle" and that "Engagement memory objects continue to carry seed_ref as the authoritative pointer after instantiation."

Observations:


3. Memory canonical log and typed projections

Phase 1-11 established the substrate's "everything is a MemoryObject in memory_events, projected into one generic and several typed views" pattern. This is the dominant architectural commitment of the engine.

memory_events (public.memory_events)

What it is: The canonical append-only event log. Every MemoryObject version is a row. Renamed from substrate_events in Phase 2 (mig 0003).

Introduced: 0001 (as substrate_events); renamed 0003.

Columns:

Indexes: by (object_id, object_version), by (engagement_id, timestamp), by (engagement_id, engagement_version), by (engagement_id, object_type). Plus the two UNIQUE constraints.

Observations:

current_memory_objects (public.current_memory_objects)

What it is: Generic materialized projection of the current version of every MemoryObject. Upserted by append_event inside the same transaction.

Introduced: 0002 (as current_substrate_objects); renamed 0003.

Columns: engagement_id, object_id, object_type, current_version, payload (JSONB), last_updated_at. Composite PK (engagement_id, object_id).

Observations:

Typed projection views

All five tables below are projector-maintained, rebuildable from memory_events, share the same architectural pattern (Path C), and project a subset of MemoryObject types into scalar columns for queryability.

| Table | Migration | Projects | Distinct shape note | |---|---|---|---| | shape_events_view | 0018 (extended 0026, 0042, 0044, 0054) | ShapeEvent | adds back-references to Manifestation + Shaping (0026); produced_at (0042); render_specialist_display_name + triggered_by_display_name on render_events_view (0044); display_number (0054) | | render_events_view | 0022 | RenderEvent | content_kind discriminator + storage columns (0053); display_number + prior_render_ref + revision_strategy (0054) | | manifestation_view | 0026 | Manifestation | state ('current' \| 'superseded') | | external_production_records_view | 0051 | ExternalProductionRecord | extends with composition_object_id + composition_step_index (0056); render_job_id nullable after 0056 | | render_compositions_view | 0056 | RenderComposition | state ('initiated' \| 'step_in_progress' \| 'waiting_for_operator_decision' \| 'completed' \| 'failed') |

Observations:

Bootstrap engagement IDs (in code)

These are deterministic UUIDs; downgrades target them precisely.


4. FORAY substrate (examination point)

Three tables (or column groups) carry the FORAY name or concept. They were introduced at three different phases for three different purposes and have not been unified.

Surface 1 — credit.foray_action_flows (value flows)

What it is: Append-only ledger of every credit movement. The substrate's value-flow log. Trigger-maintained materialized balance via credit.asset_balances.

Introduced: 0062_phase_47_credit_substrate. Created in its own credit schema.

Columns:

Trigger: credit.update_balance_on_flow() — AFTER INSERT, UPSERTs both sides into credit.asset_balances.

Companion table: credit.asset_balances — materialized; never written directly by application code.

Read paths: credit/balance.py (sum / check), credit/reconciliation_evaluator.py (drift detection), credit/proposal_applier.py (correction inserts).

Write paths (in credit/flows.py): write_issuance_flow, write_consumption_flows (5 rows per turn), write_suspension_flow, write_reactivation_flow, write_deletion_flow, write_balance_zeroing_flows, write_referral_credit_flow.

Observations:

Surface 2 — audit.foray_events (narrative events)

What it is: Append-only narrative-event log. State changes that need an audit record but don't move value. v0.1 ships one event_type: setting_change written from the tune_setting handler.

Introduced: 0068_audit_foray_events. Created in its own audit schema, deliberately distinct from credit.

Columns:

Write path: audit/events.py:write_setting_change_event, called from orchestration/tune_setting.py. Best-effort discipline: failures are swallowed.

Observations:

Surface 3 — memory_events.{content_hash, attestation, foray_tx_ref} + _foray payload sub-block (readiness wiring)

What it is: Phase 25 readiness wiring on the canonical event log. Three columns + an in-payload sub-block. Two of the three are dead today.

Introduced: 0047_phase_25_engagement_creation_ui.

Columns / fields:

Observations:

What is shared

All three surfaces share four conceptual elements:

  1. A "transaction id"transaction_id on credit, tx_id on audit, foray_tx_ref on memory_events. Three different column names. Two are UUID-typed, one is TEXT.
  2. An actor — credit uses polymorphic from_party / to_party VARCHAR(128); audit uses UUID-typed actor_person_id; memory_events carries actor_id + actor_kind (its own taxonomy of contributor/agent/person/companion).
  3. A payload — credit calls it metadata (JSONB), audit calls it payload (JSONB), memory_events has both payload and the _foray sub-block.
  4. A timestamp — all three.

What isn't shared

Where conceptual unification would land

If pursued, unification would have to settle:

The FORAY substrate today is best read as "three sibling surfaces that share a grammar but not a shape." The grammar is (transaction, asset-or-event-type, actor, payload, timestamp). The shapes are concrete, and currently divergent.


5. Credit and accounting

The credit substrate landed across three migrations: Phase 47 (mig 0062, foundation), Phase 48 (mig 0063, evaluators + SMTP), Phase 49 (mig 0064, persons lifecycle columns).

credit.foray_action_flows + credit.asset_balances

Covered in §4 Surface 1.

credit.credit_grant

What it is: One row per claim_token. The grant lifecycle anchor.

Introduced: 0062.

Columns: id, claim_token UNIQUE, recipient_email (nullable post-claim), recipient_email_hash, grant_kind CHECK in (form_initiated, operator_curated, referrer_initiated), asset_id, credit_amount, initiated_by, campaign_ref, metadata (Python: grant_metadata), status CHECK in (pending_claim, claimed, expired, revoked), expires_at, claimed_at, claimed_by_person_id (DB FK; ORM-less), created_at.

Observations:

credit.email_grant_registry

What it is: Per-email-hash issuance ledger for eligibility decisions.

Introduced: 0062.

Columns: email_hash (PK), email_normalized_hash (parallel hash over Gmail-aliased form), first_grant_at, last_grant_at, total_grants_issued, last_grant_status CHECK (pending_claim/claimed/expired/deleted), last_status_at.

Observations:

credit.oracle_rate_config

What it is: Per (credit_asset, provider_token_asset) conversion rate. rate_per_million credits debited per 1,000,000 provider tokens.

Introduced: 0062. Seeded with 10 (credit_asset, token_asset) pairs.

Observations:

credit.evaluator_state

What it is: Persistent state for the Phase 48 evaluators (suspension/deletion + reconciliation). Per-evaluator typed shape.

Introduced: 0063.

Observations:

email_send_attempts (public schema, despite being mostly credit-driven)

What it is: One row per send_email invocation. Observability and deduplication for deletion-warning emails.

Introduced: 0063. ORM in loomworks/email/models.py.

Observations:

persons lifecycle columns (Phase 47 + 49)

See §1.persons for the full column list. Migrations 0062 + 0064 added eleven columns covering tier, account_status (with CHECK), referral, expiration, near-exhaustion thresholds, exhaustion preference, and previous responder model. Two extensions of the same row by two phases.

Observations:


6. Conversation and orchestration

conversation_turns (public.conversation_turns)

What it is: General-purpose per-person/per-engagement Companion conversation log. Distinct from Phase 31's seed-conversation events (which live on the candidate engagement's memory_events log under operator_turn / companion_turn event kinds — see Observations).

Introduced: 0059_phase_42_conversation_turns. Extended 0069 (input_mode), 0070 (completeness_check_prefix).

Columns: id, person_id (FK), engagement_id (FK, nullable), role TEXT ('operator' | 'companion'), content TEXT, classified_intent TEXT (nullable — only on companion turns), input_mode TEXT NOT NULL DEFAULT 'text' CHECK in ('text','voice'), completeness_check_prefix BOOLEAN NOT NULL DEFAULT FALSE, created_at.

Indexes: (person_id, engagement_id, created_at DESC).

Intent labels (Pydantic Literal in orchestration/classifier.py:47, ~15 values):

Observations:

Intent enum sourcing

The IntentLabel literal in orchestration/classifier.py:47 is the canonical list. The handlers that consume each intent live in orchestration/router.py. The intent list has grown across phases — most recently save_filter (engagement-nav phase two), tune_setting (voice listening), create_engagement_* cluster (Phase 55).

Observations:


7. Companion notifications and approval cards

companion_notifications (public.companion_notifications)

What it is: One row per proactive Companion notification. A single row carries either an informational notification (Phase 44) or an approval card (Phase 45). The discriminator at projection time is whether approval_status is non-null.

Introduced: 0060_phase_44_companion_notifications. Extended 0061_phase_45_approval_card_columns.

Columns:

Indexes: (person_id, status, created_at DESC); (person_id, trigger_ref).

Observations:


8. Settings and tunables

person_settings (public.person_settings)

What it is: Per-Operator preference store, keyed by flat dotted-namespace string (e.g., voice.listening.blur_intensity).

Introduced: 0067_voice_person_settings.

Columns: person_id (FK CASCADE), setting_key TEXT, setting_value TEXT (JSON-encoded), updated_at. Composite PK.

Observations:

system_config (public.system_config)

What it is: System-wide Fernet-encrypted KV store. Used for Loomworks-managed LLM keys, evaluator cadence keys, SMTP credentials, etc.

Introduced: 0048_phase_31_system_config. Heavily seeded by mig 0062 (9 keys), 0063 (13 keys), 0064 (3 keys).

Columns: id, config_key UNIQUE, encrypted_value TEXT (Fernet ciphertext), label, created_at, updated_at.

Observations:


9. Audit (narrative events)

audit.foray_events

Covered in §4 Surface 2.

Observations beyond §4:


10. Cross-engagement grouping

workspaces, engagement_workspace, engagement_tags, saved_filters

What it is: Operator-scoped engagement-grouping primitives backing the Phase-two navigation destinations.

Introduced: 0066_engagement_navigation_phase_two_substrate.

workspaces: id, owner_person_id (FK CASCADE), name, created_at, archived_at. UNIQUE(owner_person_id, name) WHERE archived_at IS NULL.

engagement_workspace: workspace_id (FK CASCADE), engagement_id (FK CASCADE), added_at. Composite PK.

engagement_tags: engagement_id (FK CASCADE), tag_value TEXT, added_at, added_by_person_id (FK). Composite PK (engagement_id, tag_value).

saved_filters: id, owner_person_id (FK CASCADE), name, criteria JSONB ({"all_of": [<predicate>, ...]}), created_at, archived_at, is_system_defined BOOLEAN. UNIQUE(owner_person_id, name) WHERE archived_at IS NULL.

Observations:


11. Operational job / queue tables

These are all non-Memory operational state — mutable rows, no provenance, no version chain. The pattern is {job_id, engagement_id, status enum, started_at, completed_at, agent identity, optional result column or ref}. Eight tables follow the pattern.

| Table | Migration | Purpose | Status enum | |---|---|---|---| | deferral_queue | 0008 | Phase 4 boundary-deferral workflow | (no status column; uses resolved_by_record_id IS NULL) | | retrieval_jobs | 0008 | Phase 4 RetrievalAgent dispatch | pending / running / complete / failed | | summarization_jobs | 0009 | Phase 5 SummarizationAgent | pending / running / complete / failed | | drift_detection_jobs | 0009 | Phase 5 DriftDetectionAgent (CHECK dropped 0016; drift_result_id added 0011) | pending / running / complete / failed | | cadence_firings | 0012 | Phase 7 scheduler firing attempts (close_time 0014) | opening / opened / failed | | seed_cadence_synthesis_jobs | 0013 | Phase 7 synthesis text production | pending / running / complete / failed | | shaping_jobs | 0018 | Phase 9 ShapingAgent dispatch | queued / dispatched / completed / failed | | render_jobs | 0022 | Phase 10 RenderDispatchAgent (status widened 0052) | queued / dispatched / awaiting_external / completed / failed |

Observations:


12. Side-table metadata

shape_event_title

What it is: Operator-facing label per ShapeEvent. Keyed by the ShapeEvent's object id.

Introduced: 0050.

Columns: id, engagement_id (FK), shape_event_object_id (UUID, unique), title TEXT, updated_at.

Observations:

render_specialist_binding

What it is: Durable per-(engagement, declared_render_type) specialist identity. Read by the lifespan bootstrap to register RenderSpecialist instances at startup.

Introduced: 0045. DRT version pin added 0046.

Observations:

engagement_api_keys, system_config, credentials

Covered in §1 and §8. Three KV-shape secret/configuration tables, separately introduced.

uploaded_files

What it is: Operational table for binary file storage. Bytes live on disk under data/files/{engagement_id}/; the table is for retrieval and metadata.

Introduced: 0038.

Observations:


13. Bootstrap-seeded engagements (constants in code)

The substrate has three engagement IDs with fixed, deterministic UUIDs.

| UUID | Name | Introduced | Purpose | |---|---|---|---| | 00000000-0000-0000-0000-000000000001 | administrative | Phase 2 | Seeds live here; admin actions emit events against this engagement | | 00000000-0000-0000-0000-000000000002 | Loomworks commons | mig 0034 (Phase 15) | The universal commons; visibility='automatic' | | 00000000-0000-0000-0000-0000000000e2 | E2E test sandbox | mig 0043 (Phase 21) | Hosts Playwright mutation traffic; visibility='private' |

Plus the per-person Personal engagement (UUID is per-person, created at signup; mig 0058 backfills for existing persons; visibility='personal').

Observations:


14. Migration shape across phases

Some patterns of the migration history itself are worth surfacing as the architecture of how the substrate evolved.

Vocabulary-extension migrations (no DDL)

Migrations 0010, 0019, 0020, 0023, 0024, 0027 are no-op DDL migrations. They exist to keep the Alembic chain walkable as a lineage record when a Pydantic Literal vocabulary was extended without a corresponding DB change. The convention was introduced at 0010 and recurs roughly once per phase that adds a vocabulary term.

Observation:

Heavy data-migration migrations

Migrations 0034 (Loomworks induction), 0035 (founding memory), 0036 (Loomworks membership backfill), 0037 (seed v2 amendment), 0041 (display number backfill), 0043 (E2E sandbox), 0055 (specification_grammar backfill), 0058 (personal engagement induction) are data migrations — they write content to memory_events / engagements / current_memory_objects rather than altering schema.

Observation:

Bundle-vs-split discipline

Most phases bundle their schema changes into one migration. Phase 16 explicitly split into mig 0038 (uploaded_files), 0039 (actor_kind widening), 0040 (engagement_api_keys), 0041 (assertion display number) — four migrations for one phase. The mig 0040 docstring is explicit about lateness ("the addendum was written after 0038/0039 landed").

Observation:


15. Cross-cutting findings

These are observations that don't fit a single conceptual area. They are not graded.

F1 — Engagements ORM stubs proliferate

At least six different layers each declare their own _EngagementRow stub mapping in their respective models.py files (persons, contributors, files, api_keys, render_specialists, notifications, orchestration). The authoritative mapping is in memory/events.py:EngagementRow. Each stub declares a subset of the engagements row's columns depending on what the FK target actually needs to know. None of the stubs declare all 10 current columns of the engagements table.

| Layer | Declares | Missing | |---|---|---| | memory/events.py | id, created_at, current_engagement_version, state, candidate_seed_id | visibility, next_display_number, created_by_person_id, title, display_identifier | | persons/models.py | id, created_at, current_engagement_version, state, candidate_seed_id, visibility | next_display_number, created_by_person_id, title, display_identifier | | contributors/models.py | id, created_at, current_engagement_version, state, candidate_seed_id | 5 | | notifications/models.py | id only | 9 | | orchestration/models.py | id only | 9 | | (others similar) | | |

Observation: the ORM stubs are documentation-in-data of what each layer thinks it needs from engagements. They are silently drifting from the actual table shape; nothing enforces consistency. The authoritative writer (append_event in memory/events.py) is also one of the stubs.

F2 — engagements.state DB value vs Pydantic Literal mismatch

The DB column engagements.state is VARCHAR(16) with no CHECK. Application code inserts 'candidate' (api/routers/engagements.py:257) but the Pydantic Engagement.state literal at engagement/types.py:61 admits only ("active", "suspended", "archived"). Two enumerations, one column, neither fully describes the in-use value set.

F3 — engagements.visibility has three values plus a deprecated anticipation

In-use: 'private', 'automatic', 'personal'. Anticipated but never used: 'discoverable' (mentioned in mig 0030 docstring). No DB CHECK; no Pydantic Literal centralising the set; readers branch on string comparisons (dashboard.py filters on visibility != 'personal').

F4 — memory_events.actor_kind ORM is behind migration

ORM MemoryEventRow.__table_args__ declares the CHECK as ('contributor', 'agent', 'person') (Phase 16 state). Migration 0057 widened the DB CHECK to also admit 'companion' (Phase 41). The DB and ORM disagree on the constraint value set.

F5 — memory_events.foray_tx_ref and content_hash are written-or-not-read

The Phase-25 FORAY readiness wiring is documentation-in-data for an integration that hasn't landed. Three of four surfaces have no consumers.

F6 — Four KV-shape stores

credentials (scope-keyed, Phase 2), engagement_api_keys (per-engagement, Phase 16), system_config (system, Phase 31), person_settings (per-person, Phase 47). Each was introduced at a different phase for a different actor scope. Each uses its own column convention (scope_id / engagement_id / config_key+global / person_id+key). They are not unified.

F7 — Polymorphism by VARCHAR vs UUID typing

Three actor conventions in three substrate surfaces.

F8 — Status enums are not shared

Eight operational/job tables (§11) use four distinct status vocabularies (pending/running/complete/failed; queued/dispatched/completed/failed; opening/opened/failed; pending/running/complete/failed with awaiting_external). No common base.

F9 — Display identifiers are dual-keyed

Engagements are addressable by UUID (the canonical id) and by display_identifier (E####). The address resolver accepts either; the API uses UUID internally; URLs may carry either. Two identifier spaces for one entity.

F10 — companion_notifications carries two row shapes

One table accommodates informational notifications (Phase 44) and approval cards (Phase 45) by discriminating on whether approval_status is non-null. 17 columns, of which 6 are nullable-by-shape rather than nullable-by-data.

F11 — Multiple state enumerations share verbs across surfaces

At least seven state columns across MemoryObject types and projection views use overlapping verbs (active / retired / confirmed / superseded / current / produced / held / committed / addressed / ...). The vocabularies are not contradictory but not coherent either — 'current' on Manifestation is the same concept as 'confirmed' on ShapeEvent (the live version), under different names.

F12 — Two conversation logs

conversation_turns (Phase 42, the general-purpose log) and the Phase 31 operator_turn / companion_turn event-kinds on the candidate engagement's memory_events. Both record conversations between an Operator and the Companion. Different storage layer, different lifecycle, deliberately not unified.

F13 — migration_events is a fourth audit-shape table

In addition to the three FORAY surfaces (§4), migration_events (§1) is a fifth-shape table — append-only, event_type discriminator, JSONB payload, no actor column, no transaction id. Five tables in the substrate carry the audit-log shape (event_type, payload, timestamp [+ actor]) with five different concrete shapes.


Appendix A — Migration index (count: 70)

0001 substrate_events → 0003 rename → 0027 Phase 11 → 0046 Phase 22 specialist binding DRT version → 0061 Phase 45 approval cards → 0064 Phase 49 lifecycle columns → 0065-0070 engagement-navigation phases + voice + audit + voice provenance + completeness check prefix.

Empty-DDL migrations (lineage only): 0006, 0010, 0017, 0019, 0020, 0023, 0024, 0025, 0027.

Heavy data migrations: 0015, 0034, 0035, 0036, 0037, 0041, 0043, 0055, 0058, 0062 (seeds), 0063 (seeds), 0064 (seeds), 0065 (display_identifier backfill), 0066 (system-defined filter backfill).

Pure CHECK / constraint changes: 0016, 0039, 0052, 0057.

View / projection introductions: 0002 (current_memory_objects), 0018 (shape_events_view + shaping_jobs), 0022 (render_events_view + render_jobs), 0026 (manifestation_view), 0051 (external_production_records_view), 0056 (render_compositions_view).


End of inventory.