Thirteen hardening modules (3,079 lines) sat in nigig-site/src/ declared in no
mod statement. They had never been compiled or tested: cargo check never saw
them, and the plan's "implemented in the worktree and pending verification"
status was unverifiable by construction.
Extract the UI-free core into crates/apps/nigig-site-core (scope 5's "Rust core
crate ... testable; safe"; plan 6's target architecture). nigig-site depends on
it and re-exports it, so there is one copy of each module source: the app and
the core's unit tests compile the same files. The core has no Makepad
dependency, so its contracts run on a memory-limited runner.
Compiling that code for the first time found four real defects, all fixed:
- Role/Capability lacked Ord, so every BTreeSet of them failed to compile
(auth.rs)
- CaptureResult::empty never initialised site_id from its site parameter
(ocr_policy.rs)
- negotiate_version(2, 5) agreed on a protocol the peer never offered, which is
the silent downgrade the function exists to prevent (sync_protocol.rs)
- an absurd frame size returned Overflow instead of the actionable budget
breach (media_bounds.rs)
New feature-tranche domain modules, each with unit tests:
- organisation.rs SITE-20 invites, per-site roles, the 4.2 matrix as testable
data, site registry with geofence, settings
- report_pack.rs SITE-21 report numbering, entry status, signatures binding
actor/device/timestamp/document hash, lock and versioning,
multi-site compilation, monthly packs
- site_diary.rs SITE-22 weather with provenance, plant, deliveries, delay
log where a weather delay needs supporting rainfall,
visitors, manpower by trade
- workforce.rs SITE-23 consent-gated registration, tag-only blocklist,
attendance with overtime, QR badges, payroll CSV that never
emits identity, offboarding tombstones
- programme.rs SITE-25 dependencies with cycle detection and rollback,
topological order, critical path, frozen baselines with
slippage, checklists gating approval, snags, RFIs,
variations needing two distinct approvers
- hse.rs SITE-28 append-only incidents, closure requires corrective
action, toolbox talks, inspections, monthly statistics
workflows.rs gains the FR-1.14 Locked state; commands.rs gains a bounded
non-empty text validator shared by the new modules.
CI: the SITE-02 crypto/repository/store lanes pointed at -p nigig-site, where
those suites no longer live; left alone they would have compiled nothing and
reported a vacuous green. Repointed at the core, and added core-contracts and
core-clippy lanes with a ">=100 tests collected" check so a lane cannot pass
vacuously. All six existing Python contract gates still pass.
Auto-purge of worker ID data refuses to run until the scope 18 retention
question is answered rather than inventing a window.
Verified 2026-09-26: cargo test -p nigig-site-core --locked = 175 passed,
0 failed, 1 ignored (needs a live Secret Service session); cargo clippy -p
nigig-site-core --all-targets --no-deps -- -D warnings clean; cargo check -p
nigig-site clean. cargo test -p nigig-site is still killed by SIGKILL compiling
makepad-widgets on a 2 GB host, as recorded in plan 2.1.
EXECUTION_PLAN.md gains a per-tranche status ledger (1a) that states plainly
which tranches are done, domain-only, externally blocked, or not started, and
records that this branch and main diverged at b3a9005 with SITE-03 published
only on main.
Contain production capabilities, remove the production sync surface, and keep legacy media/export/transport implementations test-only.
Require authenticated existing-key storage with preservation-first recovery and sticky write disablement, backed by deterministic fault and concurrency tests plus dependency and workflow contracts.