| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 9s
standards workspaces build + test / macOS energy backends (pull_request) Has been skipped
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 56s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m20s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 2m45s
§2.2 requires a steward that can restart to keep a durable journal and to
re-establish spend by replaying it. Nothing required the journal to have one
writer, and `FileJournal::open` was
OpenOptions::new().read(true).append(true).create(true)
with no lock at all.
Mesh's journal is hash-chained (`{seq, prev}`), and that changes the failure
from jcp-wire's without removing it. **The chain detects a second writer; it
does not prevent one.** Two stewards sharing a journal each replay it, each
re-establish the same spend and each serve against it, so the grant is
overspent *while both are running*. Their records then collide on `seq`, the
chain no longer forms, and `Mesh::with_journal` refuses the journal entirely —
so the detection arrives after the overspend and costs the steward its ability
to restart. `open` also truncates a torn trailing line, so a concurrent opener
can cut the file out from under an appender.
`open` now takes an exclusive lock, **before** the read and the truncation: an
opener refused afterwards would already have cut the holder's file.
The lock is `std::fs::File::try_lock`, stable since Rust 1.89 — no `unsafe`,
which this workspace denies, no new dependency, no lockfile change in any
workspace, and no platform caveat, because std covers Windows as well as unix.
Verified on the toolchain rather than assumed: a second `try_lock` on a held
file returns `WouldBlock`, and the lock releases when the file is dropped. It
is also released when the process dies, so a crash leaves no stale lock to
recover, which a lock-file sidecar would need a story for.
Where a platform cannot lock at all, `open` **fails** rather than proceeding:
serving against a record another steward may also be writing is the overspend
this exists to stop.
Falsification, five mutations, all killed by their named test. **M5 survived the
first round** — swallowing the unsupported-platform error broke nothing, because
that arm is unreachable on a platform whose locks work, and an unreachable arm
is exactly where a fail-open hides. `lock_outcome` is therefore split out from
the I/O so every arm is reachable from a test, and M5 now fails only its own.
This is the third fix running where the untested thing was the central claim.
M2 is the other one worth reading: the lock still present but taken after the
truncation fails **only** the no-truncation test, isolating the ordering from
the existence of the lock.
§2.2 gains the requirement, since the gap was in the spec before it was in the
code. `jcp-wire` carried the identical defect and is fixed the same way in
#346; the two standards deliberately keep their own copies of this machinery,
as `mesh-receipt` already vendors JCR-1 rather than depending on `jcp-schema`.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
| .. | ||
| crates | ||
| Cargo.lock | ||
| Cargo.toml | ||