Files
blocker/tests/Cargo.toml
T
SellPL c723efb186 feat(core): add workspace skeleton and the pure decision engine
Establishes the cargo workspace and the shared `blocker-core` crate. The
engine is deliberately written before any platform code, because CLAUDE.md
section 2 makes it the single source of decision truth and M1 acceptance
requires it to be pure.

**Workspace** — five crates plus a test crate, zero external dependencies.
Section 3 requires every crate to justify its binary-size cost, so M0 adds
none. [profile.release] is workspace-only (cargo rejects it in members) and
carries the section 5 settings that make the 5 MB stripped budget reachable.

**Purity contract** — `evaluate(&EngineInput) -> Decision` reads no clock, no
disk and no OS API; everything arrives in the input. `tests/purity.rs`
enforces this mechanically by asserting blocker-core has zero dependencies, so
a stray I/O reach-in fails the build rather than silently making the golden
tables useless as a parity contract.

Decisions worth calling out:

- **Monotonic time is a separate type from wall time.** Section 1.5.3 requires
  a system date change never to shorten a lock. Keeping them apart makes that
  structural rather than a rule to remember.
- **`start > end` means overnight.** No `crosses_midnight` flag: the comparison
  already encodes it and a second field is a second way to be wrong. The
  weekday for a window that started yesterday evening is yesterday's, which
  `overnight_window_survives_past_midnight` pins down.
- **`next_wakeup` is armed over every non-paused schedule, not only active
  ones.** Filtering to active conditions first would let the daemon sleep
  straight through the moment a schedule is due to start.
- **Allowlist needs the installed-app inventory.** `EngineInput` carries
  `installed_apps`; an empty slice fails open rather than guessing.
- **Wall-clock correction extends, never shortens, and clamps to the 24h cap.**
  Extending unbounded would satisfy anti-tamper and violate section 1.5.4.
- **`cast_possible_truncation` is denied workspace-wide.** Truncating a
  millisecond counter would corrupt a lock timer.

Verified: 22 tests pass, `cargo fmt --check` clean, `cargo clippy -D warnings`
clean, stripped release daemon 0.279 MB against the 5 MB budget.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-02 13:10:25 +00:00

36 lines
1.3 KiB
TOML

[package]
name = "blocker-tests"
version = "0.1.0"
edition = "2021"
description = "Cross-platform scenario tests: golden decision tables that are the parity contract for every platform layer."
license = "UNLICENSED"
[dependencies]
blocker-core = { path = "../core" }
# NO serde HERE — YET.
#
# The golden tables are designed as JSON (see src/golden.rs), and JSON needs
# serde/serde_json. Those crates are deliberately NOT added in M0, for two
# reasons:
#
# 1. CLAUDE.md section 0 rule 3 requires stopping to ask before adding any
# dependency not listed in section 3. serde is not on that list. It is
# transitively required by rusqlite and uniffi (both listed), which is why
# the design assumed it would be present — but "will be present later" is
# not "approved to add now".
#
# 2. The development machine has 9.7 GB free. Fetching the registry is the
# step that actually consumes disk, and the dependency-purity test needs a
# Cargo.lock to exist at all.
#
# The format is specified in src/golden.rs as the contract M1 implements against.
# The parse layer arrives in M1 alongside rusqlite, in one dependency change
# with an ADR entry. See docs/DECISIONS.md ADR-3.
[lints]
workspace = true
[lib]
name = "blocker_tests"
path = "src/lib.rs"