@llblab/pi-kit 0.26.0 → 0.27.1
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/BACKLOG.md +4 -2
- package/CHANGELOG.md +9 -0
- package/README.md +6 -6
- package/node_modules/@llblab/pi-claude-usage/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-claude-usage/README.md +3 -1
- package/node_modules/@llblab/pi-claude-usage/lib/status.ts +3 -8
- package/node_modules/@llblab/pi-claude-usage/lib/telegram.ts +15 -1
- package/node_modules/@llblab/pi-claude-usage/package.json +1 -1
- package/node_modules/@llblab/pi-codex-usage/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +2 -2
- package/node_modules/@llblab/pi-codex-usage/lib/status.ts +3 -11
- package/node_modules/@llblab/pi-codex-usage/lib/telegram.ts +15 -0
- package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +12 -5
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +9 -0
- package/node_modules/@llblab/pi-state-flow/README.md +116 -34
- package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.d.ts +24 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.js +80 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.d.ts +17 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +40 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +149 -298
- package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +29 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +58 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/operation.d.ts +37 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/operation.js +59 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.d.ts +31 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.js +117 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +7 -7
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +28 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +6 -1
- 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 +14 -6
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +2 -2
- package/node_modules/@llblab/pi-state-flow/docs/README.md +19 -9
- package/node_modules/@llblab/pi-state-flow/docs/agent-contract-relocation.md +4 -4
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +644 -91
- package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +116 -37
- package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +118 -21
- package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +68 -8
- package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +88 -14
- package/node_modules/@llblab/pi-state-flow/docs/performance.md +83 -66
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +391 -62
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +317 -62
- package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +85 -1
- package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +47 -0
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +161 -295
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +63 -0
- package/node_modules/@llblab/pi-state-flow/lib/operation.ts +75 -0
- package/node_modules/@llblab/pi-state-flow/lib/ownership.ts +120 -0
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +7 -8
- package/node_modules/@llblab/pi-state-flow/lib/query.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +1 -2
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +29 -0
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +5 -1
- package/node_modules/@llblab/pi-state-flow/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +14 -6
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +2 -2
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +10 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +4 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +16 -12
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +7 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +12 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +137 -83
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +26 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +57 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +109 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +3 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/status.js +31 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +4 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +17 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +48 -12
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +6 -5
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +2 -0
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +4 -0
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +17 -10
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +8 -2
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +135 -97
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +25 -0
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +140 -4
- package/node_modules/@llblab/pi-telegram/lib/model.ts +2 -4
- package/node_modules/@llblab/pi-telegram/lib/status.ts +30 -1
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +4 -4
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +21 -3
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +46 -13
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +5 -5
|
@@ -4,7 +4,10 @@ This document describes the implemented lazy-state contract. [BACKLOG.md](../BAC
|
|
|
4
4
|
|
|
5
5
|
## Thesis
|
|
6
6
|
|
|
7
|
-
State Flow provides `lazy` as an object-root semantic plane in every scope's runtime view.
|
|
7
|
+
State Flow provides `lazy` as an object-root semantic plane in every scope's runtime view.
|
|
8
|
+
|
|
9
|
+
- It may be absent from stored state. Reads then use `{}` or values inherited through the effective overlay, without rewriting storage.
|
|
10
|
+
- Nested lazy values are ordinary JSON. They are durable and versioned with the same causal lineage as hot state, but excluded from ordinary baseline hydration.
|
|
8
11
|
|
|
9
12
|
The model-facing surface remains small:
|
|
10
13
|
|
|
@@ -46,7 +49,13 @@ global | CWD | session
|
|
|
46
49
|
└── lazy
|
|
47
50
|
```
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
Hot planes:
|
|
53
|
+
|
|
54
|
+
- `intents`, `contract`, `working` and `artifacts` stay hot in every scope.
|
|
55
|
+
- Session-owned `response` is also hot. New Global and CWD states use an empty structural slot, and stored scopes may omit it. Effective uses the highest-priority present response, and each newly accepted answer is written only in Session.
|
|
56
|
+
- `intents` may keep compact active direction while referring to large supporting detail in `lazy`.
|
|
57
|
+
|
|
58
|
+
`lazy` differs only in projection policy:
|
|
50
59
|
|
|
51
60
|
- It is canonical semantic JSON, validated and versioned with its owning scope.
|
|
52
61
|
- Its bodies are excluded from automatic state and recent-transition projections, including lazy writes, replacements and deletions. Empty visible patches/transitions disappear without renumbering history; hot changes remain visible.
|
|
@@ -55,13 +64,34 @@ global | CWD | session
|
|
|
55
64
|
|
|
56
65
|
### Semantic references
|
|
57
66
|
|
|
58
|
-
A reference is semantic content, not a runtime type.
|
|
67
|
+
A reference is semantic content, not a runtime type. There are two forms:
|
|
68
|
+
|
|
69
|
+
- **Structured:** the optional `{"$ref":"cwd.lazy.plan"}` object.
|
|
70
|
+
- **Textual:** inside any ordinary string or paragraph, `$` immediately followed by one valid `read_state` path, for example `$effective.lazy.memory[7]`. The prefix separates a deliberate reference from incidental path-like text, and leaves a deterministic seam if code-based parsing is ever justified.
|
|
71
|
+
|
|
72
|
+
File paths, document sections, URIs, artifact locators, Skill identities and agent identities keep their native syntax.
|
|
73
|
+
|
|
74
|
+
**What State Flow does with references.** It preserves all forms exactly as ordinary JSON. It does not scan prose, index targets, validate existence, rewrite relative locators, or infer authority, dependency, hydration, execution or completion. The single exception is [intent ownership](#intent-ownership).
|
|
75
|
+
|
|
76
|
+
When a reference matters, the agent resolves it explicitly: with `read_state` for semantic paths, or with the appropriate external read/tool for other resources. A locator helps retrieval but does not replace content required for the current decision.
|
|
59
77
|
|
|
60
|
-
|
|
78
|
+
**Reference repair is reactive, not a maintenance scan.** The agent does not enumerate, audit or resolve references merely to test them. Only after one requested `read_state` value path is missing does State Flow perform one bounded reverse lookup over current model-patchable semantic planes for exact structured `$ref` and `$path` matches. The reverse lookup searches current reference owners only, never history. If it finds matches, the tool returns `{value:null, hint:[{type:"dangling-reference", message, paths}]}`:
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
- `hint` is explicit top-level metadata, not state data. Its conditional message describes unavailability.
|
|
81
|
+
- Its path array contains at most three runtime-verified current reference owners, not verified new locations of the target.
|
|
82
|
+
- The hint contains no lazy bodies and proves neither prior existence, retention nor relocation.
|
|
83
|
+
- The null sentinel is never returned alone for this case.
|
|
63
84
|
|
|
64
|
-
|
|
85
|
+
Without a durable match, the ordinary missing-path error remains, and it does not prove the agent invented the path. Keys, patch and multi-path reads keep ordinary all-or-error semantics.
|
|
86
|
+
|
|
87
|
+
After a hint, the agent may reconcile a proven stale owning value while preserving its surrounding meaning; this applies equally to `$ref` objects and contextual references in prose. None of these prove a durable reference is broken:
|
|
88
|
+
|
|
89
|
+
- effective-state absence alone (it does not identify the owner);
|
|
90
|
+
- unavailable history;
|
|
91
|
+
- inaccessible external resources;
|
|
92
|
+
- a transient read failure.
|
|
93
|
+
|
|
94
|
+
**Historical search is task-driven.** Missing paths or runtime hints alone do not require historical search. The agent may choose a targeted historical read when a previous value is useful to the current task, without separate user permission; otherwise it continues without searching. Found values are historical evidence, not automatically current memory. Never automatically restore deleted data, scan all offsets, hydrate bodies or trigger repair inference. A proven stale reference can be repaired within touched work without resurrecting its target.
|
|
65
95
|
|
|
66
96
|
When present, the `lazy` root must be an object. Its nested values may include arrays, objects, and scalars, for example:
|
|
67
97
|
|
|
@@ -82,6 +112,35 @@ When present, the `lazy` root must be an object. Its nested values may include a
|
|
|
82
112
|
|
|
83
113
|
State Flow does not inject IDs, provenance, revisions, range descriptors, or truncation fields into those values.
|
|
84
114
|
|
|
115
|
+
### Intent ownership
|
|
116
|
+
|
|
117
|
+
Intents can own the memory they create:
|
|
118
|
+
|
|
119
|
+
- A structured `{"$ref"}` anywhere inside an `intents` entry means "delete with me" for an existing object key under `working` or `lazy` of the same scope, such as `{"$ref":"cwd.lazy.plan"}` inside `cwd.intents.release`.
|
|
120
|
+
- A textual `$cwd.lazy.plan` mention means "I use this" and never owns.
|
|
121
|
+
|
|
122
|
+
**What happens when a patch deletes an intent key.** State Flow first applies the authored operations, then deletes each owned target that no remaining intent of that scope references, directly, through an ancestor or through a descendant. Everything happens in one atomic cohort, with one revision per changed scope.
|
|
123
|
+
|
|
124
|
+
- **Supersession works in one patch:** delete the old intent and reference the same targets from its replacement.
|
|
125
|
+
- **Writes in the deleting patch do not save a target.** Updates, nested additions and keys created by that same patch are deleted silently along with it, and the accepted record stores only the net deletion. Save survivors to an unowned path instead.
|
|
126
|
+
- **Editing is not deleting.** Editing an intent to drop a reference leaves the target as ordinary unowned state. Unowned entries remain legal.
|
|
127
|
+
|
|
128
|
+
**What is never deleted.** The cascade reads only the `intents` plane of the intent's own scope. These targets are skipped silently, and no patch is rejected, warned about or delayed:
|
|
129
|
+
|
|
130
|
+
- other scopes;
|
|
131
|
+
- plane roots and array elements;
|
|
132
|
+
- `contract`/`artifacts`/`response`/`intents` targets;
|
|
133
|
+
- unscoped or `effective` paths;
|
|
134
|
+
- missing targets;
|
|
135
|
+
- keys outside the `read_state` key grammar `[A-Za-z_$][A-Za-z0-9_$-]*`, for example keys with spaces, dots or non-Latin letters.
|
|
136
|
+
|
|
137
|
+
**Edge cases:**
|
|
138
|
+
|
|
139
|
+
- Deletion is scope-local, so an effective read may afterwards show a same-path value inherited from a broader scope. The receipt then reports that value rather than `deleted: true`.
|
|
140
|
+
- Concurrent shared writers keep last-accepted-wins behaviour: a later write into an intent another session already deleted simply recreates a partial intent.
|
|
141
|
+
|
|
142
|
+
**History and limits.** The accepted patch record stores cascaded keys as explicit deletions, so replay never re-derives them, and nothing is archived beyond ordinary retained history. Ownership adds no validation, unresolved-reference warning, cross-scope cascade, age-based cleanup, size budget, growth notice, archive of deleted entries or automatic hydration.
|
|
143
|
+
|
|
85
144
|
### Effective lazy overlay
|
|
86
145
|
|
|
87
146
|
The explicit `effective.lazy` path recursively overlays `global.lazy → cwd.lazy → session.lazy` using the existing scope precedence and conflict semantics. It is read-only as an effective view and is not inserted into ordinary hot baseline state.
|
|
@@ -114,9 +173,14 @@ Active obligations, current constraints, unresolved next actions, and facts requ
|
|
|
114
173
|
}
|
|
115
174
|
```
|
|
116
175
|
|
|
117
|
-
|
|
176
|
+
Rules:
|
|
118
177
|
|
|
119
|
-
|
|
178
|
+
- `projection` defaults to `value`.
|
|
179
|
+
- A batch uses one projection for every path, evaluates every path against one captured state view, and returns results in request order. Duplicate paths stay duplicate results.
|
|
180
|
+
- An absent documented top-level field has value `null`, including an empty or absent `response`; the root view simply omits it.
|
|
181
|
+
- If any other path is invalid, the whole read fails; there is no mixed partial result.
|
|
182
|
+
|
|
183
|
+
The single `path` form is first-class. Top-level `offset` and `scope` inputs are rejected; history and ownership belong in the semantic path itself, such as `cwd[1].lazy.memory`.
|
|
120
184
|
|
|
121
185
|
### Response shape
|
|
122
186
|
|
|
@@ -128,13 +192,23 @@ There are three projections:
|
|
|
128
192
|
| `keys` | `{ "meta": ..., "keys": ... }` | Minimal structural facts followed by immediate keys |
|
|
129
193
|
| `patch` | `{ "patch": ... }` | Historical semantic patch at the selected boundary |
|
|
130
194
|
|
|
131
|
-
A single-path request returns one payload. A multi-path request returns positionally aligned arrays under the same projection fields.
|
|
195
|
+
A single-path request returns one payload. A multi-path request returns positionally aligned arrays under the same projection fields.
|
|
196
|
+
|
|
197
|
+
One missing value path with exact current durable references returns this sentinel instead; it is diagnostic metadata, not semantic state:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{ "value": null, "hint": [{ "type": "dangling-reference", "message": "The requested value is unavailable in the selected state. These current values reference that path, not a verified new location. Use this evidence if relevant to the task.", "paths": ["cwd.working.note"] }] }
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
What each projection contains:
|
|
132
204
|
|
|
133
|
-
`value`
|
|
205
|
+
- `value` deliberately mirrors the effective-state snapshot injected at iteration start: semantic state without revision, provenance, range, transport or storage fields.
|
|
206
|
+
- `patch` likewise contains only the selected semantic patch.
|
|
207
|
+
- Only structural discovery earns `meta`, and `keys` stays the final and most valuable field in that response.
|
|
134
208
|
|
|
135
|
-
The response
|
|
209
|
+
The response repeats neither the requested path nor the projection, and returns no internal revision. Runtime owns revision selection, locking, CAS and publication; echoing that machinery would not help the model be correct.
|
|
136
210
|
|
|
137
|
-
Errors use the normal tool-error channel
|
|
211
|
+
Errors use the normal tool-error channel, never successful JSON with an `error` field. The dangling-reference sentinel above is the only missing-path exception; keys, patch, multi-path and unmatched value reads still fail.
|
|
138
212
|
|
|
139
213
|
### Path and range model
|
|
140
214
|
|
|
@@ -443,7 +517,7 @@ Lazy mutations inherit existing guarantees:
|
|
|
443
517
|
- Exact retained-boundary selection on restore and branch navigation.
|
|
444
518
|
- Read-only discovery with no commit, timestamp update, or transition.
|
|
445
519
|
|
|
446
|
-
Lazy trees are co-located in canonical scope checkpoints/tails and use the same bounded lineage as hot state.
|
|
520
|
+
Lazy trees are co-located in canonical scope checkpoints/tails and use the same bounded lineage as hot state. The [performance guide](performance.md) owns current synthetic workloads and measurement limits. No separate lazy index or sharded authority exists; any future layout change requires measured need and must preserve canonical semantics, ownership, and one causal lineage.
|
|
447
521
|
|
|
448
522
|
## Failure semantics
|
|
449
523
|
|
|
@@ -488,7 +562,7 @@ Before release, implementation evidence must prove:
|
|
|
488
562
|
- Whole-array replacement and indexed scalar, array, object, nested, multi-index, and stale-basis patches remain atomic.
|
|
489
563
|
- Restore and fork select lazy state from the same retained canonical boundary as the rest of the owning session scope.
|
|
490
564
|
- Malformed canonical lazy data fails closed without rewriting the store; rejected queries and patches preserve accepted hot state.
|
|
491
|
-
- Unsupported
|
|
565
|
+
- Unsupported store formats and `read_state` inputs fail actionably without rewriting retained bytes.
|
|
492
566
|
|
|
493
567
|
## Limits and change authority
|
|
494
568
|
|
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Scope
|
|
4
4
|
|
|
5
|
-
State Flow must complement Pi's session rather than create a competing transcript or lifecycle. Measure
|
|
5
|
+
State Flow must complement Pi's session rather than create a competing transcript or lifecycle. Measure these costs separately:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- native transcript opening and context construction;
|
|
8
|
+
- canonical semantic-state size and retained-tail depth;
|
|
9
|
+
- exact registered-artifact count;
|
|
10
|
+
- optional settled-turn backup.
|
|
11
|
+
|
|
12
|
+
Correctness is not a performance trade-off. Current canonical state, bounded retained history, causal-basis checks, the complete Pi trace and direct completion must all remain correct.
|
|
13
|
+
|
|
14
|
+
Benchmark inputs are synthetic temporary fixtures using the installed Pi SDK, deterministic faux providers and isolated credentials. They make no external model or network calls and must never use a live state store.
|
|
15
|
+
|
|
16
|
+
This guide describes the current workloads and how to interpret them. It does not claim timings for the current source tree: obtain those by running the benchmark and recording its source and dependency identities.
|
|
8
17
|
|
|
9
18
|
## Running the workload
|
|
10
19
|
|
|
@@ -12,7 +21,7 @@ All benchmark inputs are synthetic temporary fixtures using the installed Pi SDK
|
|
|
12
21
|
npm run benchmark
|
|
13
22
|
```
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
Executables live in `benchmarks/`; contract tests live in `tests/benchmark.test.ts` and `tests/benchmark-session.test.ts`. See the [benchmark guide](../benchmarks/README.md) for environment variables and report paths.
|
|
16
25
|
|
|
17
26
|
A fast correctness smoke is:
|
|
18
27
|
|
|
@@ -20,111 +29,119 @@ A fast correctness smoke is:
|
|
|
20
29
|
BENCH_PATCHES=2 BENCH_SAMPLES=1 BENCH_ROUNDS=2 BENCH_STATE_BYTES=1024 npm run benchmark
|
|
21
30
|
```
|
|
22
31
|
|
|
23
|
-
Treat timings as observations from the named host and source identity, not universal thresholds. Compare runs only when workload fingerprints, dependencies, payloads
|
|
32
|
+
Treat timings as observations from the named host and source identity, not universal thresholds. Compare runs only when workload fingerprints, dependencies, payloads and validation outcomes match. A failed correctness probe invalidates its timing sample.
|
|
33
|
+
|
|
34
|
+
To include an isolated post-resume probe:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
BENCH_PATCHES=2 BENCH_SAMPLES=1 BENCH_ROUNDS=2 BENCH_STATE_BYTES=1024 BENCH_POST_RESUME=1 npm run benchmark
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Within-run prompt-prefix probe
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
The report records `promptPrefixRuns` for each State Flow and native Pi user run, without duplicating runs across lifecycle checkpoints. Isolated post-resume probes expose the same per-run metrics.
|
|
26
43
|
|
|
27
|
-
|
|
44
|
+
**Per inference:**
|
|
28
45
|
|
|
29
|
-
|
|
46
|
+
- `contextBytes`: UTF-8 byte length of `JSON.stringify(context.messages)` as seen by the installed faux provider.
|
|
47
|
+
- `sharedPrefixBytes`: longest common byte prefix of that serialization and the previous inference **in the same run**; `null` on the first inference.
|
|
30
48
|
|
|
31
|
-
|
|
49
|
+
**Per run:**
|
|
32
50
|
|
|
33
|
-
|
|
51
|
+
- `patchStateBarriers`: successful tool completions.
|
|
52
|
+
- `nativeUserBytes` / `specificationBytes`: JSON-serialized string values, excluding their containing message/field frames. `specificationBytes` is `null` for native Pi.
|
|
34
53
|
|
|
35
|
-
|
|
54
|
+
Byte-prefix measurements omit provider framing, tool schemas, tokenization, cache policies and quality. Serialized synthetic-message timestamps can shorten this proxy prefix without proving provider-visible cache churn. Validate fresh state visibility after barriers independently of prefix preservation.
|
|
36
55
|
|
|
37
|
-
|
|
56
|
+
### Trajectory workload
|
|
38
57
|
|
|
39
|
-
|
|
58
|
+
The opt-in `BENCH_PREFIX=1` probe in the [benchmark guide](../benchmarks/README.md) exercises active memory, ordinary passive memory and Stop handoff separately.
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
| ---: | ---: | ---: | ---: |
|
|
43
|
-
| 1 | — / 9860 | — / 7197 | — / 6019 |
|
|
44
|
-
| 2 | 9732 / 31025 | 5801 / 28360 | 6018 / 27183 |
|
|
45
|
-
| 3 | 9731 / 52193 | 5801 / 49528 | 27182 / 48353 |
|
|
46
|
-
| 4 | 9732 / 73359 | 5801 / 70696 | 48352 / 69519 |
|
|
47
|
-
| 5 | 9732 / 94528 | 5801 / 91865 | 69518 / 90688 |
|
|
48
|
-
| 6 | 9733 / 115695 | 5802 / 113034 | 90687 / 111857 |
|
|
49
|
-
| 7 | 9732 / 136864 | 5801 / 134201 | 111856 / 133026 |
|
|
50
|
-
| 8 | 9212 / 137813 | 5666 / 134999 | 133025 / 133800 |
|
|
51
|
-
| 9 | 9907 / 158983 | 5825 / 156169 | 133799 / 154965 |
|
|
52
|
-
| 10 | 9907 / 180150 | 5825 / 177338 | 154964 / 176134 |
|
|
53
|
-
| 11 | 9235 / 181075 | 5689 / 178112 | 176133 / 176908 |
|
|
60
|
+
Each measured run issues six 20,497-byte native reads, a patch, two more reads and a second patch. Exact read content must stay visible through all eleven inferences. Both patches and terminal completion are checked outside the provider. The report's `trajectory[].promptPrefixRuns` entries retain every inference, not just aggregate ratios.
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
A warm prefix alone does not prove updated memory reaches the model; freshness has separate native-SDK regressions.
|
|
56
63
|
|
|
57
64
|
### Frozen-head measurement
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
Projection freezes whole heads, including timestamps, and delivers accepted values and changing notices at stable tail positions.
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
- Active completion/new runs, native compaction/selection and mode changes are cache boundaries.
|
|
69
|
+
- Passive user turns and patches are not cache boundaries.
|
|
70
|
+
- Volatile projection IDs distinguish current updates from retained results after a rebase.
|
|
62
71
|
|
|
63
|
-
|
|
64
|
-
| ---: | ---: | ---: | ---: |
|
|
65
|
-
| 1 | — / 10461 | — / 7985 | — / 6620 |
|
|
66
|
-
| 2 | 10460 / 31625 | 7984 / 29148 | 6619 / 27784 |
|
|
67
|
-
| 3 | 31624 / 52792 | 29147 / 50316 | 27783 / 48952 |
|
|
68
|
-
| 4 | 52791 / 73959 | 50315 / 71484 | 48951 / 70120 |
|
|
69
|
-
| 5 | 73958 / 95127 | 71483 / 92653 | 70119 / 91287 |
|
|
70
|
-
| 6 | 95126 / 116295 | 92652 / 113822 | 91286 / 112456 |
|
|
71
|
-
| 7 | 116294 / 137463 | 113821 / 134989 | 112455 / 133625 |
|
|
72
|
-
| 8 | 137462 / 138416 | 134988 / 135941 | 133624 / 134579 |
|
|
73
|
-
| 9 | 138415 / 159580 | 135940 / 157106 | 134578 / 155742 |
|
|
74
|
-
| 10 | 159579 / 180746 | 157105 / 178275 | 155741 / 176911 |
|
|
75
|
-
| 11 | 180745 / 181697 | 178274 / 179229 | 176910 / 177863 |
|
|
72
|
+
See [projection semantics](architecture.md#pi-lifecycle) for ownership and limits.
|
|
76
73
|
|
|
77
|
-
|
|
74
|
+
Regression tests assert prefix equality independently of exact host timestamps and IDs. Separate native tests prove accepted-state freshness, repeated barriers, passive cross-turn stability and bootstrap rebasing. Measure prefix retention with the trajectory workload; it is not provider cache accounting, a latency estimate, a token-cost estimate or a quality guarantee.
|
|
78
75
|
|
|
79
76
|
## Current cost model
|
|
80
77
|
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
- Canonical publication writes the affected scope/runtime cohort under file CAS and cooperating-writer exclusion;
|
|
84
|
-
- Run preparation awaits one current-head transaction at the first active `context
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
78
|
+
- **Semantic projection:** proportional to projected state size.
|
|
79
|
+
- **Temporal reads:** bounded by configured `historyLimit` (`0..100`, default `7`).
|
|
80
|
+
- **Canonical publication:** writes the affected scope/runtime cohort under file CAS and cooperating-writer exclusion; executes no Git command.
|
|
81
|
+
- **Run preparation:** awaits one current-head transaction at the first active `context`. Later requests in the same run reuse completed preparation.
|
|
82
|
+
- Registered-artifact maintenance is proportional to already-registered paths and uses metadata-only `size + mtimeNs` inspection inside that acceptance.
|
|
83
|
+
- No-change preparation on a complete cohort writes only runtime metadata, without folding wider scope tails.
|
|
84
|
+
- No directory discovery or generic body hashing occurs.
|
|
85
|
+
- **Optional Git backup:** runs only after accepted work reaches `agent_before_settle`.
|
|
86
|
+
- Canonical-lock capture costs are proportional to owned file count and bytes. All Git commands and filters run after that lock is released.
|
|
87
|
+
- Lock waiting is asynchronous/cancelable when a host operation signal exists. Otherwise optional backup defers on contention; see [settlement cancellation](compatibility.md#settlement-cancellation).
|
|
88
|
+
- Git subprocesses remain synchronous after capture. Independent canonical processes can publish during slow Git, but this is not a host-event-loop latency bound.
|
|
89
|
+
- Remote push runs asynchronously, skips overlapping attempts per repository within one Pi process, and is awaited at session shutdown within its timeout and process-group termination behavior.
|
|
90
|
+
- Backup is neither acceptance nor recovery authority.
|
|
91
|
+
- **Native transcript and context:** opening, Pi context construction and foreign custom-context preservation remain Pi/history costs, not canonical-state storage costs.
|
|
92
|
+
|
|
93
|
+
Discarded semantic history is unavailable. Git cold reads, revision restoration, queue workers, in-place format conversion, terminal repair and fallback inference are absent. Remote pushes exist but are asynchronous and outside these local benchmark workloads; do not count them as measured costs.
|
|
89
94
|
|
|
90
95
|
## Tool-preflight parent traversal
|
|
91
96
|
|
|
92
|
-
Tool preflight follows Pi's public parent links from the selected leaf to find the assistant response owning the current tool call.
|
|
97
|
+
Tool preflight follows Pi's public parent links from the selected leaf to find the assistant response owning the current tool call.
|
|
93
98
|
|
|
94
|
-
|
|
99
|
+
- It does not construct the whole branch.
|
|
100
|
+
- Traversal remains proportional to the selected ancestry when no nearby match exists.
|
|
101
|
+
- `tests/extension.test.ts` covers zero and two hundred prior request/answer pairs, foreign custom entries, duplicate call IDs, sibling tools and unmatched calls, while preserving exact selected-branch behavior.
|
|
102
|
+
|
|
103
|
+
This limits allocation; it is not an unconditional constant-time claim.
|
|
95
104
|
|
|
96
105
|
## Context projection and trajectory selection
|
|
97
106
|
|
|
98
|
-
The context domain projects the cached semantic overlay once per context emission to compare current state with its last communicated view.
|
|
107
|
+
The context domain projects the cached semantic overlay once per context emission to compare current state with its last communicated view.
|
|
108
|
+
|
|
109
|
+
- It serializes the complete head only at a projection boundary. Later synthetic notices retain their original native-message positions.
|
|
110
|
+
- Projection caching targets request-prefix stability, not constant-time state processing. View copies/diffs remain state-dependent, and notices accumulate until a natural reset, without a size threshold.
|
|
111
|
+
- `currentRunTrajectory` allocates one retained-message array, not arrays for discarded ordinary prefixes.
|
|
112
|
+
- Foreign custom context may require scanning earlier entries, and Pi may clone native messages before the extension runs.
|
|
99
113
|
|
|
100
|
-
`tests/context.test.ts` exercises small and large semantic payloads, zero and two hundred prior request/answer pairs, repeated requests, stale/missing anchors, foreign custom messages
|
|
114
|
+
`tests/context.test.ts` exercises small and large semantic payloads, zero and two hundred prior request/answer pairs, repeated requests, stale/missing anchors, foreign custom messages and post-barrier context emission. These tests assert projection counts and retained identities; they impose no wall-time threshold.
|
|
101
115
|
|
|
102
116
|
## Memory-only owned-draft COW
|
|
103
117
|
|
|
104
|
-
|
|
118
|
+
Private copy-on-write limits repeated deep-copy work without changing public detachment or persistence guarantees.
|
|
119
|
+
|
|
120
|
+
**Public boundaries:**
|
|
105
121
|
|
|
106
|
-
- `applyPatch`
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
- `applyPatch` retains one detached entry basis, then private helpers copy object/array paths only when they change and clone incoming replacements. Mutable caller-owned/accepted scopes are never shared with returned drafts. Inherited objects are detached before their existing merge behavior is applied, preventing prototype borrowing while preserving prototype-named deletion and signed-zero behavior. Public/staged isolation, late response reconciliation, atomic rejection and CAS remain intact; no public freeze/proxy layer is introduced.
|
|
110
|
-
- Temporal replay/public readers, provenance, serialization, hashing, storage layout and Git remain outside the first optimization. Revisit only if fresh measurement and safe ownership evidence earn a further change.
|
|
122
|
+
- Exported `applyPatch` returns a mutable, fully detached result, including untouched branches and incoming patch values. `overlayStates` and temporal reads rely on detached outputs. Never share caller-owned mutable objects across that boundary.
|
|
123
|
+
- Staged responses are intentionally mutable before commit (`tests/transition.test.ts`). Artifact/Skill compilation replaces entries in the staged artifact registry.
|
|
124
|
+
- Failed publication must leave accepted scopes untouched. Commit detaches the accepted result again; the adapter then installs detached runtime reads.
|
|
111
125
|
|
|
112
|
-
|
|
126
|
+
**Private draft:**
|
|
113
127
|
|
|
114
|
-
|
|
128
|
+
- `applyPatch` retains one detached entry basis. Private helpers copy object/array paths only when they change and clone incoming replacements.
|
|
129
|
+
- Mutable caller-owned/accepted scopes are never shared with returned drafts.
|
|
130
|
+
- Inherited objects are detached before their merge behavior is applied, preventing prototype borrowing while preserving prototype-named deletion and signed-zero behavior.
|
|
131
|
+
- Public/staged isolation, late response reconciliation, atomic rejection and CAS remain intact. There is no public freeze/proxy layer.
|
|
115
132
|
|
|
116
|
-
|
|
133
|
+
**Measurement boundaries.** Temporal replay/public readers, provenance, serialization, hashing, storage layout and Git have their own costs. Change them only when fresh measurements and safe ownership evidence justify it.
|
|
117
134
|
|
|
118
|
-
|
|
135
|
+
Deep-clone counts, serialized clone-input volume and container visits are **deep-cloning work proxies, not allocated heap bytes or total allocation**. They omit new shallow path copies. Timed samples must exclude instrumentation and correctness checks. Neither these counters nor structural sharing establishes a serialization/hash/disk-I/O speedup. Public detachment still requires an entry copy, commit still detaches accepted values, and full runtime cost is broader than a pure staging probe.
|
|
119
136
|
|
|
120
137
|
## Validation and reporting
|
|
121
138
|
|
|
122
139
|
A performance report is valid only when it records:
|
|
123
140
|
|
|
124
141
|
- source/workload fingerprint and dependency stack;
|
|
125
|
-
- payload sizes, history lengths, rounds
|
|
142
|
+
- payload sizes, history lengths, rounds and samples, with the actual `historyLimit`;
|
|
126
143
|
- phase-local wall time and relevant resource counters;
|
|
127
|
-
- correctness results for final state, transition count, native read evidence
|
|
144
|
+
- correctness results for final state, transition count, native read evidence and baseline immutability;
|
|
128
145
|
- failure status and released resources for every unsuccessful phase.
|
|
129
146
|
|
|
130
147
|
Run `npm run validate` before treating benchmark output as release evidence. The [compatibility matrix](compatibility.md) identifies the tested SDK baseline, and the [temporal acceptance map](temporal-acceptance.md) owns behavioral evidence.
|