Skip to content

Define mpsc-log design and roadmap - #6

Merged
leynos merged 27 commits into
mainfrom
docs/mpsc-log-design-roadmap
Aug 23, 2026
Merged

Define mpsc-log design and roadmap#6
leynos merged 27 commits into
mainfrom
docs/mpsc-log-design-roadmap

Conversation

@leynos

@leynos leynos commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

This branch defines the initial product and delivery plan for mpsc-log so
reviewers have a concrete contract before implementation begins. It adds the
terms of reference, technical design, lock-file naming ADR, selected jo field
syntax ADR, testing strategy ADR, glossary, event schema, sidecar example, and
GIST-aligned roadmap for the CLI, then indexes those artefacts from the
documentation contents page.

It also tracks the generated Cargo lockfile for this binary crate, corrects the
crate-name doctest import, applies the repository make fmt output, and
addresses review feedback on merge precedence, UTC timestamp validation,
integer schema coercions, df12-build fixture coverage, lock naming, duplicate
key compatibility language, partial-tail versus corrupt-final-line handling,
scheduled rollover ordering, ToR wording, and compression backend exploration.

No issue, roadmap task, or execplan is associated with this branch. The branch
creates the initial roadmap rather than implementing a roadmap task.

Review walkthrough

Validation

  • make fmt: passed.
  • make check-fmt: passed.
  • make markdownlint: passed.
  • make nixie: passed.
  • jq empty docs/mpsc-log-event-schema.json: passed.
  • make lint: passed.
  • make test: passed.
  • main...docs/mpsc-log-design-roadmap: ten commits ahead, eighteen files changed.

Notes

This branch establishes the design and roadmap before implementation. The
roadmap explicitly leaves query tooling, dashboards, network-filesystem
guarantees, full jo parity, public Rust library API support, and max_age
retention out of the v1 implementation path unless a later ADR changes the
product boundary.

References

Summary by Sourcery

Establish the design contracts and implementation roadmap for mpsc-log before feature development begins.

New Features:

  • Define the initial mpsc-log product contract, technical architecture, JSON event schema, TOML sidecar format, and implementation roadmap.
  • Document the selected jo-inspired object-field syntax with deterministic last-wins duplicate-path semantics.
  • Establish adjacent journal lock-file naming and reserved filename rules.
  • Specify a risk-based testing strategy covering unit, behavioural, end-to-end, property-based, bounded-model, snapshot, and proof-based validation.

Bug Fixes:

  • Correct the crate-name doctest import and resolve formatter and typo-check issues.

Enhancements:

  • Add project vocabulary, implementation architecture guidance, documentation navigation, and detailed contracts for locking, sidecar precedence, timestamp validation, tail repair, rotation, retention, and failure handling.

Build:

  • Track the generated Cargo.lock for reproducible dependency resolution.

Documentation:

  • Add the terms of reference, comprehensive technical design, three ADRs, glossary, event schema, sidecar example, and GIST-aligned delivery roadmap.

Tests:

  • Document required coverage for concurrency, repair, rotation, compression, coercion, fixture validation, and failure injection.

Chores:

  • Apply repository formatting and update typo configuration for the documented compression backend.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Define the initial mpsc-log product boundary and technical design for JSONL records, coercion, timestamps, locking, tail repair, rotation, compression, retention and diagnostics.
  • Add ADRs for lock-file naming, layered testing, and jo-inspired field syntax with last-wins duplicate keys.
  • Add the event JSON Schema, example sidecar configuration, context glossary, roadmap and documentation index updates.
  • Specify the five-second lock timeout, unlocked sidecar pre-read, append commit point, rollback behaviour and residual at-least-once semantics.
  • Define size-only rotation after tail repair and before append, including oversized records and rollover ordering.
  • Document v1 scope, delivery phases, acceptance criteria and explicit deferrals.
  • Add Cargo.lock, correct a doctest import, apply formatting and update typo configuration for flate2.

Walkthrough

Adds the mpsc-log product boundary, shared terminology, detailed journal design, architectural decisions, event schema, sidecar example, phased roadmap, documentation index links, and typo configuration for flate2.

Changes

mpsc-log Documentation Suite

