@llblab/pi-kit 0.5.2 → 0.7.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 (141) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +5 -5
  3. package/node_modules/@llblab/pi-actors/AGENTS.md +1 -1
  4. package/node_modules/@llblab/pi-actors/CHANGELOG.md +6 -0
  5. package/node_modules/@llblab/pi-actors/README.md +1 -1
  6. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +3 -0
  7. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +14 -1
  8. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +45 -3
  9. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +1 -1
  10. package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +16 -3
  11. package/node_modules/@llblab/pi-actors/dist/lib/observability.js +92 -7
  12. package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +0 -1
  13. package/node_modules/@llblab/pi-actors/dist/lib/pi.js +15 -24
  14. package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.d.ts +17 -0
  15. package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.js +44 -0
  16. package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +4 -0
  17. package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +102 -4
  18. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +58 -39
  19. package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +14 -6
  20. package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +1 -1
  21. package/node_modules/@llblab/pi-actors/docs/async-runs.md +1 -1
  22. package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +18 -23
  23. package/node_modules/@llblab/pi-actors/lib/async-runs.ts +18 -1
  24. package/node_modules/@llblab/pi-actors/lib/command-templates.ts +41 -3
  25. package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +1 -1
  26. package/node_modules/@llblab/pi-actors/lib/observability.ts +119 -5
  27. package/node_modules/@llblab/pi-actors/lib/pi.ts +15 -28
  28. package/node_modules/@llblab/pi-actors/lib/run-delivery-lineage.ts +68 -0
  29. package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +120 -4
  30. package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +69 -44
  31. package/node_modules/@llblab/pi-actors/lib/runtime.ts +17 -6
  32. package/node_modules/@llblab/pi-actors/package.json +1 -1
  33. package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +1 -1
  34. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +2 -2
  35. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -0
  36. package/node_modules/@llblab/pi-grow-loop/README.md +6 -6
  37. package/node_modules/@llblab/pi-grow-loop/index.ts +6 -3
  38. package/node_modules/@llblab/pi-grow-loop/package.json +1 -1
  39. package/node_modules/@llblab/pi-state-flow/AGENTS.md +33 -12
  40. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +125 -2
  41. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +87 -45
  42. package/node_modules/@llblab/pi-state-flow/README.md +203 -107
  43. package/node_modules/@llblab/pi-state-flow/docs/README.md +4 -0
  44. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +188 -0
  45. package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +42 -0
  46. package/node_modules/@llblab/pi-state-flow/index.ts +164 -2
  47. package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +138 -0
  48. package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +273 -0
  49. package/node_modules/@llblab/pi-state-flow/lib/config.ts +48 -0
  50. package/node_modules/@llblab/pi-state-flow/lib/context.ts +18 -5
  51. package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +268 -0
  52. package/node_modules/@llblab/pi-state-flow/lib/discovery.ts +117 -0
  53. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +562 -0
  54. package/node_modules/@llblab/pi-state-flow/lib/episode.ts +24 -12
  55. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +606 -70
  56. package/node_modules/@llblab/pi-state-flow/lib/git.ts +666 -0
  57. package/node_modules/@llblab/pi-state-flow/lib/history.ts +95 -0
  58. package/node_modules/@llblab/pi-state-flow/lib/json.ts +24 -0
  59. package/node_modules/@llblab/pi-state-flow/lib/maintenance.ts +141 -0
  60. package/node_modules/@llblab/pi-state-flow/lib/memory.ts +52 -0
  61. package/node_modules/@llblab/pi-state-flow/lib/migration.ts +88 -0
  62. package/node_modules/@llblab/pi-state-flow/lib/publication.ts +296 -0
  63. package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +23 -7
  64. package/node_modules/@llblab/pi-state-flow/lib/rehydration.ts +79 -0
  65. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +264 -0
  66. package/node_modules/@llblab/pi-state-flow/lib/session.ts +6 -0
  67. package/node_modules/@llblab/pi-state-flow/lib/skills.ts +99 -7
  68. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +305 -48
  69. package/node_modules/@llblab/pi-state-flow/lib/state.ts +74 -7
  70. package/node_modules/@llblab/pi-state-flow/lib/status.ts +125 -6
  71. package/node_modules/@llblab/pi-state-flow/lib/storage.ts +196 -0
  72. package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +233 -0
  73. package/node_modules/@llblab/pi-state-flow/lib/terminal.ts +70 -24
  74. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +254 -29
  75. package/node_modules/@llblab/pi-state-flow/package.json +8 -2
  76. package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +128 -0
  77. package/node_modules/@llblab/pi-telegram/AGENTS.md +14 -9
  78. package/node_modules/@llblab/pi-telegram/BACKLOG.md +20 -4
  79. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +22 -5
  80. package/node_modules/@llblab/pi-telegram/README.md +13 -9
  81. package/node_modules/@llblab/pi-telegram/docs/README.md +1 -0
  82. package/node_modules/@llblab/pi-telegram/docs/architecture.md +220 -18
  83. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +1 -1
  84. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +70 -19
  85. package/node_modules/@llblab/pi-telegram/docs/outbound.md +13 -7
  86. package/node_modules/@llblab/pi-telegram/docs/public-api.md +13 -5
  87. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +3 -1
  88. package/node_modules/@llblab/pi-telegram/index.ts +4 -1415
  89. package/node_modules/@llblab/pi-telegram/lib/activity.ts +19 -5
  90. package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +6 -3
  91. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +37 -2
  92. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +600 -135
  93. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +962 -55
  94. package/node_modules/@llblab/pi-telegram/lib/bus.ts +350 -26
  95. package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +544 -0
  96. package/node_modules/@llblab/pi-telegram/lib/commands.ts +234 -11
  97. package/node_modules/@llblab/pi-telegram/lib/config.ts +178 -25
  98. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +18 -18
  99. package/node_modules/@llblab/pi-telegram/lib/extension.ts +1792 -0
  100. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +20 -2
  101. package/node_modules/@llblab/pi-telegram/lib/journal.ts +2184 -126
  102. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +7 -1
  103. package/node_modules/@llblab/pi-telegram/lib/locks.ts +38 -1
  104. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +154 -15
  105. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +74 -40
  106. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +28 -42
  107. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +18 -14
  108. package/node_modules/@llblab/pi-telegram/lib/paths.ts +29 -0
  109. package/node_modules/@llblab/pi-telegram/lib/polling.ts +85 -17
  110. package/node_modules/@llblab/pi-telegram/lib/preview.ts +115 -70
  111. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +5 -2
  112. package/node_modules/@llblab/pi-telegram/lib/queue.ts +66 -22
  113. package/node_modules/@llblab/pi-telegram/lib/replies.ts +47 -39
  114. package/node_modules/@llblab/pi-telegram/lib/routing.ts +305 -112
  115. package/node_modules/@llblab/pi-telegram/lib/status.ts +10 -0
  116. package/node_modules/@llblab/pi-telegram/lib/sync.ts +308 -39
  117. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +315 -7
  118. package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +664 -0
  119. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +226 -0
  120. package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +118 -0
  121. package/node_modules/@llblab/pi-telegram/lib/threads.ts +1686 -129
  122. package/node_modules/@llblab/pi-telegram/lib/updates.ts +1319 -97
  123. package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +1643 -0
  124. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +968 -0
  125. package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +84 -0
  126. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  127. package/node_modules/@llblab/pi-telegram/screenshot.png +0 -0
  128. package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +83 -0
  129. package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +101 -0
  130. package/node_modules/@llblab/{skills → pi-telegram/skills}/show-me/SKILL.md +28 -6
  131. package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +43 -0
  132. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/delivery-and-threads.md +1 -1
  133. package/node_modules/@llblab/skills/abcd-context/AGENTS.md +1 -0
  134. package/node_modules/@llblab/skills/abcd-context/CHANGELOG.md +6 -2
  135. package/node_modules/@llblab/skills/abcd-context/SKILL.md +1 -1
  136. package/node_modules/@llblab/skills/abcd-context/docs/validation-design.md +11 -5
  137. package/node_modules/@llblab/skills/abcd-context/scripts/_self-test.mjs +61 -0
  138. package/node_modules/@llblab/skills/abcd-context/scripts/validate-context.mjs +67 -0
  139. package/node_modules/@llblab/skills/package.json +2 -3
  140. package/node_modules/@llblab/skills/release-flow/SKILL.md +2 -4
  141. package/package.json +7 -6
