@llblab/pi-kit 0.25.0 → 0.27.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.
Files changed (169) hide show
  1. package/BACKLOG.md +5 -1
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +10 -8
  4. package/node_modules/@llblab/pi-actors/AGENTS.md +2 -0
  5. package/node_modules/@llblab/pi-actors/CHANGELOG.md +4 -1
  6. package/node_modules/@llblab/pi-actors/LICENSE +21 -0
  7. package/node_modules/@llblab/pi-actors/README.md +1 -1
  8. package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +1 -1
  9. package/node_modules/@llblab/pi-actors/package.json +4 -3
  10. package/node_modules/@llblab/pi-claude-usage/AGENTS.md +6 -3
  11. package/node_modules/@llblab/pi-claude-usage/BACKLOG.md +2 -1
  12. package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +8 -0
  13. package/node_modules/@llblab/pi-claude-usage/README.md +48 -3
  14. package/node_modules/@llblab/pi-claude-usage/index.ts +8 -1159
  15. package/node_modules/@llblab/pi-claude-usage/lib/extension.ts +30 -0
  16. package/node_modules/@llblab/pi-claude-usage/lib/fast.ts +24 -0
  17. package/node_modules/@llblab/pi-claude-usage/lib/query.ts +146 -0
  18. package/node_modules/@llblab/pi-claude-usage/lib/status-format.ts +297 -0
  19. package/node_modules/@llblab/pi-claude-usage/lib/status.ts +366 -0
  20. package/node_modules/@llblab/pi-claude-usage/lib/telegram.ts +44 -0
  21. package/node_modules/@llblab/pi-claude-usage/lib/usage-store.ts +221 -0
  22. package/node_modules/@llblab/pi-claude-usage/lib/usage.ts +128 -0
  23. package/node_modules/@llblab/pi-claude-usage/package.json +9 -5
  24. package/node_modules/@llblab/pi-clean-room/AGENTS.md +1 -0
  25. package/node_modules/@llblab/pi-clean-room/CHANGELOG.md +5 -0
  26. package/node_modules/@llblab/pi-clean-room/LICENSE +21 -0
  27. package/node_modules/@llblab/pi-clean-room/README.md +1 -1
  28. package/node_modules/@llblab/pi-clean-room/package.json +3 -2
  29. package/node_modules/@llblab/pi-codex-usage/AGENTS.md +9 -6
  30. package/node_modules/@llblab/pi-codex-usage/BACKLOG.md +2 -1
  31. package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +17 -0
  32. package/node_modules/@llblab/pi-codex-usage/README.md +75 -17
  33. package/node_modules/@llblab/pi-codex-usage/index.ts +8 -1602
  34. package/node_modules/@llblab/pi-codex-usage/lib/extension.ts +25 -0
  35. package/node_modules/@llblab/pi-codex-usage/lib/fast.ts +23 -0
  36. package/node_modules/@llblab/pi-codex-usage/lib/query.ts +368 -0
  37. package/node_modules/@llblab/pi-codex-usage/lib/status-format.ts +347 -0
  38. package/node_modules/@llblab/pi-codex-usage/lib/status.ts +435 -0
  39. package/node_modules/@llblab/pi-codex-usage/lib/telegram.ts +45 -0
  40. package/node_modules/@llblab/pi-codex-usage/lib/usage-store.ts +229 -0
  41. package/node_modules/@llblab/pi-codex-usage/lib/usage.ts +425 -0
  42. package/node_modules/@llblab/pi-codex-usage/package.json +11 -6
  43. package/node_modules/@llblab/pi-command-fast/AGENTS.md +7 -0
  44. package/node_modules/@llblab/pi-command-fast/BACKLOG.md +9 -0
  45. package/node_modules/@llblab/pi-command-fast/CHANGELOG.md +7 -0
  46. package/node_modules/@llblab/pi-command-fast/LICENSE +21 -0
  47. package/node_modules/@llblab/pi-command-fast/README.md +42 -0
  48. package/node_modules/@llblab/pi-command-fast/dist/command.d.ts +8 -0
  49. package/node_modules/@llblab/pi-command-fast/dist/command.js +52 -0
  50. package/node_modules/@llblab/pi-command-fast/dist/index.d.ts +3 -0
  51. package/node_modules/@llblab/pi-command-fast/dist/index.js +3 -0
  52. package/node_modules/@llblab/pi-command-fast/dist/models-json.d.ts +10 -0
  53. package/node_modules/@llblab/pi-command-fast/dist/models-json.js +81 -0
  54. package/node_modules/@llblab/pi-command-fast/package.json +49 -0
  55. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +1 -0
  56. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -1
  57. package/node_modules/@llblab/pi-grow-loop/LICENSE +21 -0
  58. package/node_modules/@llblab/pi-grow-loop/README.md +1 -1
  59. package/node_modules/@llblab/pi-grow-loop/package.json +3 -2
  60. package/node_modules/@llblab/pi-state-flow/AGENTS.md +7 -6
  61. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +13 -5
  62. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +16 -1
  63. package/node_modules/@llblab/pi-state-flow/LICENSE +21 -0
  64. package/node_modules/@llblab/pi-state-flow/README.md +117 -35
  65. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.d.ts +24 -1
  66. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.js +80 -1
  67. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.d.ts +18 -1
  68. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +41 -1
  69. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +346 -303
  70. package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +31 -2
  71. package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +74 -5
  72. package/node_modules/@llblab/pi-state-flow/dist/lib/operation.d.ts +37 -0
  73. package/node_modules/@llblab/pi-state-flow/dist/lib/operation.js +59 -0
  74. package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.d.ts +31 -0
  75. package/node_modules/@llblab/pi-state-flow/dist/lib/ownership.js +117 -0
  76. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +7 -7
  77. package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +1 -1
  78. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +10 -1
  79. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +60 -1
  80. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +6 -0
  81. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +8 -5
  82. package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +2 -0
  83. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +28 -0
  84. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +6 -1
  85. package/node_modules/@llblab/pi-state-flow/dist/package.json +10 -9
  86. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +14 -6
  87. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +2 -2
  88. package/node_modules/@llblab/pi-state-flow/docs/README.md +19 -9
  89. package/node_modules/@llblab/pi-state-flow/docs/agent-contract-relocation.md +4 -4
  90. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +646 -89
  91. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +116 -37
  92. package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +118 -21
  93. package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +70 -8
  94. package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +88 -14
  95. package/node_modules/@llblab/pi-state-flow/docs/performance.md +83 -66
  96. package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +391 -62
  97. package/node_modules/@llblab/pi-state-flow/docs/usage.md +317 -61
  98. package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +85 -1
  99. package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +49 -2
  100. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +342 -301
  101. package/node_modules/@llblab/pi-state-flow/lib/git.ts +77 -5
  102. package/node_modules/@llblab/pi-state-flow/lib/operation.ts +75 -0
  103. package/node_modules/@llblab/pi-state-flow/lib/ownership.ts +120 -0
  104. package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +7 -8
  105. package/node_modules/@llblab/pi-state-flow/lib/query.ts +1 -1
  106. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +1 -1
  107. package/node_modules/@llblab/pi-state-flow/lib/session.ts +52 -1
  108. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +8 -7
  109. package/node_modules/@llblab/pi-state-flow/lib/status.ts +29 -0
  110. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +5 -1
  111. package/node_modules/@llblab/pi-state-flow/package.json +10 -9
  112. package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +14 -6
  113. package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +2 -2
  114. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
  115. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +10 -0
  116. package/node_modules/@llblab/pi-telegram/README.md +1 -1
  117. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +4 -1
  118. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +16 -12
  119. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +1 -1
  120. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +7 -1
  121. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +12 -3
  122. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +137 -83
  123. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +26 -0
  124. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +57 -2
  125. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +109 -4
  126. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -4
  127. package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +3 -1
  128. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +31 -1
  129. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +4 -4
  130. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +1 -0
  131. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +17 -4
  132. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +2 -2
  133. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +48 -12
  134. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  135. package/node_modules/@llblab/pi-telegram/docs/architecture.md +6 -5
  136. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +2 -0
  137. package/node_modules/@llblab/pi-telegram/docs/public-api.md +2 -2
  138. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +4 -0
  139. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +17 -10
  140. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +8 -2
  141. package/node_modules/@llblab/pi-telegram/lib/commands.ts +135 -97
  142. package/node_modules/@llblab/pi-telegram/lib/extension.ts +25 -0
  143. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +140 -4
  144. package/node_modules/@llblab/pi-telegram/lib/model.ts +2 -4
  145. package/node_modules/@llblab/pi-telegram/lib/status.ts +30 -1
  146. package/node_modules/@llblab/pi-telegram/lib/sync.ts +4 -4
  147. package/node_modules/@llblab/pi-telegram/lib/threads.ts +21 -3
  148. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +46 -13
  149. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  150. package/node_modules/jsonc-parser/CHANGELOG.md +76 -0
  151. package/node_modules/jsonc-parser/LICENSE.md +21 -0
  152. package/node_modules/jsonc-parser/README.md +364 -0
  153. package/node_modules/jsonc-parser/SECURITY.md +41 -0
  154. package/node_modules/jsonc-parser/lib/esm/impl/edit.js +185 -0
  155. package/node_modules/jsonc-parser/lib/esm/impl/format.js +261 -0
  156. package/node_modules/jsonc-parser/lib/esm/impl/parser.js +659 -0
  157. package/node_modules/jsonc-parser/lib/esm/impl/scanner.js +443 -0
  158. package/node_modules/jsonc-parser/lib/esm/impl/string-intern.js +29 -0
  159. package/node_modules/jsonc-parser/lib/esm/main.d.ts +351 -0
  160. package/node_modules/jsonc-parser/lib/esm/main.js +178 -0
  161. package/node_modules/jsonc-parser/lib/umd/impl/edit.js +201 -0
  162. package/node_modules/jsonc-parser/lib/umd/impl/format.js +275 -0
  163. package/node_modules/jsonc-parser/lib/umd/impl/parser.js +682 -0
  164. package/node_modules/jsonc-parser/lib/umd/impl/scanner.js +456 -0
  165. package/node_modules/jsonc-parser/lib/umd/impl/string-intern.js +42 -0
  166. package/node_modules/jsonc-parser/lib/umd/main.d.ts +351 -0
  167. package/node_modules/jsonc-parser/lib/umd/main.js +194 -0
  168. package/node_modules/jsonc-parser/package.json +37 -0
  169. package/package.json +8 -8
