0.30.0
Added
-
project.yamlnames the store, and every verb opens it (H1).aep.project/1gainsstore:—markdown(the default, so no existing project changes meaning),sqlite: <path>(relative to.engineering/, as every project path is),postgres: <url>, andhybrid: {authority, read, on_unreachable, on_divergence, local, replica}, whose words are carried and checked — a hybrid missing one is refused by name atprotocol validate, which now validates the discoveredproject.yamltoo — and not yet opened (story:hybrid-backend). Everyprotocol artifactverb,protocol drive(throughaep_driver::PlanSource, which the driver now reads its plan from) andprotocol conformance --backend projectopen through it;--store <dir>remains the markdown override.protocol artifact historyover a SQLite or Postgres plan reads the entity's event log back as journal entries, so the same history prints over every store.examples/planning-passkeys/.engineering/project.sqlite.yamlis the example on SQLite, andstore_selection.rsruns every verb over both, each as its own process, and compares the output. Two things were found by that comparison and written down rather than hidden: an edge moves a document's revision and not an entity's (story:relation-bumps-a-document-revision-but-not-an-entity), andvalidate's drift lines have no counterpart where there is no second record. -
An observation is an event on the entity it is about. The
Identityprojection — the shape of a SQLite or Postgres plan — writes an event at the entity's unchanged revision for a relation (on its source) and for recorded evidence (on its target), where before it wrote nothing: a relation is a record of its own and evidence changes nothing, so the contract named no affected entity. That is what a rebuilt history and a second process's evidence count read. The pin moved toentity-runtime0.13.0: 0.12.2's providers accept an observation at a reached revision (SQLite and Postgres previously failed the second one on the primary key; the file store dropped it silently) and its provider suite has a tenth case holding them to it; 0.13.0 adds the serialisableDivergenceandHybrid::rememberthe hybrid plan's verbs need. -
store: hybrid— the plan kept twice, under four declared words (H4,story:hybrid-backend).aep-backend-hybridis the adapter, shaped by the plan's own projection, overentity-runtime'sHybrid<MarkdownProvider, R>: markdown for pull requests and a SQLite or Postgres replica for tooling, withauthority,read,on_unreachableandon_divergencetyped inproject.yamland none defaulted. The atomicity guarantee is the runtime's, cited rather than chosen (store-v0.1.md§ 10). Two verbs are ours:protocol artifact divergenceslists what one side took and the other did not and says which side is authoritative (exit 1 while anything is outstanding);protocol artifact catch-upreplays them at the side that missed them and writes back what it could not. Divergences live indivergences.jsonlbeside the plan between commands, because every verb is its own process — which is whatentity-runtime0.13.0's serialisableDivergenceandHybrid::rememberexist for. The sixteen suites run against the composite with either side as authority;protocol conformance --backend hybridruns them from the command line, and--backend projectresolves a hybrid project to that.MarkdownProjectionnow hydrates any plan-shaped store (PlanStore) through itsStoretraits rather than reading the directory, so a hybrid's declared read path governs hydration too.examples/planning-passkeys/.engineering/ project.hybrid.yamlis the example kept twice, andstore_selection.rsruns every verb over it beside the other two stores, then makes the replica refuse a write, lists the divergence from a second process and catches it up from a third.
Fixed
-
A seeded plan kept its tags.
seed::from_manifestcarried title, summary and owner and not tags, so a plan seeded into SQLite answeredlist --kindand a board with untagged artifacts. -
describe_typereports the ladder (D-P5 closed).TypeDescriptor::lifecycleis filled for every planning kind — the initial status, every status, everyfrom -> [to]edge, and, new on the descriptor,requires: which rungs cost evidence, of which kind, how many. Rendered from the sameEntityDefinitionthe kernel decides a move with, so what a harness reads and what the store enforces cannot drift; the memory, SQLite and markdown backends report identically, and the edges equalprotocol artifact lifecycle <kind>'s output for every kind. -
aep-backend-postgres: the contract over PostgreSQL (P5, as a type).PostgresBackendisEntityBackend<entity_postgres::PostgresStore>— the runtime's provider with a server, one transaction per commit, writers of one instance serialised by a row lock. Two processes writing one artifact resolve to one accepted write and one refusal naming the revision it lost to; the loser latches and reopens. The sixteen suites and the faulty-backend guard run against a server whenENTITY_POSTGRES_URLnames one; the gate's newpostgres-checkstep printspostgres-check: skipped, ENTITY_POSTGRES_URL unsetwhen it does not, and CI runs them against apostgres:16service.protocol conformance --backend postgres --store <url>runs them from the command line. The pin moved toentity-runtime0.12.1.
Changed
- The ladder bridge (
kernel) moved fromaep-backend-markdownintoaep-backend-entity, where the adapter renders and decides with it; the markdown crate re-exports it under the same path.Identity::with_lifecyclesgives a SQLite plan its ladders.