Data Model — Landing-Pass Campsite Follow-ups
This is a test-infrastructure + CLI-internals mission; it introduces no persistent domain entities. The only "model" changes are the small structural elements below.
SG-1 — ShardGroup.default_fallback (new optional field)
hash-bucket shard for any under-root file not present in file_assignment, instead of None.
win; the fallback only fires for unlisted under-root files; the group's shard union still covers the full root universe (GC-1 union invariant).
row is unaffected unless it also opts in.
- Where:
tests/_shard_registry.py(theShardGroupdataclass). - Type:
bool, defaultFalse. - Meaning: when
True,shard_for(path)returns a deterministic - Invariant: explicit
file_assignmententries are checked first and always - Consumers: the
archrow (tests/_arch_shard_map.py) opts in; thenext
LN-1 — Lane.UNINITIALIZED (new canonical member)
src/specify_cli/status/lane_reader.py.
it from get_wp_lane() instead of the bare string LEGACY_UNINITIALIZED_SENTINEL, so the loader's return type is a pure Lane.
distinct. get_wp_lane returns the sentinel when a WP is absent from the snapshot (empty event log, or WP not present); GENESIS is a WP that is seeded but has no explicit lane (lane_reader.py:72 default). Collapsing them onto GENESIS regresses worktree_topology.py:81 (unseeded→"planned") and merge/done_bookkeeping.py (done-detection). Verified in code.
== "uninitialized" equality (via StrEnum) and any serialized form remain behavior-identical. UNINITIALIZED is a non-display, non-transitionable read sentinel (like GENESIS). Full, verified blast radius (post-tasks squad):
allowed_targets() -> frozenset() (EMPTY)** and register it in _STATE_MAP/_FACTORY_ALIASES — NOT an alias to GenesisState. Aliasing to genesis (targets {PLANNED, CANCELED}) would inject 2 edges into the import-time ALLOWED_TRANSITIONS build (transitions.py:43-48) → the ==29 count test fails AND the sentinel becomes transitionable. An unmapped member crashes transitions.py:44 at import.
through a canonical non-display-lane authority): reducer.py:134,166, wp_metadata.py:385, tasks_status_view.py:163, and lifecycle.py:119 (the last has no genesis filter today — it already emits "genesis": 0).
requires every non-genesis member in CANONICAL_LANES. UNINITIALIZED is exempted like genesis (non-display) — update the parity exemption, do NOT add it to the tuple.
tests/specify_cli/cli/commands/agent/, tests/integration/, tests/test_dashboard/ derive "all non-genesis lanes" or a hardcoded roster and must also exclude/extend for UNINITIALIZED.
merge/done_bookkeeping.py:151 both rely on Lane("uninitialized") RAISING today; once it is a member the except goes dead — preserve the GENESIS-fallback / force-done=False contract explicitly.
annotation → dict[str, Lane] (verify workspace/context.py:497,513 does not surface a new diagnostic). Requires behavior tests on the unseeded path — the regression is type-invisible because consumers already str(...)-coerce.
- Where:
src/specify_cli/status/models.py(add member), consumed via - Change: add a NEW
Lane.UNINITIALIZED = "uninitialized"member and return - Why a new member, NOT reuse of
Lane.GENESIS: the two are semantically - Invariant: the StrEnum value stays
"uninitialized", so existing - FSM (
wp_state.py): add a **dedicatedUninitializedStatewith - Display filters must exclude UNINITIALIZED at five sites (route
CANONICAL_LANESparity (status_lanes.py):test_parity.py:812- ~12 lane-roster tests across
tests/status/,tests/specify_cli/status/, - Consumer contract (WP06):
coordination/status_transition.py:557and - Effect: removes the
Lane | strunion at its source;get_all_wp_lanes
RR-1 — Remediation registry
ALL_REMEDIATION_TEXTS collection is the canonical set. Both _REMEDIATION_HINTS (field → remedy) and _build_remediation_lines() (trigger → bullet) reference the constants.
(the full set), not just the dict; every referenced command resolves under --help. Rendered output is byte-identical to today.
- Where:
src/specify_cli/sync/preflight.py. - Change: all remediation sentences become named module constants; a single
- Invariant: the command-name validation guard scans
ALL_REMEDIATION_TEXTS
No API contracts
No external route, request/response body, auth header, websocket, sync payload, or tracker control-plane semantics change → contracts/ is intentionally empty (recorded in plan.md).