@@ -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. It may be absent from stored state; reads then use `{}` or values inherited through the effective overlay without rewriting storage. Nested lazy values are ordinary JSON: durable and versioned with the same causal lineage as hot state, but excluded from ordinary baseline hydration.
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
- `intents`, `contract`, `working`, and `artifacts` remain hot in every scope. Session-owned `response` is also hot; New Global and CWD states use an empty structural slot; stored scopes may omit it. Effective uses the highest-priority present response, and each newly accepted answer is written only in Session. `intents` may keep compact active direction while referring to large supporting detail in `lazy`. `lazy` differs only in projection policy:
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. The optional `{"$ref":"cwd.lazy.plan"}` object provides the structured state-reference form. Inside any ordinary string or paragraph, a semantic-state reference uses `$` 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 provides a deterministic seam if code-based parsing is ever justified. File paths, document sections, URIs, artifact locators, Skill identities, and agent identities retain their native syntax.
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
- State Flow 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. When a reference matters, the agent resolves it explicitly with `read_state` for semantic paths or the appropriate external read/tool for other resources. A locator supports retrieval but does not replace content required for the current decision.
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
- 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. If found, the tool returns `{value:null, hint:[{type:"dangling-reference", message, paths}]}`. `hint` is explicit top-level metadata rather than state data; its conditional message describes unavailability, and its path array contains at most three runtime-verified current reference owners, not verified new locations of the target. The hint contains no lazy bodies and proves neither prior existence, retention nor relocation. The null sentinel is never returned alone for this case. Keys, patch, and multi-path reads keep ordinary all-or-error semantics; no durable match retains the missing-path error and does not prove the agent invented the path. The agent may then reconcile a proven stale owning value while preserving surrounding meaning. This applies equally to `$ref` objects and contextual references in prose. Effective-state absence alone does not identify the owner, and unavailable history, inaccessible external resources, or transient read failure do not prove that a durable reference is broken.
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
- 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 continue 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. The reverse lookup searches current reference owners only, never history. A proven stale reference can be repaired within touched work without resurrecting its target.
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
- `projection` defaults to `value`. A batch uses one projection for every path, evaluates every path against one captured state view, and returns results in request order. Duplicate paths remain duplicate results. An absent documented top-level field has value `null`, including an empty or absent `response`; the root view simply omits it. If any other path is invalid, the whole read fails; there is no mixed partial result.
176
+ Rules:
118
177
 
