@llblab/pi-kit 0.22.2 → 0.23.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/CHANGELOG.md +7 -0
- package/README.md +4 -4
- package/node_modules/@llblab/pi-grow-loop/AGENTS.md +10 -6
- package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +7 -0
- package/node_modules/@llblab/pi-grow-loop/README.md +2 -0
- package/node_modules/@llblab/pi-grow-loop/dist/index.d.ts +33 -0
- package/node_modules/@llblab/pi-grow-loop/dist/index.js +286 -0
- package/node_modules/@llblab/pi-grow-loop/dist/pi-grow-loop/index.d.ts +1 -0
- package/node_modules/@llblab/pi-grow-loop/dist/pi-grow-loop/index.js +1 -0
- package/node_modules/@llblab/pi-grow-loop/dist/skills/grow-loop/SKILL.md +117 -0
- package/node_modules/@llblab/pi-grow-loop/dist/skills/while-true/SKILL.md +233 -0
- package/node_modules/@llblab/pi-grow-loop/index.ts +67 -12
- package/node_modules/@llblab/pi-grow-loop/package.json +9 -8
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +23 -17
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +5 -3
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +11 -0
- package/node_modules/@llblab/pi-state-flow/README.md +18 -6
- package/node_modules/@llblab/pi-state-flow/dist/index.d.ts +2 -1
- package/node_modules/@llblab/pi-state-flow/dist/index.js +1 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.d.ts +2 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.js +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +3 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +7 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.d.ts +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +54 -40
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +20 -20
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +755 -325
- 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 +14 -17
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +4 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +65 -23
- package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.d.ts +16 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +32 -15
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +28 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +276 -26
- package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +5 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +36 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +3 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +3 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +1 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +3 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +11 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +150 -24
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +14 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +52 -18
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +8 -8
- package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +3 -1
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +53 -7
- package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +84 -44
- package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +12 -2
- package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +6 -4
- package/node_modules/@llblab/pi-state-flow/docs/performance.md +2 -2
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +28 -8
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +41 -14
- package/node_modules/@llblab/pi-state-flow/index.ts +3 -0
- package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +5 -5
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +8 -3
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +57 -40
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +20 -20
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +719 -316
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +16 -18
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +60 -24
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +34 -21
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +290 -25
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +37 -2
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +3 -0
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +4 -1
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +141 -22
- package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +60 -19
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +8 -8
- package/node_modules/@llblab/pi-state-flow/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +3 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-telegram/README.md +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/skills.d.ts +7 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +32 -7
- package/node_modules/@llblab/pi-telegram/dist/package.json +3 -8
- package/node_modules/@llblab/pi-telegram/lib/skills.ts +43 -7
- package/node_modules/@llblab/pi-telegram/package.json +3 -8
- package/node_modules/@llblab/pi-telegram/scripts/build-dist.mjs +103 -32
- package/package.json +6 -6
|
@@ -73,7 +73,7 @@ A changed accepted response is runtime-owned, session-only semantic state and ad
|
|
|
73
73
|
|
|
74
74
|
## Pi lifecycle
|
|
75
75
|
|
|
76
|
-
`patch_state` is the sole mutation tool. It
|
|
76
|
+
`patch_state` is the sole mutation tool. It acquires store exclusion before selecting current Global/CWD, stages the authored operations while preserving private Session ownership, and validates/publishes one atomic cohort. Replay, history and revisions use that actual basis; correct repeats create no semantic transition. It then acts as an inference barrier. Pi executes no sibling tools from the same assistant response; the next inference sees the rematerialized current effective state.
|
|
77
77
|
|
|
78
78
|
Tool preflight follows Pi's public `getLeafEntry()` / `getEntry(parentId)` links to the nearest assistant containing the current call ID. It inspects that response's complete tool batch without constructing the whole branch or caching a batch across calls/selections. Foreign custom entries and earlier sibling results remain in the native trace. A missing call ID still searches the selected ancestry and preserves the existing unmatched-call behavior; this is not an unconditional constant-time guarantee. See [measured traversal evidence](performance.md#tool-preflight-parent-traversal).
|
|
79
79
|
|
|
@@ -81,6 +81,8 @@ Tool preflight follows Pi's public `getLeafEntry()` / `getEntry(parentId)` links
|
|
|
81
81
|
|
|
82
82
|
Before answering, the model uses `patch_state` only when future-relevant durable state must change. The exact accepted ordinary answer is reconciled directly into runtime-owned `response` at `turn_end`, including `""` when the accepted answer is empty; no terminal eligibility latch, finalization patch, repair inference, or fallback budget exists. If required ordinary-artifact compilation prevents reconciliation, State Flow reports the failure without generating another inference. Optional Skill acquisition never blocks unrelated reconciliation. State Flow does not parse `state_flow` or generic HTML comments; historical comments are ordinary text and other extensions retain their own comment handling.
|
|
83
83
|
|
|
84
|
+
The always-injected protocol lists the six planes once, states scope ownership and response finalization once, combines stewardship with handoff rules, and shares provenance ownership across artifacts and Skills. Ordinary and bootstrap modes retain the same read/patch grammar, references, acquisition and safety obligations; bootstrap adds only its reconciliation requirement. This is prose deduplication, not a change to tool semantics, configurable retention or retained Session restoration/fork. `tests/protocol.test.ts` guards the preserved obligations and unique rule ownership.
|
|
85
|
+
|
|
84
86
|
## Lifecycle planes
|
|
85
87
|
|
|
86
88
|
```text
|
|
@@ -89,13 +91,17 @@ MUTATION BARRIER patch_state(scope patches) → rematerialized next inferenc
|
|
|
89
91
|
CONTEXT PROJECTION active State Flow projection | passive post-stop handoff
|
|
90
92
|
```
|
|
91
93
|
|
|
92
|
-
Stopping State Flow ends active episode semantics, restores the configured passive tool policy, and switches projection to a frozen effective-state handoff, the active user-run trajectory if interrupted, and post-stop conversation. Paired tool results arriving after Stop remain visible. Foreign context-bearing custom messages survive; a proven active boundary excludes completed earlier ordinary conversation. Direct completion persists no private validation feedback. This projection survives same-physical-session reload, resume, and tree restoration. Active restart uses it for one bootstrap run alongside active runtime context. New and forked physical sessions inherit neither projection. No semantic transition is created.
|
|
94
|
+
Stopping State Flow ends active episode semantics, restores the configured passive tool policy, and switches projection to a frozen effective-state handoff, the active user-run trajectory if interrupted, and post-stop conversation. Paired tool results arriving after Stop remain visible. Foreign context-bearing custom messages survive; outside unfinished bootstrap, a proven active boundary excludes completed earlier ordinary conversation. Stop during bootstrap preserves its incoming context boundary instead of treating uncompiled conversation as completed: an initial bootstrap keeps all available native context, while a restart keeps its earlier passive boundary across repeated toggles. Direct completion persists no private validation feedback. This projection survives same-physical-session reload, resume, and tree restoration. Active restart uses it for one bootstrap run alongside active runtime context. New and forked physical sessions inherit neither projection. No semantic transition is created.
|
|
93
95
|
|
|
94
96
|
A proven pre-runtime branch has no accepted runtime to persist: Stop appends State Flow's existing `{disabled:true}` checkpoint in Pi without creating canonical files. Its cached passive view remains readable under the configured policy, but is not runtime authority. Accepted canonical publication, including a later Start or passive patch, ends this pre-runtime condition; failed selected-boundary recovery never qualifies for it.
|
|
95
97
|
|
|
98
|
+
Explicit Start independently prepares the validated current same-session canonical cohort rather than replaying the selected Pi pointer. Active/passive or unfinished runtime metadata and expired/pre-runtime selections do not erase current private memory or block activation. `withStartTransaction` acquires exclusion before capture and binds private stream identity to current runtime lineage, with one synchronous, single-use exact-cohort acceptance before installation. Pending repeats share the same operation. Current branch/physical identity, initialization permission and bootstrap context are rechecked after waiting; Stop, selection and shutdown withdraw obsolete activation. Only acceptance enables the new mode, clears Stop fences and cancels older Stop persistence. Caches, preparation policy and one native checkpoint install before yielding without a second persistence call; a later failure cannot roll them back. Commands, deferred settled Start and Telegram await completion, and presentation receipts for both success and failure revoke with selection. It preserves private values, artifact provenance, independent revisions and step, discards the old unfinished specification, and retains available aligned history within the configured limit. Incompatible but independently valid live shared streams require a fresh origin rather than invented cross-writer history. An empty session origin is allowed only with wholly absent private authority and initialization-safe branch provenance; incomplete or contradictory evidence remains closed. Initial physical fork copying still requires its exact-source contract; an already accepted child can activate its own current memory without recopying its parent. Repeated Start while already active does not change the current run or pending response reconciliation.
|
|
99
|
+
|
|
96
100
|
Lifecycle-only persistence for accepted runtimes reconciles valid live global/CWD drift before publishing the current session's config/runtime pair. Changed shared streams establish a fresh proven origin, not a semantic transition; the runtime adopts their already-advanced owner revisions without incrementing them, while semantic files and all provenance files remain unchanged. Cached reads may constrain wider tails left by another writer without rewriting them. Same-session file races and explicitly requested stale provenance writes still fail closed under CAS. The host refreshes its scope cache after adoption: Stop freezes the accepted view, and new-run registered-artifact maintenance runs against that view before inference.
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
Local Stop disables active projection and response/compaction behavior before attempting canonical persistence. For accepted runtimes it freezes the passive handoff immediately, then awaits `withLifecycleTransaction` with Stop-owned cancellation and any available Pi operation signal. Repeated pending calls share one acceptance. After acquisition, recheck runtime/physical owner/policy and derive the snapshot from current lifecycle state, including an intervening same-instance passive patch. Successful publication installs the adopted shared cache, final handoff and native checkpoint before yielding. Session/tree selection, shutdown or accepted Start revoke obsolete Stop work; a failed Start leaves it pending. Shutdown drains the canceled operation. A post-acceptance lifecycle failure never restores old metadata or retries native writes. If persistence fails, it keeps accepted cached memory and all available native context, then records `owner`, `persistenceError` and `preserveContext: true` in the existing native passive-stop marker. This is a same-session policy override and write fence, not semantic authority or a substitute checkpoint. No canonical failure is repaired by resetting memory. Tree/reload/resume with that pending marker use `TemporalRuntime.refreshCurrentMemory()` to validate and read current memory without historical restoration or publication; unavailable evidence remains unavailable. A later accepted checkpoint supersedes the fence, while preserving the context boundary for bootstrap. Repeated degraded Stop is inert. Successful explicit Start uses the same detached validation path under CAS before clearing the fence. Status and inspection distinguish accepted cached/read-only memory from unavailable publication. If Pi's own trace is unwritable, the local disablement still precedes the error, but durable fallback cannot be guaranteed.
|
|
103
|
+
|
|
104
|
+
The existing native passive-stop marker stores the stop timestamp and an optional `from` timestamp identifying the active run's first user message. Native user events are observed independently of State Flow enablement, so starting mid-tool and repeated Start/Stop retain the actual first-user timestamp. Native user-run preparation and session-start/tree events reset capture; semantic mode changes do not. The same marker accepts optional `preserveContext: true` when compilation is unfinished and no narrower incoming boundary is sufficient; omitted flags keep legacy selection behavior. This projection flag creates no semantic storage authority. Transcript bodies remain in Pi's trace rather than being copied into another state store. A recorded active anchor uses the same conservative selector as active inference: if native compaction removed it, or matching is ambiguous/nonfinite, retain the available native summary and tool trajectory without guessing a post-stop boundary or rereading discarded raw entries. An interrupted run keeps its captured anchor even after Pi becomes idle; if capture is unavailable, Stop preserves all available context. Completed idle runs and legacy markers without an active anchor or preservation flag retain only post-stop conversation plus foreign custom context. The initial system prompt is composed at `before_agent_start`; Stop does not rewrite an already-issued request, while the next provider request receives the current owned protocol section as described below.
|
|
99
105
|
|
|
100
106
|
The current user specification stays at user authority and appears only in synthetic user runtime context. State is fallible assistant-produced data. Active/passive protocol contributes to Pi's native `state_flow` system-prompt section at `before_agent_start`, rather than forcing the entire prompt. Later companion sections and `context_with_system` transformations compose normally; explicit foreign forced prompts retain Pi's documented precedence. Native section diffs remove/reinstate the initial protocol across user requests. At `context_with_system`, the context domain also refreshes only the owned section from current enablement/bootstrap/passive policy, covering Stop/Start inside the same tool loop and accepted-boundary continuations. Unchanged effective protocol reuses the original array without relocating native deltas; a changed mode preserves foreign sections/content/tools and conversation identity/order without mutating native frames or creating missing system authority. Accepted completion removes the specification, not memory availability: a companion's actionable `turn_end` or `agent_before_settle` continuation can request another inference without `before_agent_start`. Every enabled request still gets one current-memory projection, omitting an absent specification and using the captured native anchor when available; no synthetic user run, persisted continuation field or State Flow scheduler is created. Completed trajectories leave model context at user-run boundaries, while Pi's full JSONL trace remains inspectable.
|
|
101
107
|
|
|
@@ -134,13 +140,47 @@ In-memory patching detaches one basis at its public boundary, then privately pat
|
|
|
134
140
|
|
|
135
141
|
All owned writes use same-directory atomic replacement, regular-file and symlink checks, prepared byte receipts and CAS validation. Unrelated files and detected concurrent bytes are preserved. Rollback restores only bytes still matching the failed publisher's output.
|
|
136
142
|
|
|
143
|
+
### Asynchronous storage transaction
|
|
144
|
+
|
|
145
|
+
`lib/storage.ts` supplies `withStorageTransaction(root, callback, signal?, waitForLock = true)`. The root must already exist. One `.state-flow-publication.lock` covers every scope in that store; the callback receives root-bound `capture` and `publish` operations and keeps exclusion until it finishes, including asynchronous completion. Capture happens after acquisition. Publication reuses the same validation, exact-byte CAS, receipts and guarded rollback as the synchronous adapter, without reacquiring the lock. Borrowed operations expire on callback completion and cannot address another store.
|
|
146
|
+
|
|
147
|
+
By default, a live PID waits asynchronously until release or cancellation; there is no ordinary-contention deadline or automatic lock theft. Only the empty creation-to-PID window has a bounded two-second grace period. Malformed, non-regular, unreadable or interrupted ownership fails without repair. Recursive acquisition of an actively owned root is an error, not implicit reentrancy; inherited async context from a completed callback does not confer ownership or block a new transaction. Cancellation before acquisition or before publication leaves canonical bytes unchanged. Once a synchronous publication has accepted its cohort, later cancellation does not undo it. Cleanup checks lock identity/contents and preserves detected replacement ownership, retaining both action and release errors when necessary. No process/power-loss crash atomicity or kernel-atomic exclusion against nonparticipating writers is implied. The writer has no file/directory flush barrier. Optimistic persistence across abrupt shutdown is an [accepted limitation](filesystem-recovery.md#power-loss-durability), not a release gate; no crash-recovery journal or additional storage namespace is planned. Short capture/stage/publication exclusion remains necessary to preserve independent fields between cooperating writers; stale whole-state last-writer-wins replacement would lose unrelated work.
|
|
148
|
+
|
|
149
|
+
`TemporalRuntime.withPatchTransaction` routes `patch_state` through this capability. Its synchronous callback receives detached current states, their causal basis and provenance, plus one single-use `publish` operation; it cannot access selection or raw storage methods. Shared drift is adopted before staging, not used to reject a stale agent. The exact accepted private cohort remains fenced against another physical writer or unselected history. A new owner prepares an empty private origin without writing it separately; validation failure leaves canonical files and accepted caches untouched. Compiled cards and evidence publish together, and an absent semantic pair cannot confer orphaned compilation evidence on a new registration. Host caches and the accepted native checkpoint update after publication, before yielding.
|
|
150
|
+
|
|
151
|
+
`TemporalRuntime.withLifecycleTransaction(action, signal?)` is the runtime-only counterpart. It requires already accepted private authority both before and after waiting; passive reads and unaccepted restore candidates cannot initialize or authorize it. Under one exclusion it captures current shared state and calls `action(publish)`, where the caller must recheck selection/policy and derive its current lifecycle snapshot before invoking `publish(snapshot)` synchronously once. Only that session's config/runtime may change: semantic files, scope provenance, scope revision counters and even wider foreign retained tails stay untouched. No-op acceptance returns `changed: false` after validating the captured cohort. Failed/canceled publication installs no candidate; cancellation after acceptance cannot undo it. The transaction APIs share the candidate/acceptance owner, without nested lock acquisition or a second persistence call. The patch transaction's existing `publish` also uses runtime-only acceptance when there is no transition/provenance update and its accepted file cohort is complete. New private authority or wholly absent shared pairs instead require ordinary atomic initialization from the staged current values. Partial/malformed evidence remains rejected. No extra publisher capability or caller-selected storage mode is needed.
|
|
152
|
+
|
|
153
|
+
`TemporalRuntime.withStartTransaction(action, signal?, allowCreateOrigin = false)` supplies `action(currentSnapshot, publish)`. It validates the current same-session head rather than requiring the caller's cached private basis; the detached snapshot omits old unfinished specifications. Root/private-origin creation is refused by default. When explicitly permitted, wholly absent private authority supplies `undefined`, and the caller must recheck branch permission after waiting before publishing its activated snapshot. Rejected staging never accepts empty setup separately. Complete current memory preserves available aligned history, while independently valid shared streams can establish a fresh origin. Start uses ordinary origin acceptance, including configured retention folding, not lifecycle-only semantic-byte preservation. The legacy prepared Start API retains its selected-cohort CAS contract but has no production caller.
|
|
154
|
+
|
|
155
|
+
`TemporalRuntime.withRestoreTransaction(checkpoint, action, signal?)` detaches the retained pointer before waiting, then captures and validates its exact private boundary beside current shared streams under one exclusion. `action(selectedSnapshot, publish)` rechecks caller selection/policy after waiting and synchronously accepts once. The candidate stays detached until publication; expiry, incomplete evidence, cancellation and CAS failure never substitute current-head or empty memory. Origin acceptance applies configured retention and causal provenance pruning, as the synchronous restore does. Accepted memory is installed before returning to caller checkpointing; later failure cannot roll it back. Native startup/tree restoration uses it through the extension's owned restoration lifetime.
|
|
156
|
+
|
|
157
|
+
`TemporalRuntime.withForkTransaction(source, checkpoint, action, signal?)` pins parent identity and boundary before waiting. Under one exclusion it selects exact retained parent authority and captures an unoccupied child target. The callback receives child lifecycle (step zero, selected mode/bootstrap, no unfinished specification), rechecks native selection/policy, then publishes synchronously once. Parent evidence is revalidated immediately before child publication; the child's exact file cohort is CAS-protected. Only acceptance installs child memory. Parent-private files stay untouched, shared provenance remains live, and configured folding remains applicable. Expired, malformed or occupied selections never become an empty or newer-parent copy. Native fork adoption and Start's exact-source retry use it.
|
|
158
|
+
|
|
159
|
+
Native `before_agent_start` now captures the prompt and contributes protocol without touching canonical storage. At the first active `context`, the adapter combines Pi's operation signal with its preparation lifetime, awaits `withPatchTransaction`, rechecks selection/policy, clones the latest lifecycle snapshot and inspects exact registered paths from the locked states. Proven-missing registrations and their provenance are removed together with run metadata in one acceptance; source reappearance or unavailable metadata does not authorize deletion. Without removals on a complete accepted cohort, publication preserves semantic/provenance files and wider retained history. Wholly absent shared pairs initialize as current empty reality, without reviving old values or incrementing the step. Caches, revisions and one native checkpoint update before the provider; subsequent context requests reuse completed preparation rather than replaying the specification. Start can request maintenance without inventing a new user run.
|
|
160
|
+
|
|
161
|
+
Stop, session/tree changes, new runs and shutdown withdraw obsolete preparations. A failed/canceled acceptance installs no draft/shared adoption; a later failure cannot roll back accepted metadata. Pi catches context-hook exceptions and continues, so preparation failure requests cancellation through public `ctx.abort()` before returning, with an actionable diagnostic and no repair inference. Idle/no-signal projections do not publish. Native tests prove this [pre-inference cancellation seam](compatibility.md#pre-inference-cancellation), including real Abort while another process is paused mid-publication.
|
|
162
|
+
|
|
163
|
+
An unaccepted request may leave no canonical specification. Native conversation after the latest valid checkpoint is therefore conservative uncompiled-context evidence, not semantic authority. Stop preserves it even at idle, and same-physical-session restoration uses the existing bootstrap flag to retain available context through reload/tree. This also covers interrupted boundary continuation after completion removed the specification. No new persistence format, guessed run anchor or reconstruction of discarded transcript bodies is introduced.
|
|
164
|
+
|
|
165
|
+
Accepted-answer reconciliation also uses `withPatchTransaction`: `turn_end` awaits exclusion, stages the response over the current shared head, and atomically publishes it with a detached completed-run snapshot. Only acceptance installs the lifecycle/cache and native checkpoint; there is no second persistence call. Its response-owned cancellation is combined with Pi's operation signal. Stop, new runs, session/tree selection, shutdown and superseding answers cancel obsolete waits; an old completion cannot clear a newer pending response or alter its snapshot/UI. Failure or pre-acceptance cancellation leaves accepted memory and the unfinished specification intact. Later native boundary handlers and continuation inference observe accepted memory.
|
|
166
|
+
|
|
167
|
+
`TemporalRuntime.refreshShared(signal?)` awaits the same exclusion for read-only shared inspection. It captures one complete cohort after acquisition, preserving the selected private file basis or lazily constructing an empty private view when none is selected. It never initializes an absent store, publishes, or advances a semantic revision. Parsing and provenance validation finish before cache installation; rejected/canceled reads preserve the prior accepted view.
|
|
168
|
+
|
|
169
|
+
`TemporalRuntime.refreshCurrentMemory(signal?)` supplies an awaited read-only recovery view of current same-session authority. It shares current-memory validation with Start, but neither publishes nor accepts write authority: returned policy is disabled and unfinished specifications are omitted. Current private values, step, revisions, bootstrap and provenance remain available beside independently validated shared streams; retention is constrained only in memory. Absence returns `undefined` without creation, and malformed evidence or cancellation (including during capture) leaves the prior cache unchanged. Lifecycle/patch publication still requires accepted authority or explicit Start. Native failed-Stop reload uses it and keeps the write fence.
|
|
170
|
+
|
|
171
|
+
Native `session_start` and `session_tree` await one extension-owned branch restoration. Its synchronous prelude revokes older selection work, pins session id, file, header timestamp and CWD, and selects active-branch evidence through the recovery domain's pure `selectRetainedCheckpoint`: newer malformed envelopes are skipped, while revision pointers and every failure resolving the selected boundary fail closed. While it waits, mode is passive and private reads/publication report the pending selection. The selected boundary, exact-source fork, truly new auto-start origin (`withStartTransaction` with creation authority, rechecking branch evidence after waiting) or failed-Stop read-only recovery then use the awaited runtime API. Bootstrap/policy derive after waiting and publish in that single acceptance; only the current lifetime installs memory, checkpoint, continuation, tools and UI before yielding, and later native-write failure only warns. New selection revokes older work; shutdown drains current and superseded restoration operations. Stop selects passive policy without cancelling retained restoration, new-session initialization or fork copying, including attachment originally requested by a now-cancelled Start waiter. The pending publisher applies that policy inside its single acceptance; configured passive tools can then patch memory without an artificial error fence. Repeated Stop is inert with respect to that acceptance. Start after Stop joins the independent memory operation before activating current memory. Selection changes, shutdown and native operation cancellation still revoke obsolete work; real validation/publication failures remain unavailable rather than becoming empty memory. Start joins pending restoration, owns initial attachment and fork retry without cancelling itself, and is inert when the result is active. A cancelled Start withdraws its join without cancelling independently owned restoration or Stop persistence. Read-only recovery uses detached candidates and rechecks cancellation/physical identity before host installation; passive attachment cannot overwrite a newer cache established by an intervening patch or inspection. Six synchronous runtime methods remain supported for library consumers and local tests/benchmarks; production lifecycle wiring uses the awaited APIs. Their contracts and cancellation boundaries are documented in [library API compatibility](compatibility.md#state-flow-library-api-compatibility).
|
|
172
|
+
|
|
173
|
+
The advisory [continuation-candidate reader](#session-continuation) also awaits coherent capture. Current-head activation on an attached branch uses the awaited Start transaction. Raw precomputed replay keeps its selected-target guard, unlike current-head authored patch staging. Model inference, source acquisition and Git commands do not belong inside a canonical critical section; artifact freshness validation remains part of publication validation.
|
|
174
|
+
|
|
137
175
|
## Optional Git backup
|
|
138
176
|
|
|
139
177
|
Canonical files always own semantic persistence, current materialization, and retained hot history. Installing Git beside the store does not change authority or enable cold semantic restoration. Retained-boundary restoration selects private session history from the current canonical lineage while global/CWD scopes remain live; expired boundaries fail closed.
|
|
140
178
|
|
|
141
179
|
Scope artifact provenance records only current evidence. Restore/fork drops session provenance for paths touched by any retained session patch after the selected boundary, including a change-away-and-back; path existence or equal final values cannot substitute for that causal check. Selected artifact semantics remain intact with unavailable evidence until a stable explicit read and compilation. Untouched paths, provenance-only refreshes of unchanged semantics, and live shared provenance remain usable.
|
|
142
180
|
|
|
143
|
-
After response reconciliation and Pi's retry/queue processing, `agent_before_settle` may commit the already-accepted State Flow-owned files once.
|
|
181
|
+
After response reconciliation and Pi's retry/queue processing, `agent_before_settle` may commit the already-accepted State Flow-owned files once. `backupCurrentStateFlowFiles(root, signal?, waitForLock = true)` now returns `Promise<string | undefined>` and must be awaited. It awaits its own Git mutex and canonical exclusion to inventory the bounded root/CWD/session namespace and capture regular-file bytes, then releases canonical exclusion before every Git command or filter. `withFilePublicationLock` owns the shared acquisition/release mechanics: both mutexes retain exact ownership across awaits, refuse recursion and preserve replacement owners or combined action/cleanup failures. The backup mutex spans capture and Git completion; the branch/head is rechecked after waiting. It never descends into artifact sources, `.git`, or unrelated directory trees. A private temporary worktree/index stages the captured snapshot with Git ignore/filter policy preserved; concurrent writers may advance canonical files without changing that snapshot.
|
|
182
|
+
|
|
183
|
+
Settlement combines an available Pi operation signal with shutdown cancellation and awaits the local backup; shutdown cancels and drains its own attempts before waiting for remote pushes. Pi SDK 0.87 has no operation signal at `agent_before_settle`, and native Abort cannot cancel a wait there. On such a host the adapter passes `waitForLock = false`: uncontended work proceeds, while live/initializing ownership raises `PublicationBusyError` and produces an explicit backup-deferred notice. Invalid/interrupted evidence remains an error, never a successful or partial capture. No commit or push follows deferral; a later accepted turn may retry. This is a narrow optional-backup admission policy, not semantic-write conflict repair or an operator configuration. The operator accepts this best-effort deferral independently of power-loss durability and retains `agent_before_settle` as the backup boundary. Moving backup to `turn_end` or extending the SDK solely for settlement waiting is not planned; backup is not a stronger canonical persistence guarantee. See the [SDK boundary evidence](compatibility.md#settlement-cancellation).
|
|
144
184
|
|
|
145
185
|
Only exact backed-up owned paths are synchronized in the caller's index, preserving unrelated staged additions, modifications, deletions, index-only content, and worktree edits. HEAD-owned paths remain candidates when their deletion is already staged. Unchanged trees and unowned-only initial backups are skipped; failed index synchronization rolls back only the backup ref, never canonical files. Failure cannot suppress the answer or trigger another inference. Notification-only `agent_settled` does not perform backup writes.
|
|
146
186
|
|
|
@@ -186,7 +226,7 @@ External transfers use the destination's native interface and receipts; accepted
|
|
|
186
226
|
The package exposes read-only host contracts that:
|
|
187
227
|
|
|
188
228
|
- read only native JSONL headers, never transcript bodies;
|
|
189
|
-
-
|
|
229
|
+
- Await a coherent canonical runtime/scope cohort without publication;
|
|
190
230
|
- rank exact profile, CWD, Git common-directory, worktree, branch and transport identity;
|
|
191
231
|
- fail closed for stopped, malformed, unavailable or ambiguous candidates;
|
|
192
232
|
- preserve explicit new/resume and native picker precedence;
|
|
@@ -194,13 +234,17 @@ The package exposes read-only host contracts that:
|
|
|
194
234
|
|
|
195
235
|
Session checkpoint/tail identities must agree with that session's retained runtime lineage before restore/fork accepts a fresh origin. This check permits sparse session changes and inherited pre-origin streams; it does not require a session patch at a shared-only transition. Continuation inspection applies the same session check while validating current global/CWD streams independently. Shared writers do not belong to another session's historical clock. Neither path repairs a contradictory session cohort or manufactures empty session authority.
|
|
196
236
|
|
|
237
|
+
`inspectStateFlowContinuationProvenance(header, repositoryRoot, signal?)` and `buildContinuationCandidates(headers, inspect, signal?)` now return Promises and must be awaited. Inspection captures runtime configuration, lineage and all three scope streams under one store exclusion. It never creates a missing store, repairs evidence, advances revisions or installs a runtime cache. Orphaned private files are incomplete evidence, not an ordinary session with no State Flow runtime. Malformed/unavailable evidence returns ineligible provenance with its diagnostic cause; cancellation rejects instead of fabricating an ineligible or new-session decision.
|
|
238
|
+
|
|
239
|
+
Candidate building accepts synchronous or asynchronous host inspectors, passes the optional signal through, snapshots the whole native-header list before waiting and detaches returned State Flow eligibility. Host metadata cannot override the native file, UUID, CWD or activity identity. `resolveContinuationStartup(context, intent, recommend, signal?)` preserves explicit host intent and passes the signal to the default-launch recommender; both async boundaries reject obsolete results after cancellation. Hosts own that cancellation lifetime. These APIs only advise: current-cohort eligibility neither restores a selected historical boundary nor overrides native branch/Stop policy.
|
|
240
|
+
|
|
197
241
|
The [tested Pi SDK baseline](compatibility.md) chooses or creates `SessionManager` before package resources and extensions load. Therefore native default auto-resume cannot be installed safely by this extension alone. The remaining host integration requires an upstream pre-session resolver hook or an SDK/launcher that invokes the advisory resolver before constructing the session.
|
|
198
242
|
|
|
199
243
|
## Model tools and embedding
|
|
200
244
|
|
|
201
245
|
### Model tools
|
|
202
246
|
|
|
203
|
-
`patch_state` accepts one or more fixed `global`, `cwd`, and `session` semantic patches. Supplied scopes contain object-valued `artifacts`, `contract`, `working`, and `intents`, plus object-valued `lazy` whose nested values are ordinary JSON; omitted fields preserve their values, recursive object merge updates them, arrays/primitives replace, and nested object-key `null` deletes. Materialized null, empty supplied scopes,
|
|
247
|
+
`patch_state` accepts one or more fixed `global`, `cwd`, and `session` semantic patches. Supplied scopes contain object-valued `artifacts`, `contract`, `working`, and `intents`, plus object-valued `lazy` whose nested values are ordinary JSON; omitted fields preserve their values, recursive object merge updates them, arrays/primitives replace, and nested object-key `null` deletes. Materialized null, empty supplied scopes, unknown top-level fields, model-authored `response`, and retired finalization or patch grammars are rejected. Correct repeated results succeed as `State already current.` without another semantic revision or history record; avoid gratuitous acknowledgment patches. Global/CWD overlap follows successful acceptance order, while unmentioned current fields survive. Session ownership is not a shared-memory merge.
|
|
204
248
|
|
|
205
249
|
```json
|
|
206
250
|
{"session":{"intents":{"next":"Verify the corrected behavior"}}}
|
|
@@ -234,7 +278,9 @@ Agent configuration is read once per extension load; session runtime configurati
|
|
|
234
278
|
|
|
235
279
|
## Observability
|
|
236
280
|
|
|
237
|
-
|
|
281
|
+
The inspection-capable Telegram port accepts synchronous or Promise-returning Start/Stop results with optional revocation signals, while the legacy `StateFlowTelegramPort` stays synchronous. Controls initiate callback acknowledgement alongside execution rather than waiting for a network round trip before local Stop. Final feedback follows completion, uses the current menu and escapes late failures without answering the callback twice. Revoked receipts, newer callback navigation and disposal suppress stale view writes; they never roll back canonical acceptance.
|
|
282
|
+
|
|
283
|
+
Status is a projection of the selected runtime and semantic view, not a second store. Compact terminal and Telegram main-menu status render `G#/C#/S#` only while active; passive Telegram renders `State Flow: off`. Requested Global, CWD and Session Rich snapshots show their independent `#revision`, while Effective shows the vector. Global/CWD Rich views omit the empty structural response placeholder; Session and Effective expose the Session-owned response. Missing evidence stays unavailable instead of appearing empty. The optional Telegram leaf adapter calls the same Start/Stop owners, and its inspectors remain available in either mode. Inspection may refresh live Global/CWD streams in memory so foreign accepted revisions become visible, but never publishes or increments a revision. If model-facing passive access is disabled and no runtime is selected, inspection may lazily load existing canonical shared state under the same read-only rule. The awaited `StateFlowTelegramInspectionPort` returns a `StateFlowTelegramInspection` containing state and matching revisions, plus an optional revocation signal checked immediately before presentation. Stop, selection changes and shutdown cancel obsolete reads without altering newer memory or clearing write fences. The existing synchronous `StateFlowTelegramPort` contract remains supported. A callback is acknowledged before waiting; late failures appear escaped in the existing menu, without a second answer to an expired query. Registration is fail-open and disposal belongs to session shutdown. Local diagnostics stay outside semantic state and cannot change accepted state. Operator-facing fields and privacy boundaries are in [usage](usage.md#status-and-controls).
|
|
238
284
|
|
|
239
285
|
## Validation boundaries
|
|
240
286
|
|
|
@@ -1,64 +1,104 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Compatibility and verification boundaries
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Supported Pi stack
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
State Flow requires matching `pi-coding-agent`, `pi-agent-core`, `pi-ai`, and `pi-tui` packages at `>=0.87.0`. Keep all four on the same release line. The open-ended peer range permits newer SDK releases; it does not certify them.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The repository-local verified stack is Linux/x64, Node 26.8.1, Git 2.55.0 and Pi SDK 0.87.0. The current release candidate passes 711 tests, typecheck, build, compiled imports and package dry-run. The release workflow uses Node 24; its result is a separate verification gate.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
| Pi SDK stack | Validation | Evidence status |
|
|
12
|
-
| --- | --- | --- |
|
|
13
|
-
| 0.87.0 | Build, typecheck, import, package dry-run; 472/472 tests in each of five ordinary and five `push.negotiate=true` isolated-Git runs | 0.18.1 candidate source-bound acceptance (2026-09-23); not a live-provider or cross-platform claim |
|
|
14
|
-
| 0.84.4 | Historical full-suite baseline | Unsupported by State Flow 0.17.0 |
|
|
15
|
-
| 0.85.1 | Historical full-suite baseline | Unsupported by State Flow 0.17.0 |
|
|
16
|
-
|
|
17
|
-
Only exact matching stacks that were actually exercised are test evidence. Mixed SDK versions and untested newer releases are permitted by package metadata but remain unverified.
|
|
9
|
+
Tests use isolated stores and scripted providers through the real Pi SDK. They do not certify installed Telegram/TUI reachability, live provider behavior, other operating systems, mixed SDK versions or untested newer SDK releases. Detailed behavioral witnesses live in [temporal acceptance](temporal-acceptance.md); benchmark methodology and source-bound results live in [performance](performance.md).
|
|
18
10
|
|
|
19
11
|
## Public host seams
|
|
20
12
|
|
|
21
|
-
State Flow
|
|
13
|
+
State Flow relies on:
|
|
22
14
|
|
|
23
|
-
-
|
|
24
|
-
- Read-only
|
|
25
|
-
- `message_end`, actionable `turn_end`, `agent_before_settle
|
|
26
|
-
- Canonical session context, `ContextEditEntry`,
|
|
27
|
-
- `getContextUsage()
|
|
15
|
+
- Awaited session lifecycle events and branch metadata for startup, shutdown, resume, fork and tree navigation.
|
|
16
|
+
- Read-only native parent traversal through `getLeafEntry()` and `getEntry(id)`.
|
|
17
|
+
- `message_end`, actionable `turn_end`, `agent_before_settle` and `agent_settled` ordering around accepted assistant messages.
|
|
18
|
+
- Canonical session context, `ContextEditEntry`, conversation `context` and full `context_with_system` boundaries.
|
|
19
|
+
- Public `getContextUsage()`, operation cancellation and native compaction hooks.
|
|
28
20
|
- Sequential tool execution and tool-call preflight.
|
|
29
21
|
- Session replacement awaiting outgoing shutdown before invalidation.
|
|
30
22
|
|
|
31
|
-
|
|
23
|
+
An embedding must deliver the native lifecycle, not merely construct or dispose a session object. Follow the [embedding lifecycle contract](architecture.md#embedding) and await extension binding for every new session.
|
|
32
24
|
|
|
33
|
-
##
|
|
25
|
+
## Context, tools and provider input
|
|
34
26
|
|
|
35
|
-
|
|
27
|
+
State Flow contributes its protocol through `systemPromptOptions.sections.state_flow` and refreshes only that section at `context_with_system`. Companion sections, native system deltas, tool declarations and non-system message identities remain intact; an explicit foreign forced prompt retains Pi's precedence. Mode changes update the next provider request without requiring another `before_agent_start`.
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
- **Canonical `SessionManager` and `ContextEditEntry` — native-tested without an extra projection owner.** Native user replacement, assistant/custom-message omission and tool-result replacement inside the tool loop reach the provider correctly. Tree selection applies only branch-relative edits; fixture reload preserves the edited projection. Raw trace bytes remain intact and selecting a pre-runtime branch does not overwrite accepted semantic files. State Flow neither assigns `agent.state.messages` as history authority nor reconstructs omitted raw entries; trajectory edits do not authorize rewriting separately owned semantic memory. Pi retains ownership of string-replacement normalization, protection of unseen boundary input and edited-usage freshness; no alternative transcript or accounting implementation is added.
|
|
39
|
-
- **Conversation `context` versus full `context_with_system` — adapted and native-tested.** State Flow supplies protocol via `before_agent_start.systemPromptOptions.sections.state_flow`, no longer forcing the entire prompt. Companion before-run sections and full-system additions now survive active/passive requests and tools; conversation hooks exclude systems while full-system hooks include them. Tests inspect model-visible declarations and read evidence, not just scripted execution. Explicit foreign forced prompts still override per-request system additions by Pi's contract. Native section diffs remove/reinstate State Flow's protocol on subsequent user requests after Stop/Start.
|
|
40
|
-
- **Mid-tool protocol-mode refresh — adapted and native-tested.** The next request after mid-read Stop, passive Stop, mid-read Start or accepted-boundary Stop/continuation now receives current protocol without another user-run preparation. `context_with_system` projects only the owned section; it keeps source frames immutable, conversation identities/order, foreign sections/content/tools and explicit forced-prompt precedence. Unchanged effective protocol is a no-op, including native later system deltas. No missing system frame, lifecycle field, controller or State Flow persistence format is invented. Retained red-to-green tests supersede the earlier defect-only diagnostic.
|
|
41
|
-
- **Deferred work from `agent_settled` — adapted and native-tested.** State Flow awaits its admitted native compaction's completion/error callback before returning from the settled handler. Fire-and-forget compaction previously overlapped Pi's deferred companion prompt dispatch and rejected that prompt. Native low-pressure, admitted-compaction and explicit-refusal cases now complete all settled observers before one follow-up starts, with correct memory/step and no lost or duplicate inference. Existing eligibility/leaf/generation/shutdown guards remain; backup stays at `agent_before_settle`. No new timer, queue or continuation owner is introduced.
|
|
42
|
-
- **Retain-none compaction — deliberately unused for State Flow-owned shortening.** Canonical memory is not a lossless replacement for the original request, images, tools or foreign custom context. Owned compaction therefore retains the complete accepted run; ordinary native manual/threshold/overflow compaction stays Pi-owned. R12/R14 native witnesses cover normalized images, steering and split-turn Stop continuation without trace rewriting.
|
|
43
|
-
- **Persisted retry/length/overflow omissions and edited-context accounting — inherited SDK behavior, now native-tested.** Retryable error, recoverable length and explicit overflow keep failed attempts raw while persisting omission edits; recovery and reload exclude them. Native split-turn recovery uses two summary requests within one compaction and one coding continuation. Failed attempts/summaries never advance State Flow response or semantic step. Separate accounting coverage replaces a large source message, observes reduced native usage without changing raw trace/memory, and rules out phantom recovery/compaction from stale provider counts. These are scripted SDK witnesses, not live-provider guarantees.
|
|
44
|
-
- **Per-model image resize profiles — SDK-owned and native-tested.** Real wide/tall PNG payloads exercise `inputLimits.images.resize` on prompt images, built-in image reads and generic tool-result images. Native model selection changes bounds from 1800×1200 to 900×600: new payloads use the smaller profile while historical user/read/generic-tool payloads remain byte-identical through later provider inputs and fixture reload. Disabled and bootstrap-enabled State Flow controls pass, alongside normalized-image steering/compaction and actual prompt/tool declarations after owned compaction. No State Flow image pipeline is introduced. Pi 0.87 describes other hard image/request-limit fields as metadata; codec byte/quality settings and provider enforcement remain upstream-owned, not independently live-provider/cross-platform certified here.
|
|
45
|
-
- **Removed `shouldStopAfterTurn` and changed runner/event shapes — no direct low-level migration required.** State Flow registers typed extension handlers rather than configuring an Agent termination option or calling `ExtensionRunner.emit("turn_end")`. Native SDK fixtures dispatch through Pi's `finishTurn`/`emitBoundary` implementation; the new companion tests exercise required boundary fields and draft persistence.
|
|
46
|
-
- **Other release fixes — inherited or outside this extension's ownership.** GIF-prefixed text detection belongs to built-in `read`; provider strict-schema defaults, cache-warming timing and crash diagnostics belong to Pi. Offline `/bug` upload behavior and prompt-template frontmatter diagnostics do not require State Flow features. No duplicate image pipeline, HTTP adapter, diagnostics service or cache scheduler is introduced. This classification is not a live-provider or cross-platform verification claim.
|
|
29
|
+
Native context edits, omitted messages and replaced tool results reach the provider through Pi's canonical context. Raw native trace remains inspectable. Branch selection applies branch-relative edits without rewriting separately owned memory. Retry, length and overflow recovery omit failed attempts from subsequent provider input without accepting them as State Flow responses or advancing semantic history. Edited-context usage accounting must not trigger phantom compaction.
|
|
47
30
|
|
|
48
|
-
|
|
31
|
+
Image resizing, encoding and provider limits remain SDK-owned. Tests exercise prompt images, built-in reads and generic tool results across model-specific resize profiles while preserving historical payloads. State Flow supplies no image pipeline or provider-limit enforcement. Provider strict schemas, cache behavior, diagnostics and other SDK capabilities are not independently certified by State Flow's tests.
|
|
32
|
+
|
|
33
|
+
Active boundary continuation receives accepted memory even when no new `before_agent_start` occurs. A completed specification is not resurrected. State Flow does not become the owner of the host's continuation scheduler.
|
|
34
|
+
|
|
35
|
+
## Pre-inference cancellation
|
|
36
|
+
|
|
37
|
+
On the tested SDK, `before_agent_start` precedes the low-level agent's `prompt`; `ExtensionContext.signal` is undefined there. State Flow captures the specification at that hook without canonical publication. The active `context` hook supplies the operation signal and awaits preparation/maintenance before provider inference.
|
|
38
|
+
|
|
39
|
+
Pi catches context-hook errors and may otherwise continue inference. State Flow therefore calls public `ctx.abort()` on preparation failure rather than relying on a thrown error as a fence. Native tests prove no provider call before coherent acceptance, cancellation while an independent writer remains held, rollback without draft installation and preservation of uncompiled native input.
|
|
40
|
+
|
|
41
|
+
Operation signals are not universal. Idle commands and session events can lack them. Do not infer native Abort cancellation from an extension-owned shutdown signal or generalize active-run tests to idle waits.
|
|
42
|
+
|
|
43
|
+
## Start, Stop and memory restoration
|
|
44
|
+
|
|
45
|
+
Start activates current same-session authority under awaited exclusion. It rechecks physical identity and initialization permission after waiting, accepts once, then installs policy, memory and checkpoint. Explicit Start does not claim to restore an expired historical boundary. Native tests prove current shared plus local-private memory at the next provider and actual Abort withdrawal for in-run Start with an operation signal.
|
|
46
|
+
|
|
47
|
+
Stop switches local policy and passive context before waiting for persistence. For accepted memory it publishes lifecycle metadata without rewriting semantic/provenance files. Repeated pending Stops share one acceptance. Selection, shutdown and accepted Start cancel obsolete Stop work; rejected Start does not. Genuine persistence failure retains readable memory and native context while fencing writes until accepted Start.
|
|
48
|
+
|
|
49
|
+
Start/Stop choose workflow policy, not whether canonical memory exists. Stop does not cancel retained restoration, auto-start initialization or fork copying: passive policy is applied at that operation's acceptance. Cancelling a Start waiter does not cancel independently owned restoration. Selection changes, shutdown and an available native operation signal can revoke obsolete restoration; post-acceptance ancillary failure cannot undo memory.
|
|
50
|
+
|
|
51
|
+
Native startup and tree handlers await restoration. Tests cover held-store tree/fork selection, exact private state over live shared streams, unchanged parent-private files, cold reopening, failed-Stop recovery and next-provider input without later-branch private values. A public SDK host can observe the child factory result before awaiting extension binding and send Stop or Stop→Start through the child's public `prompt` method while copying waits. This proves that embedding route, not that the installed CLI or Telegram exposes the child before runtime replacement finishes.
|
|
52
|
+
|
|
53
|
+
Read-only recovery validates current private memory without initializing absent storage or granting patch/lifecycle publication authority. Invalid or expired historical evidence never authorizes newer, empty or unrelated private memory as fallback.
|
|
54
|
+
|
|
55
|
+
## Settlement cancellation
|
|
49
56
|
|
|
50
|
-
|
|
57
|
+
On Pi SDK 0.87.0, the agent clears its active run before `agent_before_settle`, so that event has no operation signal. Native `AgentSession.abort()` cannot withdraw an extension's lock wait at this boundary.
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
Optional Git backup remains at `agent_before_settle`. It waits for exclusion only when the host supplies a suitable signal; otherwise contention produces an explicit diagnostic-only deferral to a later eligible turn. Malformed/interrupted ownership remains a failure, not permission to steal a lock. Git commands run outside canonical exclusion. Shutdown drains owned attempts and pending pushes. Backup failure does not roll back memory, suppress an answer or request repair inference.
|
|
60
|
+
|
|
61
|
+
This optional-backup policy does not apply to required semantic publication or restoration. The persistence model is [optimistic canonical storage](filesystem-recovery.md#power-loss-durability), not power-loss-safe acknowledgement or crash-atomic multi-file publication. No journal, replacement Abort handler or background publication worker supplies a stronger guarantee.
|
|
62
|
+
|
|
63
|
+
State Flow-owned compaction requires known sufficient context usage and a proven retained run anchor. It preserves the complete accepted run, skips protected foreign context and never requests retain-none shortening. Native manual/threshold/overflow compaction remains Pi-owned. The settled handler awaits native compaction completion or refusal so deferred companion prompts do not race it. Unknown or insufficient usage skips compaction; a benign refusal permits a later attempt.
|
|
64
|
+
|
|
65
|
+
## Telegram adapter
|
|
66
|
+
|
|
67
|
+
The optional adapter uses the same Start/Stop and inspection owners as native commands. Inspection returns coherent state plus matching revisions without publication. Controls and inspections acknowledge callbacks before waiting, suppress revoked results and escape late failures in the current menu. Legacy synchronous presentation ports remain supported.
|
|
68
|
+
|
|
69
|
+
Adapter tests establish those contracts with isolated transport fixtures. They are not a live Telegram smoke test. Missing or unready transport remains fail-open and cannot change core memory behavior.
|
|
70
|
+
|
|
71
|
+
## State Flow library API compatibility
|
|
72
|
+
|
|
73
|
+
The package root exports `TemporalRuntime`. The Pi registration shim is a separate default-only entrypoint, not the named library API.
|
|
74
|
+
|
|
75
|
+
Use these awaited runtime operations:
|
|
76
|
+
|
|
77
|
+
| Operation | API | Authority boundary |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| Shared inspection | `refreshShared` | Read-only; no initialization or revision advance |
|
|
80
|
+
| Current private recovery | `refreshCurrentMemory` | Read-only; no publication authority |
|
|
81
|
+
| Authored semantic patch | `withPatchTransaction` | Current shared basis and selected private authority; one atomic acceptance |
|
|
82
|
+
| Accepted-runtime lifecycle | `withLifecycleTransaction` | Config/runtime only; cannot initialize or repair semantic storage |
|
|
83
|
+
| Current-head activation | `withStartTransaction` | Origin creation defaults off and requires explicit authorization |
|
|
84
|
+
| Retained restoration | `withRestoreTransaction` | Exact retained private boundary beside current shared streams |
|
|
85
|
+
| Child creation | `withForkTransaction` | Exact parent authority and an unoccupied independent child |
|
|
86
|
+
|
|
87
|
+
Await completion before consuming results. Transaction callbacks stage and publish synchronously, recheck caller selection/policy after waiting and use their publication capability once within its lifetime. Install host state only after acceptance. Keep inference, source acquisition and Git outside canonical exclusion. Raw precomputed replay retains its selected-basis guards.
|
|
88
|
+
|
|
89
|
+
Continuation inspection/candidate building and Git backup also return Promises. Callers must await them rather than treating a Promise as a boolean or accessing a result before completion. Continuation inspection is advisory: it cannot initialize, restore or select a session on the host's behalf.
|
|
90
|
+
|
|
91
|
+
The supported synchronous runtime methods are `loadPassive`, `prepareBoundaryRestore`, `restoreBoundary`, `acceptRestoredOrigin`, `prepareBoundaryFork` and `initialize`. They remain available to library consumers and local tests/benchmarks, but production lifecycle wiring uses the awaited APIs. They are not signature-compatible substitutes and do not acquire the awaited APIs' cancellation behavior. Their presence is not permission to bypass ownership, retained-history or raw-replay checks.
|
|
92
|
+
|
|
93
|
+
## Validation procedure
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
npm run validate
|
|
60
|
-
```
|
|
95
|
+
Validate another SDK line in an isolated copy so the installed extension, sessions and production store remain unchanged:
|
|
61
96
|
|
|
62
|
-
|
|
97
|
+
1. Copy the complete intended source tree, including retained uncommitted changes when applicable.
|
|
98
|
+
2. Install or link matching versions of all four Pi SDK packages and record the resolved dependency graph.
|
|
99
|
+
3. Use isolated agent/session directories, synthetic Git identity and fixture data only.
|
|
100
|
+
4. Run `npm run validate` and record the exact source/toolchain identity with the result.
|
|
101
|
+
5. Inspect the compiled public API through `dist/index.js` and the Pi default registration through `dist/pi-state-flow/index.js`.
|
|
102
|
+
6. Compare generated `dist` and packaged Skills with source, and verify package inventory after final documentation edits.
|
|
63
103
|
|
|
64
|
-
|
|
104
|
+
Focused tests do not replace the full integration suite. Tree-bound evidence can be reused only when its relevant inputs are unchanged. Ref-, environment- and external-publication-sensitive checks require their own verification. A successful tag push is not release completion: verify the owning workflow, published GitHub Release and exact npm package identity.
|
|
@@ -4,7 +4,7 @@ State Flow classifies absence separately from partial or malformed evidence. Rec
|
|
|
4
4
|
|
|
5
5
|
| Resource or cohort | Owner / authority | Total absence | Partial or malformed presence | Allowed repair and writes |
|
|
6
6
|
| --- | --- | --- | --- | --- |
|
|
7
|
-
| Global `checkpoint.json` + `patches.jsonl` | State Flow; authoritative shared semantics |
|
|
7
|
+
| Global `checkpoint.json` + `patches.jsonl` | State Flow; authoritative shared semantics | Authored patches use current empty reality; stale precomputed replay refuses it | Either half missing, malformed replay, or invalid envelope fails closed | Normal CAS publication may materialize the complete empty pair |
|
|
8
8
|
| CWD `checkpoint.json` + `patches.jsonl` | State Flow; authoritative shared semantics with CWD identity | Same as global; selected values are not resurrected | Same as global; owner mismatch also fails closed | Normal CAS publication may materialize the complete empty pair |
|
|
9
9
|
| Session `checkpoint.json` + `patches.jsonl` | State Flow; authoritative private semantics | Fresh lifecycle origin may initialize; an existing selected session requires exact retained authority | Partial or malformed pair fails closed | Fresh initialization or exact retained-boundary recovery only |
|
|
10
10
|
| Global/CWD `meta.json` | State Flow; temporal boundaries, CWD identity, and artifact provenance | Missing metadata removes temporal authority and fails closed; only an omitted `artifacts` leaf degrades provenance to `{}` | Malformed metadata or semantic/boundary mismatch fails closed | Normal CAS publication from a complete proven cohort |
|
|
@@ -19,6 +19,16 @@ State Flow classifies absence separately from partial or malformed evidence. Rec
|
|
|
19
19
|
| Pi State Flow entries | Pi session log / State Flow entry owner | Missing required selected boundary blocks that restore | Malformed or contradictory owner/version/boundary fails the dependent restore | Append through Pi entry APIs only; never replace failed selection with passive state |
|
|
20
20
|
| Optional diagnostic log | State Flow logger; outside the canonical repository | No diagnostic evidence | I/O failure warns once without changing accepted state | Append local JSONL only when opted in; never use it as semantic recovery authority |
|
|
21
21
|
|
|
22
|
+
## Power-loss durability
|
|
23
|
+
|
|
24
|
+
**Current limitation:** `lib/durable.ts` writes same-directory temporary files with `writeFileSync`, then replaces owned paths one at a time with `renameSync`. There is no file/directory `fsync` barrier. A successful call or subsequent readback proves filesystem-visible bytes, not persistence beyond volatile OS/device caches. Guarded rollback handles caught errors while the process is alive; it cannot run after abrupt termination, and several individually atomic replacements are not one crash-atomic cohort. A crash may leave mixed old/new files or unavailable evidence. Existing rollback and cancellation tests do not establish power-loss survival.
|
|
25
|
+
|
|
26
|
+
**Selected contract (operator decision, 2026-09-24):** optimistic ordinary-operation persistence is sufficient for this release. Loss of recent work after abrupt power loss is an accepted risk, not a requirement for a new recovery mechanism. Power-loss-safe acknowledgement is removed from the release gates; do not add a patch journal, temporary recovery store, flush protocol or storage-format redesign for that scenario. Existing same-directory temporary replacement files remain an implementation detail, not a new patch store. No at-most-one-patch loss bound is promised: an interrupted multi-file publication can leave incomplete evidence and require operator recovery.
|
|
27
|
+
|
|
28
|
+
Ordinary concurrent publication still preserves unrelated current Global/CWD fields, orders overlapping writes by acceptance and protects private Session authority. Use one short asynchronously awaited capture/stage/publication exclusion plus CAS; inference, source acquisition and Git stay outside it. Optimism does not authorize replacing a stale whole state, accepting a partial cohort, fabricating empty memory, ignoring a reported write failure or stealing an unavailable lock. Optional Git backup and remote synchronization may defer to a later eligible settled turn; neither every intermediate commit nor immediate remote replication is required.
|
|
29
|
+
|
|
30
|
+
**Native Pi comparison:** inspection of Pi SDK 0.87.0 `dist/core/session-manager.js` shows `_persist()` appending JSONL with `appendFileSync` and initially writing entries with `writeFileSync`; `_rewriteFile()` writes through an opened file descriptor and closes it. These paths specify no `fsync`, `fdatasync` or `flush: true` barrier. Its `flushed` flag tracks whether the initial in-memory entries were written, not stable-media acknowledgement. This is source evidence for that SDK line, not a power-failure experiment or a guarantee about other versions/filesystems. Stronger durability is technically possible with persistence barriers and a coherent recovery protocol, but is deliberately outside this release scope. Process-kill tests alone would not prove volatile-cache survival.
|
|
31
|
+
|
|
22
32
|
## Transaction rule
|
|
23
33
|
|
|
24
34
|
Every semantic repair follows the ordinary transaction path:
|
|
@@ -30,4 +40,4 @@ Every semantic repair follows the ordinary transaction path:
|
|
|
30
40
|
5. Recheck CAS and ownership.
|
|
31
41
|
6. Publish with per-file atomic replacement, conflict-preserving rollback, and then install the accepted runtime state; this is not kernel-atomic multi-file CAS.
|
|
32
42
|
|
|
33
|
-
A
|
|
43
|
+
A wholly absent shared scope is current empty reality, not permission to restore cached cold values or leftover compilation evidence. Authored `patch_state` operations select this basis under the awaited store lock and publish only after complete validation; a rejected first patch never leaves separately published empty initialization. Raw precomputed replay targeting a disappeared selected basis still fails closed. Discarded history is unavailable and is never reconstructed or promoted back into current shared memory.
|
|
@@ -27,11 +27,13 @@ Artifact provenance is current-only, not a historical registry. Any retained par
|
|
|
27
27
|
|
|
28
28
|
## Lifecycle and failure
|
|
29
29
|
|
|
30
|
-
`TemporalRuntime.
|
|
30
|
+
`TemporalRuntime.withForkTransaction(source, checkpoint, action, signal?)` pins source identity/boundary before waiting and selects exact parent authority plus an unoccupied child under one awaited exclusion. The caller rechecks native selection/policy and publishes its child lifecycle synchronously once. Parent evidence is revalidated before publication, the child cohort is CAS-protected, and only accepted memory installs. Cancellation or rejection cannot initialize an empty child; post-acceptance failure cannot roll it back or authorize another parent copy. Existing child storage, identity mismatch, missing parent files, malformed storage, concurrency conflict, or an expired boundary fails closed.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Native fork adoption and Start's exact-source retry use this transaction inside the extension's owned restoration lifetime; the synchronous `prepareBoundaryFork()` adapter remains public only until consumer cleanup. Both paths publish the fresh child origin before any runtime-only lifecycle write. Native evidence holds a publisher across fork adoption; it does not certify idle native Abort.
|
|
33
33
|
|
|
34
|
-
A
|
|
34
|
+
A failed or expired selection never substitutes the parent's current/newer private state and never falls through to an older disabled marker. In the same live extension instance, explicit Start may retry the unaccepted fork after missing identity or storage evidence is corrected. Stop does not cancel an in-flight fork or its Start-owned retry: it selects passive child policy, which is applied inside the existing fork acceptance. Cancelling the Start waiter does not cancel that independently owned copy. After acceptance, configured passive tools can patch child memory without enabling active behavior; ordinary cold reopening loads that child-owned state. Selection, shutdown, native Abort, invalid source evidence and expired history still can prevent acceptance. Recovery of forks abandoned before this correction is not certified; missing child files never authorize a parent recopy. Once child storage has been accepted, explicit Start can activate its validated current child-owned memory even after selecting an inherited parent checkpoint; this neither restores parent history nor copies newer parent data. Child-owned checkpoints subsequently use ordinary retained-boundary reload/resume without rereading the parent header.
|
|
35
|
+
|
|
36
|
+
A child-owned passive-projection reset prevents copied parent Stop markers from resurfacing after child reload. Disabled sources remain disabled, including a same-owner native failed-Stop policy that could not reach canonical config. A child inherits neither that parent's write fence nor its passive projection; source history must still be provable and copying must pass CAS. Ordinary activation policy is not overridden. Nested forks require each direct parent boundary to remain retained; ancestry is not recursively reconstructed.
|
|
35
37
|
|
|
36
38
|
## Support boundary
|
|
37
39
|
|
|
@@ -39,4 +41,4 @@ Supported copying requires a persisted regular parent session file, matching hea
|
|
|
39
41
|
|
|
40
42
|
## Evidence
|
|
41
43
|
|
|
42
|
-
Native integration tests cover retained private selection versus newer parent/shared state, fresh child origin, independent child mutation, child reload/resume, disabled sources, Stop projection fencing, malformed parent identity/CWD, retry, and expired-boundary refusal. Runtime tests cover single-use preparation, canonical child publication, live shared ownership, artifact provenance, occupied child storage, and retention reduction/increase without parent-private mutation or reconstructed history. Continuation tests cover header-only reading and refusal of non-regular or symlinked locators.
|
|
44
|
+
Native integration tests cover retained private selection versus newer parent/shared state, fresh child origin, independent child mutation, child reload/resume, disabled sources, Stop projection fencing, malformed parent identity/CWD, retry, and expired-boundary refusal. Runtime tests cover single-use preparation, canonical child publication, live shared ownership, artifact provenance, occupied child storage, and retention reduction/increase without parent-private mutation or reconstructed history. Awaited runtime witnesses additionally hold an independent partial writer for over two seconds, cancel waiting copies, mutate admitted locators, expire source history during waiting, race parent/child bytes, serialize competing child acceptances, reject every occupied child file, roll back injected publication failure and retain accepted memory after checkpoint failure. Shared unknown metadata and unrelated provenance remain intact. Continuation tests cover header-only reading and refusal of non-regular or symlinked locators. The extension mode matrix holds storage across native fork selection or Start-owned fork retry. Stop returns with passive policy while the copy remains pending; release permits selected memory to be accepted with disabled policy. Passive patching and subsequent cold header/trace reopening through `SessionManager.open` retain independent child memory. Expired parent history still refuses without canonical writes or replacement checkpoints. These are isolated extension fixtures. A separate native SDK fixture observes the child through the public session factory before awaiting extension binding, sends Stop and optionally Start through the child's public `prompt` method while fork copying waits, and checks the requested mode, independent private state and next-provider patch after release. No private SDK hook or direct State Flow handler invocation is used. This proves a supported embedding route, not installed Telegram/TUI reachability before the child replaces the current runtime session.
|
|
@@ -35,8 +35,8 @@ A later 0.19 decision about freezing the projected head must compare compatible
|
|
|
35
35
|
- Current semantic projection is proportional to projected state size.
|
|
36
36
|
- Retained temporal reads are bounded by configured `historyLimit` (`0..100`, default `7`).
|
|
37
37
|
- Canonical publication writes the affected scope/runtime cohort under file CAS and cooperating-writer exclusion; it executes no Git command.
|
|
38
|
-
- Registered-artifact maintenance is proportional to already-registered paths and uses metadata-only `size + mtimeNs` inspection. It performs no directory discovery or generic body hashing.
|
|
39
|
-
- Optional Git backup runs only after accepted work reaches `agent_before_settle`. Its canonical-lock capture costs are proportional to owned file count and bytes; all Git commands and filters run after that lock is released.
|
|
38
|
+
- Run preparation awaits one current-head transaction at the first active `context`; completed preparation is reused on later requests in the same run. Registered-artifact maintenance is proportional to already-registered paths and uses metadata-only `size + mtimeNs` inspection inside that acceptance. No-change preparation on a complete cohort writes only runtime metadata, without folding wider scope tails. It performs no directory discovery or generic body hashing.
|
|
39
|
+
- Optional Git backup runs only after accepted work reaches `agent_before_settle`. Its canonical-lock capture costs are proportional to owned file count and bytes; all Git commands and filters run after that lock is released. Lock waiting is asynchronous/cancelable when a host operation signal exists; otherwise optional backup defers on contention because [Pi 0.87 cannot cancel settlement waits](compatibility.md#settlement-cancellation). Git subprocesses remain synchronous after capture: independent canonical processes can publish during slow Git, but this is not a host-event-loop latency bound. Remote push runs asynchronously, skips overlapping attempts per repository within one Pi process, and is awaited at session shutdown within its existing timeout and process-group termination behavior. Backup is not an acceptance or recovery authority.
|
|
40
40
|
- Native transcript opening, Pi context construction, and foreign custom-context preservation remain Pi/history costs rather than canonical-state storage costs.
|
|
41
41
|
|
|
42
42
|
Discarded semantic history is unavailable. Git cold reads, revision restoration, queue workers, migration, terminal repair and fallback inference are absent from the current architecture. Remote pushes do exist but are asynchronous and outside these local benchmark workloads; do not count them as measured costs.
|