@llblab/pi-kit 0.24.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/BACKLOG.md +5 -1
- package/CHANGELOG.md +12 -0
- package/README.md +11 -8
- package/node_modules/@llblab/pi-actors/AGENTS.md +2 -0
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +4 -1
- package/node_modules/@llblab/pi-actors/LICENSE +21 -0
- package/node_modules/@llblab/pi-actors/README.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +1 -1
- package/node_modules/@llblab/pi-actors/package.json +4 -3
- package/node_modules/@llblab/pi-claude-usage/AGENTS.md +23 -0
- package/node_modules/@llblab/pi-claude-usage/BACKLOG.md +4 -0
- package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +21 -0
- package/node_modules/@llblab/pi-claude-usage/LICENSE +22 -0
- package/node_modules/@llblab/pi-claude-usage/README.md +155 -0
- package/node_modules/@llblab/pi-claude-usage/banner.jpg +0 -0
- package/node_modules/@llblab/pi-claude-usage/index.ts +8 -0
- package/node_modules/@llblab/pi-claude-usage/lib/extension.ts +30 -0
- package/node_modules/@llblab/pi-claude-usage/lib/fast.ts +24 -0
- package/node_modules/@llblab/pi-claude-usage/lib/query.ts +146 -0
- package/node_modules/@llblab/pi-claude-usage/lib/status-format.ts +297 -0
- package/node_modules/@llblab/pi-claude-usage/lib/status.ts +366 -0
- package/node_modules/@llblab/pi-claude-usage/lib/telegram.ts +44 -0
- package/node_modules/@llblab/pi-claude-usage/lib/usage-store.ts +221 -0
- package/node_modules/@llblab/pi-claude-usage/lib/usage.ts +128 -0
- package/node_modules/@llblab/pi-claude-usage/package.json +64 -0
- package/node_modules/@llblab/pi-clean-room/AGENTS.md +1 -0
- package/node_modules/@llblab/pi-clean-room/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-clean-room/LICENSE +21 -0
- package/node_modules/@llblab/pi-clean-room/README.md +1 -1
- package/node_modules/@llblab/pi-clean-room/package.json +3 -2
- package/node_modules/@llblab/pi-codex-usage/AGENTS.md +9 -6
- package/node_modules/@llblab/pi-codex-usage/BACKLOG.md +2 -1
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +17 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +75 -17
- package/node_modules/@llblab/pi-codex-usage/index.ts +8 -1602
- package/node_modules/@llblab/pi-codex-usage/lib/extension.ts +25 -0
- package/node_modules/@llblab/pi-codex-usage/lib/fast.ts +23 -0
- package/node_modules/@llblab/pi-codex-usage/lib/query.ts +368 -0
- package/node_modules/@llblab/pi-codex-usage/lib/status-format.ts +347 -0
- package/node_modules/@llblab/pi-codex-usage/lib/status.ts +435 -0
- package/node_modules/@llblab/pi-codex-usage/lib/telegram.ts +45 -0
- package/node_modules/@llblab/pi-codex-usage/lib/usage-store.ts +229 -0
- package/node_modules/@llblab/pi-codex-usage/lib/usage.ts +425 -0
- package/node_modules/@llblab/pi-codex-usage/package.json +11 -6
- package/node_modules/@llblab/pi-command-fast/AGENTS.md +7 -0
- package/node_modules/@llblab/pi-command-fast/BACKLOG.md +9 -0
- package/node_modules/@llblab/pi-command-fast/CHANGELOG.md +7 -0
- package/node_modules/@llblab/pi-command-fast/LICENSE +21 -0
- package/node_modules/@llblab/pi-command-fast/README.md +42 -0
- package/node_modules/@llblab/pi-command-fast/dist/command.d.ts +8 -0
- package/node_modules/@llblab/pi-command-fast/dist/command.js +52 -0
- package/node_modules/@llblab/pi-command-fast/dist/index.d.ts +3 -0
- package/node_modules/@llblab/pi-command-fast/dist/index.js +3 -0
- package/node_modules/@llblab/pi-command-fast/dist/models-json.d.ts +10 -0
- package/node_modules/@llblab/pi-command-fast/dist/models-json.js +81 -0
- package/node_modules/@llblab/pi-command-fast/package.json +49 -0
- package/node_modules/@llblab/pi-grow-loop/AGENTS.md +1 -0
- package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -1
- package/node_modules/@llblab/pi-grow-loop/LICENSE +21 -0
- package/node_modules/@llblab/pi-grow-loop/README.md +1 -1
- package/node_modules/@llblab/pi-grow-loop/package.json +3 -2
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +43 -56
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +17 -3
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +25 -0
- package/node_modules/@llblab/pi-state-flow/LICENSE +21 -0
- package/node_modules/@llblab/pi-state-flow/README.md +18 -15
- package/node_modules/@llblab/pi-state-flow/dist/index.d.ts +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/index.js +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.d.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +7 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +16 -7
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +9 -9
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +5 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +7 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +3 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +3 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +503 -235
- package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +16 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/history.d.ts +11 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +6 -7
- package/node_modules/@llblab/pi-state-flow/dist/lib/logging.d.ts +4 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/logging.js +1 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +4 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +13 -13
- package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.d.ts +7 -6
- package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +9 -9
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +3 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +17 -12
- package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +13 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +62 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +23 -8
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +52 -20
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +22 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +30 -10
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +5 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +19 -28
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +17 -15
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +52 -52
- package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.d.ts +8 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.js +34 -18
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.d.ts +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +13 -19
- package/node_modules/@llblab/pi-state-flow/dist/package.json +12 -11
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +2 -2
- package/node_modules/@llblab/pi-state-flow/docs/README.md +2 -1
- package/node_modules/@llblab/pi-state-flow/docs/agent-contract-relocation.md +72 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +44 -36
- package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +14 -6
- package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +7 -5
- package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +6 -6
- package/node_modules/@llblab/pi-state-flow/docs/performance.md +1 -1
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +13 -12
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +37 -33
- package/node_modules/@llblab/pi-state-flow/index.ts +3 -2
- package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +2 -2
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +20 -10
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +15 -14
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +8 -6
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +6 -6
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +484 -232
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +14 -5
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +16 -11
- package/node_modules/@llblab/pi-state-flow/lib/logging.ts +5 -1
- package/node_modules/@llblab/pi-state-flow/lib/query.ts +16 -16
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +11 -11
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +19 -13
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +57 -3
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +57 -22
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +46 -13
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +23 -32
- package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +66 -65
- package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +39 -19
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +19 -27
- package/node_modules/@llblab/pi-state-flow/package.json +12 -11
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +2 -2
- package/node_modules/jsonc-parser/CHANGELOG.md +76 -0
- package/node_modules/jsonc-parser/LICENSE.md +21 -0
- package/node_modules/jsonc-parser/README.md +364 -0
- package/node_modules/jsonc-parser/SECURITY.md +41 -0
- package/node_modules/jsonc-parser/lib/esm/impl/edit.js +185 -0
- package/node_modules/jsonc-parser/lib/esm/impl/format.js +261 -0
- package/node_modules/jsonc-parser/lib/esm/impl/parser.js +659 -0
- package/node_modules/jsonc-parser/lib/esm/impl/scanner.js +443 -0
- package/node_modules/jsonc-parser/lib/esm/impl/string-intern.js +29 -0
- package/node_modules/jsonc-parser/lib/esm/main.d.ts +351 -0
- package/node_modules/jsonc-parser/lib/esm/main.js +178 -0
- package/node_modules/jsonc-parser/lib/umd/impl/edit.js +201 -0
- package/node_modules/jsonc-parser/lib/umd/impl/format.js +275 -0
- package/node_modules/jsonc-parser/lib/umd/impl/parser.js +682 -0
- package/node_modules/jsonc-parser/lib/umd/impl/scanner.js +456 -0
- package/node_modules/jsonc-parser/lib/umd/impl/string-intern.js +42 -0
- package/node_modules/jsonc-parser/lib/umd/main.d.ts +351 -0
- package/node_modules/jsonc-parser/lib/umd/main.js +194 -0
- package/node_modules/jsonc-parser/package.json +37 -0
- package/package.json +10 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Temporal acceptance
|
|
2
2
|
|
|
3
|
-
This is a maintained property-to-test map for the current canonical-file contract, not a second backlog or a substitute for running tests. Paths and quoted test names refer to a source checkout; tests are not shipped in the npm runtime package.
|
|
3
|
+
This is a maintained property-to-test map for the current canonical-file contract, not a second backlog or a substitute for running tests. Paths and quoted test names refer to a source checkout; tests are not shipped in the npm runtime package. Some test labels retain internal Start/Stop terminology: activation uses `/state-flow-active`; inactive scenarios explicitly select Passive or Off according to their tools/context assertions.
|
|
4
4
|
|
|
5
5
|
## Required properties and witnesses
|
|
6
6
|
|
|
@@ -20,10 +20,10 @@ This is a maintained property-to-test map for the current canonical-file contrac
|
|
|
20
20
|
14. **Accepted response changes are transitions:** `tests/extension.test.ts` verifies that an ordinary accepted answer becomes runtime-owned `response` without a finalization patch or fallback inference, and “an empty accepted answer finalizes the run and stores an empty response” proves `""` is accepted after an earlier barrier. `tests/transition.test.ts` proves the empty value is an ordinary Session-owned semantic change when it replaces prior text.
|
|
21
21
|
15. **Correct repeats succeed without semantic changes:** “accepts canonical atomic scope patches and correct repeats without another checkpoint” preserves canonical bytes and native checkpoint count on repetition, while still rejecting empty supplied scopes and obsolete finalization-shaped calls. Runtime current-head witnesses preserve revisions, lineage and step across identical patches and compilations; a changed accepted response remains a runtime-owned transition.
|
|
22
22
|
16. **Configured hot-history bounds:** `tests/temporal.test.ts` verifies hot-range and unavailable pre-origin boundaries; the real-Pi history-reader test rejects offset eight at the default limit seven without a transition. `tests/config.test.ts` exercises materialized and scope patch-history paths at limits 0, 1, 7, and 12, including single-path/one-item batch reads above seven and distinct configured versus actually retained boundaries.
|
|
23
|
-
17. **Historical restoration is distinct from activation:** `tests/recovery.test.ts` rejects unavailable selections without older-pointer or disabled-marker fallback. Extension/native tests fence passive publication until explicit current-memory activation, with unchanged canonical bytes
|
|
23
|
+
17. **Historical restoration is distinct from activation:** `tests/recovery.test.ts` rejects unavailable selections without older-pointer or disabled-marker fallback. Extension/native tests fence passive publication until explicit current-memory activation, with unchanged canonical bytes in both inactive modes. Native “real Pi activates current … memory after expired tree selection and reload” cases cover passive, active and interrupted work plus the next provider's private-memory input. Runtime current-head tests preserve semantics, provenance, revisions, step and available history across old modes, distinguish absent from incomplete private authority, adopt validated foreign shared streams without private leakage or invented history, and reject a concurrent private writer. Native pre-runtime and inherited-fork-selection witnesses preserve current owned session memory instead of resetting it or recopying a parent. Repeated active Start leaves response reconciliation intact. Ordinary conversation with only a pre-runtime mode checkpoint still bootstraps; unaccepted fork identity/CWD repair retries the exact source.
|
|
24
24
|
18. **Tree/resume select the correct lineage:** `tests/integration.test.ts` — “real Pi preserves branch-local state through compaction and rejects an expired sibling after fresh-origin navigation” and “real Pi old tree branch stop and resume preserve selected semantics without rewinding shared files”.
|
|
25
|
-
19. **Stop changes policy, not semantic history:** `tests/runtime.test.ts` lifecycle-only witnesses use a separate process to advance global/CWD semantics or provenance, including wider foreign retention, then prove exact semantic/sidecar preservation, unchanged steps, idempotent Stop, and same-session/stale-evidence refusal. Native Stop/new-request witnesses verify the accepted shared view reaches handoff/inference without a lifecycle semantic write, while the current-head native witness accepts a shared write racing after inference and retains its actual accepted predecessor. Mid-tool Stop tests preserve ordinary/bootstrap trajectories through tree, reload, resume, and restart. The native “real Pi retains a native split-turn continuation through late tools” Stop/no-Stop controls actually remove the original user with native threshold compaction, then require summary, paired reads and foreign context in model input. The Stop case also checks frozen semantics/step, unchanged trace prefix, tree/reload/cold resume/bootstrap restart, no resurrection of discarded input, and persistent foreign context after the next active run. Pure passive-selector tests cover missing, colliding and nonfinite recorded active anchors and explicit preservation of unfinished compilation. The native “real Pi repeated Start/Stop preserves uncompiled conversation and its prior boundary” cases cover initial/restarted bootstrap, repeated idle toggles, reload, unchanged native trace, and release after accepted compilation; extension tests cover interrupted idle Stop with and without a captured anchor. Completed idle/legacy cutoffs remain bounded. The extension's failed-Stop matrix covers concurrent private writers, invalid lock ownership and malformed runtime files
|
|
26
|
-
20. **
|
|
25
|
+
19. **Stop changes policy, not semantic history:** `tests/runtime.test.ts` lifecycle-only witnesses use a separate process to advance global/CWD semantics or provenance, including wider foreign retention, then prove exact semantic/sidecar preservation, unchanged steps, idempotent Stop, and same-session/stale-evidence refusal. Native Stop/new-request witnesses verify the accepted shared view reaches handoff/inference without a lifecycle semantic write, while the current-head native witness accepts a shared write racing after inference and retains its actual accepted predecessor. Mid-tool Stop tests preserve ordinary/bootstrap trajectories through tree, reload, resume, and restart. The native “real Pi retains a native split-turn continuation through late tools” Stop/no-Stop controls actually remove the original user with native threshold compaction, then require summary, paired reads and foreign context in model input. The Stop case also checks frozen semantics/step, unchanged trace prefix, tree/reload/cold resume/bootstrap restart, no resurrection of discarded input, and persistent foreign context after the next active run. Pure passive-selector tests cover missing, colliding and nonfinite recorded active anchors and explicit preservation of unfinished compilation. The native “real Pi repeated Start/Stop preserves uncompiled conversation and its prior boundary” cases cover initial/restarted bootstrap, repeated idle toggles, reload, unchanged native trace, and release after accepted compilation; extension tests cover interrupted idle Stop with and without a captured anchor. Completed idle/legacy cutoffs remain bounded. The extension's failed-Stop matrix covers concurrent private writers, invalid lock ownership and malformed runtime files in both inactive modes: the selected mode remains applied, canonical bytes stay unchanged, accepted memory and native conversation survive, and only Passive projects the handoff; reload is read-only, and writes remain fenced until accepted Start. Native “real Pi failed Stop stays passive through late tools, tree, reload and resume” cases verify provider inputs, rejected tool calls, untouched trace prefixes, private memory, current foreign writes, and recovery through explicit Start. A native fork witness retains disabled policy without inheriting the parent's fence. Session tests bind fence lifetime to owner/reset/accepted-checkpoint evidence; runtime current-head tests prove read-only loading changes no canonical bytes. `tests/storage.test.ts` fences lifecycle-only writes to config/runtime files; `tests/extension.test.ts` covers idle/legacy cutoffs and new/fork boundaries.
|
|
26
|
+
20. **Compact mode, inspectable revisions:** `tests/status.test.ts` proves Active/Passive terminal indicators omit revisions, Off alone hides the indicator, and `/state-flow-status` retains the effective `g#c#s#` vector with blank lines between top-level JSON planes. `tests/telegram.test.ts` verifies mode-only section labels, capitalized radio options with one mode-specific selected marker and ⚫️ inactive markers, direct scope buttons, owner Rich headings with `#revision` and Effective with `g#c#s#`. Telegram can inspect existing shared memory even in Off without initializing or mutating storage. Failure-fenced inspection retains accepted cached memory without overwriting another writer.
|
|
27
27
|
21. **Independent revisions survive folding and foreign writers:** `tests/temporal.test.ts` proves each materially changed scope advances once for sparse and multi-scope cohorts, response-only transitions advance only Session, no-ops advance none, selected retained history restores the matching revision, and folding never resets it. `tests/durable.test.ts` covers revision serialization plus the pre-revision 0.17 retained-tail baseline. `tests/runtime.test.ts` uses an independent file-backed writer to advance Global, then refreshes the first runtime without file mutation and proves `G1/C0/S1` becomes `G1/C0/S2` after one private Session patch.
|
|
28
28
|
22. **Current-head atomic model publication:** `tests/runtime.test.ts` applies authored independent/overlapping assignments, deletion and arrays to current shared values, preserves another owner's private files, and derives the predecessor/revisions from that basis. Compilation witnesses replace complete cards with matching provenance, preserve untouched evidence, accept repeats and refuse orphaned evidence after semantic-pair disappearance. Partial/malformed shared evidence and concurrent/unselected private authority stay fenced. Fault injection rolls back a mixed publication without installing the candidate's shared adoption or private draft. Extension tests reject a first passive patch without publishing empty setup, and recheck acquired-source freshness after lock waiting. Native “real Pi awaits foreign publication” cases hold an independent process beyond the former wait budget, verify responsive waiting/cancellation with unchanged canonical bytes, and require the next provider to see accepted current Global/CWD plus its own Session, never the foreign private layer.
|
|
29
29
|
23. **Awaited response acceptance owns its lifecycle:** `tests/extension.test.ts` verifies waiting against current shared memory, one accepted checkpoint without a second publication, rollback without candidate/cache or lifecycle installation, cancellation at Stop/session/tree/shutdown boundaries, shutdown fencing and superseding-answer isolation. Native “real Pi awaits response publication” witnesses wait behind an independent writer for over two seconds, then prove later boundary handlers and continuation inference see the accepted response, current Global/CWD and only their own Session. Native Abort withdraws the wait without changing canonical bytes, the prior response or unfinished specification, and without requesting a repair inference.
|
|
@@ -32,25 +32,26 @@ This is a maintained property-to-test map for the current canonical-file contrac
|
|
|
32
32
|
26. **Advisory startup inspection awaits coherent evidence:** `tests/continuation.test.ts` pauses an independent publisher between private-tail and metadata replacement for over two seconds. Inspection and the default-launch recommendation wait; cancellation rejects without suggesting another session or changing bytes/lock ownership. After release, eligibility uses the complete accepted cohort. Absent/empty stores stay uninitialized; malformed, orphaned, symlinked and invalid-lock evidence stays ineligible. Async host callbacks preserve detached native headers and eligibility, cannot override native identity, and cannot return late decisions or inspect more candidates after cancellation. Existing native-session, shared-drift and private-lineage witnesses remain applicable; these are advisory APIs, not an installed native startup hook.
|
|
33
33
|
27. **Awaited runtime-only acceptance preserves semantic authority:** `tests/runtime.test.ts` applies both raw and awaited lifecycle publication beside independently advanced Global/CWD state or evidence at limits 0/7, preserving wider stored tails, orphaned provenance, unknown metadata and private values. An independent publisher pauses mid-cohort for over two seconds; waiting/cancellation changes no accepted bytes/cache, and the post-wait callback uses current lifecycle input. Authority, malformed/partial/absent storage, private races, newer selections, single-use/expired capabilities and rollback remain fenced; correct repeats add no history. Native “real Pi context provides a cancellable lifecycle boundary” probes prove acceptance before the provider and actual Abort cancellation without later inference/publication. Those embedding probes establish the SDK seam; production preparation is covered separately below. No-transition patch publication passes the same wider-history/evidence matrix for complete accepted cohorts; an absence witness distinguishes its normal atomic initialization from the explicit lifecycle-only API, which still refuses missing semantic storage.
|
|
34
34
|
28. **Pre-inference preparation accepts once or stops inference:** Extension witnesses prove capture/no-signal projection is read-only, current-head maintenance shares lifecycle acceptance, reappearing sources survive, duplicate contexts reuse preparation and pre-acceptance failure rolls back both maintenance and metadata. Abort, Stop, selection, shutdown and superseded runs preserve newer state/fences; post-acceptance failure cannot replay an old specification. Native “real Pi production preparation” holds an independent partial publisher for over two seconds, then proves matching `G2/C2/S2`, source/provenance cleanup and private isolation before the first provider, while the native missing-CWD witness preserves current-empty initialization without resurrection, or actual Abort with no publication/inference after release. Native fault injection proves public `ctx.abort()` fences Pi's otherwise fail-open context hook. Session/native tests retain uncheckpointed input through reload/Stop/cold resume and interrupted boundary-continuation tool evidence through idle Stop/reload, without inventing a run or reviving a completed specification.
|
|
35
|
-
29. **Awaited Stop preserves immediate policy and accepted authority:** Extension tests
|
|
36
|
-
30. **Awaited Start activates current authority without stale rollback:** Runtime witnesses preserve semantics, provenance, revisions, step and aligned history across old mode/unfinished-work combinations; expired/single-use capabilities, partial private authority, unauthorized absent-root creation, noncooperating private-byte replacement after capture, rollback and no-op acceptance are checked. Extension witnesses prove coalescing, no early policy/cache/checkpoint changes, post-wait bootstrap/private-step derivation, Stop/session/tree/shutdown cancellation, physical-owner revalidation and no rollback/replayed checkpoint after acceptance. A completed Start failure loses Telegram presentation authority when selection changes during callback acknowledgement. Native “real Pi
|
|
35
|
+
29. **Awaited Stop preserves immediate policy and accepted authority:** Extension tests cover all inactive-choice pairs: immediate Passive projection or complete Off withdrawal, one runtime-only acceptance of the latest pending choice, current shared adoption with unchanged semantic/provenance bytes, and lifecycle derivation after an intervening same-instance passive patch. Operation cancellation keeps the selected inactive mode and fences writes; selection/shutdown/accepted Start withdraw obsolete work without later mutation, while rejected Start leaves Stop pending. Publication faults roll back config/runtime without installing shared adoption; native checkpoint faults after acceptance do not roll back or retry writes. Native “real Pi off keeps local mode off while awaiting a partial foreign publication without private leakage” holds an independent writer for over two seconds, proves accepted shared/local memory through inspection and verifies that Off injects no shared-memory values or handoff into the next provider request. Telegram controls acknowledge early, await results, escape late errors and suppress revoked/navigated/disposed views; legacy synchronous controls remain compatible.
|
|
36
|
+
30. **Awaited Start activates current authority without stale rollback:** Runtime witnesses preserve semantics, provenance, revisions, step and aligned history across old mode/unfinished-work combinations; expired/single-use capabilities, partial private authority, unauthorized absent-root creation, noncooperating private-byte replacement after capture, rollback and no-op acceptance are checked. Extension witnesses prove coalescing, no early policy/cache/checkpoint changes, post-wait bootstrap/private-step derivation, Stop/session/tree/shutdown cancellation, physical-owner revalidation and no rollback/replayed checkpoint after acceptance. A completed Start failure loses Telegram presentation authority when selection changes during callback acknowledgement. Native “real Pi active keeps local mode off while awaiting a partial foreign publication without private leakage” waits over two seconds behind an independent partial writer, then verifies current Global/CWD and local Session in the next provider input. Native “real Pi Abort cancels an in-run Start without waiting for the canonical owner or another provider call” uses the actual command and active operation signal: cancellation returns while the store remains held, without changed files/checkpoints, another provider call or late activation. Idle/no-signal waits and the separate initial-attachment/fork recovery paths are not certified by that Abort witness.
|
|
37
37
|
31. **Awaited retained restoration selects and accepts one coherent cohort:** Runtime restore matrices cover limits 0/1/12, historical/head artifact provenance and contradictory lineage. An independent partial publisher holds exclusion for over two seconds: cancellation preserves cache/files, successful restoration retains historical local Session over current shared values, and all five foreign-private files remain unchanged. Pointer mutation after admission cannot retarget selection; lifecycle policy is checked after waiting. Further witnesses cover expiry during the wait, missing/malformed/foreign authority, private checkpoint/runtime CAS races, rollback/retry, expired/single-use capabilities and post-acceptance failure. No current-head/empty fallback, invented history or unaccepted cache installation is permitted. Native caller cutover evidence is item 35.
|
|
38
38
|
32. **Awaited exact-source fork preserves parent and child authority:** Runtime restore/fork matrices cover limits 0/1/12, provenance and contradictory lineage. An independent partial writer held over two seconds proves responsive cancellation, pinned source identity/checkpoint, current shared adoption and historical private copying without parent/foreign-private changes. Source expiry during waiting and competing child acceptances prove post-wait checks. Every occupied child file, unsupported legacy evidence, invalid/missing parent authority and parent/child byte races refuse publication. Fault injection proves rollback/retry; expired/single-use capabilities and post-acceptance checkpoint failure cannot replace accepted child memory. Child lifecycle resets step and unfinished specification while retaining selected mode/bootstrap; later child writes leave the parent unchanged. Shared unknown metadata and unrelated provenance survive. Native fork caller evidence is item 35.
|
|
39
39
|
33. **Awaited current-memory recovery stays read-only:** Awaited loader matrices at limits 0/7 preserve current same-session values, step, revisions and bootstrap beside independently advanced shared streams without inheriting foreign private memory or unfinished specifications. No composed history is invented and no canonical files change, even when the in-memory view folds wider tails. Recovered caches cannot authorize lifecycle/patch publication. An independent partial writer held over two seconds proves cancelable coherent capture; injected cancellation during capture prevents cache installation. Missing roots/private authority remain absent, malformed/partial/identity/provenance errors retain the prior cache and bytes. Native failed-Stop wiring evidence is item 35.
|
|
40
40
|
34. **Lifecycle fixtures await completion without trapping withdrawal:** Direct startup/tree fixture calls await their handlers before inspecting completed state. Preparation, response, Start, Stop and Telegram inspection cancellation families dispatch replacement selection separately, prove the obsolete operation withdraws while storage remains held, then release exclusion and join the replacement. Canonical-byte and stale trace/notice assertions remain; UI stability is measured after legitimate replacement completion. Item 35 records the resulting native cutover.
|
|
41
|
-
35. **Native branch restoration awaits one owned lifetime:** Extension witnesses hold exclusion across startup, tree, auto-start and failed-Stop reload: mode stays
|
|
41
|
+
35. **Native branch restoration awaits one owned lifetime:** Extension witnesses hold exclusion across startup, tree, auto-start and failed-Stop reload: mode stays in the selected inactive policy, private reads/patches report the pending selection, and files/checkpoints stay unchanged until acceptance. Joined Starts stay inert; bootstrap derived after waiting shares the single runtime write. Replacement selection/shutdown withdraw obsolete restoration while storage remains held. Stop changes the pending acceptance's policy without revoking its memory operation; mode separation is covered by items 37–38. Failed-Stop reload stays read-only and fenced; post-acceptance checkpoint failure warns without rollback or replay. Native tree/fork witnesses hold a publisher, then require selected private memory, unchanged parent-private files and matching next-provider input. The initial cutover probes, except their shutdown case, also failed against pre-cutover synchronous orchestration.
|
|
42
42
|
36. **Recovery joins, draining and cache installation retain separate owners:** Start cancellation returns while independently owned restoration still waits; physical identity stays pinned across that join, so a changed owner cannot be activated. Recovery-domain tests preserve other joiners and observe late owner failures even after pre-cancellation. Shutdown waits for both current and superseded restoration operations, including delayed reader completion. Passive reads remain detached when physical CWD changes, and late native cancellation prevents both passive and private recovery cache installation. A private patch accepted between passive capture and attachment completion retains its newer cache and canonical bytes. These extension/domain witnesses supplement the native cutover probes rather than claiming universal idle Abort support.
|
|
43
43
|
37. **Fork memory creation is independent of active/passive policy:** The extension native-fork/Start-retry × warm/cold × retained/expired matrix holds exclusion while Stop selects passive policy. The copy must remain pending rather than be cancelled, including when Stop withdraws its Start waiter. After release, retained source memory is accepted once with disabled policy, passive patching changes child-owned memory without enabling the mode, and native trace reopening through `SessionManager.open` preserves that child state. Expired source history refuses canonical publication and substitute checkpoints. These fixtures replace the former tests that codified Stop cancelling copying; the separate public SDK control/next-provider witness is item 40; installed UI reachability remains unverified.
|
|
44
|
-
38. **Stop cannot manufacture a restoration failure:** Held-store retained-boundary and auto-start fixtures require repeated Stop to return promptly without cancelling memory acceptance, adding an error fence or publishing early. Release accepts the selected/initial memory with passive policy, permits passive patches and retains them across reload. Stop→Start while waiting activates only after memory acceptance. A separate Start-owned attachment witness withdraws the Start waiter without cancelling restoration. The native SDK tree witness invokes `/state-flow-
|
|
44
|
+
38. **Stop cannot manufacture a restoration failure:** Held-store retained-boundary and auto-start fixtures require repeated Stop to return promptly without cancelling memory acceptance, adding an error fence or publishing early. Release accepts the selected/initial memory with passive policy, permits passive patches and retains them across reload. Stop→Start while waiting activates only after memory acceptance. A separate Start-owned attachment witness withdraws the Start waiter without cancelling restoration. The native SDK tree witness invokes `/state-flow-passive` during awaited `navigateTree`, then verifies selected private memory, passive tool availability and a successful next-provider patch; selected conversation remains visible and later-branch private memory stays absent. This public SDK route is not installed Telegram/TUI reachability certification.
|
|
45
45
|
39. **Native Skill compilation reconciles an independent writer without private leakage:** The Global/CWD × duplicate/competing/invalid matrix runs real Pi acquisition and compiler tool calls while a separate process publishes between the model's source read and its patch. Identical compiler output leaves shared checkpoint/tail/provenance bytes, scope revision and runtime step unchanged. Different output replaces the complete artifact and matching source-hash/compiler evidence, preserves independent peer fields, and advances the affected revision once. The next provider sees adopted shared state and local private memory, never the peer's private sentinel; all five peer-private files remain unchanged. An invalid compilation combined with a Session mutation rejects without changing any captured canonical file or accepting the accompanying Session field. The peer uses the runtime publication API, not a second provider; these ordered interleavings supplement the separate held-writer cancellation tests.
|
|
46
|
-
40. **A public SDK host can control a child while fork binding awaits memory:** The fixture observes the public `createAgentSession` result before awaiting `bindExtensions`, without private SDK hooks or direct calls to State Flow command handlers. During a held-store `runtime.fork`, it calls the child's public `prompt('/state-flow-
|
|
46
|
+
40. **A public SDK host can control a child while fork binding awaits memory:** The fixture observes the public `createAgentSession` result before awaiting `bindExtensions`, without private SDK hooks or direct calls to State Flow command handlers. During a held-store `runtime.fork`, it calls the child's public `prompt('/state-flow-passive')`; an optional subsequent Start waits for memory acceptance. Stop returns while the fork remains pending. After release, the child has a distinct identity, selected private memory and the requested passive/active policy. Its next provider sees selected rather than later-parent private state, successfully patches child memory and leaves all parent-private files unchanged. This certifies the embedding route on the tested SDK, not whether the installed CLI or Telegram exposes that child before its runtime replacement completes.
|
|
47
47
|
41. **Automatic history does not hydrate lazy memory:** Context tests cover large writes, replacements and deletions in Global/CWD/Session, mixed hot/lazy cohorts, empty scoped patches/transitions and omission of an empty window. Visible records retain their identities, order and original positions; artifact evidence is still hidden. Native SDK active/bootstrap/reload/Stop→Start witnesses keep lazy bodies out of State Flow-owned automatic blocks while retained canonical files still contain them. Current tool trajectory and unfinished bootstrap retain previously communicated bodies. Semantic files remain byte-identical through projection/preparation, and no hydration or repair inference is added. The four native mode witnesses fail against the unfiltered projection in an isolated source copy.
|
|
48
48
|
42. **Hints do not create a recovery task:** Query tests preserve single-value hint conditions, current-only reference-owner lookup, no body disclosure and existing keys/patch/batch/unavailable-history behavior. Active/passive native witnesses compare exact canonical bytes and checkpoint counts around hints and reads, and require the exact scripted tool and provider-call counts. A task that needs no old detail performs no historical read; a task that needs it explicitly reads the exact retained Global/CWD/Session values without separate permission or restoring deleted data. Protocol and both Skill tests enforce this permission and boundary. Native provider assertions have completion sentinels outside the provider callbacks so a swallowed scripted provider error cannot produce a false pass. These are runtime/contract witnesses, not a claim about every model's discretionary behavior.
|
|
49
|
+
43. **Session mode has one owner:** `tests/config.test.ts` and `tests/snapshot.test.ts` cover enum round trips, read-only legacy decoding, invalid/mixed session policies and pre-runtime mode retention without semantic initialization. Native global-default tests prove later defaults affect only new sessions. Extension inactive-choice matrices prove coalescing, no semantic revision and last-choice wins. Held-store “fenced reload preserves …” cases cover all four inactive pairs, unchanged canonical bytes, retained write fences, immediate/final tools/context/status and a subsequent reload. Telegram “pre-runtime Telegram Passive reports only its current successful selection” proves truthful success after cache installation and suppression of superseded receipts through the real composition port.
|
|
49
50
|
|
|
50
51
|
## Additional preservation boundaries
|
|
51
52
|
|
|
52
53
|
- `tests/continuation.test.ts` independently advances global/CWD at limits 0/7, then proves read-only eligibility agrees with actual restore and preserves the session layer, including shared-only transitions. `tests/temporal.test.ts` covers sparse/inherited session lineage, conflicting checkpoint/tail identities and parents, future patches, and immutable inputs. The runtime restore/fork contradiction witnesses preserve source/target files rather than accepting a new origin over mixed session files. The native “real Pi refuses contradictory session files without passive substitution and retries the repaired selection” witness retains shared access, fences private access and publication, permits local Stop without a substitute checkpoint, and succeeds after exact-source repair. These are synthetic integrity tests, not evidence of spontaneous cross-session leakage.
|
|
53
|
-
- `tests/extension.test.ts` distinguishes pre-runtime Stop from accepted-runtime Stop
|
|
54
|
+
- `tests/extension.test.ts` distinguishes pre-runtime Stop from accepted-runtime Stop in inactive modes: global-only and shared storage remain unchanged, repeated selection/reload retain the native `{mode}` marker, and subsequent Start/passive patch establishes a retained session boundary. Malformed/incomplete scope files remain unavailable; Stop does not repair CWD-only storage, while explicit Start may initialize its wholly absent global scope. The native “real Pi Stop preserves a global-only passive branch through reload, patch, and Start” witness checks the same lifecycle without Git. `tests/invariants.test.ts` rejects the retired Skill converter in both package and domain exports; existing Skill/transition witnesses preserve real source hashing, hashing failure, and retired-field rejection.
|
|
54
55
|
- `tests/durable.test.ts` and `tests/storage.test.ts` cover canonical-format rejection, owned regular files, raw-byte rollback, prepared-output receipts, stale/omitted-scope CAS, literal paths, malformed cohorts, and shared-writer exclusion.
|
|
55
56
|
- `tests/git.test.ts` proves settled backup preserves unrelated staged/index-only/worktree data, already-staged owned deletions, Git ignore/filter policy, literal paths, and opaque bytes. Controlled Git pauses before/after snapshot capture allow an independent canonical writer to advance and create a new scope; the commit must match exactly one captured cohort, never mixed live bytes. Every observed Git command runs outside the backup's canonical lock. Namespace/type witnesses exclude unrelated traversal and refuse non-regular sources. No-op/unowned-only initial backups skip; Git/index failures preserve canonical acceptance and caller data. `tests/episode.test.ts` proves one diagnostic-only attempt at `agent_before_settle`, without answer changes or an automatic retry.
|
|
56
57
|
- `tests/integration.test.ts` native new/resume/fork witnesses preserve canonical files and retained boundaries. Fork witnesses cover selected private state over current shared layers, fresh child ownership, reload/resume, disabled-source fencing, identity/CWD refusal, retry, and expired-boundary refusal. `tests/runtime.test.ts` restore/fork provenance witnesses preserve current-head, untouched-path, and shared evidence while discarding evidence for later-changed private artifacts, including change-away-and-back. The test-only provenance reader is checked against nonempty canonical `meta.json` evidence in every scope before and after reload; native restore/fork tests verify missing-evidence invalidation, explicit recompilation, parent preservation, and provenance across reload.
|
|
@@ -62,7 +63,7 @@ This is a maintained property-to-test map for the current canonical-file contrac
|
|
|
62
63
|
- `tests/integration.test.ts` — “real Pi boundary continuation keeps accepted State Flow memory” exercises actual companion `turn_end` and `agent_before_settle` draft entries and continuation. Each next provider input has one freshly rebased head after accepted completion and matching-projection updates after a continued patch, the accepted response and current tool declarations. There is only one `before_agent_start`, no restored specification in runtime checkpoints or model projection, exactly one requested continuation and correct final response/step. The pure “projects accepted memory without resurrecting a completed specification for boundary continuation” witness preserves source state, omits lazy bodies, and keeps available context when both specification and native capture are absent.
|
|
63
64
|
- `tests/integration.test.ts` — “real Pi context edits remain canonical through tools, tree selection and reload” proves native user-content replacement, assistant/custom-message omission and live tool-result replacement reach provider input without resurrecting raw history. Selecting an unedited branch restores its native view without overwriting accepted semantic files; selecting the edited branch and reloading preserves its edits and independent memory. Raw JSONL stays append-only.
|
|
64
65
|
- `tests/integration.test.ts` — “real Pi structured prompt composes with context hooks” covers active, passive, disabled and explicit foreign-force modes. Conversation hooks exclude systems; full-system hooks receive them; companion before-run and per-request sections plus actual tool declarations survive. User specifications remain outside system authority. Stop/Start on subsequent user requests removes/reinstates the owned section once.
|
|
65
|
-
- `tests/integration.test.ts` — “real Pi preserves native run identity across mode toggles” covers initially enabled, mid-tool Start and repeated Start/Stop with
|
|
66
|
+
- `tests/integration.test.ts` — “real Pi preserves native run identity across mode toggles” covers initially enabled, mid-tool Start and repeated Start/Stop with explicit Active/Passive/Off selections. Actual provider inputs retain original user/read evidence but not the preceding disabled request; persisted Stop markers name the observed native user, and fixture reload preserves trajectory, frozen state and raw trace prefix. `tests/compaction.test.ts` — “native session boundaries invalidate observed run capture without projection reacquisition” pairs session-start/tree resets with an admitted unchanged-run control. Run identity remains native rather than guessed; an independent optional Stop-marker flag preserves uncompiled bootstrap context without changing the captured anchor.
|
|
66
67
|
- `tests/integration.test.ts` — “real Pi refreshes protocol within the same run” covers mid-read Stop, passive Stop, mid-read Start and accepted-boundary Stop/continuation. The next provider request has current protocol/tools, foreign context and tool evidence, no elevated specification and only one user-run preparation; response reconciliation follows the actual mode and earlier native system frames remain intact. `tests/context.test.ts` — “refreshes only owned system protocol without mutating native frames” covers old/replaced/deleted sections, foreign content/tools, conversation identity/order, frozen inputs, absent-frame non-synthesis and unchanged-delta no-ops.
|
|
67
68
|
- `tests/integration.test.ts` — “real Pi recovery omits failed attempts without accepting them” checks retry/length/overflow through actual SDK dispatch: durable omission edits, raw trace preservation, unchanged accepted response/step until successful recovery, native split-turn summaries and fixture reload. “real Pi edited-context accounting discards stale provider usage” checks reduced native usage after replacement and one subsequent inference without phantom compaction.
|
|
68
69
|
- `tests/integration.test.ts` — “real Pi settled dispatch preserves deferred companion work” covers low pressure, real owned compaction and explicit compaction refusal. The native completion/error callback finishes before settled dispatch returns; all companion observers precede exactly one deferred request, which sees accepted memory and reconciles the expected response/step. The admitted case verifies an actual State Flow-owned compaction rather than relying only on a token estimate.
|
|
@@ -75,7 +76,7 @@ This is a maintained property-to-test map for the current canonical-file contrac
|
|
|
75
76
|
- Runtime/Skill guidance names the reported artifact owner. Registered-Skill unit and native witnesses use Pi's public command source metadata to map user/project/temporary Skills to global/CWD/session, ignore unregistered `SKILL.md` reads, skip matching hashes, permit unrelated patches while compilation remains optional, retain strict attempted-output validation, and publish source-hash provenance to the exact reported owner.
|
|
76
77
|
- `tests/transition.test.ts` rejects authored provenance fields and field deletions in every scope through both staging entrypoints, without requiring a preceding read; legacy semantic edits and whole-artifact deletion remain valid. The native “real Pi rejects no-read provenance forgery atomically and accepts a corrected model patch” witness proves whole-cohort rejection and recovery, while existing artifact/Skill tests preserve runtime-owned compilation evidence and legacy decoding.
|
|
77
78
|
- `tests/storage.test.ts` covers exact file-cohort references, file CAS/rollback, and shared writer exclusion. The asynchronous transaction witnesses pause an independent writer between tail and metadata renames for longer than the old wait budget: the waiting process remains responsive and captures the complete accepted receipt only after release. Local waiters, cancellation before acquisition/publication, interrupted/malformed/empty locks, root/lifetime binding, active recursive refusal, deferred work after context expiry, rollback and replaced-owner preservation are separately checked. The current-head and response witnesses above additionally prove awaited model patch/finalization integration; runtime startup/recovery and exact restoration/fork cutover, including Start's initial attachment and unaccepted-fork paths, are covered by items 35–40. Current-head Start and accepted-runtime Stop are covered above; optional settlement backup uses the selected no-signal deferral rather than an upstream release gate. `tests/runtime.test.ts` and native Pi lifecycle tests cover retained-boundary restart, immediate barriers, finalized response, config-only stop, and unavailable-reference provenance. Canonical files supply current state and bounded hot history; arbitrary cold revision recovery is unsupported.
|
|
78
|
-
- `tests/runtime.test.ts` and native integration cover retained-boundary restoration and fork after lowering `historyLimit` to 0/1: current shared values/provenance and selected private state survive folding, parent-private fork files remain unchanged, out-of-window selections fail closed, and later increases do not reconstruct discarded history. `tests/config.test.ts` covers optional agent configuration, path precedence/expansion, invalid input, load-time caching and read-only behavior. Session tests and native Pi distinguish configured new-session auto-start from branch-local resume/tree/stop. `tests/extension.test.ts` proves registered artifacts are reconciled only at enabled inference boundaries. The global default is
|
|
79
|
+
- `tests/runtime.test.ts` and native integration cover retained-boundary restoration and fork after lowering `historyLimit` to 0/1: current shared values/provenance and selected private state survive folding, parent-private fork files remain unchanged, out-of-window selections fail closed, and later increases do not reconstruct discarded history. `tests/config.test.ts` covers optional agent configuration, path precedence/expansion, invalid input, load-time caching and read-only behavior. Session tests and native Pi distinguish configured new-session auto-start from branch-local resume/tree/stop. `tests/extension.test.ts` proves registered artifacts are reconciled only at enabled inference boundaries. The global default is Off without a configured mode; CWD materialization alone never grants Active mode.
|
|
79
80
|
|
|
80
81
|
## Validation and limits
|
|
81
82
|
|
|
@@ -9,42 +9,43 @@ For the concept and installation, start with the [README](../README.md). This gu
|
|
|
9
9
|
State Flow has three distinct model-facing states. **Active versus passive changes the agent's workflow, not the existence of disk memory.**
|
|
10
10
|
|
|
11
11
|
- **Active:** Both `read_state` and `patch_state` are available, subject to host restrictions and valid memory authority. Prompts require the agent to consolidate future-relevant results into state before ending an iteration. The final meaningful semantic patch preserves decisions, outcomes and continuation needed after the completed conversation is removed from model projection. The next iteration starts from accepted state and its new input, not the previous iteration's completed reasoning. Native trace remains inspectable; a clean model context does not mean deleting Pi history.
|
|
12
|
-
- **Passive:** Both memory tools
|
|
13
|
-
- **
|
|
12
|
+
- **Passive:** Both memory tools are available. Existing state is projected into context, and the agent may read or patch it as useful. Ordinary conversation continuity remains: State Flow does not impose the active iteration-ending context reset or the same mandatory consolidation pressure. Accepted patches still reach the same canonical store with the same validation and ownership guarantees.
|
|
13
|
+
- **Off:** Neither memory tool is exposed to the model, and State Flow injects no protocol, bootstrap/state context or frozen passive handoff. Stored memory and the native conversation trace are not deleted.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
One session-owned `mode` selects these behaviors; there are no independent passive-tool/projection switches. Host restrictions and genuine unavailable/corrupt-memory fences remain separate from mode selection.
|
|
16
16
|
|
|
17
17
|
**Completion is semantic, not ceremonial.** In active mode, necessary final state changes must be accepted before relying on state-only continuation. This does not require an empty `patch_state` when memory is already current, an extra model turn, or a special finalization tool. Each `patch_state` remains an inference barrier, not automatically the end of an iteration; the runtime separately persists the accepted ordinary answer as Session `response` and completes the run.
|
|
18
18
|
|
|
19
19
|
Here, “bootstrap from state” means constructing model context from durable memory. The implementation's `meta.bootstrap` is narrower: the one transition run that retains an existing conversation while active mode is first enabled and that conversation is compiled into state. It is not a flag that must be re-entered on every active iteration. Native compaction is also separate from model-context projection; its safety checks and usage threshold still apply.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Active, Passive and Off select the current session's workflow and model-facing access, not a different storage algorithm. Native Off attachment defers memory acquisition, including creation of a fork's private memory, until explicit Passive/Active selection. Once acquired, a fork owns Session state copied from the selected parent boundary and lives independently in its selected mode. See [fork support](#fork-support-and-limits).
|
|
22
22
|
|
|
23
23
|
### Lifecycle operations
|
|
24
24
|
|
|
25
|
-
`/state-flow-
|
|
25
|
+
`/state-flow-active` activates the current Pi branch over validated current same-session memory, initializing absent storage when safe. No remote is required. Starting mid-conversation retains Pi's active context for one complete bootstrap run, during which the agent must compile future-relevant information into state. Repeating Active while already active leaves the in-progress run unchanged. On an attached branch, current-memory activation waits asynchronously for a coherent canonical cohort; pending repeats share the wait. Until acceptance, the existing inactive mode, deferred historical selection and any write fence remain in effect. Cancelling pending Active from Off preserves later acquisition choices; a superseding Passive still selects its retained private boundary rather than newer current memory, and ordinary cancellation creates no write fence. Passive, Off or branch selection can withdraw obsolete activation; an error after acceptance does not undo accepted memory.
|
|
26
26
|
|
|
27
|
-
- **New session:**
|
|
28
|
-
- **Resume:**
|
|
29
|
-
- **Tree navigation:**
|
|
27
|
+
- **New session:** Adopts global `mode`, defaulting to Off. An inactive default is recorded once in Pi as `{mode:"off"}` or `{mode:"passive"}` without creating semantic storage. An Active default initializes a distinct empty Session layer over global/CWD memory, never another session's private continuation.
|
|
28
|
+
- **Resume:** Retains the selected session's mode; Passive/Active restore state and lineage, while Off attaches native policy only without probing semantic files or emitting recovery warnings. Later global default changes do not override it.
|
|
29
|
+
- **Tree navigation:** In Passive/Active, restores the selected retained private boundary over live shared scopes without checking out or resetting the shared store. Off defers this acquisition until explicit mode selection.
|
|
30
30
|
- **Abort inference:** Stops generation or an outstanding response-publication wait while already accepted patches remain durable for continued work and corrected direction in the same session. Cancellation before response acceptance keeps the previous response and unfinished run; cancellation after acceptance never rolls it back. It does not require immediate remote replication.
|
|
31
31
|
- **Native boundary continuation:** A companion may continue through Pi's `turn_end` or `agent_before_settle` boundary without a new user prompt. State Flow keeps projecting current memory and accepted response across those requests and subsequent patches; it does not restore the completed specification or request another turn itself.
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
32
|
+
- **Passive:** `/state-flow-passive` enables both memory tools and projection. A proven pre-runtime branch records only `{mode}` in Pi and loads shared memory read-only. Accepted runtimes persist Passive and adopt unrelated shared drift without semantic/provenance writes or revision/step changes. Pending repeats share one acceptance.
|
|
33
|
+
- **Off:** `/state-flow-off` removes memory tools/context, cancels owned restoration/fork, activation, preparation, response, patch and Passive-persistence waits, and clears semantic caches immediately. It saves native policy and continuation/fork bookmarks only; existing canonical bytes, including the old stored runtime mode, stay untouched even when malformed or busy. Repeated Off is inert. Already accepted data is preserved; future explicit Passive/Active reacquires memory. Global defaults and other sessions remain unchanged.
|
|
34
|
+
- **If Passive cannot persist:** The selected Passive policy stays applied; Off itself never attempts canonical persistence. Accepted memory and native conversation remain intact; Off still exposes no State Flow context or tools. Pi records the selected mode and a write fence, not a replacement semantic checkpoint. Tree/reload/resume in Passive read validated current same-session memory without publishing or restoring an older selection. Off retains native policy and the write fence without reading memory; explicit Passive may acquire that read-only current authority later. Newer mode choices survive an in-flight read-only recovery. Repeating the same choice is inert; changing inactive mode updates only native policy and keeps the fence. Explicit Active clears the fence only after canonical acceptance. This fallback requires a writable Pi trace and never repairs storage; native fenced policy overrides an older canonical config.
|
|
35
|
+
- **Continue in Passive after Active:** The same physical session projects a frozen state handoff, any interrupted current request and tool trajectory (including late results), and post-stop conversation. Outside an unfinished bootstrap, a proven active boundary excludes completed earlier conversation; when native split-turn compaction removed the original request anchor, Stop instead preserves the available summary and tools without reconstructing discarded raw input. An unfinished bootstrap keeps all available native context, or the earlier passive boundary it received; repeated Start/Stop cannot move that boundary past uncompiled conversation. An interrupted run retains its captured anchor even after Pi becomes idle, falling back to all available context when that anchor is unknown. Other extensions' custom context survives. Only Stop after a completed idle run retains just later conversation plus foreign custom context. Reload/resume/tree preserve this projection; new/forked physical sessions do not inherit it. Mid-tool Start and repeated Start/Stop retain the first user event already observed while disabled, so subsequent Stop does not mistake that busy run for idle. Active restart uses the retained projection for one bootstrap run. Off retains this boundary for a later Passive/Active selection but never projects it.
|
|
36
|
+
- **Completed-history compaction:** After an accepted run settles without queued input, State Flow asks Pi for a native compaction boundary only when public context usage reaches 24,000 tokens. No extra model summary is requested; Pi keeps the complete latest run—from its original request through steering, tools, foreign context and final answer—in active history and retains the complete append-only JSONL/tree. State Flow uses the native first-user anchor, independent of image-normalization hints or later steering; images and earlier tool results remain available to the model. Uncertain projection retains available context without changing that anchor. A missing or ambiguous native anchor skips compaction instead of choosing the last steering message. On resume, native `buildContextEntries()` and TUI rendering omit the older completed prefix. Unknown or smaller usage skips the request, and custom Pi retention settings may still decline it benignly. Foreign custom context in the removed prefix, bootstrap/abort/error, Stop and pending input prevent State Flow-owned shortening; obsolete/inactive owned requests are canceled before their hook can fall through to a model summary, and late completion cannot clear a newer request; ordinary manual/threshold/overflow compaction remains native and may preserve unfinished work not yet patched into memory.
|
|
36
37
|
|
|
37
38
|
State Flow does not undo tool effects. After interruption or returning to an older branch, check the relevant workspace or external system before repeating consequential operations. Restored memory is not restored reality.
|
|
38
39
|
|
|
39
40
|
### Fork support and limits
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
Memory-enabled native fork replacement copies the source session checkpoint, retained patch tail and matching provenance into the new session's own storage. Off records child-owned pending-fork policy only, deferring header/store reads and copying until explicit Passive/Active, including after cold reload. Global/CWD values and provenance stay current; applying a smaller `historyLimit` may fold shared tails under CAS. An earlier fork selection copies that point's private state, not the parent's later private work. Parent-private data/history remain intact; the selected mode is retained, so an inactive source does not become Active automatically.
|
|
42
43
|
|
|
43
44
|
The child starts at step zero and a new temporal origin. Its copied tail obeys the configured retention limit, but pre-origin records are not additional aligned causal boundaries addressable through `effective[n]` or scoped paths. The child's own transitions build its hot window; owned checkpoints support normal reload/resume. Parent Stop projection is not inherited, including after child reload.
|
|
44
45
|
|
|
45
46
|
Initial copying requires a native fork start event, a regular canonical direct-parent session file, matching CWD/identity, a readable temporal source and an unused child namespace. Missing/unsafe evidence or CAS conflicts leave the copy unavailable rather than importing unrelated or newer private state. Explicit Start can retry an unaccepted copy in the same loaded fork after the cause is corrected.
|
|
46
47
|
|
|
47
|
-
Selecting a copied parent checkpoint through the child's `/tree` does not make it child-owned: historical restoration stays disabled without resetting existing child data. Select a child-owned checkpoint, resume the original session, or explicitly Start from the validated current child-owned memory; Start does not copy newer parent data. Cold recovery before the first child checkpoint
|
|
48
|
+
Selecting a copied parent checkpoint through the child's `/tree` does not make it child-owned: historical restoration stays disabled without resetting existing child data. Select a child-owned checkpoint, resume the original session, or explicitly Start from the validated current child-owned memory; Start does not copy newer parent data. Cold recovery before the first child checkpoint requires an Off-deferred pending-fork marker; otherwise it and startup paths lacking the fork event remain unsupported. In-memory parent locators and cross-CWD imports remain unsupported. File-only copying requires an exact still-available source cohort. See the [contract](fork-contract.md) and [SDK compatibility boundary](compatibility.md#public-host-seams); do not rewrite UUIDs or delete pointers to force recovery.
|
|
48
49
|
|
|
49
50
|
## Configuration
|
|
50
51
|
|
|
@@ -52,9 +53,7 @@ Optional global `config.json` at the root of the State Flow repository, normally
|
|
|
52
53
|
|
|
53
54
|
```json
|
|
54
55
|
{
|
|
55
|
-
"
|
|
56
|
-
"passiveBootstrap": true,
|
|
57
|
-
"passiveTools": true,
|
|
56
|
+
"mode": "off",
|
|
58
57
|
"logging": false,
|
|
59
58
|
"showSuccessfulPatches": true,
|
|
60
59
|
"historyLimit": 7
|
|
@@ -62,35 +61,38 @@ Optional global `config.json` at the root of the State Flow repository, normally
|
|
|
62
61
|
```
|
|
63
62
|
|
|
64
63
|
The canonical store is `state-flow/` beneath the agent directory. Keeping configuration inside that repository removes the separate agent-level `state-flow.json`; SDK embeddings may still provide an explicit repository override.
|
|
65
|
-
- `
|
|
66
|
-
- `
|
|
67
|
-
- `passiveTools`: Defaults to `true`. Exposes `read_state` and `patch_state` outside active episodes. Reads remain side-effect free; the first explicit patch may initialize absent canonical storage but never converts predecessor formats or enables an episode or State Flow compaction.
|
|
68
|
-
- `logging`: Defaults to `false`. When enabled, records rejected patches, preparation failures and accepted-answer reconciliation failures locally at `tmp/state-flow/logs.jsonl` beneath the agent directory. Asynchronous Git push failures are recorded there even when this setting is off.
|
|
64
|
+
- `mode`: `"active"`, `"passive"` or `"off"`; defaults to `"off"`. Supplies the default only for genuinely new sessions. Active initializes missing storage when safe; Passive reads existing memory without publishing, and its first explicit patch may initialize absent storage without starting an episode or compaction. Off exposes neither memory tools nor State Flow context.
|
|
65
|
+
- `logging`: Defaults to `false`. When enabled, records rejected patch executions, active barrier blocks, preparation failures and accepted-answer reconciliation failures locally at `tmp/state-flow/logs.jsonl` beneath the agent directory. Asynchronous Git push failures are recorded there even when this setting is off.
|
|
69
66
|
- `showSuccessfulPatches`: Defaults to `true`. In interactive Pi, successful `patch_state` rows show only the applied pretty-printed JSON arguments, with blank lines between adjacent memory sections; set it to `false` to keep only the compact summary. Rejected calls still use ordinary error rendering; State Flow adds no private validation turn.
|
|
70
67
|
- `historyLimit`: Defaults to `7` and accepts integers from `0` through `100`. It counts accepted semantic transitions, **not elapsed time or conversation length**. It bounds materialized-history and scope patch-history offsets. Lowering it on reload/restore/fork folds excess tails forward without losing current state; selected boundaries outside the new window are unavailable. Zero retains only current checkpoints. Raising the limit affects only future retention and cannot reconstruct discarded history.
|
|
71
68
|
|
|
69
|
+
Session `config.json` uses the same `mode` key for its concrete choice; commands and Telegram change that session only. Before canonical runtime acceptance, Pi's native `{mode}` checkpoint owns the choice instead of a manufactured storage pair. Off remains native-only even after an accepted runtime: its mode/bookmark overrides the earlier canonical mode without requiring store access or granting semantic authority. Edit global defaults manually or through an authorized agent, not `patch_state`. Legacy flag decoding is read-only; see [mode compatibility](compatibility.md#mode-configuration-compatibility).
|
|
70
|
+
|
|
71
|
+
**Passive model-facing footprint:** When selected, Passive declares both memory tools even with no canonical store; its system-prompt section and projected memory message appear only after a validated memory view is loaded. New sessions default to Off, which exposes none of these State Flow model-facing surfaces. With unavailable memory the tools may still reject reads or writes; declared tools do not prove usable storage.
|
|
72
|
+
|
|
73
|
+
A source-bound UTF-8 byte probe of the 0.22.0 tree (`3242d762`, isolated `tests/harness.ts` and `tests/storage-fixture.ts`, default config, empty native transcript, `before_agent_start("Probe")` then `context`) measured the two `{name,description,parameters}` tool definitions as **1,728 JSON bytes**. A wholly absent store added **0 protocol and 0 projected-message bytes**. A validated empty Global state (`{}`) added **959 protocol bytes** and **321 serialized message bytes**; `global.working={sample:"x"}` added the same **959** plus **351 message bytes**. These component sizes include the projection marker in the message but exclude native prompt/tool wrappers, conversation, provider tokenization and variable user memory; they are not token-cost or cache-hit claims.
|
|
74
|
+
|
|
72
75
|
Settings are read once at extension load. After editing, use `/reload` or restart Pi. A missing file uses defaults without creating a configuration file; malformed JSON, unknown keys, or invalid values fail loading rather than silently selecting another store.
|
|
73
76
|
|
|
74
77
|
`PI_CODING_AGENT_DIR` changes both the default State Flow repository and its global configuration location. State Flow has no source-directory or Knowledge-root configuration. SDK repository overrides are documented under [embedding](architecture.md#embedding); an overridden repository owns its own root `config.json`.
|
|
75
78
|
|
|
76
79
|
### Diagnostic logging and privacy
|
|
77
80
|
|
|
78
|
-
Rejected
|
|
81
|
+
Rejected `patch_state` execution records may contain exact attempted arguments and useful draft text, plus the error category and tool/call identity. The `barrier-block` category instead records only the blocked tool name, call id, reason and batch tool names (never sibling arguments or reasoning); Passive has no patch barrier, and logging off records no barrier blocks. Asynchronous push failures retain the available redacted Git error there regardless of `logging`; interactive warnings stay short and appear once per failure streak, then reset on success. If logging the push failure is unavailable, one warning exposes the available detail instead. Successful patches are not logged; reasoning bodies are excluded. Logs are not semantic state, scope metadata, Pi checkpoints, or publication input. If the log path overlaps a custom state repository, capture fails closed instead of committing it. A logging failure changes no accepted state and produces at most one local warning.
|
|
79
82
|
|
|
80
|
-
Logs remain local unless you move them; rotation/deletion is operator-owned. State Flow-authored errors and warnings display as one compact line: long operands
|
|
83
|
+
Logs remain local unless you move them; rotation/deletion is operator-owned. State Flow-authored errors and warnings display as one compact line: flatten nested/aggregate causes into transportable text rather than relying on `Error.cause`. Elide long operands with `…` before shortening prose so the operation, exact offending scope, target basename/suffix and actionable reason remain visible; do not split Unicode pairs or mistake prose apostrophes for quoted paths. Enabled diagnostic records keep the full target and rejected input for investigation. An explicit Start retry reports its final failure once rather than repeating its startup warning. Tool failures still keep the required blank line beneath their heading. Treat logs and state files as private. Removing a secret from current state does not erase older offsets, Git history, native sessions, or remote copies.
|
|
81
84
|
|
|
82
85
|
## Status and controls
|
|
83
86
|
|
|
84
87
|
`/state-flow-status` separates runtime configuration/metadata from semantic state. It reports:
|
|
85
88
|
|
|
86
|
-
- Selected CWD/session keys, internal step,
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
- Memory-bearing scopes. Promotion-shaped values receive no special interpretation.
|
|
89
|
+
- Selected CWD/session keys, internal step, effective `g#c#s#` scope-revision vector, and available hot-history depth.
|
|
90
|
+
- Known recovery or publication failures, actual artifact counts when nonzero, and pending invalidations. Status does not discover or validate sources.
|
|
91
|
+
- One JSON representation of effective global → CWD → session memory, with a blank line between top-level semantic planes. Nested JSON is unchanged; individual scope JSON remains available through `read_state`.
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
Status omits the already-visible mode and generic ownership/configuration prose. Failed inspection reports unavailable evidence, not invented empty state. Status is observational: it does not read source files, calculate fingerprints, create invalidations, or mutate semantic state.
|
|
92
94
|
|
|
93
|
-
The terminal indicator is `state-flow
|
|
95
|
+
The terminal indicator is accent `state-flow` plus dim `active` or `passive`; Off hides it. Global, CWD and Session own independent semantic revisions; one atomic transition advances each materially changed scope once, including session-only response reconciliation. Effective has no scalar counter and uses the compact lowercase `g#c#s#` revision vector (for example, `g15c8s31`), without slashes or spaces between counters. That vector appears in `/state-flow-status` and Telegram's Effective inspection, not the compact indicators. When `pi-telegram` is available, its main-menu section shows `State Flow: active`, `State Flow: passive` or `State Flow: off`. Off exposes neither tool nor State Flow model context. Requested owner-scope Rich snapshots show `#revision`; Effective shows the vector. During a failed-Passive write fence, memory-enabled inspection uses the accepted cache without a potentially conflicting refresh. Otherwise, Telegram inspection waits cancelably to load or refresh one coherent shared view, even when passive model tools are disabled. It does not initialize, publish, or advance storage. Data and displayed revisions belong to the same observation; absent/invalid memory stays unavailable. Stop, session/tree changes and shutdown cancel obsolete observations. The button acknowledges immediately, and a late failure appears in the menu instead of an expired callback popup. The submenu heading displays the current value in monospace. The bold Mode heading uses a long dash, description ending in a colon, and a blank line before its settings-style list. Each line uses a monospaced minus and lowercase monospaced mode value, then a plain colon and description. The descriptions progress from regular chat with no memory (Off, the new-session default), to ordinary chat with memory tools and an available combined memory view (Passive), to the same memory access with completed answers followed by memory-first continuation (Active); they do not claim a new physical Pi session or disable native compaction. The bold Inspect memory heading follows the same long-dash-description-colon and blank-line pattern. Its four lines use the same monospaced minus/value and plain colon format for `global`, `cwd`, `session` and `effective`, describing individual scopes and their combined view. Explicit Off inspection reads current stored memory through a disposable reader; Session and Effective require validated same-session private authority and cannot show a fabricated empty layer or revision. Shared Global/CWD inspection remains available independently of private failures. These reads install no model/runtime cache, change no bytes or mode, clear no write fence, and leave the selected historical/fork boundary intact for future Passive/Active acquisition; automatic Off callbacks never acquire memory. Current stored data is not proof that a selected past boundary is restorable. A horizontal radio row presents `Off | Passive | Active`: the selected option uses 🟡, 🟣 or 🟢 respectively, and each inactive option uses ⚫️. Four direct Global/CWD/Session/Effective buttons follow without another chooser. Ordinary successful controls add no redundant mode receipt; diagnostic outcomes remain visible. Telegram Active requested during a run waits for settlement; Passive and Off apply immediately. All controls use the same lifecycle owners as the terminal commands. The adapter is optional and the Pi commands remain available without it. Open implementation work is tracked in [BACKLOG.md](../BACKLOG.md).
|
|
94
96
|
|
|
95
97
|
## Storage and recovery
|
|
96
98
|
|
|
@@ -105,11 +107,13 @@ Each scope materializes an anchored semantic-only `checkpoint.json` plus semanti
|
|
|
105
107
|
|
|
106
108
|
### Missing, partial, and malformed storage
|
|
107
109
|
|
|
110
|
+
Missing documented fields inside a valid checkpoint or patch are supported. Current and historical semantic views include only known fields present in the selected scope or overlay; absent fields and empty responses are omitted. Higher scopes contribute only present values. Unknown top-level fields are ignored when reading checkpoints/patches and are not emitted on subsequent writes; nested data within known planes remains intact. An explicit `read_state` value query for an absent documented top-level field returns `null`, including empty/absent `session.response`. Reading and Start do not normalize files, advance revisions or require a migration. An empty semantic object is different from a missing file or missing ownership metadata.
|
|
111
|
+
|
|
108
112
|
A checkpoint and tail are one semantic pair. If both live files for a global or CWD scope disappear, State Flow treats that complete absence as current empty shared reality. An authored `patch_state` applies to that empty basis under exclusion; normal file-cohort CAS creates the accepted pair without resurrecting cold values or orphaned compilation evidence. Raw precomputed replay still refuses a removed selected target rather than replaying stale normalized changes.
|
|
109
113
|
|
|
110
114
|
Exactly one surviving pair member is corruption and fails closed. Present malformed JSON, incomplete predecessor envelopes, semantic/metadata boundary mismatches, identity contradictions, and partial session runtime evidence also remain fail-closed and are not replaced. A missing or expired private retained boundary is unavailable; State Flow does not substitute Git history or newer private files.
|
|
111
115
|
|
|
112
|
-
After a selected-boundary failure,
|
|
116
|
+
After a selected-boundary failure, Passive may still expose current global/CWD memory, but it never grants access to the unavailable historical session layer or permission to publish an empty replacement. Historical session reads and every `patch_state` refuse without changing canonical files or appending substitute checkpoints. Passive/Off selection remains available and records the native policy/write fence described above; a subsequent reload may expose validated current memory read-only, not the unavailable selected history. Status distinguishes a write fence from unavailable materialization.
|
|
113
117
|
|
|
114
118
|
**Explicit Start uses current memory, not unavailable history.** It independently validates the current same-session canonical cohort, preserving private memory, artifact provenance, revisions, step and available aligned history. Expired active/passive pointers and unfinished runtime work no longer block activation. A pre-runtime selection also keeps current accepted same-session memory rather than resetting it. Start bootstraps the conversation available on the selected Pi branch without resurrecting an old unfinished specification or claiming that expired historical private state was restored. Independently advanced shared scopes may require a new temporal origin; unavailable history is never invented. Exact-cohort CAS rejects a concurrent writer, and incomplete/corrupt storage remains untouched. An unaccepted native fork still retries its exact source rather than inventing child memory. When evidence is missing, repair it, select a retained boundary, or open a genuinely new Pi session.
|
|
115
119
|
|
|
@@ -119,13 +123,13 @@ Missing artifact provenance inside an otherwise complete scope `meta.json` means
|
|
|
119
123
|
|
|
120
124
|
Canonical scope/runtime files own current materialization and retained hot history regardless of Git availability. Pi checkpoints identify a retained semantic boundary, not a Git commit or arbitrary historical snapshot. Restart and branch restoration fail closed when the selected boundary has expired rather than substituting newer files as the selected past.
|
|
121
125
|
|
|
122
|
-
After an accepted turn has reconciled its response, Pi 0.87's final actionable `agent_before_settle` boundary may create one best-effort backup commit when Git is available. The local attempt completes before settlement continues. Its capture waits cancelably when Pi supplies an operation signal; on Pi 0.87 that signal is absent at settlement, so an occupied backup/storage mutex explicitly defers backup until a later accepted turn instead of trapping Abort. Deferral neither changes memory nor starts a push.
|
|
126
|
+
After an accepted turn has reconciled its response, Pi 0.87's final actionable `agent_before_settle` boundary may create one best-effort backup commit when Git is available. The local attempt completes before settlement continues. Its capture waits cancelably when Pi supplies an operation signal; on Pi 0.87 that signal is absent at settlement, so an occupied backup/storage mutex explicitly defers backup until a later accepted turn instead of trapping Abort. Deferral neither changes memory nor starts a push. Off and shutdown cancel owned pending local attempts. Only cleanup of already-acquired locks/resources may continue; no new capture is admitted in Off. If the attached branch has an explicitly configured remote/ref, State Flow starts a non-interactive asynchronous push of the exact current commit without force. Settlement does not wait for the network. Within one Pi process, an in-flight push per repository skips overlapping attempts; a later accepted turn retries the latest backup without a durable queue. Off terminates only its admitted push and suppresses canceled reporting; an overlapping caller cannot revoke another owner's push. Normal completion of the agent operation does not revoke independent push ownership. Shutdown cancels its own pushes and waits for that repository's in-flight push to close or time out. Already accepted local/remote commits are never rolled back by cancellation. Commit or push failure is diagnostic-only; repeated push failures warn once per failure streak and remain locally diagnosable. Git availability never changes semantic authority, step, or retained lineage.
|
|
123
127
|
|
|
124
128
|
### Moving a store and the 0.17 format boundary
|
|
125
129
|
|
|
126
130
|
An SDK `repositoryRoot` override or a different `PI_CODING_AGENT_DIR` selects a location; it does not relocate existing state or retained history. Copy the complete canonical store while all writers are quiescent, or use a genuinely new Pi session for an independent store. Copying only current checkpoints without their tails and metadata cannot preserve retained boundaries.
|
|
127
131
|
|
|
128
|
-
Starting with 0.17, State Flow accepts only its canonical checkpoint/tail, temporal metadata, and separate session config/runtime contract; that boundary still applies to current versions. A canonical 0.17 scope written before independent revisions remains readable: its initial counter uses only the retained semantic tail and is persisted in metadata version 2 on the next owned write, without inventing folded ancestry. Version 1 remains readable; older writers refuse version 2 through the existing provenance-version fence, so cooperating instances should upgrade together. Predecessor checkpoint envelopes, combined session metadata,
|
|
132
|
+
Starting with 0.17, State Flow accepts only its canonical checkpoint/tail, temporal metadata, and separate session config/runtime contract; that boundary still applies to current versions. A canonical 0.17 scope written before independent revisions remains readable: its initial counter uses only the retained semantic tail and is persisted in metadata version 2 on the next owned write, without inventing folded ancestry. Version 1 remains readable; older writers refuse version 2 through the existing provenance-version fence, so cooperating instances should upgrade together. Predecessor checkpoint envelopes, combined session metadata, `state.json`, hashed layouts, and semantic Pi checkpoint envelopes fail as unsupported without rewriting existing bytes. Canonical semantic objects lacking fields introduced later, such as `intents` or `lazy`, are valid sparse state and do not cross this format boundary. State Flow does not provide an in-place converter; external conversion or a fresh store is operator-owned.
|
|
129
133
|
|
|
130
134
|
### Conflicts and interrupted publication
|
|
131
135
|
|
|
@@ -135,7 +139,7 @@ Final-answer reconciliation also waits cancelably, then saves the response and c
|
|
|
135
139
|
|
|
136
140
|
Run preparation and missing-artifact maintenance wait cancelably before the first enabled inference, accepting current shared memory and lifecycle together. If preparation fails, State Flow aborts that native operation rather than sending a rejected or stale draft to the provider; previously accepted memory remains available. Cancellation can leave the new request without a specification checkpoint, so its native conversation is conservatively preserved through idle Stop/reload. Boundary continuation never replays a completed specification.
|
|
137
141
|
|
|
138
|
-
Telegram shared inspection also awaits exclusion read-only. Backup capture also uses the awaited API, with the no-signal settlement exception described above. Accepted-runtime
|
|
142
|
+
Telegram shared inspection also awaits exclusion read-only. Backup capture also uses the awaited API, with the no-signal settlement exception described above. Accepted-runtime Passive selection changes local tools/context immediately, then awaits runtime-only persistence; pending repeats share one acceptance. Off cancels that wait and records native policy without acquiring the store. Selection/shutdown or a successful Start cancel obsolete Stop work. An available host operation signal can cancel persistence without restoring an older mode; idle commands do not necessarily have that signal. Current-head Start similarly waits before enabling mode, with Stop/selection/shutdown cancellation and any available native operation signal. Startup, tree, auto-start, fork and failed-Stop reload restoration, including Start's initial attachment and fork retry, also await exclusion; until acceptance, mode stays in the selected inactive policy and private memory reports the pending selection. Off remains Off; later inactive choices survive read-only recovery without cancelling it. Interrupted, malformed or unreadable locks are never stolen. Reconcile the owner rather than deleting locks or state directories merely because an operation is slow. File-cohort exclusion, exact prepared bytes and compare-and-swap checks are not kernel-atomic multi-file transactions against nonparticipating writers.
|
|
139
143
|
|
|
140
144
|
Fatal process termination can leave an incomplete canonical file cohort. Before repair, quiesce all store writers and preserve the complete store plus selected Pi retained-boundary references. Reconcile exact files against the last complete checkpoint/tail/metadata cohort; no automatic crash repair or power-loss durability is promised. Git backup has no semantic recovery authority.
|
|
141
145
|
|
|
@@ -110,12 +110,13 @@ export {
|
|
|
110
110
|
export {
|
|
111
111
|
emptyState,
|
|
112
112
|
isMaterializedState,
|
|
113
|
+
isSemanticState,
|
|
113
114
|
isStateDocument,
|
|
114
115
|
overlayStates,
|
|
115
116
|
projectStateForModel,
|
|
116
117
|
updateMaterializedArtifacts,
|
|
117
118
|
type AtomicScopePatches, type MaterializedState, type ScopedPatch,
|
|
118
|
-
type ScopedStates, type ScopePatch, type SemanticTransition,
|
|
119
|
+
type ScopedStates, type ScopedSemanticStates, type ScopePatch, type SemanticState, type SemanticTransition,
|
|
119
120
|
type StateDocument,
|
|
120
121
|
type StatePatch,
|
|
121
122
|
type StateScope,
|
|
@@ -142,5 +143,5 @@ export {
|
|
|
142
143
|
type StateFlowTelegramSnapshot,
|
|
143
144
|
type StateFlowTelegramView
|
|
144
145
|
} from "./lib/telegram.ts";
|
|
145
|
-
export { advanceTemporalState, readTemporalState, temporalScopeRevisions, type ScopeRevisions, type TemporalState } from "./lib/temporal.ts";
|
|
146
|
+
export { advanceTemporalState, readTemporalState, readTemporalView, temporalScopeRevisions, type ScopeRevisions, type TemporalState } from "./lib/temporal.ts";
|
|
146
147
|
export { parseStateReadPath, readStatePath, type StateReadQuery, type StateReadResult } from "./lib/query.ts";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
1
|
+
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import { estimateTokens, type CompactionResult } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
|
|
4
4
|
export const STATE_FLOW_COMPACTION_SUMMARY = "State Flow accepted the completed work before this boundary. Current memory is restored from its retained semantic boundary and projected separately; use the retained native entries for subsequent work.";
|
|
5
5
|
/** A modest margin above Pi's default 20k retained suffix absorbs estimation drift. */
|
|
@@ -5,13 +5,15 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
5
5
|
import { getDurableRepositoryRoot } from "./durable.ts";
|
|
6
6
|
import { DEFAULT_HISTORY_LIMIT, MAX_HISTORY_LIMIT } from "./history.ts";
|
|
7
7
|
import { isObject } from "./json.ts";
|
|
8
|
+
import { isStateFlowMode, type InactiveMode, type StateFlowMode } from "./snapshot.ts";
|
|
8
9
|
|
|
9
10
|
export interface StateFlowConfig {
|
|
10
11
|
/** Canonical State Flow repository. SDK callers may still override it explicitly. */
|
|
11
12
|
directory: string;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/** Default mode for genuinely new sessions only; each session owns its selected mode. */
|
|
14
|
+
mode: StateFlowMode;
|
|
15
|
+
/** Non-active fallback for legacy `enabled:false` evidence and unavailable selections; never serialized. */
|
|
16
|
+
inactiveMode: InactiveMode;
|
|
15
17
|
/** Opt-in local capture of rejected patch attempts and unresolved terminal drafts. */
|
|
16
18
|
logging: boolean;
|
|
17
19
|
/** Show successful patch_state arguments in the interactive tool row. */
|
|
@@ -25,9 +27,8 @@ export function loadStateFlowConfig(agentDir = getAgentDir(), repositoryRoot = g
|
|
|
25
27
|
const path = join(directory, "config.json");
|
|
26
28
|
const defaults: StateFlowConfig = {
|
|
27
29
|
directory,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
passiveTools: true,
|
|
30
|
+
mode: "off",
|
|
31
|
+
inactiveMode: "off",
|
|
31
32
|
logging: false,
|
|
32
33
|
showSuccessfulPatches: true,
|
|
33
34
|
historyLimit: DEFAULT_HISTORY_LIMIT,
|
|
@@ -39,23 +40,32 @@ export function loadStateFlowConfig(agentDir = getAgentDir(), repositoryRoot = g
|
|
|
39
40
|
} catch (error) {
|
|
40
41
|
throw new Error(`Cannot read State Flow configuration: ${path}`, { cause: error });
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
+
// autoStart/passiveBootstrap/passiveTools are read-only compatibility inputs; explicit mode is authoritative.
|
|
44
|
+
const allowed = new Set(["mode", "autoStart", "passiveBootstrap", "passiveTools", "logging", "showSuccessfulPatches", "historyLimit"]);
|
|
43
45
|
if (!isObject(value) || Object.keys(value).some((key) => !allowed.has(key))) {
|
|
44
46
|
throw new Error(`State Flow configuration contains unknown settings: ${path}`);
|
|
45
47
|
}
|
|
48
|
+
if (Object.hasOwn(value, "mode") && !isStateFlowMode(value.mode)) throw new Error(`State Flow mode must be "active", "passive" or "off": ${path}`);
|
|
46
49
|
if (Object.hasOwn(value, "autoStart") && typeof value.autoStart !== "boolean") throw new Error(`State Flow autoStart must be a boolean: ${path}`);
|
|
47
50
|
if (Object.hasOwn(value, "passiveBootstrap") && typeof value.passiveBootstrap !== "boolean") throw new Error(`State Flow passiveBootstrap must be a boolean: ${path}`);
|
|
48
51
|
if (Object.hasOwn(value, "passiveTools") && typeof value.passiveTools !== "boolean") throw new Error(`State Flow passiveTools must be a boolean: ${path}`);
|
|
49
52
|
if (Object.hasOwn(value, "logging") && typeof value.logging !== "boolean") throw new Error(`State Flow logging must be a boolean: ${path}`);
|
|
50
53
|
if (Object.hasOwn(value, "showSuccessfulPatches") && typeof value.showSuccessfulPatches !== "boolean") throw new Error(`State Flow showSuccessfulPatches must be a boolean: ${path}`);
|
|
51
54
|
if (Object.hasOwn(value, "historyLimit") && (!Number.isSafeInteger(value.historyLimit) || (value.historyLimit as number) < 0 || (value.historyLimit as number) > MAX_HISTORY_LIMIT)) throw new Error(`State Flow historyLimit must be an integer from 0 to ${MAX_HISTORY_LIMIT}: ${path}`);
|
|
55
|
+
const legacyInactive: InactiveMode = value.passiveBootstrap !== false || value.passiveTools !== false ? "passive" : "off";
|
|
56
|
+
const hasLegacyMode = Object.hasOwn(value, "autoStart") || Object.hasOwn(value, "passiveBootstrap") || Object.hasOwn(value, "passiveTools");
|
|
57
|
+
const mode = isStateFlowMode(value.mode) ? value.mode : value.autoStart === true ? "active" : hasLegacyMode ? legacyInactive : "off";
|
|
52
58
|
return {
|
|
53
59
|
directory,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
passiveTools: value.passiveTools !== false,
|
|
60
|
+
mode,
|
|
61
|
+
inactiveMode: isStateFlowMode(value.mode) ? inactiveModeFor(value.mode) : hasLegacyMode ? legacyInactive : "off",
|
|
57
62
|
logging: value.logging === true,
|
|
58
63
|
showSuccessfulPatches: value.showSuccessfulPatches !== false,
|
|
59
64
|
historyLimit: typeof value.historyLimit === "number" ? value.historyLimit : DEFAULT_HISTORY_LIMIT,
|
|
60
65
|
};
|
|
61
66
|
}
|
|
67
|
+
|
|
68
|
+
/** Explicit modes never carry a separate passive policy: only Off stays off when inactive. */
|
|
69
|
+
export function inactiveModeFor(mode: StateFlowMode): InactiveMode {
|
|
70
|
+
return mode === "off" ? "off" : "passive";
|
|
71
|
+
}
|