@oortmem/core 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/model.d.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import type { Address, Author, Provenance } from './address.js';
2
- export type MemoryType = 'semantic' | 'episodic' | 'procedural' | 'preference';
2
+ import type { Judgment } from './judgment.js';
3
+ /**
4
+ * `judgment` (CON-71) is an expert's recorded decision: written only through the explicit
5
+ * judgment path (`recordJudgment`), never by the write path's gate or writer, and always with a
6
+ * `judgment` record next to the text.
7
+ */
8
+ export type MemoryType = 'semantic' | 'episodic' | 'procedural' | 'preference' | 'judgment';
9
+ /** The types the write path (gate and writer) can give a memory: every type but `judgment`. */
10
+ export type ObservedMemoryType = Exclude<MemoryType, 'judgment'>;
3
11
  export type Tier = 'hot' | 'warm' | 'cold';
4
12
  /**
5
13
  * The pre-level view of where a memory lives. For a Planet memory (every
@@ -73,6 +81,11 @@ export interface Memory {
73
81
  supersedes: string | null;
74
82
  supersededBy: string | null;
75
83
  source: MemorySource;
84
+ /**
85
+ * The expert's decision, verbatim, on a `judgment` memory (CON-71); absent on every other type.
86
+ * `text` is a rendering of it for recall; this record is what judging reads.
87
+ */
88
+ judgment?: Judgment;
76
89
  embedding?: Int8Array;
77
90
  createdAt: string;
78
91
  updatedAt: string;
package/dist/observe.js CHANGED
@@ -84,7 +84,9 @@ async function candidatesFor(store, text, v, grant, now) {
84
84
  const out = [];
85
85
  for (const id of ids) {
86
86
  const m = await store.get(grant, id);
87
- if (m !== null && isLive(m, now))
87
+ // A judgment (CON-71) is the expert's own words: the write path never refines, supersedes or
88
+ // corrects one. Only the judgment commands change it.
89
+ if (m !== null && isLive(m, now) && m.type !== 'judgment')
88
90
  out.push(m);
89
91
  if (out.length === CANDIDATES)
90
92
  break;
package/dist/recall.d.ts CHANGED
@@ -31,6 +31,8 @@ export interface RecallQuery {
31
31
  * or `knownAt`, the mode is read from the query ("on 2 April", "how has … changed").
32
32
  */
33
33
  mode?: RecallMode;
34
+ /** Also return withdrawn judgments (CON-71), in any mode. Default false. */
35
+ includeWithdrawn?: boolean;
34
36
  }
35
37
  /** The temporal view a recall used, and whether it was read from the query. */
36
38
  export interface RecallTemporal {
package/dist/recall.js CHANGED
@@ -31,6 +31,8 @@ export async function recall(q, deps) {
31
31
  // Scrub once: the query text reaches embedders and rerankers, which may be remote. Temporal
32
32
  // words ("on 2 April", "changed over time") pick the view and are not searched for.
33
33
  const { view, temporal, text } = viewFor(q, scrub(q.text).text, now);
34
+ if (q.includeWithdrawn === true)
35
+ view.includeWithdrawn = true;
34
36
  const t0 = clock();
35
37
  const degraded = [];
36
38
  const timings = {
@@ -727,6 +727,35 @@ function levelConformance(name, make) {
727
727
  });
728
728
  expect(authorOf(got)).toEqual({ agentId: 'claude-code' });
729
729
  });
730
+ it('levels.judgment-roundtrips', async () => {
731
+ // CON-71: a judgment memory keeps its `judgment` record exactly, cold copy included.
732
+ const m = makeMemory({
733
+ id: 'judgment-1',
734
+ scope: localScope(undefined),
735
+ type: 'judgment',
736
+ pinned: true,
737
+ embedding: vec(4, 3, 2, 1),
738
+ judgment: {
739
+ subject: { summary: 'Post claims a cure', ref: 'https://example.test/p/1' },
740
+ verdict: 'rejected',
741
+ verdicts: ['approved', 'rejected'],
742
+ reason: 'No cited source.\nSecond line, verbatim.',
743
+ criteria: ['no-source'],
744
+ domain: 'content',
745
+ by: 'ada',
746
+ decidedAt: '2026-01-01T00:00:00.000Z',
747
+ via: 'cli',
748
+ withdrawn: { at: '2026-02-01T00:00:00.000Z', by: 'ada' },
749
+ },
750
+ });
751
+ await store.upsert(TG, m);
752
+ expect(await store.get(TG, 'judgment-1')).toEqual(m);
753
+ const plain = makeMemory({ id: 'plain-1', scope: localScope(undefined) });
754
+ await store.upsert(TG, plain);
755
+ expect('judgment' in (await store.get(TG, 'plain-1'))).toBe(false);
756
+ expect((await store.coldPut(TG, m)).skipped).toEqual([]);
757
+ expect(await store.coldGet(TG, 'judgment-1')).toEqual(m);
758
+ });
730
759
  it('levels.every-level-roundtrips', async () => {
731
760
  for (const c of cases()) {
732
761
  await store.upsert(c.g, c.m);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oortmem/core",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Oort core: the tiered hot, warm and cold memory engine for AI agents (types, scoring, recall, consolidation).",
5
5
  "keywords": [
6
6
  "oort",