119
- The single `path` form is first-class. The retired top-level `offset` and `scope` inputs are rejected; history and ownership belong in the semantic path itself, such as `cwd[1].lazy.memory`.
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. One missing value path with exact current durable references instead returns `{ "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"] }] }`; this explicit sentinel is diagnostic metadata, not semantic state.
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` otherwise deliberately mirrors the effective-state snapshot injected at iteration start: it is semantic state without revision, provenance, range, transport, or storage fields. `patch` likewise contains only the selected semantic patch. Only structural discovery earns `meta`, and `keys` remains the final and most valuable field in that response.
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 does not repeat the requested path or projection and does not return an internal revision. Runtime owns revision selection, locking, CAS, and publication; the model cannot improve correctness by echoing that machinery.
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 rather than successful JSON containing an `error` field. The explicit dangling-reference sentinel above is the sole missing-path exception; keys, patch, multi-path, and unmatched value reads still fail.
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. Git-era publication and cold-restoration measurements do not describe this implementation. 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.
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 predecessor stores and retired `read_state` inputs fail actionably without rewriting retained bytes.
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 native-history cost separately from canonical semantic-state size, retained-tail depth, exact registered-artifact count, and optional settled-turn backup. Correctness—current canonical state, bounded retained history, causal-basis checks, complete Pi trace, and direct completion—is not a performance trade-off.
5
+ State Flow must complement Pi's session rather than create a competing transcript or lifecycle. Measure these costs separately:
6
6
 
7
- All 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.
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
- Current 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.
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, and validation outcomes match. A failed correctness probe invalidates its timing sample.
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
- ### Within-run prompt-prefix probe (0.18.1)
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
- The v3 report records `promptPrefixRuns` for each State Flow and native Pi user run, with no duplication across lifecycle checkpoints. Per inference, `contextBytes` is the UTF-8 byte length of `JSON.stringify(context.messages)` as seen by the installed faux provider; `sharedPrefixBytes` is the longest common byte prefix of that serialization with the previous inference **in the same run**, or `null` on the first inference. Per run, `patchStateBarriers` counts successful tool completions, and `nativeUserBytes` / `specificationBytes` count JSON-serialized *string values*, excluding their containing message/field frames (`specificationBytes` is `null` for native Pi). Isolated post-resume probes expose the same per-run metrics.
44
+ **Per inference:**
28
45
 
29
- A bounded local sample used `BENCH_PATCHES=2 BENCH_SAMPLES=1 BENCH_ROUNDS=2 BENCH_STATE_BYTES=1024 BENCH_POST_RESUME=1 npm run benchmark` on Node 26.8.1 Linux/x64 and Pi/AI 0.87.0. The runtime-source SHA-256 was `0f4eea2394c52c6ac545260cae967a16581b8768a24a8c611c13a389e6df01a9`, workload-source SHA-256 `e9b8158d953d8622776aa075835c4aa95c98855ed5c90e85de05dccae1087e91`, base commit `5f0f688650738d4d0e9850b2529b0273c47121a8` (the measured tree had uncommitted 0.18.1 changes). Both source hashes stayed unchanged during the run and all correctness phases passed. At user run 1, native Pi's second inference shared 2,776 of 2,777 prior serialized bytes; State Flow shared 9,365 of 9,467 at inference 2 and 9,173 with inference 2 at inference 3 (one accepted barrier). In both State Flow runs, the 21-byte serialized `specification` value duplicated the 21-byte current native user string value; native Pi had no projection field. These are synthetic short-run observations, not representative cache-hit rates or timing predictions.
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
- Byte-prefix measurements omit provider framing, tool schemas, tokenization, cache policies and quality. In particular, serialized synthetic-message timestamps can shorten this proxy prefix without proving provider-visible cache churn. Fresh state visibility after barriers must be validated independently of prefix preservation.
49
+ **Per run:**
32
50
 
33
- ### Trajectory-dominant baseline
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
- The opt-in `BENCH_PREFIX=1` probe in the [benchmark guide](../benchmarks/README.md) exercises active memory, ordinary passive memory and Stop handoff separately. Each measured run issues six 20,497-byte native reads, a patch, two more reads and a second patch. Exact read content remains visible through all eleven inferences; both patches and terminal completion are checked outside the provider. The v3 `trajectory[].promptPrefixRuns` entries retain every inference, not just aggregate ratios.
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
- Baseline: Node 26.8.1 Linux/x64, Pi/AI 0.87.0, base commit `2834dcb447f58867b579c6f2709bc71211b9537a` with uncommitted benchmark changes; runtime SHA-256 `a5a961d4d706d4a2d6649201553e39484d0e4c29d27cf4014f072b39cd78a01a`, workload SHA-256 `1785e73e4992c3d986d2851f2d81963c0b0cfde8ceacfd4337659ebc9d1492ba`. Both source identities remained unchanged and the native workload passed. The local report is `/tmp/state-flow-prefix-baseline.json`; the reproducible command and measurements below do not depend on retaining that temporary file.
56
+ ### Trajectory workload
38
57
 
39
- Each cell is **shared prefix / current serialized context bytes**; `—` means first inference. Inferences 8 and 11 follow accepted patches.
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
- | Inference | Active | Passive | Stop handoff |
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
- In that baseline, Stop handoff already reused a frozen message, unlike active and ordinary passive projection. A warm prefix alone does not prove updated memory reaches the model; freshness has separate native-SDK regressions.
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
- The implemented projection freezes whole heads, including timestamps, and delivers accepted values and changing notices at stable tail positions. Active completion/new runs, native compaction/selection and mode changes are cache boundaries; passive user turns and patches are not. Volatile projection IDs distinguish current updates from retained results after a rebase. See [projection semantics](architecture.md#pi-lifecycle) for ownership and limits.
66
+ Projection freezes whole heads, including timestamps, and delivers accepted values and changing notices at stable tail positions.
60
67
 
61
- The identical trajectory workload (`1785e73e4992c3d986d2851f2d81963c0b0cfde8ceacfd4337659ebc9d1492ba`) on the same Node/Pi stack measured runtime SHA-256 `d2c424a52d55b0c1ca47a8b1a1beba9c0dda665c8f024d6aa3b6ad95af9d3b46`, with unchanged base commit and uncommitted implementation changes. Both source identities remained stable; all native workload assertions passed. Local report: `/tmp/state-flow-prefix-after.json`.
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
- | Inference | Active | Passive | Stop handoff |
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
- Every continuation shares **all prior serialized bytes except the closing array bracket**, including both patch barriers in all three modes. At inference 8, the active prefix grows from 9,212 baseline bytes to 137,462; passive grows from 5,666 to 134,988. Initial contexts grow modestly because result guidance and projection identity are explicit. These are message-byte measurements, not provider cache accounting, latency, token-cost or quality guarantees. Regression tests assert prefix equality independently of exact host timestamps/IDs; separate native tests prove accepted-state freshness, repeated barriers, passive cross-turn stability and bootstrap rebasing.
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
- - Current semantic projection is proportional to projected state size.
82
- - Retained temporal reads are bounded by configured `historyLimit` (`0..100`, default `7`).
83
- - Canonical publication writes the affected scope/runtime cohort under file CAS and cooperating-writer exclusion; it executes no Git command.
84
- - 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.
85
- - 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.
86
- - Native transcript opening, Pi context construction, and foreign custom-context preservation remain Pi/history costs rather than canonical-state storage costs.
87
-
88
- 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.
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. It does not construct the whole branch, but traversal remains proportional to the selected ancestry when no nearby match exists. `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.
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
- This is a bounded-allocation improvement, not an unconditional constant-time claim.
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. It serializes the complete head only at a projection boundary; later synthetic notices retain their original native-message positions. 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. `currentRunTrajectory` allocates one retained-message array rather than arrays for discarded ordinary prefixes. Foreign custom context may require scanning earlier entries, and Pi may clone native messages before the extension runs.
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, and post-barrier context emission. These tests assert projection counts and retained identities; they impose no wall-time threshold.
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
- The pre-implementation baseline is bound to runtime `72e6dcb846b46015a8967bbd44925d7868fc6e273e1113e839936d0d1cc2581f`; the implemented candidate is `de26b5e229a9128f68d018f3cba1d4ab1fb769f901418aef014e70e3e4758191`. This optimization reduces repeated deep-copy work, not the public detachment or persistence contract.
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` is exported and currently returns a mutable, fully detached result, including untouched branches and incoming patch values. `overlayStates` and temporal reads rely on detached outputs. Preserve that boundary rather than sharing caller-owned mutable objects.
107
- - Previously, staging cloned the full cohort and each scope before `applyPatch`, which recursively deep-cloned touched containers again. The cohort clone was overwritten scope by scope, while empty completion patches re-cloned large untouched planes. Those staging pre-clones and recursive deep clones are now removed.
108
- - Staged responses are intentionally mutable before commit (`tests/transition.test.ts`); artifact/Skill compilation replaces entries in the staged artifact registry. Failed publication must leave accepted scopes untouched. Commit detaches the accepted result again, and the adapter installs detached runtime reads afterward.
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
- Local synthetic artifacts: `/tmp/pi-state-flow-cow-baseline.ts` and `/tmp/pi-state-flow-cow-baseline.json`; probe SHA-256 `093c6924eb77dbc48c0633446410e771590c85e80fd6560b64baa426bb6acb39`. Node 26.8.1, Linux/x64. The probe uses frozen three-scope states with 64 KiB and 512 KiB cold payload targets per scope, five patch shapes, stage/commit phases, two warmups and seven uninstrumented timing samples. The publisher is a no-op: no canonical files, live store or Git are touched. Every output container is checked for detachment, and repeated semantic hashes must agree.
126
+ **Private draft:**
113
127
 
114
- For 512 KiB per scope, the session-leaf case records 31 `structuredClone` calls and 6.06 MiB of serialized clone inputs during staging; stage plus in-memory commit records 36 calls and 7.58 MiB. Observed medians were 6.89 ms and 9.59 ms respectively. Indexed-array, all-scope and response-only cases show the same approximate clone-input volume. Full per-case counts, container visits, timings and semantic hashes are in the report.
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
- The identical probe after implementation (`/tmp/pi-state-flow-cow-after.json`) matches all 18 semantic output hashes and reduces deep-clone input volume/container visits in every row. For the same large session-leaf workload, staging drops to 10 clone calls / 1.52 MiB; stage+commit drops to 15 / 3.03 MiB (approximately 75% and 60% less serialized deep-clone input). Medians were 4.28 ms and 8.23 ms; the isolated public-leaf median instead moved from 0.26 to 0.34 ms, so no universal wall-time improvement is claimed. A separate deterministic comparison (`/tmp/pi-state-flow-cow-equivalence.ts`, report `.json`) matches pre-COW values/errors on 2,005 cases, including 784 rejections, with frozen basis/patch preservation.
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
- These volumes/counts are **deep-cloning work proxies, not allocated heap bytes or total allocation**; new shallow path copies are not counted. Timed samples exclude instrumentation and correctness checks. Neither these observations nor structural sharing establishes a serialization/hash/disk-I/O speedup. Public detachment still requires an entry copy, commit still detaches accepted values, and the full runtime cost model remains broader than this pure staging probe.
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, and samples (these workloads use the default `historyLimit` bound to the recorded runtime source);
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, and baseline immutability;
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.