Core error taxonomy + name validation (ADR-008 §4/§5, ADR-017 §3); AGENTS.md updated to Phase 1 posture

This commit is contained in:
glm-5.3-flash committed 2026-10-07 15:04:04 +00:00
1 parent 34e0b9732d
commit 74105a16ae
8 files changed
+413 -84

No files matched your search

+54 -3
View File
@@ -1,7 +1,7 @@
---
id: core-errors-and-validation
name: Core error taxonomy and name validation
status: pending
status: completed
depends_on: [scaffold-workspace]
scope: narrow
risk: low
@@ -65,8 +65,59 @@ engine and the contract suite reference the same constant.
## Notes
> To be filled by implementation agent
- `thiserror` v2 added to `alkstore` — the crate's first (and, until
wave 2's serde work, only) dependency.
- `Error::Database` carries
`#[source] Box<dyn std::error::Error + Send + Sync>` — the opaque
engine-detail carrier per ADR-008 §5. The `#[error(...)]` text is
deliberately terse ("database error") so it doesn't shadow the
source chain's detail. An `Error::database(err)` convenience
constructor wraps anything `Into<Box<dyn Error + Send + Sync>>`.
- `Error::PayloadTooLarge { limit: usize }` — the limit is `usize`
(a byte count, not a std::io::ErrorKind-style re-export); doc text
carries the ADR-020 §4 serialization-quantity pin and the
pg-only/never-SQLite asymmetry.
- Validation helpers split by name class exactly per ADR-008 §4's
third-round annotation: `validate_shared_name` (six shared kinds —
non-empty + reserved-prefix rejection) and `validate_local_name`
(stream-consumer names, `try_lock` owner, `worker_id` — non-empty
only). `NameKind::Shared`/`NameKind::Local` + `validate_name(kind,
name)` is the underlying pair; the two named helpers are the
ergonomic surface. Whitespace-only names are rejected as
`InvalidName` for both kinds (never a meaningful name on any
engine); names are not trimmed (the caller's name is stored as
given — engine quoting is the engine's obligation).
- The reserved-string test asserts its shared-name rejection carries
`ReservedName` (it carries the reserved prefix, so it can never be
a legal *shared* name) while `validate_local_name` accepts it — the
two name classes distinguished in tests, mirroring the ADR text.
- `#[non_exhaustive]` was verified on the enum definition, not in
this crate's tests: in-crate matching stays exhaustive (the
mechanical catch-all enforcement binds downstream crates, per the
Rust rules ADR-017 §3 relies on) — a test here asserting a
necessary wildcard is unreachable-code, flagged clippy `warn(unreachable_patterns)`.
- `schedule()`/`run_schedules`' `InvalidSpec`/`LeadershipLost`
variants (core-contract §Errors, ADR-009 §6) are *not* minted here
— the six-variant list is this task's exact scope; the scheduler
variants land with the trait-surface task that pins their
signatures.
## Summary
> To be filled on completion
Core error taxonomy and name validation implemented in `alkstore`.
`src/error.rs`: `Error` — exactly the six v1 variants
(`PayloadTooLarge { limit }`, `ReservedName { name }`,
`InvalidName { name }`, `Closed`, `Codec(String)`, `Database`
with `#[source]`), `thiserror`-derived, `#[non_exhaustive]`, plus
the `Result<T>` alias (the prelude shape downstream crates use).
`src/validation.rs`: `RESERVED_PREFIX = "__alkstore_"`,
`RESERVED_LISTENER_RECONNECTED =
"__alkstore_listener_reconnected__"` (public for the pg engine and
contract suite), `NameKind::{Shared, Local}`, and
`validate_shared_name`/`validate_local_name`/`validate_name`
helpers. All types re-exported from `src/lib.rs`. Ten unit tests
cover empty/whitespace-only/reserved-prefix/reserved-string/legal
names for both classes and the error display/source behavior.
`cargo test -p alkstore` (10 pass), `cargo clippy
--all-targets -- -D warnings`, and `cargo fmt --check` all clean;
workspace `cargo build` compiles all three crates.