Project Delivery projection¶
Project Delivery answers "how is the project actually going?" at checkpoint granularity, and it is built so that a good-looking answer cannot hide a weak one.
Like the Board it is a read-only fold with its own watermark. Unlike the Board it is not about individual tickets: each row is a delivery checkpoint.
The problem it solves¶
Status reporting drifts optimistic. A row says "done", and three separate things are quietly conflated: the work was merged, the work was verified, and the evidence for that verification is still valid.
Project Delivery keeps them apart by carrying two states per row plus explicit reasons.
Headline state versus underlying maturity¶
| Field | Values |
|---|---|
headline_state |
planned, in_progress, ready_to_land, merged, verified, released, blocked, done |
underlying_maturity |
planned, in_progress, ready_to_land, merged, verified, released |
blocked and done exist only as headline states. underlying_maturity cannot be blocked, so a blocked
row still tells you how far the work genuinely got. A row that reads done still exposes the maturity that
earned it.
Every row states its own trust¶
These fields are required on every row. They are the reason this projection does not overclaim. The values are the exact strings you will read in the JSON output; the right-hand column says what each one means:
| Field | Values | Reads as |
|---|---|---|
criteria |
{proven, declared} |
Proof coverage as a fraction. Anything not proven is excluded from proven and named in the reasons |
freshness |
fresh, stale, STATE_UNKNOWN |
Whether the view has caught up. STATE_UNKNOWN means "cannot be established" — never "fine" |
confidence |
development_degraded, disaster_safe, STATE_UNKNOWN |
How far the environment itself can be trusted: development_degraded is a development environment making no data-safety promise |
health |
CP3_D_NOT_PROVEN, CURRENT, STATE_UNKNOWN |
Whether the disaster-recovery checkpoint has been proven; CP3_D_NOT_PROVEN means it has not |
durability |
CP3_D_NOT_PROVEN, CP3_D_PROVEN, STATE_UNKNOWN |
Whether writes are proven to survive losing this host, rather than assumed to |
recovery |
EXTERNAL_FAILURE_DOMAIN_UNPROVEN / _PROVEN, STATE_UNKNOWN |
Whether a standby outside this machine's failure domain has been proven |
data_class |
RECONSTRUCTIBLE_ONLY, DISASTER_SAFE_CTOWER_ENGINEERING, STATE_UNKNOWN |
What may be stored here. RECONSTRUCTIBLE_ONLY means only data you could rebuild from elsewhere |
derivation_reasons |
at least one string | Why this row says what it says |
derivation_reasons has minItems: 1. A row cannot assert a state without giving a reason for it.
At this revision the only environments that exist are development and test fixtures, and they report
CP3_D_NOT_PROVEN with development_degraded — durability unproven, environment not to be trusted with real
work. That is the honest reading, not a defect.
Freshness and rebuild¶
Every row carries how far the underlying record had got when it was folded
(source_record_position, projection_record_position), when that happened (reconciled_at), when the
answer goes stale (freshness_due_at), a digest of the row's meaning (projection_semantic_digest), and
which rebuild produced it (rebuild_generation).
The projection is disposable: rows can be deleted and deterministically rebuilt from the record. Rebuilding
at the same source watermark must reproduce byte-equivalent semantic rows and the same derivation reasons —
that is what projection_semantic_digest is for. A projection you cannot rebuild is a second source of
truth, and ctower does not allow one.
SPEC.md requires that expiry, revocation, a dependency-digest change, rollback, an incident, or a
superseding outcome remove exactly the conditions that depended on invalidated proof before a row may keep
saying done. None of those invalidation sources exists at this revision — only candidate-digest
invalidation does, and it names evidence and verdict IDs rather than rows. Doing it slot by slot is part of
the typed evidence slots rule, which is specified and not built.
Reading it¶
ctl --base-url http://127.0.0.1:8080 project delivery query ctower --output json
--output text (the default) renders a compact CLI projection; --output json emits the deterministic
structured view. The operation is GET /v1/projects/{project_key}/delivery, requires an authenticated
principal, and project_key currently accepts only ctower.
Each HTTP row carries qualifying_stage_slots. A slot has slot_key, state, assigned_seat, and
signing_seat. assigned_seat is a closed tagged union: an assigned value is exactly
{"state":"assigned","seat":{...}}, while an unassigned value is exactly
{"state":"unassigned"} and cannot carry seat. The nested seat has seat_key, seat_label, and the
pinned catalog_revision (catalog_key, positive revision, and content_digest). signing_seat has the
same seat shape or is null.
Compact output follows every checkpoint with one line per qualifying slot:
slot=<slot-key> state=<filled|unfilled|unknown> assigned=<label>[<seat-key>]@<catalog-key>@<revision>|unassigned signed=<label>[<seat-key>]@<catalog-key>@<revision>|-
The assigned text follows assigned_seat.state; it never infers assignment from the presence of a seat.
The signed dash represents a null signing seat.
If the projection cannot serve a trustworthy answer it refuses with project-delivery-unavailable rather
than returning a stale row.
Implementation status¶
The read-only contract, the strict schema, and the CLI text/JSON projection are implemented. This evidence is available through the command line only. A product browser view is planned for a later increment.
Related¶
- Board lanes — the ticket-granularity projection.
- Proof — where
criteria.provencomes from. - Delivery state — the current capability matrix in the engineering record.