pi-memory-evolution 0.2.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.
@@ -0,0 +1,224 @@
1
+ # Core memory quality: evidence, aging, feedback and second lookup
2
+
3
+ This is the next **unreleased 0.2.0** development step. It improves the three core
4
+ requirements without introducing an approval queue, vector service or another model
5
+ provider. The default path remains automatic capture/evolution and per-user-turn recall.
6
+ It is an evidence-policy implementation, not a claim of independently verified memory.
7
+
8
+ ## Evidence and automatic updates
9
+
10
+ New records have an optional, host-assigned `evidence` object:
11
+
12
+ ```text
13
+ basis: summary | user_statement | tool_observation | manual_correction
14
+ method: local | model | manual
15
+ sourceId: source event or manual action identifier
16
+ at: evidence timestamp
17
+ ```
18
+
19
+ Summary extraction is labeled `summary/local`; model consolidation from a summary is
20
+ `summary/model`, not user testimony. Claims from explicit user learning statements are
21
+ `user_statement/model`: the source is the user, but the extraction is still inferred.
22
+ Completed-work observations are `tool_observation/model`, only for nominated project
23
+ states. A failure observation is still an observation, never automatic proof of success.
24
+ Literal `/memory correct` creates `manual_correction/manual` evidence. Manual action
25
+ identifiers and their actual before/after states are retained in event history; they do
26
+ not imply a separate raw-summary row.
27
+
28
+ The model's allowed output fields remain kind/content/replaces/searchTerms. It cannot
29
+ set evidence, confidence, verification, utility or feedback. Existing evidence/feedback
30
+ is supplied to the background model as historical data, and store guards enforce the
31
+ write policy regardless of its interpretation.
32
+
33
+ ### Conservative replacement
34
+
35
+ All existing subject/origin, pin, generation, source-time, nomination and transactional
36
+ checks still apply. A replacement cannot change the memory kind to escape its evidence
37
+ policy. Ordinal source priorities are:
38
+
39
+ | Evidence | Priority |
40
+ |---|---:|
41
+ | Unknown | 0 |
42
+ | Summary | 1 |
43
+ | User statement about a fact/project state | 2 |
44
+ | User statement about a preference/decision | 3 |
45
+ | Tool observation about project state | 3 |
46
+ | Literal manual correction | 4 |
47
+
48
+ `confirmed` records and explicit `accurate` assessments are also protected at priority 4
49
+ for replacement. These are source appropriateness rules, **not truth probabilities**.
50
+ A current explicit user learning/correction statement may supersede earlier testimony.
51
+ A fresh, linked tool observation can update project progress even if its earlier state
52
+ was manually corrected: correcting “pending” must not freeze progress forever. Neither
53
+ exception overrides pinning, source-time or origin checks.
54
+
55
+ A lower-priority proposed replacement does not overwrite the stronger old record. Its
56
+ new variant (including a variant locally extracted from that same source) is quarantined
57
+ as `conflicted`; duplicate additions in the same model batch cannot bypass this. Existing
58
+ unrelated variants are not silently quarantined. History records how many weaker
59
+ replacements were withheld. Original evidence remains recallable. The transaction is
60
+ undoable and the processed job is not repeatedly billed as a failure.
61
+
62
+ An explicit incorporated user reaffirmation or fresh progress observation can refresh
63
+ unchanged content's evidence date. Pure aliases and repeated summaries cannot. If a
64
+ replacement reuses an already stored target value, incorporated newer evidence is
65
+ attached instead of leaving the target's old date/source unchanged. New content does
66
+ not inherit old utility/accuracy feedback. A literal correction clears old aliases and
67
+ feedback; undo restores the actual prior metadata.
68
+
69
+ **Limit:** conflict detection still depends on the model identifying a `replaces` target
70
+ in its bounded same-origin candidate set. Arbitrary contradictory additions, paraphrases
71
+ and cross-origin identities are not automatically resolved. Multiple source events are
72
+ not treated as independent corroboration; repeated summaries may share the same root
73
+ observation. There is no reinforcement count or model-generated confidence score.
74
+
75
+ ## Gradual aging and relevance-first ranking
76
+
77
+ Aging is computed at read time; no periodic writes, deletion or artificial timestamp
78
+ refresh is required. All times are numeric and negative ages clamp to zero.
79
+
80
+ ```text
81
+ freshness = floor + (1 - floor) * 2 ** (-ageDays / halfLifeDays)
82
+ ```
83
+
84
+ | Kind | Half-life of the decaying portion | Floor | Hard recall expiry |
85
+ |---|---:|---:|---|
86
+ | project_state | 3 days | 0.50 | after 7 days |
87
+ | fact | 90 days | 0.75 | none |
88
+ | decision | 180 days | 0.85 | none |
89
+ | preference | 365 days | 0.95 | none |
90
+
91
+ Pinning sets freshness to 1 and exempts age expiry, but adds no credibility, cannot
92
+ revive a conflict, and cannot bypass relevance. Facts/decisions/preferences never vanish
93
+ just because they are old. The project-state cap remains unchanged so upgrading does not
94
+ revive already expired project claims. This first step classifies by memory kind, not
95
+ semantic subtypes such as completed/blocked tasks or volatile configuration facts.
96
+
97
+ The existing lexical score and subject/literal/coverage/relative-cutoff gates run first.
98
+ The 75% relative cutoff is based on **raw relevance**, not quality-adjusted scores.
99
+ Only eligible matches are ordered by:
100
+
101
+ ```text
102
+ rankScore = relevance * freshness * evidenceWeight * utility * accuracy
103
+
104
+ evidenceWeight = 1 + 0.04 * sourcePriority
105
+ utility = useful: 1.05, unhelpful: 0.90, otherwise: 1
106
+ accuracy = accurate: 1.05, incorrect: 0.50, otherwise: 1
107
+ ```
108
+
109
+ Incorrect assessments are excluded altogether by lifecycle guards; the defensive 0.50
110
+ factor never makes them eligible. Pin/date/ID resolve remaining equal rank scores. The
111
+ constants are conservative policy choices, not statistically calibrated accuracy or an
112
+ online-learned ranker. Changing utility cannot increase source priority. Old records
113
+ without evidence metadata get the neutral evidence factor 1, not fabricated authority.
114
+
115
+ Short named-attribute queries additionally require the named subject and requested
116
+ attributes. For example, after SQLite authentication is suppressed, PostgreSQL
117
+ authentication and SQLite timeout cannot substitute as answers. This rule applies to
118
+ queries with up to four normalized features, one nonnumeric nonconcept subject and an
119
+ explicit attribute; generic status/progress words are not mandatory answer tokens.
120
+ Explicit origin names may identify a subject, but attribute evidence must be in the body
121
+ or aliases. Numeric replacement values are not mistaken for subject names; Chinese
122
+ `多少` is query framing, not an entity. This is a bounded grammatical heuristic, not
123
+ general entity/coreference recognition.
124
+
125
+ `/memory explain` exposes raw score, rankScore, source basis/method, freshness, utility,
126
+ accuracy and exclusion reasons. Diagnostics still omit memory bodies and are capped at
127
+ 8 KB in memory. `/memory show` includes persisted evidence/feedback and current quality.
128
+ The digest reserves its trust guidance, stays within three claims / 2048 UTF-8 bytes,
129
+ and adds evidence basis/method and `aging` (freshness below 0.85). Its source label points
130
+ to the current evidence when known; legacy records fall back to their original source.
131
+ An `accurate` label means a user assessment, not independent verification.
132
+
133
+ ## Explicit feedback without an approval workflow
134
+
135
+ Optional controls:
136
+
137
+ ```text
138
+ /memory feedback <id> useful
139
+ /memory feedback <id> unhelpful
140
+ /memory feedback <id> accurate
141
+ /memory feedback <id> incorrect
142
+ ```
143
+
144
+ Two independent last-verdict slots store utility and accuracy, each with a source ID and
145
+ timestamp. Usefulness is a global modest utility preference, not a query-specific
146
+ ranking model. `unhelpful` must not imply the fact is false. `accurate` is an explicit
147
+ user attestation, not a test result. Neither refreshes the evidence clock.
148
+
149
+ `incorrect` quarantines the selected claim and active exact duplicates within its origin;
150
+ it never touches equal text from another origin. Known queued repeats/observers retire.
151
+ It is reversible through actual event undo, literal correction or explicit resolution.
152
+ A conflicted/forgotten record cannot be revived by positive feedback. Resolution
153
+ preserves the evidence date, preventing stale states from appearing fresh again.
154
+
155
+ Feedback is local and has no paid learning call. A whole user-role message of the form
156
+ `记忆 <24-hex-id> 有用。` or `memory <24-hex-id> is incorrect.` uses the same path. Chinese
157
+ 有用/没用/正确/错误 map to the four verdicts. The parser does not accept examples, quotes,
158
+ questions, multiple statements or vague “wrong”; assistant/tool text is never scanned as
159
+ user feedback. IDs outside this conservative syntax remain addressable by the command.
160
+ Natural-language correction prose continues through the existing model path, not an
161
+ inferred utility score. User-role input has the same trust boundary as existing learning
162
+ cues; this is not a separate identity/authentication system for external RPC clients.
163
+
164
+ Receipts are keyed by source ID plus memory ID. Replaying after restart or undo cannot
165
+ reapply the old event. Repeating the same verdict with a new event adds no weight or
166
+ memory revision, but its receipt timestamp still prevents an older intervening verdict
167
+ from winning. Feedback older than the current content's evidence timestamp is ignored.
168
+ There is no retrieval/use count and no credit from assistant success claims or citation
169
+ frequency. Feedback changes invalidate stale in-flight model writes transactionally.
170
+ Receipts are audit/deduplication data; forget/undo does not securely erase them.
171
+
172
+ ## Read-only mid-task recall
173
+
174
+ `memory_recall({ query })` registers through Pi's public tool API. It is available unless
175
+ a user tool allowlist disables it; the extension never changes that allowlist. The query
176
+ is an explicit topic of 1–512 characters. The tool uses the same global relevance,
177
+ lifecycle and quality policy, returning at most three claims within 2048 UTF-8 bytes.
178
+ A context-free continuation returns no arbitrary recent fallback. Cancellation and store
179
+ failures produce safe errors, not invented empty-success results.
180
+
181
+ No model call is made by the retrieval function, and it neither mutates memory/history
182
+ nor persists queries in the memory DB. Pi still stores normal tool calls/results in its
183
+ transcript, and the surrounding agent model turns incur normal usage. The agent decides
184
+ whether a second lookup is needed; this does not guarantee autonomous gap detection.
185
+ Per-user-turn automatic injection remains enabled even when this tool is disabled.
186
+
187
+ ## Schema and activation
188
+
189
+ Schema 2/3/4 upgrades transactionally to **5**. Missing retry fields are added as before,
190
+ plus `feedback_receipts(source_id, memory_id, verdict, at)`. Existing memory/source/event
191
+ JSON is not rewritten; IDs, timestamps, tombstones, aliases, source jobs and history are
192
+ preserved. Missing optional evidence stays unknown. No JSONL re-import, evidence-date
193
+ reset, automatic state revival or fabricated verification occurs.
194
+
195
+ Reads validate evidence/feedback shape and tool-observation kind, and return independent
196
+ copies of nested metadata. Status validates receipt fields in addition to existing
197
+ record/job/history integrity. Unsupported schema versions fail before DDL. Old builds
198
+ reject schema 5: do not manually downgrade its marker.
199
+
200
+ Stop all Pi processes sharing the state directory and back up the complete state before
201
+ activation. Update/restart all those processes together (or reload after a consistent
202
+ backup); do not mix old writers with the new schema. A rollback requires a matching
203
+ backup. Development tests use temporary directories, not the production database.
204
+
205
+ ## Validation
206
+
207
+ - This step passed 194 tests, strict typecheck and package dry-run inspection. The later
208
+ [progress-pipeline follow-up](progress-pipeline.md) records the current validation and
209
+ the fixes for long tasks, natural requirement capture and interrupted work.
210
+ - New tests cover source/method labels, model metadata forgery rejection, weaker
211
+ replacement quarantine, same-batch duplicate/replacement bypasses, conflict-clock preservation, fresh progress after manual
212
+ correction, reused replacements, alias-only stability, aging floors/expiry/pins,
213
+ relevance-first ordering, source-kind appropriateness, feedback replay/restart/undo,
214
+ late/repeated feedback, cross-origin isolation, queued observers, nested-copy safety,
215
+ stale model rejection, malformed metadata, schema-4 migration with unchanged raw JSON
216
+ and history, named-attribute negatives, and bounded evidence injection.
217
+ - The real installed Pi/Bun test uses a loopback fake model. It exercises actual
218
+ `memory_recall` schema loading and tool-result payloads, cross-directory lookup without
219
+ memory/history writes, evidence labels, exact-ID feedback without paid learning,
220
+ quarantine and no wrong-subject fallback. Existing work-observation, failed-push,
221
+ startup/timer recovery, model/authentication and conversational tests remain.
222
+ - No live paid provider, production-memory migration, or multi-day natural-usage accuracy
223
+ evaluation was performed. Test counts show regression coverage, not real-world recall
224
+ precision or proof of truth. See [design.md](design.md) for unchanged invariants.
package/docs/design.md ADDED
@@ -0,0 +1,328 @@
1
+ # Memory evolution v0.2
2
+
3
+ ## Goal
4
+
5
+ Automatically improve memory with Pi's active model, then recall relevant claims across
6
+ sessions and directories. Directory placement must not determine which memories a
7
+ conversation can use. No approval workflow, secondary agent, external retrieval service
8
+ or automatic changes to project files, system configuration, skills or extension code.
9
+
10
+ ## Runtime
11
+
12
+ 1. `session_start`: open/migrate lazily, check persisted pending/failed work across all
13
+ origins and start a bounded recovery timer (one source per check, every 15 seconds
14
+ after the previous check/call ends).
15
+ 2. `session_compact`: atomically capture a sanitized session-qualified source and bounded
16
+ local claims; enqueue semantic consolidation.
17
+ 3. `agent_end`: capture explicit cues and natural user requirements/preferences,
18
+ distinguishing recall questions from new statements. For work with linked operation
19
+ results, capture a bounded `progress` source, including operations completed before an
20
+ interrupted final response. Mixed statements/work use separate serialized sources;
21
+ assistant/tool text never becomes a user preference. Pure memory lookup/inspection
22
+ without a recognized work operation cannot trigger progress learning.
23
+ 4. `before_agent_start`: resolve the current topic, search the whole memory database and
24
+ append a bounded, source-labeled digest to this turn's system prompt. No model call.
25
+ 5. `session_shutdown`: stop polling, abort work, return cancelled jobs to pending without
26
+ increasing their failure count, drain the serial task chain and close SQLite.
27
+
28
+ Factories do not write state or start background work. Processes with a nonempty
29
+ `PI_SUBAGENT_AGENT_ID` are skipped. Recovery polls only indexed persisted job state;
30
+ there is no full-ledger backfill or scanning of arbitrary historical Pi session files.
31
+ The timer is unreferenced so it cannot hold a print process open and is never started
32
+ from the factory. Session-scoped context getters resolve the current model/auth at each
33
+ attempt; no stale model snapshot or foreground turn cancellation controls recovery.
34
+
35
+ ## Conversation-aware recall
36
+
37
+ `adapter/session-context.ts` uses the public `buildContextEntries()` facade, not session
38
+ files or `getEntries()` across branches. It examines at most 4096 trailing active entries
39
+ and at most 4096 messages in total (including retained tails), selecting at most 6 user
40
+ texts of 2,048 UTF-8 bytes each. Consecutive topic-less continuations share a slot; reset
41
+ and unknown-topic barriers remain. Retained user tails survive compaction. Assistant/tool/custom and
42
+ injected messages are excluded, as are raw compaction summaries. Context is transient:
43
+ it is never re-captured as a source. Missing/invalidated context leaves direct-query
44
+ recall available rather than poisoning the hook.
45
+
46
+ `memory/query.ts` separates conversational recall framing from the subject, without
47
+ rewriting literal paths/filenames or stored evidence. Its query-only discourse vocabulary
48
+ handles Chinese/English asking/remembering phrases; technical memory/recall questions
49
+ retain those concepts. Unknown single-character query subjects remain unmatched barriers,
50
+ not permission to inherit an old topic or generate CJK fragment matches.
51
+
52
+ The bounded user history is replayed oldest first. Topic-less follow-ups inherit the last
53
+ resolved subject/focus. Related or attribute-only follow-ups carry a **structured** plan:
54
+ current query plus supporting subject context. Thus `SQLite → port? → auth? → continue`
55
+ retains SQLite without treating old port matches as answers about authentication. The
56
+ context does not grow by concatenating every earlier facet. Explicit new subjects stand
57
+ alone, even when unknown to the database; reset phrases stop inheritance. A fresh session
58
+ saying only `continue` identifies no topic and injects nothing.
59
+
60
+ All stored claims, including `legacy` imports, are candidates. Retrieval is local:
61
+ `Intl.Segmenter` words, exact path/filename identifiers, and a small Chinese/English
62
+ concept map. Synonyms contribute one feature rather than duplicated votes. Model-derived
63
+ `searchTerms` extend the vocabulary; old records need no reprocessing for the bootstrap
64
+ concepts. Paths such as `/work/pi-memory-evolution` do not imply the topic `memory`.
65
+ Common/filler words and generic configuration words cannot qualify a record.
66
+
67
+ For eligible records, a seen query feature weighs `1 + log((N+1)/(df+1))`; an unseen
68
+ feature weighs **1**, not the maximum IDF. Literals multiply weight by 2. Strongest field
69
+ factors are **assertion body 1, aliases 0.8, quoted question mention 0.25, explicit origin
70
+ identifier 0.2**. Quoted questions (`“...?”`, `「...?」`, `"...?"`) cannot qualify alone:
71
+ a replay note repeating a user's question is not evidence of its answer. Other quoted
72
+ facts remain ordinary evidence. Concept words in origins are excluded. Source IDs, legacy
73
+ labels and cwd have no authority bonus.
74
+
75
+ Current-focus coverage must be >=45%; at least 3 focus features still require 2 matches.
76
+ A single match cannot qualify alongside unknown non-attribute words. All explicit literal
77
+ constraints must match, including qualified paths rather than only shared basenames.
78
+ Supporting context contributes at 0.35 weight and cannot replace current-focus evidence.
79
+ Named context subject features must match; a concept-only contextual subject needs 60%
80
+ weighted subject coverage. Generic attributes are not subject anchors. Evidence gets mild
81
+ length normalization `0.8 + 0.2 * min(1, 12 / max(1, bodyFeatureCount))`. This cannot bypass
82
+ the subject/coverage gates. Scores below 75% of the best eligible result are rejected.
83
+ After these relevance gates, scores are multiplied by separate evidence/freshness/feedback
84
+ factors; pin/date/ID break remaining ties. These are policy weights, not truth probabilities.
85
+ Short queries with one nonnumeric named subject and explicit attributes require both, with
86
+ generic status/progress excluded from the mandatory-attribute check. Explicit origin names
87
+ can still help a named-origin query; attributes require body/alias evidence. Facet redundancy is tracked per origin **and kind**,
88
+ so a project-state mention cannot suppress a factual/preference answer. Exact same-content
89
+ same-origin duplicates are still removed, and distinct origins remain separate.
90
+ There is **no arbitrary recency fallback** or minimum result count.
91
+
92
+ One evaluation provides selection and bounded diagnostics. `/memory explain` shows the
93
+ last automatic snapshot, including actual digest count/bytes; `/memory explain <query>`
94
+ previews an explicit query without user-history inheritance. Snapshots hold normalized
95
+ focus/context (up to 32 features each), lifecycle counts and up to 10 scored candidates
96
+ (up to 16 matched features each), with no memory bodies. Serialized diagnostics are
97
+ sanitized/capped at 8,000 bytes plus an ellipsis, held only in the extension instance,
98
+ replaced on every automatic attempt (including empty/error), and never persisted as
99
+ learning input. Selection is not a guarantee of model understanding.
100
+
101
+ These are precision-oriented heuristics, not semantic verification or universal
102
+ translation. Word segmentation can vary with the runtime's ICU version; uncommon
103
+ languages, short/ambiguous queries and unannotated old records may still be missed.
104
+
105
+ The digest contains at most 3 claims within 2,048 UTF-8 bytes, with historical-data trust
106
+ guidance reserved first and an explicit warning that selected matches are not the complete
107
+ inventory. Each JSON row includes ID, kind, status, origin, source ID,
108
+ stored update date, evidence basis/method, aging warning, optional explicit accuracy
109
+ assessment and a matching excerpt of up to 400 bytes. The source label uses the current
110
+ evidence source when known (including manual corrections), otherwise the original source ID. Oversized metadata labels
111
+ are clipped with an ellipsis/hash suffix. Origins are provenance hints, not evidence
112
+ that another project's fact applies here. Identical content is deduplicated only within
113
+ one origin: equal port/path text from different contexts can mean different facts.
114
+
115
+ Forgotten/conflicted claims never recall. Unpinned project-state claims expire from recall
116
+ after 7 days; facts/preferences/decisions have no automatic age deletion. All kinds have
117
+ bounded gradual freshness decay, with separate half-lives/floors and pin exemption.
118
+ Pin/unpin, legacy annotation, explicit feedback and conflict resolution preserve the evidence
119
+ date, and undo restores the prior date. Event history separately records when an operation occurred.
120
+
121
+ See [core-quality.md](core-quality.md) for the evidence contract, exact ranking policy,
122
+ weaker-replacement guard, replay-safe feedback and read-only mid-task `memory_recall` tool.
123
+ Neither automatic injection nor tool lookup is counted as evidence/usefulness feedback.
124
+
125
+ ## Completed-work observations
126
+
127
+ The old cue/compaction-only input loop could retain “not committed” even when a normal
128
+ work turn later committed/pushed: that turn was never an evolution source.
129
+ `progress-observation.ts` requires a work request, linked call/result IDs, and at least
130
+ one recognized work operation. It scans up to 4096 current-turn messages, retains at most
131
+ 8 observations by operation importance, and preserves chronological order. Commit/push
132
+ and test/process results outrank late routine inspection. Each stored operation <=1024
133
+ bytes, output <=2048 bytes; serialized evidence including request/report, bounded resource
134
+ hints and omitted-count/completion flags stays <=28,000 bytes. Head/tail previews preserve
135
+ failure endings. Internal memory tools and observations referencing the owned state directory
136
+ are excluded. An error/aborted final response uses `completion=interrupted` and no assistant
137
+ report: observed operations are evidence, not proof the entire task finished.
138
+
139
+ `memory/progress-targets.ts` separately nominates at most 8 active, unpinned project
140
+ states using user topics and explicit operation resources. It does not use answer-recall
141
+ literal gates, per-path top-2, relative cutoffs or facet deduplication. Explicit cd/git -C
142
+ and real checkout roots from file operations can match qualified paths or explicit bare
143
+ project names; capture origin alone supplies no evidence. Pending states receive nomination
144
+ priority. Conflicting absolute paths of the same basename cannot qualify through a topic
145
+ fallback. States expired from ordinary recall may receive new evidence, without reviving
146
+ forgotten/conflicted records. Tool output cannot nominate targets. No tracked related state means no call. `progress` sources are not parsed as local
147
+ summary claims: the model must return `project_state` plus `replaces` naming an eligible
148
+ host-nominated ID. Store guards enforce these restrictions even for a malformed model
149
+ batch. No new preference/fact, unrelated target or cross-origin overwrite is allowed.
150
+ The prompt requires evidence for each outcome and warns that commit/test success is not
151
+ push success, assistant reports are not proof, and failures/unfinished clauses must
152
+ remain. Outputs stay **provisional**: this is not independent success verification.
153
+
154
+ One qualified work source may add one background call. A mixed statement/work turn can
155
+ add a separate user-source call, serialized with progress to retain their distinct authority.
156
+ There is no assistant-only/ordinary-chat polling or startup transcript replay. Interrupted
157
+ work that was durably captured can recover with the existing retry mechanism. Hard kills
158
+ before agent_end, unknown commands and sources outside the scan/selection budgets remain
159
+ limits; there is no new disk-backed per-tool work journal. `/memory learning` reports
160
+ capture/nomination decisions, while status/history expose processed-versus-changed outcomes.
161
+ See [progress-pipeline.md](progress-pipeline.md) for policy details and validation.
162
+ Existing stale records are not guessed complete on upgrade. New observations/compactions
163
+ can retire them; exact-ID correction remains available. An incorporated new observation
164
+ may refresh an unchanged pending state's evidence date. Alias-only enrichment cannot.
165
+
166
+ ## Model boundary and conservative writes
167
+
168
+ `adapter/pi-api.ts` calls Pi 0.85's public
169
+ `ctx.modelRegistry.complete(ctx.model, context, options)`, preserving model/provider/auth
170
+ resolution. Model identity is captured before awaiting completion, so switching models
171
+ or invalidating a context cannot mislabel provenance. No credentials are copied to state.
172
+
173
+ Each input contains a sanitized source (at most 32,000 bytes) and up to 32 recently updated
174
+ active claims **from that source origin**, each capped at 1,440 bytes. This deliberately
175
+ limits automatic replacement authority, **not recall eligibility**. One origin can cover
176
+ multiple projects. The prompt requires an explicitly identifiable same subject/fact and
177
+ preservation of project/resource qualifications; matching cwd alone is not identity.
178
+
179
+ Output is validated JSON (an outer Markdown fence is tolerated), at most 64,000 bytes
180
+ and 16 claims of 4–480 UTF-16 code units each. Fields are restricted to `kind`, `content`,
181
+ optional `replaces` and `searchTerms`. Aliases are at most 8 sanitized strings of 2–64
182
+ characters, with total JSON <=1024 bytes. Malformed claims/aliases reject the batch.
183
+ The prompt asks for concise Chinese/English aliases, never added facts. Existing text
184
+ can gain aliases without changing its provenance/evidence date; correction clears stale
185
+ aliases and undo restores the actual prior metadata. Unknown, cross-origin, pinned,
186
+ stale, duplicate-target and cyclic replacements are rejected transactionally. Only normal
187
+ `stop` completion is accepted, never truncated/tool/error output. Model paths are not
188
+ used for file operations, and model claims remain `provisional`, not awaiting approval. Host-assigned evidence types
189
+ cannot be supplied by model output. A weaker proposed replacement is withheld; only that
190
+ source's new variant is quarantined and recorded, never an unrelated existing stronger claim.
191
+ A fresh explicit user statement or linked project-state tool observation can still supersede
192
+ older evidence. Unsupported semantic contradictions without a model `replaces` link are
193
+ not detected globally.
194
+
195
+ Each attempt uses at most one model call, no tools, an 8,192-output-token cap (clamped
196
+ against a smaller model limit), a fresh request session ID and `cacheRetention: "none"`.
197
+ A 120-second outer deadline bounds waiting
198
+ even when a provider ignores abort; remote computation/billing cannot be guaranteed to
199
+ stop. Failed calls retain local summary claims. User-cue prose is saved but needs a
200
+ successful model attempt to become claims; it has no local extraction fallback.
201
+
202
+ Global recall is **not global rewriting**. Cross-origin variants remain separate instead
203
+ of guessing which project they describe. Exact-ID correction/forget works from any
204
+ session, affecting the target and exact duplicates within its origin, not identical text
205
+ from unrelated origins. Suppression hashes and same-origin conflict controls retain that
206
+ boundary. Some truly equivalent cross-origin corrections will consequently coexist;
207
+ explicit controls are available without becoming approval gates for automatic learning.
208
+
209
+ ## Persistence and lifecycle
210
+
211
+ One SQLite database, WAL + FULL synchronous mode and private file permissions.
212
+ `sqlite.ts` selects built-in Bun or Node SQLite, with no external database dependency.
213
+
214
+ - `memories`: claims, optional search aliases, revision/status/layer, source ID, capture origin (`scope`) and hash;
215
+ optional `suppressedHashes` carries correction history through legacy annotation;
216
+ optional host-assigned `evidence` and last explicit utility/accuracy `feedback` describe
217
+ provenance and user assessments, never model-generated confidence.
218
+ - `sources`: sanitized evidence and durable job state/lease/attempt, consecutive failure
219
+ count, next retry timestamp, last failure timestamp and a fixed error category;
220
+ `progress` evidence additionally carries a bounded, unique target-ID list.
221
+ - `blocked`: origin-qualified exact-content hashes for forgotten/superseded claims.
222
+ - `events`: actual before/after states, actor, operation timestamp and source/model reason.
223
+ - `feedback_receipts`: exact source-ID/memory-ID idempotency keys, verdict and numeric
224
+ timestamp, including redundant/late feedback receipts; undo never reopens them.
225
+ - `metadata`: schema/import marker.
226
+
227
+ The `scope` field records canonical cwd, not an inferred repository/branch/subject identity
228
+ (or an explicit annotation of a legacy record). It is no longer a recall boundary. Reads
229
+ are cached globally or for an explicitly requested origin, invalidated by local commits
230
+ and SQLite `data_version` across connections. New IDs hash a JSON tuple of origin/kind/
231
+ content; existing IDs remain valid. Low-level origin filters are exact, including literal
232
+ `*` values; automatic recall uses the unfiltered reader.
233
+
234
+ Batches use `BEGIN IMMEDIATE`; no transaction spans network I/O. Source-origin generation
235
+ and job attempt are checked before completion can commit. A lease lasts the attempt
236
+ budget plus 30 seconds (150 seconds by default), preventing another process from stealing
237
+ work at the old 60-second boundary. The timer converts expired leases to an `interrupted`
238
+ failure with backoff; attempt/state checks prevent late results or failures from changing
239
+ a new owner's job. Model waiting and recurring recovery use the same serial task chain;
240
+ queued capture/manual work prevents the timer from piling up duplicate tasks.
241
+
242
+ Automatic selection/claim both enforce persisted due time and failure budget, ordered by
243
+ retry time then oldest source. Each actual failure schedules 1 minute, 5 minutes, 15 minutes,
244
+ then 1 hour of backoff. Five consecutive failures pause that source with a warning and
245
+ status diagnostics; repeated crashes also consume the budget. Shutdown cancellation does
246
+ not. Successful completion resets the failure fields. Other eligible work continues;
247
+ there is no unbounded per-source model loop. `/memory evolve` selects one newest eligible
248
+ source and can override the delay/cap for one explicit attempt (not reset the budget).
249
+ Completed/retired jobs are never forced to run again. A source resumed in another directory
250
+ retains its original provenance. While Pi is closed no polling occurs.
251
+
252
+ Only allowlisted error codes are persisted, never exception strings, provider error bodies,
253
+ model response text or credentials. Stage categories distinguish provider/unavailable,
254
+ output limit, invalid output, write rejection, stale output, timeout and interrupted work.
255
+ Status reports retrying/paused counts and up to five failed-job details with next due times;
256
+ normal structural validation is still separate from model/job health.
257
+
258
+ Capture is idempotent. Raw summaries are evidence only, never a parent recall fallback.
259
+ Exact forgotten content cannot be re-added within its origin under another source/kind.
260
+ Suppression also retires known repeating pending/failed sources, including formatted
261
+ claims beyond the normal 16-claim ingestion quota, except the current valid replacement
262
+ transaction's source. This conservatively skips the whole source's pending model pass;
263
+ unrelated local claims remain, but unlearned prose may need a new source.
264
+
265
+ Memory reads validate indexed identity/origin/hash against JSON. Undo validates paired,
266
+ unique before/after IDs and only succeeds when the current records still equal the event's
267
+ after state. New records become tombstones rather than being physically erased. Status
268
+ also validates source jobs/history and the schema marker. Unsupported schema versions
269
+ are rejected before DDL. Schemas 2/3/4 upgrade transactionally to 5 without rewriting
270
+ claims/history or resetting evidence timestamps; missing retry columns/indexes and the
271
+ feedback receipt table are added. Old evidence metadata stays absent/unknown.
272
+ Old failures below the cap are due immediately, with unknown cause/time explicitly labeled.
273
+ The source/alias/retry contract is validated on read.
274
+ These detect structural corruption, not all well-formed edits by an owner of the database.
275
+ Undo does not clear suppression hashes or reopen jobs. Forget/undo is not secure erasure.
276
+
277
+ ## Existing data and commands
278
+
279
+ Earlier 0.2 SQLite records, IDs, histories and origin labels stay intact and become
280
+ eligible for global relevance-based recall, including existing `legacy` claims. The
281
+ schema-2/3/4-to-5 upgrade requires no data copying, JSONL re-import or manual reset.
282
+ Stop/back up before upgrading, reload all processes sharing the DB, and restore a matching
283
+ backup for rollback; older code must not be pointed at a manually downgraded marker.
284
+
285
+ Original JSONL memory/action ledgers are imported once, without rewriting originals.
286
+ Invalid JSON/actions halt import rather than losing corrections or reviving forgotten
287
+ facts. Parent corrections preserve unchanged children and derive new facts without
288
+ reintroducing explicitly suppressed child content. Missing origins retain the `legacy`
289
+ label. Adoption is an optional annotation, not a recall prerequisite. Completed imports
290
+ are not replayed; earlier discarded revision information is not automatically reconstructed.
291
+ Old signals/proposals/execution plans remain historical files, never automatic actions.
292
+
293
+ List defaults to all origins, 20 per page sorted by update time then ID; `all` is an alias.
294
+ `here` and `legacy` are optional inspection filters, not recall settings. Search uses only
295
+ its explicit query and returns up to 10 global recallable matches. History shows the latest
296
+ 10 global events. `show` includes provenance. Status identifies capture origin and global
297
+ recall mode. There is no full export command; concurrent writes can shift page boundaries.
298
+
299
+ ## Validation and limits
300
+
301
+ Temporary-directory tests cover lifecycle sequences, real SQLite multi-process writes,
302
+ replay/migration/corruption/undo/timeout, global recall, topic switching, weak matches,
303
+ context tails, provenance and cross-origin write guards. The real-Pi RPC test uses a
304
+ loopback fake OpenAI-compatible model: two automatic updates in one directory, then a
305
+ fresh Pi process/session in another directory to verify recall, contextual follow-ups,
306
+ topic changes, bilingual aliases and exact-ID forget. A real temporary Git repository
307
+ also exercises commit success + push failure through actual tool events and the
308
+ constrained progress-update path. It also verifies model/auth reuse, no approval, startup
309
+ recovery of persisted failures, and recovery after malformed model output via the real
310
+ 15-second timer without user activity. Unit tests cover persisted backoff/caps, migration
311
+ from the actual schema-3 table shape, long leases, competing owners, cancellation, timeout,
312
+ late results, suppressed sources, backlog draining, and fixed-code diagnostics.
313
+ The [quality validation record](quality-validation.md) records the three-issue follow-up
314
+ and distinguishes synthetic/real-host checks from real-data read-only replay.
315
+
316
+ Model inference and sanitization are not perfect. Provisional labels, pin/correct/undo
317
+ are recovery controls, not proof of truth. Lexical matching can miss semantic or cross-
318
+ language equivalence. Missing retained user context after compaction can leave a vague
319
+ follow-up unresolved. Cross-origin semantic identity is not inferred reliably. This is
320
+ one user's agent database, not a multi-user access-control boundary. Raw evidence/history
321
+ grows until deliberately managed; no automatic purge or physical secret erasure is claimed.
322
+ Background model usage is not added to Pi's normal session token accounting.
323
+
324
+ Node/npm development requires 22.19+ to match Pi 0.85's engine; the standalone Bun host is
325
+ also tested. There is no installed GitHub Actions workflow: `npm run check` and
326
+ `npm run test:pi` run locally. Fake-provider validation is not live-provider accuracy or a
327
+ multi-day TUI trial. See [README.md](../README.md) for commands/recovery, and the historical
328
+ [follow-up review](review-0.2.md) for previously reproduced defects and validation limits.