Build-order step 1 (Part G): the state store + durability layer everything else sits on.
nisse_dev.state.StateStore (spec A2):
SQLite in WAL mode with synchronous=FULL — every commit is fsynced, so a power cut mid-write can never produce torn state
Checkpoint per transition: transition() writes the full state-machine position (state, project, data) as one immediately-committed statement
Durable intent log: begin_intent() records a unit of work before it starts; commit_intent/abort_intent resolve it; pending intents survive restart
schema_version from the first commit with a sequential migration hook; failed migrations roll back cleanly, and a state file newer than the code refuses to open
nisse_dev.reconcile.reconcile_on_boot (spec A3, first cut):
Pending intents are resolved against external truth via registered reconcilers — observable checks, never model self-assessment
Verified effect → intent committed (never repeated); verified no-effect → aborted; unverifiable or unknown kind → gate to AWAIT_INPUT, never blind-resume
Returns a BootReport with human-readable notes for the transport notice
Placement: in nisse_dev, not nisse-core — spec §0.1 says the library is extracted after the dev agent works (extraction is build step 10). The delegation-resume rule (A3 step 5) lands when delegations exist (step 7).
Tests: 18 new unit tests; an integration test spawns a subprocess that dies via os._exit mid-work and verifies state integrity plus intent visibility on the next boot. 22 unit + 3 integration green locally.
Build-order step 1 (Part G): the state store + durability layer everything else sits on.
**`nisse_dev.state.StateStore`** (spec A2):
- SQLite in **WAL mode with `synchronous=FULL`** — every commit is fsynced, so a power cut mid-write can never produce torn state
- **Checkpoint per transition**: `transition()` writes the full state-machine position (state, project, data) as one immediately-committed statement
- **Durable intent log**: `begin_intent()` records a unit of work before it starts; `commit_intent`/`abort_intent` resolve it; pending intents survive restart
- **`schema_version` from the first commit** with a sequential migration hook; failed migrations roll back cleanly, and a state file newer than the code refuses to open
**`nisse_dev.reconcile.reconcile_on_boot`** (spec A3, first cut):
- Pending intents are resolved against external truth via registered **reconcilers** — observable checks, never model self-assessment
- Verified effect → intent committed (never repeated); verified no-effect → aborted; unverifiable or unknown kind → **gate to `AWAIT_INPUT`**, never blind-resume
- Returns a `BootReport` with human-readable notes for the transport notice
**Placement**: in `nisse_dev`, not `nisse-core` — spec §0.1 says the library is extracted after the dev agent works (extraction is build step 10). The delegation-resume rule (A3 step 5) lands when delegations exist (step 7).
**Tests**: 18 new unit tests; an integration test spawns a subprocess that dies via `os._exit` mid-work and verifies state integrity plus intent visibility on the next boot. 22 unit + 3 integration green locally.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Build-order step 1: the critical path everything else sits on.
- StateStore: SQLite in WAL mode with synchronous=FULL, so every
state transition and intent-log write is committed and fsynced
before returning; a power cut cannot tear state
- Durable intent log: begin_intent records a unit of work before it
starts; commit/abort resolve it; pending intents survive restart
- schema_version stamped from the first commit, with a sequential
migration hook; a newer state file than the code supports is
refused rather than misread
- reconcile_on_boot (A3 first cut): pending intents are checked
against external truth by registered reconcilers (observable
checks, never model self-assessment); verified effects are
committed, verified no-ops aborted, anything unverifiable gates
to AWAIT_INPUT — never blind-resume
- Lives in nisse_dev per spec 0.1: the library is extracted after
the dev agent works, not designed up front
- Integration test kills a subprocess mid-work with os._exit and
verifies state integrity and intent visibility on reopen
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Build-order step 1 (Part G): the state store + durability layer everything else sits on.
nisse_dev.state.StateStore(spec A2):synchronous=FULL— every commit is fsynced, so a power cut mid-write can never produce torn statetransition()writes the full state-machine position (state, project, data) as one immediately-committed statementbegin_intent()records a unit of work before it starts;commit_intent/abort_intentresolve it; pending intents survive restartschema_versionfrom the first commit with a sequential migration hook; failed migrations roll back cleanly, and a state file newer than the code refuses to opennisse_dev.reconcile.reconcile_on_boot(spec A3, first cut):AWAIT_INPUT, never blind-resumeBootReportwith human-readable notes for the transport noticePlacement: in
nisse_dev, notnisse-core— spec §0.1 says the library is extracted after the dev agent works (extraction is build step 10). The delegation-resume rule (A3 step 5) lands when delegations exist (step 7).Tests: 18 new unit tests; an integration test spawns a subprocess that dies via
os._exitmid-work and verifies state integrity plus intent visibility on the next boot. 22 unit + 3 integration green locally.🤖 Generated with Claude Code