Story: Add a read-only entity profile and make ores.database hostable

Table of Contents

This page documents a story in Sprint 26. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

1. Goal

Two outcomes, in order. First, a named variability profile that produces a read-only entity: the generated protocol carries list, get and get_many, and no write verb and no version read. Second, ores.database becomes a composite that can host such an entity, so the database metadata the UI needs can travel on the wire without the foundation library linking the layers above it.

The first outcome stands alone. Read-only entities are needed beyond this component, and the mechanism a profile would carry is already implemented as a per-entity flag, so the work is to make it bindable.

2. Status

Field Value
State BACKLOG
Parent sprint Sprint 26
Now Not yet started.
Waiting on Nothing.
Next Start the profile task.
Last touched 2026-09-26

3. Acceptance

  • A model binds one named profile and the emitted protocol carries list, get and get_many only: no put_, no delete_, no *_versions_*.
  • A codegen regression test covers the profile, so the read-only promise cannot regress in silence.
  • ores.database carries api, core and service parts, and the foundation library lives in a part rather than the composite root.
  • The generated database.api link closure stays inside ores.utility and ores.platform, both of which sit below ores.database. No part of the component links a layer that links the component.
  • The whole tree builds and the component's suites pass, with every consumer of ores.database migrated in the same change.

4. Tasks

Task State Start End Description
Add a read-only entity profile DONE   2026-09-26 Extend _FEATURE_NAMESPACE so a profile can carry read_only and current_state, add the profile document, and prove the generated protocol carries list, get and get_many only.
Make ores.database a composite and host the generated entity BACKLOG     Prototype the api/core emission under one modelling directory, move the foundation library into a part, and add database.api, database.core and database.service so database_info can be a generated read-only entity without inverting the layering.

5. Decisions

  • The profile comes first. The composite depends on knowing what it hosts, and the profile is needed whether or not the composite happens.
  • The composite task starts with a prototype of the api=/=core emission under one modelling directory, not with moving the library. If the generator duplicates output across parts, the shape of the composite changes, and the move would have been wasted.
  • The clean-up story closed without the composite and without this component in COMPONENTS_UNDER_TEST. This story is not a continuation of that acceptance criterion; it adds capability the clean-up never had.

6. Notes

  • The table ores_database_info_tbl was moved to hand-written SQL in the clean-up, so this story re-models an existing table rather than inventing one. It reads as operational metadata, and where the read surface lives is a product question this story does not settle: ores.database is the table's owner, while ores.telemetry already reports system state over NATS.
  • Open question carried from the clean-up: ores.iam.account sets :read_only: true and generates no protocol. Its description credits a "one-owner gate" that could not be found in org_loader.py. Resolve it before the profile rests on the read_only flag.

7. Out of scope

  • Reopening the ores.database clean-up story. It closed on the component as it stands, and its record says so.

Emacs 29.3 (Org mode 9.6.15)