@@ -0,0 +1,188 @@
1
+ # State Flow architecture
2
+
3
+ ## Purpose
4
+
5
+ State Flow is a Pi extension that materializes compact, scoped semantic state across agent runs while preserving Pi's native session trace and tool loop. It is inspired by SKILL.state but uses its own temporal model, storage plane, artifact compiler, and publication lifecycle.
6
+
7
+ The extension owns durable memory while enabled. Global semantic memory is always available; there are no ownership or global-memory feature switches.
8
+
9
+ ## Composition
10
+
11
+ `index.ts` is the public export and extension composition boundary. Independent modules under `lib/` own one concern each and are mirrored by tests:
12
+
13
+ - `state`, `json`: semantic shape, validation, recursive overlay and deletion.
14
+ - `temporal`, `history`: causal boundaries, checkpoint/tail folding and hot history.
15
+ - `durable`, `storage`, `git`: exact files, CAS publication, Git commits and restoration.
16
+ - `snapshot`, `session`, `runtime`, `recovery`, `episode`: Pi branch/runtime lifecycle.
17
+ - `transition`, `terminal`, `validation`, `context`: inference barriers and final reconciliation.
18
+ - `artifact`, `acquisition`, `maintenance`, `skills`, `rehydration`: source routing and compilation.
19
+ - `memory`: external promotion records and memory diagnostics.
20
+ - `continuation`: native-header discovery, runtime-provenance inspection, deterministic recommendation, and host startup precedence.
21
+ - `publication`: remote policy, durable CAS queue/store, cross-process leases, and asynchronous worker lifecycle.
22
+ - `status`, `extension`: operator projection and Pi adapter wiring.
23
+
24
+ ## Semantic state
25
+
26
+ Every materialized scope has exactly this shape:
27
+
28
+ ```json
29
+ {
30
+ "artifacts": {},
31
+ "contract": {},
32
+ "working": {},
33
+ "response": ""
34
+ }
35
+ ```
36
+
37
+ - `artifacts` maps exact source paths to compiled routing metadata.
38
+ - `contract` retains durable requirements, decisions, interfaces and rejected approaches.
39
+ - `working` retains verified current facts, unresolved work and exact continuation.
40
+ - `response` is the latest complete user-facing answer for the session scope.
41
+
42
+ Effective state recursively overlays:
43
+
44
+ ```text
45
+ global → CWD → session
46
+ ```
47
+
48
+ Later scopes win. A scope-local `null` deletion removes only that scope's key and may reveal an inherited value. Scope represents applicability and ownership, never instruction authority.
49
+
50
+ State Flow is the memory owner while enabled. Cross-project/user/environment knowledge belongs in global state, project-only knowledge in CWD, and branch/run continuation in session. Global availability is not a feature switch and does not authorize secrets, raw history, transient progress, speculative clutter, or unsupported assertions. Explicitly uncertain hypotheses remain eligible only when they can affect an open decision.
51
+
52
+ ## Temporal model
53
+
54
+ All scopes participate in one active causal lineage. One accepted semantic transition receives one opaque identity shared by every changed scope. Sparse transitions do not create records for unchanged scopes.
55
+
56
+ Each scope stores:
57
+
58
+ ```text
59
+ checkpoint.json + patches.jsonl
60
+ ```
61
+
62
+ The checkpoint is an older anchored materialization. The tail contains at most seven effective patches. On overflow, the oldest tail patch folds into the checkpoint before the new patch is appended.
63
+
64
+ `state[n]`, `state.global[n]`, `state.cwd[n]` and `state.session[n]` resolve the same nth previous causal boundary. They are not independent per-scope patch counters. Pre-origin history is unavailable rather than empty.
65
+
66
+ True semantic no-ops create no identity, commit or history step. A changed finalized response is semantic state and advances history.
67
+
68
+ ## Pi lifecycle
69
+
70
+ `patch_state` is the sole mutation tool. It validates and publishes one scope patch immediately, then acts as an inference barrier. Pi executes no sibling tools from the same assistant response; the next inference sees rematerialized `state[0]`.
71
+
72
+ `read_state` reads one cached effective or scoped projection at offsets zero through seven. It never publishes or advances history.
73
+
74
+ Every successful enabled run ends with terminal reconciliation. A private `state_flow` comment may provide multi-scope transitions, followed by one blank line and the visible answer. An ordinary answer means an empty model patch but still updates session `response` when changed. Pi's finalized message at `turn_end` is authoritative for response reconciliation.
75
+
76
+ The current user specification stays at user authority and appears only in synthetic user runtime context. State is fallible assistant-produced data. Completed trajectories leave model context at user-run boundaries, while Pi's full JSONL trace remains inspectable.
77
+
78
+ ## Storage and identity
79
+
80
+ The default store is `<agentDir>/state-flow`, independent from Markdown discovery at `<agentDir>/knowledge`.
81
+
82
+ Owned paths are:
83
+
84
+ ```text
85
+ checkpoint.json
86
+ patches.jsonl
87
+ <cwd-key>/checkpoint.json
88
+ <cwd-key>/patches.jsonl
89
+ <cwd-key>/<session-key>/checkpoint.json
90
+ <cwd-key>/<session-key>/patches.jsonl
91
+ <cwd-key>/<session-key>/config.json
92
+ <cwd-key>/<session-key>/meta.json
93
+ ```
94
+
95
+ CWD and session keys mirror Pi's native encoding. The Pi UUID remains authoritative; readable directory keys never replace identity validation.
96
+
97
+ `config.json` owns branch runtime behavior. `meta.json` owns lineage, counters, identity, publication provenance and remote-publication policy. Pi checkpoints retain only an exact Git revision, an exact `file:<hash>` cohort reference, or a proven ordinary-disabled marker.
98
+
99
+ All owned writes use same-directory atomic replacement, regular-file and symlink checks, prepared byte receipts and CAS validation. Unrelated files, staging and concurrent bytes are preserved. Rollback restores only bytes still matching the failed publisher's output.
100
+
101
+ ## Optional Git
102
+
103
+ If Git is unavailable specifically through executable `ENOENT`, State Flow uses file-only persistence. File mode retains exact current materialization and proven hot history but offers no arbitrary cold revisions.
104
+
105
+ With Git, each effective semantic cohort creates one local commit immediately through an isolated index. Git supplies cold history and exact branch restoration. Runtime `revision: "self"` resolves to the commit that owns the runtime record, never arbitrary `HEAD`. Runtime-only writes may use `temporalRevision` to select older semantic streams without rewinding live shared files.
106
+
107
+ Installing Git over a file-only store adopts the exact current cohort without fabricating earlier history. Legacy layouts remain read-only historical inputs until explicitly migrated.
108
+
109
+ ## Remote publication
110
+
111
+ Local acceptance and remote replication are separate.
112
+
113
+ The persisted `remotePublication` policy is:
114
+
115
+ - `turn-end`: default for new runtimes; local commits are immediate and the newest turn target is queued.
116
+ - `off`: local commits only.
117
+ - `transition`: synchronous compatibility behavior for legacy runtimes.
118
+
119
+ A destination is identified by canonical Git common directory, remote and full ref. Queue files live beneath the Git common directory and are not semantic history.
120
+
121
+ The queue uses exact commit targets, strict versioned JSON, symlink-safe atomic writes, CAS receipts and exclusive writer locks. A proven descendant may supersede an older target; divergent targets and changed destinations fail closed.
122
+
123
+ After terminal acceptance, an asynchronous non-interactive worker pushes the newest target. Queue failure never rolls back semantic state or regenerates an answer. Failed and interrupted attempts remain retryable across restart. Destination-scoped worker leases prevent cross-process overlap, preserve live owners, recover proven-dead owners and use exact release tokens. Confirmation removes only the exact completed target; a newer descendant remains queued.
124
+
125
+ ## Artifact routing
126
+
127
+ Markdown discovery recursively finds regular lowercase `*.md` beneath the configured Knowledge root, rejects symlinks, hashes opaque bytes and never injects source bodies.
128
+
129
+ Artifact metadata requires:
130
+
131
+ ```json
132
+ {
133
+ "description": "routing summary",
134
+ "hash": "sha256:<source bytes>",
135
+ "compiler": "artifact-v1"
136
+ }
137
+ ```
138
+
139
+ Compiler output may add arbitrary finite non-null JSON metadata. Known optional fields include `kind`, `compiled_at`, `tags` and `compilation`. Tags are unique trimmed non-empty strings and support deterministic candidate filtering, but never authorize reading.
140
+
141
+ Freshness depends on source hash and compiler revision. New, changed, compiler-stale, malformed or explicitly refreshed sources become invalidations. Exact successful native Pi reads are correlated with current candidates; stale reads require same-path compiler output before trusted hash/compiler metadata is attached.
142
+
143
+ Compilation is routing, not a substitute for source text. Full source is read only for a concrete unresolved gap, exact source/edit operation, invalidation, contradiction/failure, explicit request or bounded maintenance. The rehydration planner supports new-bootstrap, resume-bootstrap and later-step phases while limiting read count and source bytes without performing hidden I/O.
144
+
145
+ Skills are CWD artifacts with stricter compilation: `kind: "skill"` and a non-empty compilation describing applicability, constraints and failure conditions. Their source bodies do not persist in state. Matching source hash and compiler metadata proves source-version consistency, not semantic fidelity, truth, or higher instruction authority.
146
+
147
+ ## Memory curation and promotion
148
+
149
+ The optional packaged `state-flow-memory` Skill performs bounded explicit audits, scope narrowing, contradiction cleanup and external handoffs. It is not part of ordinary retention or background maintenance. Curation compiles a read Skill at CWD before accumulating global compilation obligations, writes and separately reads a migration destination before source deletion, then verifies the changed scope and effective overlay. Simultaneously pending CWD/global acquisitions use existing terminal multi-scope reconciliation; `patch_state` remains single-scope and separate calls are not atomic migration.
150
+
151
+ External promotion remains a semantic two-phase handoff, not a memory-owner mode. Optional global `working.memory_promotions` entries record `pending`, `accepted`, `failed` or `unknown` status plus owner. Accepted records additionally require destination pointer and revision. Failed or uncertain promotion preserves the State Flow candidate; the only accepted copy is never deleted.
152
+
153
+ ## Session continuation
154
+
155
+ The package exposes read-only host contracts that:
156
+
157
+ - read only native JSONL headers, never transcript bodies;
158
+ - inspect exact file/Git State Flow runtime provenance without mutation;
159
+ - rank exact profile, CWD, Git common-directory, worktree, branch and transport identity;
160
+ - fail closed for stopped, malformed, unavailable or ambiguous candidates;
161
+ - preserve explicit new/resume and native picker precedence;
162
+ - project new-bootstrap, resume-bootstrap and later-step rehydration phases.
163
+
164
+ Pi 0.84.4 chooses or creates `SessionManager` before package resources and extensions load. Therefore native default auto-resume cannot be installed safely by this extension alone. The remaining host integration requires an upstream pre-session resolver hook or an SDK/launcher that invokes the advisory resolver before constructing the session.
165
+
166
+ ## Configuration
167
+
168
+ `state-flow.json` is loaded once per extension load/reload:
169
+
170
+ ```json
171
+ {
172
+ "directory": "~/.pi/agent/state-flow",
173
+ "autoStart": false,
174
+ "remotePublication": "turn-end"
175
+ }
176
+ ```
177
+
178
+ Unknown keys fail loading. State Flow memory ownership and global availability are fixed invariants and have no configuration options.
179
+
180
+ ## Observability
181
+
182
+ `/state-flow-status` reports branch mode, runtime revision, temporal head/history depth, scope keys, patch tails, artifact freshness, memory-bearing scopes, external-promotion summaries, remote policy/queue state, pending publication and terminal retry state. Unavailable materialization is reported as unavailable, never fabricated as empty. Artifact source bodies are not read for status.
183
+
184
+ ## Validation boundaries
185
+
186
+ Structural validation proves JSON shape, exact identity, causal lineage, freshness, CAS and publication invariants. A valid state, receipt, source hash, or compiler revision cannot prove semantic importance, truth, sufficient compilation, correct scope, useful curation, or historical deletion. Those remain model-judgment concerns evaluated separately from deterministic transport checks.
187
+
188
+ The continuity requirement and deterministic evidence map is in [continuity-acceptance.md](continuity-acceptance.md). The executable temporal requirement map is in [temporal-acceptance.md](temporal-acceptance.md). Canonical remaining work is in [BACKLOG.md](../BACKLOG.md), and shipped outcomes belong in [CHANGELOG.md](../CHANGELOG.md).
@@ -0,0 +1,42 @@
1
+ # Temporal acceptance
2
+
3
+ The numbering below follows the twenty required tests in the temporal design correction. This is a maintained property-to-test map, not a second backlog or a substitute for running tests. Paths and quoted test names refer to a source checkout; tests are not shipped in the npm runtime package.
4
+
5
+ ## Required properties and witnesses
6
+
7
+ 1. **Zero patches:** `tests/temporal.test.ts` — “zero patches preserve the initial materialization without fabricating a past” compares current state with the checkpoint and rejects invented prior history.
8
+ 2. **One patch:** `tests/temporal.test.ts` — “one patch shifts current to history and reads return detached materializations” checks new current state and the preceding checkpoint state.
9
+ 3. **Seven patches:** `tests/temporal.test.ts` — “seven patches and repeated eighth-patch folding preserve every hot state exactly” compares every effective/scoped offset with retained snapshots at seven transitions.
10
+ 4. **Eighth-patch folding:** The same test explicitly checks checkpoint advancement through T1, its absorbed value, and the retained T2–T8 tail, alongside every hot offset.
11
+ 5. **Repeated folding:** The same test repeats through forty transitions. `tests/git.test.ts` — “temporal Git writer preserves all hot states through sparse folding and cold revision reads” exercises persisted representation too.
12
+ 6. **Sparse scopes share one target:** `tests/temporal.test.ts` — “sparse scope patches use effective boundaries, not each scope's mutation count” reproduces the T181–T184 example.
13
+ 7. **CWD indexing is not local-patch indexing:** That sparse test explicitly asserts both CWD offsets 1 and 2 equal C′. `tests/extension.test.ts` — “read_state lazily projects all hot offsets and scopes at one boundary without publication or Git calls” checks all 32 offset/scope combinations.
14
+ 8. **Shared multi-scope identity:** `tests/transition.test.ts` — “publishes one exact multi-scope replay cohort without explanatory windows or current-state DTOs” verifies one identity across changed scope records and exact replay.
15
+ 9. **Unchanged scopes stay stable:** The sparse temporal example checks global state at a boundary where only CWD/session change; “true no-ops do not enter history while response-only changes do” also checks that an unchanged session receives no new patch.
16
+ 10. **Historical deletion overlay:** `tests/temporal.test.ts` — “mixed sparse changes and deletion overlays match an independent snapshot oracle through compaction” explicitly checks session → CWD → global fallback and retained historical values.
17
+ 11. **Barrier shifts current to offset 1:** `tests/integration.test.ts` — “real Pi patch_state barriers rematerialize every scope before the next inference” observes the predecessor immediately after a barrier.
18
+ 12. **Next inference sees new current state:** The same real-Pi test inspects actual model-input projections after session, CWD, and global barriers. “real Pi reads prior scoped state lazily after a barrier and rejects offset eight without a transition” adds model-tool access to the predecessor.
19
+ 13. **No automatic old full-state duplication:** `tests/context.test.ts` — “projects only the latest seven compact accepted transitions” rejects full-state records in transition context. The real-Pi barrier test requires exactly one current runtime projection per inference. Explicitly requested history remains ordinary tool-result trajectory, not eager snapshot injection.
20
+ 14. **Terminal changes are transitions:** `tests/terminal.test.ts` — “ordinary terminal answers commit once without retries and rotate the next request” and “reconciles response state with the finalized message after later handlers” verify accepted response persistence and replay.
21
+ 15. **True terminal no-op creates no fake history:** `tests/terminal.test.ts` — “identical finalized terminal state completes the runtime lifecycle without fake semantic history” checks unchanged semantic lineage/tails/step. Runtime lifecycle metadata may still change; omitting a memory patch is not a no-op when response changes.
22
+ 16. **Offset eight is outside hot history:** `tests/temporal.test.ts` — “hot range and unproven pre-migration history are explicit read boundaries”; the real-Pi history-reader test also exercises native tool rejection without a transition.
23
+ 17. **Cold Git history remains recoverable:** `tests/git.test.ts` — “temporal Git writer preserves all hot states through sparse folding and cold revision reads” loads older committed states without moving the worktree.
24
+ 18. **Tree/resume select the correct lineage:** `tests/integration.test.ts` — “real Pi preserves branch-local state through compaction, tree navigation, stop, and restart” and “real Pi old tree branch stop and resume preserve selected semantics without rewinding shared files”.
25
+ 19. **Stop changes config, not semantic history:** `tests/git.test.ts` — “session config/meta publish atomically with temporal files and config-only stop creates no semantic step”; `tests/runtime.test.ts` verifies old-branch stop without semantic writes and failed-restore stop/resume.
26
+ 20. **Lossless current-state migration:** `tests/migration.test.ts` — “migration anchors exact current materializations and never replays explanatory journals”; `tests/git.test.ts` — “migrates all three current snapshots in one isolated commit without losing semantic or cold history”; runtime tests cover revision-linked migration with malformed explanatory history.
27
+
28
+ ## Additional preservation boundaries
29
+
30
+ - `tests/durable.test.ts`, `tests/git.test.ts`, and `tests/migration.test.ts` cover owned regular files, raw-byte rollback, prepared-output receipts, stale/omitted-scope CAS, linked-worktree publication exclusion, unrelated staging, and exact-commit push retry.
31
+ - `tests/recovery.test.ts` and `tests/runtime.test.ts` distinguish invalid immutable targets from transient publication failures, preserve checkpoint provenance, and prevent invalid-only recovery from becoming permission to replace runtime.
32
+ - `tests/context.test.ts` and `tests/extension.test.ts` prohibit process queries during ordinary context/history reads. `tests/transition.test.ts` rejects stale staging even when semantic values coincide across different causal boundaries.
33
+ - `tests/status.test.ts` distinguishes selected temporal history depth from retained per-scope tails and unavailable materialization from an empty state.
34
+ - `tests/storage.test.ts` covers Git absence, exact file-cohort references, file CAS/rollback and shared writer exclusion. `tests/runtime.test.ts` and the native Pi Git-absent lifecycle test cover file-pointer restart, immediate barriers, finalized response, config-only stop, and unavailable-reference provenance. File-only mode supplies current/hot state; Git-dependent cold and arbitrary branch recovery require Git and the original committed objects.
35
+ - File-to-Git tests in `tests/storage.test.ts`, `tests/runtime.test.ts` and the native Pi lifecycle cover full-cohort adoption over unborn/stale HEAD, exact inherited bytes, unchanged semantic step/hot history, rollback, staging preservation and subsequent configured-remote publication. `tests/git.test.ts` rejects omitted uncommitted streams; working-tree equality alone cannot prove a Git commit contains the selected state.
36
+ - `tests/config.test.ts` covers optional agent configuration, path precedence/expansion, invalid input, load-time caching and read-only behavior. Session tests and native Pi distinguish configured new-session auto-start from branch-local resume/tree/stop. The global default is manual; CWD materialization alone no longer grants automatic activation.
37
+
38
+ ## Validation and limits
39
+
40
+ Run `npm run validate` in the source checkout. Run context/DAG validation and `npm pack --dry-run --ignore-scripts` for documentation, dependency direction, and package inventory after an applicable full validation.
41
+
42
+ Real-Pi tests use the actual Pi SDK and native tool loop with a deterministic faux model and temporary Git repositories. They do not prove that an unconstrained model always follows the memory protocol, nor do they migrate production Knowledge or publish the real repository. Complete native trace remains available; normal model projection retains only the required active context. Cooperative locking and conflict preservation are not kernel-atomic multi-file transactions against nonparticipating writers. Test counts do not establish exhaustive equivalence with every removed predecessor assertion.
@@ -1,4 +1,166 @@
1
+ export {
2
+ ArtifactReadTracker,
3
+ decideArtifactAcquisition,
4
+ type ArtifactAcquisitionDecision,
5
+ type ArtifactAcquisitionIntent,
6
+ type ArtifactAcquisitionOptions,
7
+ type ArtifactAcquisitionReason,
8
+ type SuccessfulArtifactRead
9
+ } from "./lib/acquisition.ts";
10
+ export {
11
+ classifyArtifactFreshness,
12
+ hashArtifactSource,
13
+ isArtifactHash,
14
+ isArtifactMetadata,
15
+ isArtifactRegistry,
16
+ ORDINARY_ARTIFACT_COMPILER,
17
+ planArtifactInvalidation,
18
+ selectArtifactsByTags,
19
+ updateArtifactRegistry,
20
+ validateArtifactMetadata,
21
+ validateArtifactRegistry,
22
+ type ArtifactCompilationUpdate,
23
+ type ArtifactCompilerOutput,
24
+ type ArtifactFreshness,
25
+ type ArtifactInvalidationOptions,
26
+ type ArtifactInvalidationPlan,
27
+ type ArtifactInvalidationReason,
28
+ type ArtifactInvalidationRequest,
29
+ type ArtifactMetadata,
30
+ type ArtifactRegistry,
31
+ type ArtifactSourceIdentity
32
+ } from "./lib/artifact.ts";
33
+ export {
34
+ buildContinuationCandidates,
35
+ discoverNativeSessionHeaders,
36
+ inspectStateFlowContinuationProvenance,
37
+ readNativeSessionHeader,
38
+ recommendContinuationFromProvenance,
39
+ resolveContinuationStartup,
40
+ type ContinuationCandidateProvenance,
41
+ type ContinuationCandidateSummary,
42
+ type ContinuationHostContext,
43
+ type ContinuationHostIntent,
44
+ type ContinuationProjectIdentity,
45
+ type ContinuationRecommendation,
46
+ type ContinuationRecommender,
47
+ type ContinuationSessionCandidate,
48
+ type ContinuationStartupDecision,
49
+ type ContinuationTransport,
50
+ type NativeSessionHeader
51
+ } from "./lib/continuation.ts";
52
+ export {
53
+ discoverGlobalMarkdownSources,
54
+ getKnowledgeRoot,
55
+ GlobalMarkdownDiscovery,
56
+ type ArtifactSourceCandidate,
57
+ type GlobalMarkdownDiscoveryResult
58
+ } from "./lib/discovery.ts";
59
+ export {
60
+ captureTemporalFileBases,
61
+ cwdScopeKey,
62
+ getDurableRepositoryRoot,
63
+ isStateFlowOwnedPath,
64
+ loadScopeStream,
65
+ parseScopeStream,
66
+ serializeScopeStream, sessionRuntimePaths, sessionScopeKey,
67
+ sessionStorageKey, temporalScopePaths,
68
+ temporalStateFileUpdates, type ScopeStreamSources, type TemporalScopePaths
69
+ } from "./lib/durable.ts";
70
+ export { default, PATCH_STATE_TOOL_NAME, READ_STATE_TOOL_NAME, type StateFlowExtensionOptions } from "./lib/extension.ts";
71
+ export {
72
+ captureTemporalGitBase,
73
+ isGitCommitAncestor,
74
+ loadTemporalRevision,
75
+ migrateLegacyStorageToGit,
76
+ publishTemporalStateToGit,
77
+ pushGitCommit,
78
+ resolveGitPushDestination, type GitPushResult, type TemporalGitBase,
79
+ type TemporalRevisionLoad
80
+ } from "./lib/git.ts";
81
+ export {
82
+ createAcceptedTransition,
83
+ projectRecentTransitionsWithLimit,
84
+ RECENT_TRANSITION_LIMIT,
85
+ validateRecentTransition, type AcceptedTransition, type RecentScopePatch,
86
+ type RecentTransition,
87
+ type RecentTransitionWindow
88
+ } from "./lib/history.ts";
1
89
  export { applyPatch, canonicalJson, hashJson, isObject, validatePatch } from "./lib/json.ts";
