@avantf/dsh-mem 0.9.0 → 0.10.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.
@@ -74,6 +74,25 @@ export type StatusFilter = (typeof STATUS_FILTERS)[number];
74
74
  * SEARCH query shares the bound because it is compared against the stored title with `=`/`LIKE`.
75
75
  */
76
76
  export declare const TITLE_MAX_CHARS = 120;
77
+ /**
78
+ * ── TWO KINDS OF TIME, TWO SHAPES (the "记忆时间显示不对" fix) ────────────────────────────────────
79
+ *
80
+ * Every INSTANT in a payload (`created_at`, `updated_at`, `archived_at`, `pinned_at`,
81
+ * `last_reinforced_at`, `bonus_window_at`, `detected_at`, the health stamp) is an ISO-8601 instant
82
+ * **with an explicit offset in the host's local zone** — `2026-10-28T19:58:48+08:00` — produced by
83
+ * `@avantf/mem-contract/time`'s `formatOffsetIso`. Storage is unchanged (SQLite `CURRENT_TIMESTAMP`
84
+ * is UTC, and the `facts_io` export/import/snapshot document keeps the SQLite text), so this is a
85
+ * RENDERING rule, not a storage one: the model gets an unambiguous instant it never has to convert,
86
+ * and a UI can `Date.parse` it directly.
87
+ *
88
+ * `event_date` / `valid_from` is the OTHER kind: a calendar DATE the caller wrote (`2026-10-28`),
89
+ * with no time and no zone. It is never passed through the instant renderer, and the two must not be
90
+ * confused: `created_at` answers "when was this recorded", `event_date` answers "as of which day is
91
+ * this true".
92
+ *
93
+ * A UI that shows these to a human formats them through `formatLocalHuman` (the same module): local
94
+ * wall clock to the minute, `2026-10-28 19:58`.
95
+ */
77
96
  export interface FactSummary {
78
97
  fact_id: number;
79
98
  content: string;
@@ -95,8 +114,15 @@ export interface FactSummary {
95
114
  pinned: boolean;
96
115
  /** Remaining ACTIVE days before `forgot`; null when pinned / non-active / trust disabled. */
97
116
  remaining_days: number | null;
117
+ /**
118
+ * @deprecated No writer since `helpful` / `unhelpful` were removed (2026-10-28). The column stays
119
+ * because it is part of the export/import/snapshot format, so an old document still round-trips;
120
+ * the value is whatever the row last carried. Do not build new logic on it.
121
+ */
98
122
  helpful_count: number;
123
+ /** When the memory was first recorded — an INSTANT, ISO-8601 with the host's offset. */
99
124
  created_at: string;
125
+ /** When it was archived — an INSTANT (ISO-8601 with offset), `null` while active. */
100
126
  archived_at: string | null;
101
127
  archive_reason: string | null;
102
128
  }
@@ -152,15 +178,21 @@ export interface FactDetail extends FactSummary {
152
178
  relations: FactRelation[];
153
179
  /** Active-day clock value at the last settle. */
154
180
  settle_clock: number;
181
+ /** When it was pinned — an INSTANT (ISO-8601 with offset), `null` when never pinned. */
155
182
  pinned_at: string | null;
183
+ /** When trust was last raised by a recall — an INSTANT (ISO-8601 with offset). */
156
184
  last_reinforced_at: string | null;
157
185
  /**
158
186
  * When this row was last CHANGED (edit/pin/unpin/reinforce/archive/restore). Retrieval and the
159
187
  * daily settle do not write it, so it is not `last_retrieved_at`; `null` on a legacy row.
188
+ *
189
+ * An INSTANT (ISO-8601 with the host's offset) — compare it with `created_at`, never with
190
+ * `valid_from`, which is a calendar date.
160
191
  */
161
192
  updated_at: string | null;
162
193
  /** Effective reinforcement events in the current 24h window (recall + feedback). */
163
194
  bonus_count: number;
195
+ /** Start of that window — an INSTANT (ISO-8601 with offset), `null` when no window is open. */
164
196
  bonus_window_at: string | null;
165
197
  /**
166
198
  * P-08: where this fact came from, as recorded rows. Empty when the writer gave no `source_ref`
@@ -168,12 +200,13 @@ export interface FactDetail extends FactSummary {
168
200
  */
169
201
  sources: FactSourceView[];
170
202
  /**
171
- * P-07: when the fact became true / stopped being true. `null` = unknown; `valid_to` set while
172
- * the row is still `active` means "still valid, known to end at T" (the state
173
- * `mem_remember valid_until` creates), while an archived row's `valid_to` is an audit stamp.
203
+ * P-07/P-13: when the fact became true (the caller's `event_date`) — a CALENDAR DATE
204
+ * (`YYYY-MM-DD`), with no time and no zone, exactly as the caller wrote it. `null` = unknown. It is
205
+ * the `event` time axis — NOT a validity window: v2 removed the "known end" (`valid_until`)
206
+ * entirely, so "this is no longer true" is expressed by `update` or `archive`, never by a deadline
207
+ * field. Do not compare it with `created_at`/`updated_at`: those are instants.
174
208
  */
175
209
  valid_from: string | null;
176
- valid_to: string | null;
177
210
  /**
178
211
  * P-07: the fact that supersedes this one, DERIVED from the existing `supersedes_id` link
179
212
  * (reverse lookup) — no redundant column. `null` when nothing supersedes it.
@@ -203,12 +236,15 @@ export interface RecallHit {
203
236
  * When this hit was first recorded: a fact's revision chain keeps the ORIGINAL row's
204
237
  * `created_at` across a supersede (`mem_remember update`), so this is when the memory was
205
238
  * first asserted, not when its current text was written (see `updated_at`).
239
+ *
240
+ * An INSTANT: ISO-8601 with the host's explicit offset (`2026-10-28T19:58:48+08:00`), so no
241
+ * conversion is needed and it can never be mistaken for `valid_from`'s calendar date.
206
242
  */
207
243
  created_at: string;
208
244
  /**
209
245
  * When this row was last CHANGED — an edit, pin/unpin, reinforcement, archive or restore.
210
246
  * Retrieval and the daily settle deliberately do not write it, so it never means "last
211
- * retrieved"; a copy can carry `null` on a legacy row.
247
+ * retrieved"; a copy can carry `null` on a legacy row. An INSTANT (ISO-8601 with offset).
212
248
  */
213
249
  updated_at: string | null;
214
250
  /**
@@ -235,12 +271,16 @@ export interface RecallHit {
235
271
  */
236
272
  final?: number;
237
273
  /**
238
- * P-07/P-13: the fact's event time / known end, serialized ONLY when non-null (the same
239
- * convention as {@link RecallHit.truncated}). `null` means "unknown", and omitting the key keeps
240
- * every pre-P-07 envelope byte-identical. Both are display/audit only — no leg filters on them.
274
+ * P-07/P-13: the fact's event time, serialized ONLY when non-null (the same convention as
275
+ * {@link RecallHit.truncated}). `null` means "unknown", and omitting the key keeps every pre-P-07
276
+ * envelope byte-identical. Display only — no leg filters on it.
277
+ *
278
+ * A CALENDAR DATE (`YYYY-MM-DD`), not an instant: the caller wrote it, it has no time and no zone,
279
+ * and it is deliberately NOT rendered in the host's zone. `created_at`/`updated_at` on the same
280
+ * hit are instants with an offset — the two answer different questions ("as of which day is this
281
+ * true" vs "when was it recorded").
241
282
  */
242
283
  valid_from?: string;
243
- valid_to?: string;
244
284
  /**
245
285
  * The fact's title, when it has one (journal entries normally do, notes usually do not).
246
286
  *
@@ -277,9 +317,14 @@ export interface TitleCandidate {
277
317
  matched_title: string;
278
318
  memory_kind: MemoryKind;
279
319
  status: FactStatus;
320
+ /** When the memory was first recorded — an INSTANT (ISO-8601 with the host's offset). */
280
321
  created_at: string;
322
+ /** When it was last changed — an INSTANT (ISO-8601 with offset), `null` when never revised. */
281
323
  updated_at: string | null;
282
- /** The fact's event time (`valid_from`), when it has one — the journal axis that tells two entries apart. */
324
+ /**
325
+ * The fact's event time (`valid_from`), when it has one — the journal axis that tells two entries
326
+ * apart. A CALENDAR DATE (`YYYY-MM-DD`), never an instant: `created_at` is the instant.
327
+ */
283
328
  event_date?: string;
284
329
  /** The first characters of the content, for judging "same transaction or not"; absent when `include_excerpt` is false. */
285
330
  excerpt?: string;
@@ -380,7 +425,9 @@ export interface RelationEvidence {
380
425
  /** The memory layer, so a caller knows whether it is reading a journal or a note. */
381
426
  memory_kind: MemoryKind;
382
427
  title?: string;
428
+ /** When the memory was first recorded — an INSTANT (ISO-8601 with the host's offset). */
383
429
  created_at: string;
430
+ /** When it was last changed — an INSTANT (ISO-8601 with offset), `null` when never revised. */
384
431
  updated_at: string | null;
385
432
  /** Set when the output budget shortened `text` (never when the evidence itself was dropped). */
386
433
  truncated?: boolean;
@@ -447,9 +494,11 @@ export interface FactEvidence {
447
494
  /** `active` for every row this stage returns; carried so the field is explicit, not implied. */
448
495
  status: FactStatus;
449
496
  title?: string;
450
- /** The fact's event time (`valid_from`), when it has one. */
497
+ /** The fact's event time (`valid_from`) — a CALENDAR DATE (`YYYY-MM-DD`), when it has one. */
451
498
  event_date?: string;
499
+ /** When the memory was first recorded — an INSTANT (ISO-8601 with the host's offset). */
452
500
  created_at: string;
501
+ /** When it was last changed — an INSTANT (ISO-8601 with offset), `null` when never revised. */
453
502
  updated_at: string | null;
454
503
  /** Set when the output budget shortened `content` (never when the fact itself was dropped). */
455
504
  truncated?: boolean;
@@ -602,6 +651,7 @@ export interface ContradictionRecord {
602
651
  fact_a: number;
603
652
  fact_b: number;
604
653
  score: number;
654
+ /** When the pair was detected — an INSTANT (ISO-8601 with the host's offset). */
605
655
  detected_at: string;
606
656
  content_a: string;
607
657
  content_b: string;
@@ -695,6 +745,7 @@ export interface RetrievalHealthSummary {
695
745
  legs_capped: number;
696
746
  /** Candidates removed by a leg's relevance floor (see `RetrievalHealth`). */
697
747
  candidates_dropped_by_floor: number;
748
+ /** When a counter last moved — an INSTANT (ISO-8601 with the host's offset), `null` before any. */
698
749
  updated_at: string | null;
699
750
  by_kind: Record<string, KindHealth>;
700
751
  }
@@ -788,7 +839,6 @@ export interface TrustDiagnostic {
788
839
  forgetting_soon: number;
789
840
  reinforced_today: number;
790
841
  bonus_granted_today: number;
791
- idle_candidates: number;
792
842
  archived_by_reason: Record<string, number>;
793
843
  oldest_settle_clock: number | null;
794
844
  /**