Layer / File(s) Summary
Product boundary and shared vocabulary
docs/terms-of-reference.md, docs/context.md
Defines the journal contract, scope, telemetry categories, constraints, open questions, and shared naming conventions.
Journal design and architectural decisions
docs/mpsc-log-design.md, docs/adr-001-*.md, docs/adr-003-*.md
Specifies field construction, locking, repair, rotation, errors, stable interfaces, lock naming, and duplicate-key semantics.
Layered verification strategy
docs/adr-002-testing-strategy.md
Records the risk-based testing approach and its verification boundaries.
Event schema and sidecar configuration
docs/mpsc-log-event-schema.json, docs/mpsc-log-sidecar.example.toml
Defines journal record validation and example rotation, locking, defaults, and field mappings.
Phased delivery roadmap
docs/roadmap.md
Sequences delivery through foundational contracts, journalling, contention, rotation, telemetry adoption, and deferred extensions.
Documentation navigation and spelling configuration
docs/contents.md, typos.local.toml, typos.toml
Links the new guides and design artefacts, and accepts flate2 in typo checking.

Suggested labels: Roadmap

Poem

Journals gather, locks align,
Schemas mark each data line.
Roadmaps chart the path ahead,
Sidecars guide the record trail.
flate2 passes spelling checks—
The docs now set the rails.