2
90
  export type { JsonObject, JsonValue } from "./lib/json.ts";
3
- export { emptyState, isStateDocument, type StateDocument } from "./lib/state.ts";
4
- export { default } from "./lib/extension.ts";
91
+ export {
92
+ DEFAULT_ARTIFACT_MAINTENANCE_MAX_READS,
93
+ DEFAULT_ARTIFACT_MAINTENANCE_MAX_SOURCE_BYTES,
94
+ DEFAULT_ARTIFACT_MAINTENANCE_MINIMUM_AGE_MS,
95
+ planArtifactMaintenance,
96
+ type ArtifactMaintenanceOptions,
97
+ type ArtifactMaintenancePlan,
98
+ type ArtifactMaintenanceRequest
99
+ } from "./lib/maintenance.ts";
100
+ export {
101
+ inspectMemoryPromotions, MEMORY_PROMOTION_STATUSES, MEMORY_PROMOTIONS_KEY, retainedMemoryScopes,
102
+ type MemoryPromotionDiagnostic,
103
+ type MemoryPromotionStatus
104
+ } from "./lib/memory.ts";
105
+ export {
106
+ acquirePublicationWorkerLease,
107
+ beginPublicationAttempt,
108
+ coalescePublicationTarget,
109
+ confirmPublicationTarget,
110
+ createPublicationQueue,
111
+ failPublicationAttempt,
112
+ loadPublicationQueue,
113
+ parsePublicationQueue,
114
+ parseRemotePublicationPolicyDocument,
115
+ publicationQueuePath,
116
+ recoverPublicationQueue,
117
+ remotePublicationDestinationKey,
118
+ removePublicationQueue,
119
+ resolveRemotePublicationPolicy,
120
+ runPublicationWorker,
121
+ savePublicationQueue,
122
+ serializePublicationQueue,
123
+ serializeRemotePublicationPolicyDocument,
124
+ validatePublicationQueue,
125
+ type CommitAncestor,
126
+ type PublicationPush,
127
+ type PublicationQueueReceipt,
128
+ type PublicationQueueState,
129
+ type PublicationQueueStatus,
130
+ type PublicationWorkerLease,
131
+ type PublicationWorkerResult,
132
+ type RemotePublicationDestination,
133
+ type RemotePublicationMode,
134
+ type RemotePublicationPolicy,
135
+ type RemotePublicationPolicyDocument
136
+ } from "./lib/publication.ts";
137
+ export {
138
+ planKnowledgeRehydration,
139
+ type RehydrationOptions,
140
+ type RehydrationPhase,
141
+ type RehydrationPlan,
142
+ type RehydrationRead,
143
+ type RehydrationRoute
144
+ } from "./lib/rehydration.ts";
145
+ export { TemporalRuntime } from "./lib/runtime.ts";
146
+ export {
147
+ hasCompiledSkillArtifact,
148
+ hashSkillSource,
149
+ migrateLegacySkillCompilations,
150
+ SKILL_ARTIFACT_COMPILER,
151
+ type SuccessfulSkillRead
152
+ } from "./lib/skills.ts";
153
+ export {
154
+ emptyState,
155
+ isMaterializedState,
156
+ isStateDocument,
157
+ overlayStates,
158
+ updateMaterializedArtifacts,
159
+ type MaterializedState, type ScopedPatch,
160
+ type ScopedStates, type ScopePatch, type SemanticTransition,
161
+ type StateDocument,
162
+ type StatePatch,
163
+ type StateScope,
164
+ type TerminalTransition
165
+ } from "./lib/state.ts";
166
+ export { advanceTemporalState, readTemporalState, type TemporalState } from "./lib/temporal.ts";
@@ -0,0 +1,138 @@
1
+ import {
2
+ classifyArtifactFreshness,
3
+ type ArtifactInvalidationReason,
4
+ type ArtifactInvalidationRequest,
5
+ type ArtifactSourceIdentity,
6
+ } from "./artifact.ts";
7
+ import { isObject } from "./json.ts";
8
+
9
+ /** Why the caller is considering source-body acquisition. */
10
+ export type ArtifactAcquisitionIntent =
11
+ | "routine"
12
+ | "new-session"
13
+ | "relevant-gap"
14
+ | "exact-source"
15
+ | "exact-edit"
16
+ | "contradiction-or-failure"
17
+ | "explicit-request"
18
+ | "maintenance";
19
+
20
+ export type ArtifactAcquisitionReason =
21
+ | ArtifactInvalidationReason
22
+ | "materialized-gap"
23
+ | "exact-source"
24
+ | "exact-edit"
25
+ | "contradiction-or-failure"
26
+ | "explicit-request"
27
+ | "maintenance";
28
+
29
+ export type ArtifactAcquisitionDecision =
30
+ | { kind: "use-materialized"; reason: "no-concrete-need" | "materialized-sufficient" }
31
+ | { kind: "read-source"; reason: ArtifactAcquisitionReason };
32
+
33
+ export interface ArtifactAcquisitionOptions {
34
+ intent: ArtifactAcquisitionIntent;
35
+ /** Caller-assessed semantic sufficiency; only relevant to a concrete relevant gap. */
36
+ materializedSufficient?: boolean;
37
+ explicitRefresh?: boolean;
38
+ }
39
+
40
+ /** A successful read correlated to a runtime-observed invalidation candidate. */
41
+ export interface SuccessfulArtifactRead extends ArtifactInvalidationRequest {}
42
+
43
+ interface PendingRead {
44
+ toolName: string;
45
+ args: unknown;
46
+ }
47
+
48
+ function readPath(toolName: unknown, args: unknown): string | undefined {
49
+ return toolName === "read" && isObject(args) && typeof args.path === "string"
50
+ ? args.path
51
+ : undefined;
52
+ }
53
+
54
+ /** Correlate successful read-tool executions with the current ordinary artifact invalidation plan. */
55
+ export class ArtifactReadTracker {
56
+ readonly successful = new Map<string, SuccessfulArtifactRead>();
57
+ readonly #pending = new Map<string, PendingRead>();
58
+ readonly #candidates = new Map<string, ArtifactInvalidationRequest>();
59
+
60
+ setCandidates(candidates: Iterable<ArtifactInvalidationRequest>): void {
61
+ this.#candidates.clear();
62
+ for (const candidate of candidates) this.#candidates.set(candidate.path, structuredClone(candidate));
63
+ }
64
+
65
+ clear(): void {
66
+ this.successful.clear();
67
+ this.#pending.clear();
68
+ }
69
+
70
+ recordStart(toolCallId: string, toolName: string, args: unknown): void {
71
+ this.#record(toolCallId, toolName, args);
72
+ }
73
+
74
+ recordCall(toolCallId: string, toolName: string, input: unknown): void {
75
+ this.#record(toolCallId, toolName, input);
76
+ }
77
+
78
+ recordEnd(toolCallId: string, toolName: string, isError: boolean): void {
79
+ const pending = this.#pending.get(toolCallId);
80
+ this.#pending.delete(toolCallId);
81
+ if (isError || !pending || toolName !== pending.toolName) return;
82
+ const path = readPath(pending.toolName, pending.args);
83
+ if (path === undefined) return;
84
+ const candidate = this.#candidates.get(path);
85
+ if (candidate !== undefined) this.successful.set(path, structuredClone(candidate));
86
+ }
87
+
88
+ #record(toolCallId: string, toolName: string, args: unknown): void {
89
+ if (toolName !== "read") {
90
+ this.#pending.delete(toolCallId);
91
+ return;
92
+ }
93
+ this.#pending.set(toolCallId, { toolName, args });
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Apply one materialized-first source acquisition policy.
99
+ *
100
+ * Freshness invalidation always wins. Otherwise routine use and a new session
101
+ * stay on materialized state; only a concrete source need permits rereading.
102
+ */
103
+ export function decideArtifactAcquisition(
104
+ source: ArtifactSourceIdentity,
105
+ metadata: unknown,
106
+ compiler: string,
107
+ options: ArtifactAcquisitionOptions,
108
+ ): ArtifactAcquisitionDecision {
109
+ const freshness = classifyArtifactFreshness(
110
+ source,
111
+ metadata,
112
+ compiler,
113
+ options.explicitRefresh ?? false,
114
+ );
115
+ if (freshness.kind === "requires-compilation") {
116
+ return { kind: "read-source", reason: freshness.reason };
117
+ }
118
+
119
+ switch (options.intent) {
120
+ case "routine":
121
+ case "new-session":
122
+ return { kind: "use-materialized", reason: "no-concrete-need" };
123
+ case "relevant-gap":
124
+ return options.materializedSufficient === true
125
+ ? { kind: "use-materialized", reason: "materialized-sufficient" }
126
+ : { kind: "read-source", reason: "materialized-gap" };
127
+ case "exact-source":
128
+ return { kind: "read-source", reason: "exact-source" };
129
+ case "exact-edit":
130
+ return { kind: "read-source", reason: "exact-edit" };
131
+ case "contradiction-or-failure":
132
+ return { kind: "read-source", reason: "contradiction-or-failure" };
133
+ case "explicit-request":
134
+ return { kind: "read-source", reason: "explicit-request" };
135
+ case "maintenance":
136
+ return { kind: "read-source", reason: "maintenance" };
137
+ }
138
+ }