Skip to content
Skip to content
Documentation navigation

Core Promotion Review

Use this review before moving module behavior into src/. A similar class name, table shape, or framework precedent is not evidence of a shared k0smos domain.

Required Decision Record

Copy this section into the durable architecture document owned by the change.

  1. Capability and proposed core contract — name the provider-neutral behavior and the smallest public interface.
  2. Consumer A — name an active consumer, its current owner, invariants, and lifecycle.
  3. Consumer B — name a second active consumer and prove its semantics match Consumer A, including tenancy, identity, authorization, concurrency, retention/deletion, and error behavior.
  4. Ownership — state what core owns and what each module continues to own. Core must not query an optional module's tables.
  5. Optionality proof — show core boots and the contract remains valid with either or both consumers inactive.
  6. Verification — name contract tests, module integration tests, and static dependency/DI ownership checks.
  7. Migration — define forward migration, compatibility window, rollback, export/reimport behavior, and failure recovery.
  8. Alternatives — compare local duplication for now, a private shared library, an event/integration contract, and a core service.
  9. Decision — accept, reject, or defer, with owner and review trigger.

An explicit user-approved exception may replace the second consumer, but the record must identify that exception and retain every other section.

Current Reviews

Candidate Named consumers/evidence Decision
Deployment locale backfill declarations Core default locale and Documentation publication locale share absent-only legacy migration, allowed-value validation, dry-run and DB-choice preservation. Accept typed declarations and active-module contribution only; owners retain allowed locales and keys.
Qualified SEO alternate transport Ecommerce product and Blog article details share current public locale/path presentation, with domain-specific translation/slug rules retained by their owners. Accept bounded extension of the existing SEO value; template-data.md records the nine-part review.
Accepted order postal snapshot read contract Ecommerce order detail and Invoice order assembly need the same immutable accepted shipping/billing facts, independently of today's address book. Accept typed values/read port only; the decision below keeps capture, SQL and retention with Ecommerce.
Migration-owned physical schema projection Bookmark, Invoice and Kit need identical nonunique MySQL TEXT lookup prefixes in both fresh portable bootstrap and explicit upgrades. AppSettings supplies its existing generated-key declaration through the same pure boundary. Accept a migration-only projection interface/base; the decision below retains every table/index declaration with its owner.
Structured document extraction and byte inspection Ai private attachments and Discovery Media evidence share checksum, format, bounded execution and cancellation semantics. Accept; src/App/AI/Document/AI.DocumentExtraction.md.
Shared AI activation Ai private chat and Discovery reuse tenant providers/Python execution with independent state. Accept; src/App/AI/AI.SharedAi.md.
Sensitive HTTP content exclusion Ai and Discovery need identical early telemetry exclusion without sharing content. Accept; src/Http/Privacy/AI.RequestPrivacy.md.
Conditional sensitive query exclusion Core public /search and Ecommerce catalogue/category search share early query-name classification and final private-response lifecycle, without sharing search or measurement state. Accept bounded extension; src/Http/Privacy/AI.RequestPrivacy.md.
Committed content changes Ecommerce catalog projection handoff and Discovery freshness share tenant identity, commit, retry and revocation semantics. Accept; bounded identity outbox and recovery only. Decision: src/Application/ContentChange/AI.ContentChange.md.
EasyStore import runs Esapi is the only EasyStore consumer. Psapi and Wpapi have durable runs, but their vendor contracts, checkpoints, entity graphs, and reconciliation rules differ. Reject promotion; reuse small HTTP/merge contracts only.
Core taxonomy Kit, Finance, Ticket, Wpapi, and Ecommerce fail the semantic match documented in ADR 0001; Blog/Page have no native assignments. Reject; keep bounded models.
Vector projection Search documents and Ecommerce catalog projections are possible inputs, not two proven consumers of a stable vector lifecycle. Defer until two retrieval use cases define matching freshness, deletion, ACL, and rebuild rules.
Graph projection No two runtime consumers or provider-neutral traversal contract exist. Repository-analysis notes are unrelated. Reject current promotion.
Signage content providers No accepted signage bounded context or two content providers with a shared lifecycle exist. Defer pending product scope and named consumers.

ArchitectureBoundaryTest protects the new module-neutral core contracts and migration-only DDL. DefinitionGroupCollisionTest prevents modules from replacing core DI keys or each other. These are ratchets: accepted promotions add their new core path to the module-neutral boundary list.

