Skip to content
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,30 @@ after its public API and format compatibility policies are established.

### Fixed

- The version-one ledger discloses the pending repository-task sealed-stage
capability escape (#146) while preserving the immutability requirement (#69).

- The version-one segment ledger points to the existing filesystem-stage
regression module for exclusive staging and dropped-stage evidence (#69).

- The version-one recovery overview links its implemented transitive
candidate-view admission to the next-head boundary and requirement anchors (#69).

- Version-one publication documentation assigns unchecked publisher
construction to the crash harness and fault injection to its decorators (#69).

- Version-one crash documentation identifies its 105 cases as a subset of
the complete command, which also executes version-two migration cases (#69).

- Version-one recovery documentation distinguishes streamed inventory
fingerprint evidence from caller-supplied classifier bytes and the segment
resumer's separate materialization (#69).

- Living version-1 format pages describe implemented initialization,
platform admission, publication, restart, recovery, and process-death
evidence rather than completed issue-era plans (#69). Historical issue
references and existing requirement/test anchors remain available.

- The migration transition-ledger guard rejects noncanonical line endings,
extra rows, misplaced discard claims, and counterfeit completion postures.
Recovery posture and namespace interruption checks use their exact columns.
Expand Down
6 changes: 4 additions & 2 deletions docs/formats/segment-store-v1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ visibility, and recovery as one contract.
ADR-0005 records the cross-cutting decision. These pages are a protocol
commitment. Segment writing and verified reading are implemented in issue #15.
Catalog generation, writer-locked publication, and immutable restart snapshots
are implemented in issue #16. Store initialization and complete executable
crash and recovery evidence remain owned by issue #17.
are implemented in issue #16. Store initialization, platform admission,
explicit recovery, and the 105-case process-death crash matrix are implemented
in issue #17. Every page below describes the behaviour of `main`; the
[requirements ledger](requirements.md) names the test behind each claim.

## Core law

Expand Down
28 changes: 18 additions & 10 deletions docs/formats/segment-store-v1/publication.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,17 @@ existing store root plus `staging`, `segments`, and `catalogs`. Both operations
perform blocking filesystem I/O. Neither operation repairs, enumerates, or
removes protocol state.

Issue #16 defines the proof type but deliberately exposes no public producer.
The filesystem transition suite uses a crate-private, test-only unchecked proof
to exercise publication mechanics. Issue #17 must implement initialization and
the platform contract before production callers can obtain admission.
`FilesystemPlatformAdmission` has private fields, so only Keep's own
initialization and platform-admission boundary can produce a production value.
A new store obtains one through `FilesystemPlatformAdmission::initialize`,
which runs the ordered initialization protocol (`KEEP-RECOVERY-002`); a
published store reacquires one through `FilesystemPlatformAdmission::reopen`,
which mutates nothing and admits the production platform
(`KEEP-RECOVERY-003`). Both are described in
[Recovery and platform contract](recovery.md). The crash matrix harness opens
an unchecked publisher only behind the `repository-tasks` Cargo feature,
then wraps the publisher in fault-injecting decorators. This bypass is
reserved for repository harnesses rather than production admission.

`publish_catalog_generation` performs complete semantic preflight before the
first storage transition. With `FilesystemCatalogPublisher`, it then executes
Expand Down Expand Up @@ -161,12 +168,13 @@ head-selected coordinates, refuses symbolic links and nonregular artifacts,
checks every length before allocation, and reconstructs logical bindings only
after all canonical bytes and physical coordinates verify.

Issue #16 does not implement store-root initialization, platform admission, or
explicit recovery. A future admission producer must prove the exact canonical
directories and persistent lock file before opening a publisher. Any retained
`head.next` or `current.cat`, and any `current.seg` not owned by the selected
staged segment, causes publication to refuse before mutation and requires issue
recovery under #17. When `HEAD` is absent, the publisher probes both immutable pools
Publication never initializes, admits, or recovers on its own. Admission
proves the exact canonical directories and the persistent lock file before a
publisher opens. Any retained `head.next` or `current.cat`, and any
`current.seg` not owned by the selected staged segment, causes publication to
refuse before mutation; the explicit recovery boundaries in
[Recovery and platform contract](recovery.md) classify and resolve that
residue. When `HEAD` is absent, the publisher probes both immutable pools
and admits first publication only when both are empty; any entry is preserved
as recovery evidence and refuses the operation. An already-current retry
refuses every fixed-name stage.
Expand Down
22 changes: 17 additions & 5 deletions docs/formats/segment-store-v1/recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,24 @@ exact truncation only when every available segment- or record-header framing
byte remains canonical. It preserves proven partial-framing and
complete-looking corruption as typed refusals. Catalog- and
next-head-stage classifiers apply the same available-fixed-framing rule before
distinguishing exact truncation from complete canonical bytes. Transitive
publication-view admission and filesystem-streaming semantic classification
remain unimplemented.
distinguishing exact truncation from complete canonical bytes. Every
classifier consumes complete, caller-supplied protocol-bounded stage bytes;
the ledger's classification rows (`KEEP-RECOVERY-010`, `KEEP-RECOVERY-011`)
are whole-byte by design, and no classifier streams from a filesystem handle.
The inventory reader returns fingerprint evidence without retaining stage
bytes. The filesystem segment resumer separately materializes its pinned
writable stage before re-admission and continuation.
`admit_recovery_stage_bytes` first requires the canonical-name stage, exact
length, and recomputed stage fingerprint to match prior observation evidence;
only `assess_recovery_stage` may dispatch those admitted bytes to a semantic
classifier. Matching evidence does not convert corrupt bytes into lawful
content.

Transitive publication-view admission for a candidate `head.next` is
implemented at [Leftover next head](#leftover-next-head). Its planner and
filesystem finalizer require the complete candidate catalog snapshot under
`KEEP-RECOVERY-017` and `KEEP-RECOVERY-018` before head replacement.

`plan_recovery_stage_discard` admits only an exact truncation assessment and
retains both its evidence and typed truncation reason. The semantic
`execute_recovery_stage_discard` port refuses evidence drift before mutation,
Expand Down Expand Up @@ -117,8 +127,10 @@ Run the repository-owned matrix:
cargo xtask durability-crash-matrix
```

The command executes the three ordered positions for each stable
`KEEP-CRASH-001`–`KEEP-CRASH-035` point: 105 canonical cases. Each case owns a
The 105 version-one cases are a subset of the complete command, which also
executes version-two migration cases. The version-one subset executes the
three ordered positions for each stable `KEEP-CRASH-001`–`KEEP-CRASH-035`
point. Each version-one case owns a
fresh filesystem store and an isolated child process group. The child retains
the writer lock and any open staged artifact while it executes the production
initialization, segment-writing, catalog-publication, or recovery-discard
Expand Down
21 changes: 14 additions & 7 deletions docs/formats/segment-store-v1/requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ retention, or garbage collection.
| `KEEP-SEGMENT-002` | Staged and sealed writer states are distinct, consuming types | `tests/segment_writer.rs` | Implemented in #15 |
| `KEEP-SEGMENT-003` | Short, interrupted, zero-progress, invalid-count, storage, permission, flush, and synchronization failures retain exact phases and offsets | `tests/segment_writer/write_contract_laws.rs`, `tests/segment_writer/refusal_laws.rs`, `tests/segment_writer/durability_laws.rs` | Implemented in #15 |
| `KEEP-SEGMENT-004` | Complete-segment admission verifies bounds, framing, checksums, logical identities, duplicate refusal, terminal state, and physical digest before exposure | `tests/segment.rs`, `tests/segment/identity_laws.rs`, `tests/segment/framing_laws.rs` | Implemented in #15 |
| `KEEP-SEGMENT-005` | The public sealed receipt exposes no mutable stage handle | `src/adapters/sealed_segment.rs` | Implemented in #15 |
| `KEEP-SEGMENT-005` | The public sealed receipt exposes no mutable stage handle | `src/adapters/sealed_segment.rs` | Production API implemented in #15; repository-task escape tracked in #146 |
| `KEEP-SEGMENT-006` | Malformed, unsupported, partial, conflicting, and corrupt input returns boundary-typed errors | `tests/segment_header/mutation_laws.rs`, `tests/segment_record_header/framing_laws.rs`, `tests/segment_seal/framing_laws.rs`, `tests/segment/identity_laws.rs` | Implemented in #15 |
| `KEEP-SEGMENT-007` | Record, nested-layout, segment-length, and temporary identity-index allocation remain explicitly bounded | `tests/segment_memory.rs`, `tests/segment_record_memory.rs`, `tests/segment_seal_memory.rs` | Implemented in #15 |
| `KEEP-SEGMENT-008` | Filesystem staging uses exclusive fixed-name creation and never enumerates storage as a content index | `tests/segment_filesystem_stage.rs`, `src/adapters/filesystem_segment_stage.rs` | Implemented in #15 |
| `KEEP-SEGMENT-009` | Every implemented write and durability phase has deterministic fault injection, while dropped unsealed stages preserve recovery evidence | `tests/segment_writer/`, `tests/segment_filesystem_stage.rs` | Implemented in #15 |
| `KEEP-SEGMENT-008` | Filesystem staging uses exclusive fixed-name creation and never enumerates storage as a content index | `src/adapters/filesystem_segment_stage_tests.rs`, `src/adapters/filesystem_segment_stage.rs` | Implemented in #15 |
| `KEEP-SEGMENT-009` | Every implemented write and durability phase has deterministic fault injection, while dropped unsealed stages preserve recovery evidence | `tests/segment_writer/`, `src/adapters/filesystem_segment_stage_tests.rs` | Implemented in #15 |
| `KEEP-SEGMENT-010` | Every public segment-format parser boundary is fuzzed from canonical deterministic seeds | `fuzz/fuzz_targets/segment_format.rs`, `xtask/src/fuzz_seed_corpus/segment_seeds.rs` | Implemented in #15 |

<!-- markdownlint-enable MD013 -->
Expand All @@ -62,7 +62,8 @@ Issue #16 implements catalog-generation admission, writer-locked filesystem
publication mechanics, and immutable reader snapshots. Production publisher
construction requires `FilesystemPlatformAdmission`, whose platform-checked
producer is implemented as the initialization slice of issue #17. Explicit
recovery remains separate work.
recovery is implemented in issue #17; its evidence is the recovery table
below.

<!-- markdownlint-disable MD013 -->

Expand Down Expand Up @@ -103,7 +104,12 @@ may now authorize a transition-checked finalization through a semantic storage
port, and the filesystem finalizer binds that transition to pinned
writer-authorized storage. These slices now include reusable-stage continuation
and the complete process-death crash matrix. Retention, compaction, garbage
collection, and host-power-loss simulation remain outside issue #17.
collection, and host-power-loss simulation remain outside version 1:
retention belongs to
[`keep.segment-store/v2`](../segment-store-v2/README.md), compaction and
garbage collection are tracked in issue #21. The process-death matrix does
not establish host-power-loss behavior; that requires separate filesystem and
device fault evidence.

<!-- markdownlint-disable MD013 -->

Expand Down Expand Up @@ -185,8 +191,9 @@ segment corpus and adds parser fuzzing and corruption evidence. Issue #16
matches the catalog and publication-head corpus, executes the documented
publication order through a real filesystem adapter, reconstructs exact
immutable restart snapshots, and adds deterministic transition-model and
seeded parser-fuzz evidence. Crash-injection and explicit recovery remain
owned by issue #17.
seeded parser-fuzz evidence. Issue #17 adds initialization, platform
admission, explicit recovery, and the 105-case process-death crash matrix
(`KEEP-RECOVERY-001`–`KEEP-RECOVERY-021`).

The format-local tradeoffs are recorded in the
[colocated rationale](rationale.md).
39 changes: 39 additions & 0 deletions xtask/tests/segment_store_implementation_documentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ const ROOT_README: &str = include_str!("../../README.md");
const FORMAT_REGISTRY: &str = include_str!("../../docs/formats/README.md");
const FORMAT_README: &str = include_str!("../../docs/formats/segment-store-v1/README.md");
const REQUIREMENTS: &str = include_str!("../../docs/formats/segment-store-v1/requirements.md");
const PUBLICATION: &str = include_str!("../../docs/formats/segment-store-v1/publication.md");
const RECOVERY: &str = include_str!("../../docs/formats/segment-store-v1/recovery.md");
const CORPUS_README: &str = include_str!("../../conformance/segment-store/v1/README.md");

#[test]
fn version_one_crash_evidence_is_distinguished_from_the_complete_command() {
assert!(
RECOVERY.contains("105 version-one cases are a subset"),
"the unqualified crash command also executes version-two migration cases"
);
}

#[test]
fn living_documentation_names_the_implemented_segment_boundary() {
for (document, claim) in [
Expand All @@ -32,3 +42,32 @@ fn living_documentation_names_the_implemented_segment_boundary() {
}
assert!(!ROOT_README.contains("Durable segment storage, retention"));
}

#[test]
fn recovery_documentation_does_not_assign_materialization_to_the_inventory_reader() {
assert!(
!RECOVERY.contains("bytes that the inventory\nreader materializes"),
"inventory fingerprinting returns evidence, not materialized stage bytes"
);
}

#[test]
fn living_v1_pages_no_longer_assign_shipped_recovery_to_a_future_issue() {
for (document, stale_claim) in [
(FORMAT_README, "remain owned by issue #17"),
(PUBLICATION, "Issue #17 must implement initialization"),
(
PUBLICATION,
"Issue #16 does not implement store-root initialization",
),
(PUBLICATION, "A future admission producer"),
(RECOVERY, "remain unimplemented"),
(REQUIREMENTS, "Explicit\nrecovery remains separate work"),
(REQUIREMENTS, "remain\nowned by issue #17"),
] {
assert!(
!document.contains(stale_claim),
"stale issue-era claim survives: {stale_claim:?}"
);
}
}
Loading