Skip to content

M9: !Sync compile-fail (trybuild) + Send assertion (§6.2/§14.6)#29

Merged
guyo13 merged 1 commit into
mainfrom
claude/youthful-hamilton-tncsqv
Jun 29, 2026
Merged

M9: !Sync compile-fail (trybuild) + Send assertion (§6.2/§14.6)#29
guyo13 merged 1 commit into
mainfrom
claude/youthful-hamilton-tncsqv

Conversation

@guyo13

@guyo13 guyo13 commented Jun 29, 2026

Copy link
Copy Markdown
Owner

M9 §14.6 — single-writer enforced at compile time

Proves the single-writer contract (§6.2) at the type level, complementing the runtime directory lock.

What's here

  • !Sync compile-fail prooftrybuild dev-dep + tests/ui.rs runner + tests/ui/wal_not_sync.rs (+ pinned .stderr): asserts that Wal<NullObserver>: Sync does not compile. The handle's PhantomData<Cell<()>> marker makes it !Sync, so sharing a handle across threads — i.e. a concurrent second writer — is a compile error (Cell<()> cannot be shared between threads safely).
  • Send positive assertion — new wal::tests::handle_is_send asserts the handle is Send (movable to another thread). Together: "Send but !Sync".
  • Directory lock — the runtime half (§14.6) is already covered by the existing wal::tests::second_open_is_locked (a second in-process Wal::open of the same dir returns WalError::Locked via the exclusive flock on dir/LOCK). Not duplicated.

trybuild .stderr fragility — handled honestly

The pinned diagnostic is toolchain-sensitive. To avoid cross-toolchain flakiness:

  • The ui test runs only in the per-PR test job (stable). The MSRV job is cargo check, which builds the runner but does not execute it, so .stderr is compared against exactly one toolchain.
  • Regenerate with TRYBUILD=overwrite cargo test --test ui after a rustc bump that changes the wording — documented in Cargo.toml, tests/ui.rs, and §14.6.
  • Generated + verified on rustc 1.94.1; the chosen error (cannot be shared between threads safely) is stable rustc phrasing, and trybuild normalizes the $RUST path.

If you'd prefer zero stderr maintenance, the alternative is a compile_fail doctest (asserts non-compilation without pinning the message) — happy to switch; I went with trybuild as §14.6 specifies.

Verification

cargo test (22 ok-lines incl. ui / handle_is_send / second_open_is_locked), cargo clippy --all-targets -D warnings, cargo fmt --check, MSRV 1.85 (trybuild v1.0.117 builds; Cargo.lock updated) all green.

Docs

§14.6 (the !Sync + dir-lock bullets marked implemented) + a new §14.13 single-writer DoD row + CLAUDE.md.

M9 status

Fuzz F1–F4 ✅, Miri ✅, !Sync/dir-lock ✅ here. Remaining: loom publish-barrier → soak → CI-matrix tidy-up; plus the F1–F4 N-CPU-hour release-gate observation (OPEN on a dedicated runner).

🤖 Generated with Claude Code


Generated by Claude Code

Proves single-writer enforcement at compile time. Adds a `trybuild` dev-dep and
`tests/ui.rs` + `tests/ui/wal_not_sync.rs` (+ pinned .stderr): asserting
`Wal<NullObserver>: Sync` must NOT compile -- the PhantomData<Cell<()>> marker
(§6.2) makes the handle !Sync, so concurrent writers are a compile error
("`Cell<()>` cannot be shared between threads safely"). The Send half (handle is
movable across threads) is asserted positively by a new `wal::tests::
handle_is_send`.

The runtime directory-lock requirement (§14.6) is ALREADY covered by the existing
`wal::tests::second_open_is_locked` (a second in-process Wal::open of the same dir
returns WalError::Locked via the exclusive flock on dir/LOCK) -- not duplicated.