Deployment locale backfill declarations — 2026-10-15

  1. Capability and contract. LocaleBackfillDefinition transports a DB key, legacy i18n key and deployment-supported values to the existing absent-only TenantLocaleBackfill. It adds no generic settings registry.
  2. Consumer A. Core's default locale uses the tenant's supported locales. Full migration and the explicit locale command share validation, dry-run and preservation of valid stored choices, including after legacy JSON cleanup.
  3. Consumer B. Documentation's publication locale requires an installed published catalog. It shares the tenant connection, absent-only writes, strict validation and explicit failure on malformed stored choices, without changing deletion/retention. Catalog availability remains owner policy.
  4. Ownership. Core owns transport, global preflight and insert/readback. Documentation owns its keys/catalog construction. Active modules opt in through LocaleBackfillProviderModuleInterface; ModuleRegistry collects declarations and ModuleRuntimeDefinitions is the sole DI owner. Core Settings imports no optional module or module registry and reads only app_settings.
  5. Optionality. Without an active offer, only core's default locale is handled. Inactive values remain untouched; no optional service is probed/autowired. The former owner-specific inactive status row is omitted. Duplicate target or legacy keys fail before locale writes, including collisions with core.
  6. Verification. Tests exercise actual PHP-DI active/inactive wiring, dry-run, global validation, invalid installed catalog, stored-choice precedence, validation after JSON cleanup and duplicate rejection. Full architecture and DI ownership checks pass. Runtime ArcadeDB code remains DDL-scanned; its capitalized explicit migration directory is now classified consistently.
  7. Migration. No schema or value rewrite is introduced. Deployment uses existing explicit/full-command backfill. Rollback retains stored choices; export/reimport preserves exact keys/values and owner activation. Existing concurrent insert/readback behavior remains; this change does not qualify concurrent native configuration writers or make all backfills atomic.
  8. Alternatives. Duplicating backfill loses global validation before writes. A private library adds packaging without resolving ownership. Events complicate synchronous migration. Hardcoded catalog construction couples an optional owner to core; typed data suffices.
  9. Decision. Accept this bounded extraction based on the two matching consumers above. Revisit if another owner needs different write/concurrency semantics; do not expand it into an arbitrary settings framework.

Accepted order postal snapshot read contract — 2026-10-13

  1. Capability and contract. Read immutable accepted shipping/billing postal facts by tenant-local order ID. Core owns readonly OrderPostalAddress and OrderPostalSnapshot values, OrderPostalSnapshotReaderInterface and a runtime-active class-string module offer. A null result means no historical capture; a nonnull snapshot with null roles means accepted absence and must never fall back to today's saved address IDs.
  2. Consumer A. Ecommerce OrderDetailPresenter::detail() shows accepted addresses on authorized order pages and response projections. Its customer/ staff adapters retain access decisions; the read port does not grant access.
  3. Consumer B. Invoice InvoiceService::createFromOrder() assembles the same order's accepted billing address, with captured shipping fallback only when billing was absent. Both use the current tenant connection and trusted order ID, read without mutation, and must not substitute current address-book facts for captured data. Malformed/missing required storage fails visibly; neither consumer may hide corruption by switching to mutable addresses.
  4. Ownership. Core owns transport/read semantics and one SalesDefinitions DI key. Ecommerce owns the append-only table, migration, codec, transactional capture and order retention/deletion lifecycle. Invoice owns invoice assembly, fiscal validation and providers. Core never queries Ecommerce SQL or imports its implementation. No generic snapshot writer/repository is promoted.
  5. Optionality. Only actual runtime-active offers are resolved. No offer yields a null reader dependency without probing optional classes. Duplicate or invalid offers fail before use. Invoice-only operation stays standalone; Ecommerce-only operation needs no Invoice service; both inactive still boot.
  6. Verification. Test inactive/active/duplicate/invalid/warm compiled DI, transport semantics, migration-only portable DDL, actual checkout transaction capture/rollback/replay, historical versus captured absence, both consumers, address deletion and unrelated order/import updates. Extend core dependency ratchets and run DI collision checks; use only disposable SQL.
  7. Migration. Add one explicit capture record per newly accepted order, including both-null roles. No historical backfill from mutable data. Apply Ecommerce migration before deploying writers/readers; missing schema fails fast. Existing receipts replay without capture. Export/reimport must preserve order ID, format version and captured facts together; existing importers never overwrite snapshots. Snapshot-dropping downgrade is refused because it loses accepted evidence; restoring an older release requires retaining this table. Legal retention/export/erasure qualification remains owner-specific work.
  8. Alternatives. Local duplicate readers would make Invoice query optional Ecommerce SQL or duplicate immutability/fallback rules. A private library adds packaging without changing ownership. Asynchronous events cannot guarantee capture inside the acceptance commit. A generic core snapshot service would incorrectly promote persistence and capture lifecycles with no matching importer contract. The narrow core read boundary is sufficient.
  9. Decision. Agent architecture review accepts the bounded read/value contract under the owner's requested ecommerce address/snapshot implementation. This is not an owner-approved exception or a fiscal/legal qualification. Revisit when another capture owner, retention/export contract or immutable fiscal fields actually requires a changed shared lifecycle.