🚥 Pre-merge checks | ✅ 18 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Developer Documentation ⚠️ Warning Reject this check: the branch adds args/clock/fs boundaries in mpsc-log-design.md, but docs/developers-guide.md has no diff and no such guidance. Update docs/developers-guide.md with the planned module and adapter responsibilities, and link to the design document and ADRs.
Domain Architecture ⚠️ Warning The new design places serde_json::Map in the domain core and requires it in ADR 003, so domain logic depends directly on a serialization representation. Introduce domain Record/Value types and ports. Keep JSON/TOML parsing, CLI path reads, filesystem operations, and sysexits mapping in adapters or main.
✅ Passed checks (18 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Testing (Overall) ✅ Passed Pass this check: the base-to-HEAD diff changes only documentation and typo configuration; src/, tests/, and Cargo files are unchanged, so no executable behaviour requiring tests was introduced.
User-Facing Documentation ✅ Passed The PR changes only draft planning/design documents and typo configuration; executable code and docs/users-guide.md are unchanged. The roadmap schedules CLI usage documentation after implementation.
Module-Level Documentation ✅ Passed Accept this check: the diff changes only documentation and typo configuration; no source module is added or altered, and existing Rust/Python modules have module-level documentation.
Testing (Unit And Behavioural) ✅ Passed PASS: The PR changes only documentation and typo configuration; it adds no executable behaviour or workflow boundary, and the documents defer behavioural and end-to-end tests to implementation.
Testing (Property / Proof) ✅ Passed PASS: The PR explicitly recommends proptest for input/state invariants, kani for bounded transitions, and Verus only for substantive introduced lemmas; no proof is introduced.
Testing (Compile-Time / Ui) ✅ Passed The main...HEAD diff contains only docs and typo-config changes. ADR 002 recommends focused snapshots for stable CLI outputs; no Rust/TypeScript compile-time behaviour or implementation output was...
Unit Architecture ✅ Passed Pass this check: the PR changes only documentation and typo configuration; source and manifest files are unchanged, and the design documents specify separate core, filesystem, and clock seams.
Observability ✅ Passed The committed diff versus main contains only documentation and typo-config changes; hashes for Cargo files, src/, and tests are unchanged, so no operational behaviour or observability gap is introd...
Security And Privacy ✅ Passed Pass this check: the diff adds only regular documentation/configuration files, no source changes or secrets, and specifies structured JSON/TOML handling without shell execution or privileged access.
Performance And Resource Use ✅ Passed The PR delta contains only documentation, schema, and typo-config changes; src, tests, and Cargo files are unchanged, so it introduces no runtime performance or resource-use regression.
Concurrency And State ✅ Passed The PR changes only documentation and typo configuration; no Rust, Cargo, or shared runtime state changed. The design defines per-journal locking and tests contention, failure, repair, and rotation...
Architectural Complexity And Maintainability ✅ Passed Pass this check: the diff adds documentation only; it specifies a small synchronous core, explicit test seams with stated purposes, no stable API or global state, and no new dependencies.
Rust Compiler Lint Integrity ✅ Passed The merge-base diff confirms 12 documentation/configuration files only; src/lib.rs and Cargo files are unchanged, with no introduced Rust suppressions, artificial references, or clones.
Title check ✅ Passed The title accurately summarises the main changes: defining the mpsc-log design and delivery roadmap.
Description check ✅ Passed The description directly explains the documentation, design, roadmap, validation, and supporting changes in the pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/mpsc-log-design-roadmap

Comment @coderabbitai help to get the list of available commands.

@pandalump
pandalump marked this pull request as ready for review June 29, 2026 16:18
@coderabbitai coderabbitai Bot added the Roadmap label Jun 29, 2026
coderabbitai[bot]

This comment was marked as resolved.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

@leynos

leynos commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

@leynos

leynos commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

docs/mpsc-log-design.md (2)

292-297: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use a week-specific placeholder for the weekly schedule example.
weekly currently reuses the same run.2026-06-29.jsonl shape as daily, which makes the archive naming look day-based. Show a week-oriented key instead.
Triage: [type:docstyle]

🛠️ Suggested edit
- | `weekly` | UTC ISO week beginning, Monday 00:00:00 | `run.2026-06-29.jsonl`    |
+ | `weekly` | UTC ISO week beginning, Monday 00:00:00 | `run.<week-start>.jsonl`  |
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/mpsc-log-design.md around lines 292 - 297, The weekly schedule example
in the rotation table should use a week-specific placeholder instead of reusing
the daily-style filename. Update the weekly row in the documentation table to
show a week-oriented base rotated filename, and keep the hourly/daily
examples unchanged so the weekly entry is clearly distinct.

25-30: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Drop the hard-coded df12-build path.
The repository-relative ../df12-build.worktrees/... path is brittle in a reference document; name the workflow target without anchoring it to one checkout layout.
Triage: [type:docstyle]

🛠️ Suggested edit
- The first integration target is the df12-build Open Dynamic Workflows (ODW) workflow at `../df12-build.worktrees/codex-annex/workflows/df12-build-odw.js`.
+ The first integration target is the df12-build Open Dynamic Workflows (ODW) workflow.
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/mpsc-log-design.md around lines 25 - 30, Remove the brittle
repository-relative df12-build path from the prose in this design doc and refer
to the workflow target generically instead. Update the sentence around the
“first integration target” wording in the mpsc-log-design section so it names
the df12-build Open Dynamic Workflows (ODW) workflow without anchoring it to
../df12-build.worktrees/..., keeping the rest of the description intact.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Lines 20-35 ---'
sed -n '20,35p' docs/mpsc-log-design.md

printf '%s\n' '--- Lines 285-302 ---'
sed -n '285,302p' docs/mpsc-log-design.md

printf '%s\n' '--- Relevant matches ---'
rg -n -C 2 --fixed-strings \
  -e '../df12-build.worktrees/' \
  -e 'first integration target' \
  -e '| `weekly`' \
  -e 'run.<week-start>.jsonl' \
  -e 'run.2026-06-29.jsonl' \
  docs/mpsc-log-design.md || true

Length of output: 3170


@leynos Both findings have been resolved.

  • Hard-coded df12-build path: Removed. docs/mpsc-log-design.md Lines 25–26 now refer generically to the df12-build Open Dynamic Workflows (ODW) workflow.
  • Weekly rotation example: Updated. Line 295 now uses the week-specific ISO-week filename run.2026-W27.jsonl, while the hourly and daily examples remain unchanged.

[resolve]

@lodyai
lodyai Bot force-pushed the docs/mpsc-log-design-roadmap branch from 81c45e0 to a396136 Compare July 18, 2026 15:47
@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

@leynos

leynos commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Roadmap item 3.3.2 ---'
rg -n -A26 -B6 '3\.3\.2\.' docs/roadmap.md || true

printf '%s\n' '--- Required duplicate-path criteria in docs/roadmap.md ---'
rg -n -i -C 3 \
  -e 'parameteri[sz]' \
  -e 'duplicate (write|path|key)|same object path' \
  -e 'top-level (key|keys)' \
  -e 'nested object path' \
  -e 'sidecar default' \
  -e '`-s`|`-n`|`-b`' \
  -e 'later write|last-wins|replace.*earlier' \
  docs/roadmap.md || true

printf '%s\n' '--- Current diff for docs/roadmap.md ---'
base="$(git merge-base HEAD origin/main 2>/dev/null || true)"
if [ -n "$base" ]; then
  git diff --unified=5 "$base" HEAD -- docs/roadmap.md
else
  git diff --unified=5 HEAD~1 HEAD -- docs/roadmap.md
fi

printf '%s\n' '--- Available documentation validation targets ---'
for file in AGENTS.md Makefile Justfile package.json Cargo.toml; do
  if [ -f "$file" ]; then
    printf '\n### %s ###\n' "$file"
    rg -n -i -C 2 '^[[:alnum:]_.-]*(fmt|markdownlint|spelling|typos|docs)[[:alnum:]_.-]*:|markdownlint|spelling|typos' "$file" || true
  fi
done

Length of output: 42019


@leynos, resolve the documentation finding.

docs/roadmap.md Lines 321–325 now require parameterized duplicate-path tests. The requirement covers:

  • duplicate writes at the same object path;
  • top-level keys;
  • nested object paths;
  • a sidecar default overridden by a CLI field;
  • explicit -s, -n, and -b coercion flags; and
  • last-wins behaviour, where the later write replaces the earlier value at that object path.

Run make markdownlint before you close the validation work. The provided result did not include that command, so Markdown validation remains unverified.

You are interacting with an AI system.

leynos and others added 27 commits August 23, 2026 20:46
Add the initial terms of reference, technical design, glossary, event
schema, sidecar example, and delivery roadmap for `mpsc-log`.
Together these documents establish the CLI contract, JSONL record shape,
sidecar configuration, concurrency model, rotation policy, validation
strategy, and df12-build telemetry adoption path.

Update the documentation index so reviewers can find the new artefacts.
Fix the generated doctest import to use the Rust crate identifier so the
workspace test gate passes.
Add ADR 001 to define how the repository's required testing prongs apply to
`mpsc-log`'s CLI, record-building, filesystem, concurrency, repair, rotation,
and telemetry contracts.

Reference the ADR from the technical design, documentation index, and roadmap
so implementation tasks inherit the testing strategy rather than treating it as
an isolated testing phase.
Run `make fmt` across the repository and keep the resulting Markdown wrapping
changes. Reshape the long companion-document link lists so the formatter target
can complete without reintroducing markdownlint line-length failures.
Resolve the still-valid review findings in the design documentation. Spell out
record merge and coercion precedence, restrict schema timestamps to canonical
UTC form, align sidecar schema examples with integer event fields, and tighten
roadmap success criteria for merge precedence and df12-build fixture coverage.
Record lock file naming as ADR 001 because concurrency and rotation safety
depend on every writer deriving the same coordination artefact.

Rename the testing strategy ADR to ADR 002, update the design and roadmap
references, and mark the lock naming roadmap task as completed.
Add a roadmap task to benchmark flate2, gzp, and gzippy before selecting the
gzip backend for rotated journal compression.

Clarify that flate2 remains the conservative design baseline until measured
throughput, atomic-output integration, dependency risk, and portability justify
a faster backend.
Add ADR 003 to state that `mpsc-log` is `jo`-inspired rather than
textually compatible with `jo` output.

Document last-wins duplicate-path semantics, update the design and terms of
reference to stop implying full `jo` compatibility, and mark the roadmap
syntax decision as complete.
Clarify that partial-tail repair only applies to unterminated final bytes and
that newline-terminated corrupt final records fail closed with `EX_DATAERR`
without truncation.

Update the roadmap, testing strategy, glossary, sidecar example, and terms of
reference so implementation and operator guidance cover this case explicitly.
Specify that scheduled rotation finalizes the previous period before checking
`max_bytes` for the pending record against the fresh active file.

Remove the brittle df12-build repository-relative path from the terms of
reference and correct the plural wording for the document title.
Clarify df12-build workflow wording and make the workflow phase list
parallel. Use a week-specific scheduled rotation filename example.
Record the crate name in the repository spelling overlay and generated
configuration so design documentation passes the Markdown spelling gate.
Keep the documentation index compliant with the Markdown blank-line rule.
Require complete telemetry for each initial df12-build event, validate
timestamp overrides before append, and avoid scheduled archive collisions.
Align the roadmap and terms of reference with these established contracts.
Address review feedback on the design and roadmap documents:

- Add a comma after "Otherwise" in the scheduled-rollover final-archive
  naming sentence in docs/mpsc-log-design.md.
- Expand roadmap item 2.2.1 to specify extension-replacement sidecar
  derivation (run, run.jsonl, and run.ndjson derive run.toml) and add an
  acceptance criterion plus tests rejecting .toml journal filenames whose
  derived sidecar path equals the journal path, while preserving the
  existing defaults and error-code requirements.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address a second round of review feedback on the design, roadmap, and terms
of reference:

- Guard the scheduled size-split step so an empty active file is never
  rotated into a spurious empty archive: when the active file holds no data,
  append the oversized pending record directly and only rotate a
  data-bearing active file into a collision-free archive name.
- Expand roadmap item 2.2.3 to require validating defaults- and CLI-supplied
  timestamp values against the RFC 3339 UTC contract before append, preserve
  valid overrides, fail invalid overrides with EX_DATAERR, and generate an
  invocation-time timestamp only when no valid one exists.
- Scope roadmap item 3.1.2's serialization guarantee to supported local
  filesystems and defer network-filesystem (NFS and CIFS) support to the
  named filesystem verification matrix in step 6.2.1, preserving the lock
  naming, contention, and EX_TEMPFAIL claims.
- Clarify in the terms of reference that rotation and compression retention
  define local generation retention, and scope the non-goal to centralized
  or downstream retention policy so local retention is clearly in scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refine roadmap item 2.2.3 so an invocation-time RFC 3339 UTC timestamp is
generated only when no `timestamp` override exists, matching the write
protocol's step 5. The previous "when no valid timestamp already exists"
wording could be read as generating a timestamp after an invalid override,
whereas an invalid default or CLI value fails with EX_DATAERR before append.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review feedback across the design, roadmap, and terms of reference:

- Present the size-only rotation threshold and plain/compressed generation
  counts in docs/mpsc-log-design.md as the `[rotation]` sidecar defaults
  (`max_bytes`, `plain_generations`, `compressed_generations`) that callers
  can override, and use the configured plain and compressed retention counts
  when describing scheduled-period retention.
- Expand roadmap items 4.3.2 and 4.3.3 with observable success conditions:
  period-boundary rollover runs before the size check, collision-free suffix
  selection when archives already exist, and appending an oversized record
  directly to an empty active journal without creating an empty archive.
- Reframe the terms-of-reference retention goals so four plain generations
  and four completed periods read as configurable defaults rather than
  universal limits, and align the compression hard-constraint bullet.
- Standardise the terms of reference on "journal" and "journal path" for the
  target file and its argument, preserving the JSON Lines (JSONL) format name,
  the glossary log terms, and the distinct workflow sidecar directory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review feedback on the rotation normative steps and sidecar naming:

- Rewrite the size-only rotation algorithm in docs/mpsc-log-design.md so every
  generation index derives from the configured plain generation count P
  (`plain_generations`) and compressed generation count C
  (`compressed_generations`) rather than the hard-coded 36, 5, 4, 3, 2, and 1.
  Define both counts as non-negative integers (negatives rejected with
  EX_CONFIG) and specify the zero-count behaviour: P = 0 gzips the active file
  straight into generation 1, C = 0 deletes the oldest plain generation instead
  of gzipping, and both zero retains only the active file. Deletion, renaming,
  compression, and retention now target the computed generations.
- Clarify the terms-of-reference sidecar filename description to state that the
  sidecar path replaces the journal's final extension with `.toml`, appending
  `.toml` only when the journal has no extension, replacing the ambiguous
  "same base filename" wording.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The size-only rotation rules allowed plain_generations and
compressed_generations to both be zero, in which case rotation discarded the
previous journal. That state transition cannot be made atomic and contradicts
the terms-of-reference constraint that a failed invocation leaves the previous
journal readable.

- Require `P + C >= 1` in docs/mpsc-log-design.md, so semantic validation
  rejects zero total retention with EX_CONFIG alongside negative counts, and
  explain why discarding the rotated journal is a configuration error rather
  than a supported mode. A single zero count remains valid.
- Make step 5 state that the previous contents always reach generation 1
  before any append: a rename when P >= 1, and otherwise a gzip whose active
  file is removed only after the output is committed, so a failed compression
  aborts with the previous journal intact.
- Note in step 6 that an append failure therefore leaves the previous contents
  readable in the rotated journal.
- Add a roadmap 2.2.1 acceptance criterion covering both rejected count
  configurations.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Size-only rotation deleted generation P + C as its first act, so a later
failure in the rename or gzip sequence had already destroyed the oldest
archive and left a partially shifted layout. That also contradicted roadmap
item 4.2.3, which requires eviction only after newer retained files are
safely in place.

- Stage the eviction instead of deleting it: rename generation P + C aside to
  a reserved staging name in the same directory, so the rename stays within
  one filesystem and is atomic.
- Unlink the staged eviction only in a new final commit step, after the
  pending record has been appended, so no failure path deletes a
  record-bearing file.
- State the failure guarantee explicitly: steps 1 to 5 are atomic renames and
  atomic-write-file commits, so a failure aborts before the append and unwinds
  the completed renames in reverse order to the prior generation layout, and a
  process killed mid-rotation leaves a staged eviction that the next
  invocation reclaims under the journal lock.
- Update step 3's C = 0 note, which previously referred to the deletion.
- Add a roadmap 4.2.3 acceptance criterion for staging, commit-point
  unlinking, and staged-eviction reclaim.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Step 3 removed plain generation P once its gzip was committed, so the claimed
unwind "back to the prior generation layout" could not hold: a reverse rename
cannot restore a removed plain source. Interruption also had no restart rule
beyond reclaiming the staged eviction, leaving a partially shifted layout
unspecified.

- Defer every removal to the commit point. Superseded sources, including the
  gzipped plain generation P and the active file when P is zero, are renamed
  aside to staging names instead of being unlinked, so the prepare phase only
  creates and renames files and every source generation stays recoverable.
- Record the planned layout transition in a rotation manifest written through
  atomic-write-file before any file is touched, and remove it at the commit
  point, so its presence means a rotation was interrupted.
- State that each prepare step is idempotent, applied only when its source
  exists and its target does not, so replaying the manifest can neither
  duplicate nor skip a generation.
- Specify the three failure paths so rotation always settles into either the
  pre-rotation or the post-rotation layout: a prepare error reverses the
  applied renames, an append error still commits because the rotation itself
  completed, and a killed process leaves the manifest for the next invocation
  to complete or reverse under the journal lock before handling its own record.
- Expand roadmap item 4.2.3 to fault-inject each rotation commit point and
  assert recovery: partial renames, uncommitted and committed gzip output,
  staged source removal, append failure, and process interruption.

Steps 1 to 7 are now one unbroken list so the phase split no longer trips
MD029; the phase boundary is stated in the lead-in instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Address four review findings across the design, roadmap, and lock-naming ADR.

Lock timeout. The timeout was documented as sidecar-configurable while the
lock had to be held before the sidecar could be read, so no document said
which timeout governed the only acquisition attempt. Resolve it with an
unlocked advisory pre-read: the single attempt uses a five-second default
that a pre-read of `[locking] timeout_ms` may override, the pre-read only
chooses how long this invocation waits and never feeds repair, rotation,
coercion, or defaults, an absent or invalid pre-read falls back to five
seconds, and no second attempt is made. Apply the same wording to the design
architecture and write-protocol sections, the sidecar table, the critical
-section diagram, roadmap items 3.1.2 and 3.1.3, and ADR 001, whose ordering
claims now refer to the authoritative sidecar read.

Append commit point. The writer only defined rollback for a `write_all`
error, although the exit-code table maps flush and filesystem metadata
failures to EX_IOERR. Define a record as committed once its bytes and
terminating newline are written and flushed, extend the restore-to-recorded
-length rollback to every in-process failure after bytes reach the file,
state that a failed rollback truncate still returns EX_IOERR and leaves the
tail for partial-tail repair, and record that a retry after EX_IOERR cannot
duplicate a committed record. Note the residual at-least-once caveat when a
process dies between the write and the exit. Expand roadmap items 3.2.1 and
3.2.3 to fault-inject those paths.

Size-only rotation predicate. The size-only subsection named `max_bytes` but
never said when rotation triggers. State that rotation is evaluated after
tail repair and before the append, compares the repaired active length plus
the serialized pending record against `max_bytes`, and rotates only a
non-empty active file, so an oversized record appends directly to an empty
active file. The scheduled subsection already carried this rule.

Non-goals. Record that `mpsc-log` is `jo`-inspired rather than `jo`
compatible, cross-referencing the CLI contract and ADR 003 rather than
duplicating the option list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The append contract contradicted itself. It assumed a failed rollback
truncate leaves an unterminated tail, then concluded that a retry after
EX_IOERR could not duplicate a committed record. Neither holds when
write_all completes, flush fails, and the rollback truncate then fails: the
active file ends with a complete newline-terminated record, which the repair
rules preserve rather than remove, so a retry appends a second copy.

- State that a failed rollback truncate leaves the commit status unknown,
  that an unterminated tail is removed by partial-tail repair while a
  complete newline-terminated record is preserved and therefore committed,
  and that the invocation returns EX_IOERR without knowing which occurred.
- Replace the no-duplication guarantee with at-least-once whenever the
  writer cannot confirm the outcome, covering both the failed rollback
  truncate and process death between the write and the exit.
- Record that `mpsc-log` keeps no unknown-commit reconciliation state, so
  callers needing exactly-once must carry an idempotency key and deduplicate
  when reading.
- Reword roadmap items 3.2.1 and 3.2.3 so the acceptance criteria allow the
  duplication instead of asserting it cannot happen, and assert it as the
  documented outcome rather than a defect.

The "exactly one record per successful invocation" claims elsewhere are
unaffected, since at-least-once applies only to unconfirmed outcomes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The design put `serde_json::Map` in the domain core, so the record model was
defined by a serialization crate and the module table did not say which
modules were domain and which were adapters. Contributors had no documented
architecture to place new code against.

Design:

- Replace the `serde_json::Map` core with domain `Record` and `Value` types.
  Add section 4.1 defining `Value` variants and the required behaviour for
  object paths, nested objects, arrays, scalars, coercion results, and
  last-wins replacement.
- Add section 4.2 declaring the `Clock` and `JournalStore` ports, and state
  that no domain module names a filesystem, locking, TOML, JSON, or
  `sysexits` API.
- Add section 4.3 defining the adapters, including the TOML adapter that
  converts sidecar defaults and schema data into domain types at the input
  boundary and the JSON adapter that emits one compact JSON object at the
  output boundary.
- Give the section 12 module table a Layer column, and record that JSON
  output serialization and process exit mapping are boundary concerns rather
  than domain modules.
- Reword the merge table and inference prose so sidecar defaults convert into
  domain `Value` equivalents rather than JSON equivalents.

Developer guide: add an implementation architecture section covering the
eight planned modules and their layers, the `src/main.rs` startup and
`sysexits` responsibility, the adapter boundary and its concerns, the two
ports, and links to the design and ADRs 001, 002, and 003.

ADR 003: replace the `serde_json::Map` mandate with the domain `Record`
object map of `Value` values serialized by the JSON adapter, keeping the
accepted last-wins semantics and the textual duplicate-name non-goal.

Contents: note that the developer guide now covers the architecture.

Compact JSON output and last-wins duplicate handling are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The architecture prose, module table, and ADR already described the domain,
its `Record` and `Value` types, and the `Clock` and `JournalStore` ports, but
Figure 1 still drew the earlier topology: CLI to argument parser and sidecar
loader, into a record builder, into a journal writer. A reader of the
architecture section saw no domain, port, or adapter boundary in the diagram.

Redraw Figure 1 with input adapters, the domain, the ports, and the output
adapters as separate groups, showing the domain reaching the outside world
only through `Clock` and `JournalStore`, the filesystem adapter implementing
`JournalStore`, and `main.rs` owning the `sysexits` mapping. Extend the
caption to state the boundary in prose.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ADR 003 pairs the accepted last-wins decision with parameterized tests over
top-level keys, nested object paths, sidecar defaults, and explicit coercion
flags, but roadmap item 3.3.2 listed only the pairwise axes, so nothing in the
delivery plan required that coverage.

Add a success criterion to 3.3.2 requiring parameterized duplicate-path tests
for duplicate writes at the same object path, across top-level keys, nested
object paths, a sidecar default overridden by a CLI field, and the explicit
`-s`, `-n`, and `-b` coercion flags, asserting that the later write replaces
the earlier value at that object path. The existing pairwise axes criterion is
unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main is now a fixed point of `make fmt`, so bring this branch's own files to
the same state instead of reverting the formatter on every run.

docs/adr-001-lock-file-naming.md and docs/terms-of-reference.md are files this
branch adds, and their mdformat drift was this branch's own. The rebase onto
the reformatted main also left four stray blank lines before headings in
docs/developers-guide.md, which mdformat removes.

Formatting only: whitespace-normalised content is unchanged in all three
files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@leynos
leynos force-pushed the docs/mpsc-log-design-roadmap branch from c63e97c to 810af68 Compare August 23, 2026 18:47
@leynos
leynos merged commit 6101a6b into main Aug 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants