* docs/plan-reorder:
docs: serve tracey web coverage dashboard from the Phase 0 bootstrap
docs: bootstrap git.ents.cloud on stock git before any crate lands
docs: pin ents-web deployment-agnosticism and retarget the honesty test
docs: make the queue reconstructible; durability a performance property
docs: reorder plan - headless-first, single-node-first
Scopes: docs
#------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# An empty message aborts the commit.
No reviews of this commit yet — record a verdict below.
Start a review
docs/development-plan.adoc
@@ -20,13 +20,32 @@
* *fable* — the two crates where a quiet bug is a security hole or a
wrong design (`ents-gate`, `ents-query` core semantics), public-API
review of every crate at its phase boundary, and integration.
-* *haiku* — trivial glue (the honesty-test root).
Every crate lands with Tracey annotations mapping its spec rules
(`.config/tracey/config.styx` already covers `docs/spec/`), tests run
via `cargo nextest run`, and a fable review of the public API before
anything in the next phase depends on it.
+== Phase 0: bootstrap
+
+Before any crate lands, redeploy the existing Fly app
+(`.config/fly.toml`) as a headless machine serving two things behind
+one host — no `gix-receive`, no gate, no CI or Sprite executor:
+
+* stock git's smart-HTTP backend (`git http-backend`) against a bare
+ repo on the `odb` volume, so `git.ents.cloud` is a real `origin` from
+ day one; and
+* `tracey web`, reading a plain working tree a post-receive hook checks
+ out on every push (the same `updateInstead` trick Phase 6 formalizes
+ for real), so the same host shows live spec coverage on HEAD.
+
+Every phase number below is one higher than in any prior ordering of
+this document.
+Nothing here is salvaged or reusable code — the single-node hosted
+root in Phase 6 (`git-ents`, the CLI-complete milestone) replaces the
+git backend wholesale, at the same hostname; whether it keeps serving
+the coverage dashboard is a later call.
+
== Crate schedule
[cols="2,1,1,1,4", options="header"]
@@ -34,23 +53,23 @@
| Crate | Phase | Complexity | Agent | Notes
| `facet-git-tree`
-| 0
+| 1
| Low
| sonnet
| Exists (external repo). Stays domain-blind. Land the
`#[facet(transparent)]` fix upstream and drop the local `[patch]`.
| `gix-ref-store`
-| 0
+| 1
| Medium
| sonnet
| Read/CAS trait split per `arch.refstore-read-cas-split`; loose-ref impl
ports the CAS discipline from `pre-redo` (`arch.loose-cas-discipline`:
no shelling to `git update-ref`). Fable reviews the trait before
- phase 2 consumes it.
+ phase 3 consumes it.
| `gix-receive`
-| 0
+| 1
| High
| opus
| Smart-HTTP wire framing + pack ingestion, zero policy. Protocol-v2 and
@@ -58,7 +77,7 @@
Quarantine semantics per `receive.object-access`.
| `ents-model`
-| 1
+| 2
| Low
| sonnet
| Entity structs, namespaces, trailers, taxonomy — declarative, but it is
@@ -66,7 +85,7 @@
review matter more than the code. Absorbs git-metadata's trailer work.
| `ents-gate`
-| 2
+| 3
| Medium
| fable
| Small in lines, security-critical in every line: tip signature,
@@ -75,7 +94,7 @@
call sites.
| `ents-query`
-| 2
+| 3
| High
| fable
| The critical path: grammar/parser (easy), static footprint extraction,
@@ -84,7 +103,7 @@
semantics against synthetic ref histories.
| `ents-anchor`
-| 2
+| 3
| Medium
| sonnet
| Mostly a port: projection (blame + fuzzy context match) survives at
@@ -92,16 +111,20 @@
(embed blob + context, no gitlinks).
| `ents-receive`
-| 3
+| 4
| Medium
| sonnet
| Orchestration above traits that already exist by now: gate
policy (mandatory/advisory), footprint matching, enqueue, `(effect,
- oid)` dedup, redaction at ingest. Defines `EventSink`. Fable reviews the
+ oid)` dedup, redaction at ingest. Defines `EventSink`, reconstructible
+ from repository state as the work set `trigger − results(self, any)`
+ (`query.workset`); the in-memory impl plus a boot-time reconciliation
+ scan is the reference implementation, durability deferred as a
+ performance property (`receive.reconstructible`). Fable reviews the
`receive()` signature — every frontend is downstream of it.
| `ents-sync`
-| 3
+| 4
| High
| opus
| Fetch/push plumbing is routine; the schema-aware three-way merge over
@@ -109,7 +132,7 @@
Absorbs git-store's merge.
| `ents-effect`
-| 4
+| 5
| Medium
| sonnet
| `Executor` trait + Docker/Sprite backends (feature-gated), toolchain
@@ -117,46 +140,65 @@
readiness probes and sprite quirks from `pre-redo`; the design is
settled, the environment is the risk.
-| `ents-web`
-| 4
-| Medium
-| sonnet
-| Broad surface, low algorithmic depth. Signing identity injected by the
- root. Accepts the honest `ents-receive` dependency (no write facade).
-
| `git-ents` (bin)
-| 5
+| 6
| Medium
| sonnet
-| Local root wiring (~50 lines) plus the real cost: subcommand surface,
- `serve` = `ents-web` + `gix-receive` on loopback,
- `denyCurrentBranch=updateInstead` worktree edge.
+| Local root wiring (~50 lines) plus the real cost: subcommand surface
+ and the `denyCurrentBranch=updateInstead` worktree edge. Headless — no
+ `serve` subcommand yet (arrives Phase 7 with `ents-web`). Doubles as
+ the single-node hosted root: loose refs and a real odb on a Fly volume
+ behind `gix-receive`, an in-memory `EventSink` with a boot-time
+ reconciliation scan, and the Sprite executor, deployed at
+ `git.ents.cloud`. Milestone: CLI-complete.
+
+| `ents-web`
+| 7
+| Medium
+| sonnet
+| Broad surface, low algorithmic depth. Lands `serve` in `git-ents`,
+ turning the single-node hosted root into a hosted web UI with
+ sessions/CSRF (`roots.web-session`). Signing identity is injected by
+ the composition root; the crate assumes nothing about network
+ reachability, so in-process webview embedding stays a supported
+ deployment (`roots.web-agnostic`).
| `git-ents-server` (bin)
-| 5
+| 8
| High
| opus
| Postgres `RefStore` (multi-ref CAS in a transaction), Tigris object
- store behind gitoxide traits, durable-queue `EventSink`, Sprite
- executor, path validation, sessions/CSRF. Salvage from the scale-out
- work at `pre-redo`; worker stays a mode until scale splits it.
+ store behind gitoxide traits, and a durable-queue `EventSink` — a new
+ composition root swapped in with zero library-crate edits. This phase
+ IS the honesty test (`roots.honesty-test`): entry is triggered by
+ measured storage/load pressure (the kiln-cache growth analysis), not a
+ date. Reuses the Sprite executor and sessions/CSRF from `git-ents`;
+ salvage the store code from the scale-out work at `pre-redo`.
|===
== Phase gates
-* *Phase 0 → 1*: `gix-ref-store` passes a CAS conformance suite
+* *Phase 0 exit*: `git.ents.cloud` resolves over HTTPS; `git clone` and
+ `git push` round-trip against it using stock git; this repo's
+ `origin` points at it; the `tracey web` dashboard at the same host
+ reflects HEAD's coverage after each push.
+* *Phase 1 → 2*: `gix-ref-store` passes a CAS conformance suite
(concurrent writers, crash injection); `gix-receive` round-trips a push
from stock git.
-* *Phase 2 → 3*: gate verdicts proven identical across call sites;
+* *Phase 3 → 4*: gate verdicts proven identical across call sites;
query evaluator handles the staged-pipeline and fan-in idioms
incrementally on a synthetic repo.
-* *Phase 3 → 4*: end-to-end local write path (`receive` in-process,
+* *Phase 4 → 5*: end-to-end local write path (`receive` in-process,
advisory gate, null `EventSink`) green; sync merge fuzz-tested against
divergent typed trees.
-* *Phase 5 exit*: the honesty test — a third single-node root (SQLite,
- local fs, Docker; `roots.honesty-test`) built by *haiku* from library
- crates alone, no library modification. If haiku can't write it in ~50
- lines, the seams failed, not haiku.
+* *Phase 6 exit*: the CLI-complete milestone — every porcelain command
+ green against the single-node hosted root; the boot-time
+ reconciliation scan regenerates obligations correctly after a
+ `kill -9` of the in-memory queue.
+* *Phase 8 exit*: the honesty test (`roots.honesty-test`) — the
+ Postgres/Tigris/durable-queue root is wired as a new composition root
+ with zero library-crate modification; a diff of library-crate
+ contents between phase entry and phase exit MUST be empty.
Backend conformance tests are shared suites written once against each
trait (`RefStore`, `EventSink`, `Executor`) and run per implementation —
docs/spec/overview.adoc
@@ -236,6 +236,7 @@
so local mutations honor the same CAS guarantee hosted storage provides.
--
-The honesty test for these boundaries — a third single-node composition
-root constructible from library crates alone — is a deployment
-requirement and lives in `roots.adoc` as <<roots.honesty-test>>.
+The honesty test for these boundaries — a new composition root
+constructible from library crates alone, no library modification — is a
+deployment requirement and lives in `roots.adoc` as
+<<roots.honesty-test>>.
docs/spec/receive.adoc
@@ -95,6 +95,20 @@
state kept outside the repository.
--
+[role="requirement", id="receive.reconstructible"]
+.The Queue Is Reconstructible From Repository State
+--
+The set of pending obligations an `EventSink` enqueues MUST be derivable
+from repository state alone, per the work set defined in
+<<query.workset>>.
+An `EventSink` implementation MAY lose queued events on crash, provided
+the composition root reconciles obligations from repository state at
+startup before serving further pushes.
+A durable queue MUST be treated as a performance optimization, never a
+correctness requirement; the dedup key in <<receive.dedup>> is unchanged
+by reconciliation.
+--
+
[role="requirement", id="receive.redaction-admin-only"]
.Redaction Records Are Admin-Only
--
docs/spec/roots.adoc
@@ -42,11 +42,14 @@
--
[role="requirement", id="roots.honesty-test"]
-.Single-Node Honesty-Test Root (Deferred)
+.Scale-Out Root Is the Honesty Test
--
-A third composition root — SQLite, local filesystem, and Docker — MUST be
-constructible without modifying library code, as the project's honesty
-test for the seam design.
+Wiring the Postgres `RefStore`, Tigris object store, and durable-queue
+`EventSink` (<<roots.hosted>>) as a new composition root MUST require
+zero modification to any library crate.
+This is the project's honesty test for the seam design: the proof is an
+actual production migration off the single-node hosted root, not a
+synthetic root built to demonstrate the seams.
--
[role="requirement", id="roots.config-isolation"]
@@ -67,6 +70,15 @@
root.
--
+[role="requirement", id="roots.web-agnostic"]
+.Web UI Is Deployment-Agnostic
+--
+The `ents-web` crate MUST receive its signing identity by injection from
+its composition root and MUST NOT assume it is reached over a network.
+In-process webview embedding, with no network transport at all, MUST
+remain a supported deployment alongside hosted and local-loopback serving.
+--
+
[role="requirement", id="roots.worktree-update"]
.Local Serve and the Working Tree
--