Migration-owned physical schema projection — 2026-10-15

  1. Capability and contract. PortableSchemaProjectionMigrationInterface declares a pure in-memory schema transformation for an explicit target platform. Fresh portable bootstrap discovers these declarations in canonical migration order after SQLite introspection. MysqlTextLookupIndexMigration shares only the nonunique prefix mechanics and queued upgrade behavior.
  2. Consumer A. Bookmark's migration retains complete URL TEXT values and Firefox GUID uniqueness while indexing a 191-character URL prefix on MySQL. The declaration affects lookup candidates only, without repository/data writes.
  3. Consumer B. Invoice's three nonunique status/customer/date/source indexes and Kit's title lookup have the same physical-index requirement. Each retains complete values, full SQL comparisons/order expressions and current identity, tenant, ACL, concurrency and retention behavior. None uses a prefix for unique identity or changes authorization/deletion. Prefixes cannot satisfy arbitrary complete-string sorting or contains-search performance requirements.
  4. Ownership. Core owns discovery and migration-only mechanics. Each module declares exact tables, index names, column order and prefix lengths in its versioned migration. Core imports no optional owner classes or queries their rows. Base's existing AppSettings generated-key projection uses the same interface instead of a hardcoded bootstrap branch; its upgrade remains separate.
  5. Optionality. No DI service or runtime module resolution is added. Missing optional tables/retired indexes are ignored in final-snapshot projection; an actual MySQL owner upgrade instead refuses a missing expected index. Complete portable bootstrap intentionally includes all installed migration schemas independently of runtime activation. SQLite/PostgreSQL are unchanged.
  6. Verification. Contract tests cover exact prefix DDL, unchanged columns/ unique identities, idempotence, absent owners, other platforms and custom-index refusal. The existing real canonical bootstrap test exercises discovery. Owned MySQL checks use all owner columns plus their FK dependencies, complete common-prefix repository queries and actual Doctrine dry-run/upgrade/rerun. The module-neutral ratchet includes src/Database; DI collision checks remain applicable. The full architecture selection has two pre-existing failures, reproduced with its HEAD test: TenantLocaleBackfill's Documentation dependency and classification of ArcadeDB's explicit migration directory. They remain unresolved; passing the new boundary is not an all-architecture qualification.
  7. Migration. Apply each owner's Version20261015120000 under reviewed MySQL migration operations/backup. DDL implicitly commits and may lock tables; the whole multi-module plan is not atomic. Completed index changes are idempotent on retry. Unexpected unique/primary/reordered/flagged indexes are refused; existing prefix tuning is deliberately normalized to 191. Rows, IDs and export/ reimport payloads do not change. Existing queries need no compatibility writer window; retain prefixes on code rollback because full TEXT indexes are invalid.
  8. Alternatives. Copying upgrade/projection logic into three modules risks different fresh/upgrade contracts. A separate private package adds no useful deployment boundary. Events and runtime module providers are inappropriate for deterministic schema construction. Generic truncation/bounded columns or unique prefixes change data/identity, while dropping lookup indexes loses their existing purpose. The small migration-only interface/base is sufficient.
  9. Decision. Agent architecture review accepts this bounded reuse for three concrete matching consumers. It adds no generic application index/identity policy, DI key or optional-owner dependency. Revisit if a future provider needs data-dependent projection, runtime activation or changed identity semantics; these require a separately reviewed contract.