trybuild .stderr fragility handled honestly: it is toolchain-sensitive, so it
runs ONLY in the per-PR `test` job (stable) -- the MSRV job is `cargo check`,
which builds the runner but does not execute it, so .stderr is compared against
exactly one toolchain. Regenerate with `TRYBUILD=overwrite cargo test --test ui`
on a rustc bump (documented in Cargo.toml, tests/ui.rs, §14.6). Generated +
verified on rustc 1.94.1; the diagnostic wording is stable rustc phrasing.

Docs: §14.6 (the !Sync + dir-lock bullets) + a new §14.13 single-writer DoD row +
CLAUDE.md. cargo test (22 ok-lines incl. ui/handle_is_send/second_open_is_locked),
clippy --all-targets -D warnings, cargo fmt --check, MSRV 1.85 (trybuild v1.0.117
builds, Cargo.lock updated) all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rpbwt9JT56hQvVXiqTS131
@guyo13 guyo13 merged commit 6401005 into main Jun 29, 2026
10 checks passed
guyo13 pushed a commit that referenced this pull request Jun 29, 2026
…Sync

Per the review on PR #30 (closed unmerged): the loom publish-barrier harness was
green independently of the crate (it imported only loom::sync::* and re-built the
integrator's cursor inside the test), so it validated a textbook Release/Acquire
fact, not this code. It can't be wired to the library either: the writer is
`!Sync` by construction (PhantomData<Cell<()>>, §6.2, proven statically by the
#29 trybuild test), so there is no intra-WAL shared-memory concurrency for loom
to model -- and a static !Sync proof is stronger than an empirical model check.
The only Release/Acquire barrier is the integrator's publish cursor (out of
scope, §1/§15.7); the WAL's observer-ordering obligation is covered by the §15.8
DurabilityObserver contract tests.

Docs-only correction (no code/dep/CI -- the loom dep/test/workflow lived only on
the closed PR #30 and never reached main):
- §14.6: replace the loom-harness bullet with a normative not-applicable note,
  conditioned on the writer staying !Sync (a future Sync redesign re-opens it).
- §14.6 concurrency cross-ref + the tooling/deps list: de-loom'd.
- v6 changelog: entry recording the removal + rationale.
- CLAUDE.md: drop loom from the dev-tools list + a status entry.

Same discipline as the §14.4d negative result: the characterized "why not" is the
deliverable, not a silent deletion. cargo fmt --check clean (docs-only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rpbwt9JT56hQvVXiqTS131
guyo13 pushed a commit that referenced this pull request Jun 29, 2026
…Sync

Per the review on PR #30 (closed unmerged): the loom publish-barrier harness was
green independently of the crate (it imported only loom::sync::* and re-built the
integrator's cursor inside the test), so it validated a textbook Release/Acquire
fact, not this code. It can't be wired to the library either: the writer is
`!Sync` by construction (PhantomData<Cell<()>>, §6.2, proven statically by the
#29 trybuild test), so there is no intra-WAL shared-memory concurrency for loom
to model -- and a static !Sync proof is stronger than an empirical model check.
The only Release/Acquire barrier is the integrator's publish cursor (out of
scope, §1/§15.7); the WAL's observer-ordering obligation is covered by the §15.8
DurabilityObserver contract tests.

Docs-only correction (no code/dep/CI -- the loom dep/test/workflow lived only on
the closed PR #30 and never reached main):
- §14.6: replace the loom-harness bullet with a normative not-applicable note,
  conditioned on the writer staying !Sync (a future Sync redesign re-opens it).
- §14.6 concurrency cross-ref + the tooling/deps list: de-loom'd.
- v6 changelog: entry recording the removal + rationale.
- CLAUDE.md: drop loom from the dev-tools list + a status entry.

Same discipline as the §14.4d negative result: the characterized "why not" is the
deliverable, not a silent deletion. cargo fmt --check clean (docs-only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rpbwt9JT56hQvVXiqTS131
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants