@oscharko-dev/keiko-memory-governance 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.
- package/dist/.tsbuildinfo +1 -0
- package/dist/conflict.d.ts +9 -0
- package/dist/conflict.d.ts.map +1 -0
- package/dist/conflict.js +236 -0
- package/dist/correction.d.ts +17 -0
- package/dist/correction.d.ts.map +1 -0
- package/dist/correction.js +69 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/forget.d.ts +5 -0
- package/dist/forget.d.ts.map +1 -0
- package/dist/forget.js +142 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/maintenance.d.ts +33 -0
- package/dist/maintenance.d.ts.map +1 -0
- package/dist/maintenance.js +180 -0
- package/dist/retention.d.ts +5 -0
- package/dist/retention.d.ts.map +1 -0
- package/dist/retention.js +54 -0
- package/dist/status-ops.d.ts +6 -0
- package/dist/status-ops.d.ts.map +1 -0
- package/dist/status-ops.js +86 -0
- package/dist/suppression.d.ts +11 -0
- package/dist/suppression.d.ts.map +1 -0
- package/dist/suppression.js +85 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +32 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +1 -0
- package/package.json +31 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Retrieval-suppression predicate.
|
|
2
|
+
//
|
|
3
|
+
// isMemorySuppressedFromRetrieval is a pure function consumed by the retrieval layer
|
|
4
|
+
// (#210) to filter result sets. It maps the discriminated MemoryStatus enum to a
|
|
5
|
+
// suppression reason and also applies two derived rules:
|
|
6
|
+
//
|
|
7
|
+
// - validity.validUntil <= nowMs → "expired" (regardless of status)
|
|
8
|
+
// - provenance.confidence <= staleConfidenceThreshold → "stale-low-confidence"
|
|
9
|
+
//
|
|
10
|
+
// Default staleConfidenceThreshold is 0.3 — same conservative floor consolidation uses
|
|
11
|
+
// (#208 _constants.ts STALE_CONFIDENCE_DEFAULT 0.3) so the two layers agree on what
|
|
12
|
+
// counts as low-confidence. The threshold is a `<=` comparison: a record exactly at
|
|
13
|
+
// the threshold is suppressed.
|
|
14
|
+
//
|
|
15
|
+
// The contracts MemoryStatus enum is the single source of truth: every legal status
|
|
16
|
+
// branches to a deterministic suppression decision. A future widening of MemoryStatus
|
|
17
|
+
// surfaces as an exhaustiveness compile error here.
|
|
18
|
+
import { GovernanceError } from "./errors.js";
|
|
19
|
+
const DEFAULT_STALE_CONFIDENCE_THRESHOLD = 0.3;
|
|
20
|
+
const NOT_SUPPRESSED = { suppressed: false };
|
|
21
|
+
function isFiniteInRange(value, min, max) {
|
|
22
|
+
return Number.isFinite(value) && value >= min && value <= max;
|
|
23
|
+
}
|
|
24
|
+
function resolveThreshold(options) {
|
|
25
|
+
const threshold = options.staleConfidenceThreshold ?? DEFAULT_STALE_CONFIDENCE_THRESHOLD;
|
|
26
|
+
if (isFiniteInRange(threshold, 0, 1))
|
|
27
|
+
return threshold;
|
|
28
|
+
throw new GovernanceError("invalid-threshold", `staleConfidenceThreshold must be a finite number in [0, 1] (got ${String(threshold)})`);
|
|
29
|
+
}
|
|
30
|
+
function statusSuppression(status) {
|
|
31
|
+
switch (status) {
|
|
32
|
+
case "archived":
|
|
33
|
+
return { suppressed: true, reason: "archived" };
|
|
34
|
+
case "forgotten":
|
|
35
|
+
return { suppressed: true, reason: "forgotten" };
|
|
36
|
+
case "conflicted":
|
|
37
|
+
return { suppressed: true, reason: "conflicted" };
|
|
38
|
+
case "rejected":
|
|
39
|
+
return { suppressed: true, reason: "rejected" };
|
|
40
|
+
case "expired":
|
|
41
|
+
// Validity-based "expired" is checked separately below so an explicit `expired`
|
|
42
|
+
// status carries the same surface reason whether the retrieval index pinned it via
|
|
43
|
+
// status or derived it from the validity window.
|
|
44
|
+
return { suppressed: true, reason: "expired" };
|
|
45
|
+
case "proposed":
|
|
46
|
+
return { suppressed: true, reason: "proposed" };
|
|
47
|
+
case "accepted":
|
|
48
|
+
case "superseded":
|
|
49
|
+
// accepted/superseded are pass-through here. Superseded records are still readable
|
|
50
|
+
// in audit views; the retrieval layer applies its own includeSuperseded toggle on
|
|
51
|
+
// top of this predicate. Review queues surface proposed records through direct
|
|
52
|
+
// status filtering rather than retrieval.
|
|
53
|
+
return null;
|
|
54
|
+
default: {
|
|
55
|
+
const _exhaustive = status;
|
|
56
|
+
void _exhaustive;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function validitySuppression(memory, nowMs) {
|
|
62
|
+
if (memory.validity.validUntil === undefined)
|
|
63
|
+
return null;
|
|
64
|
+
if (memory.validity.validUntil > nowMs)
|
|
65
|
+
return null;
|
|
66
|
+
return { suppressed: true, reason: "expired" };
|
|
67
|
+
}
|
|
68
|
+
function confidenceSuppression(memory, threshold) {
|
|
69
|
+
if (memory.provenance.confidence > threshold)
|
|
70
|
+
return null;
|
|
71
|
+
return { suppressed: true, reason: "stale-low-confidence" };
|
|
72
|
+
}
|
|
73
|
+
export function isMemorySuppressedFromRetrieval(memory, nowMs, options = {}) {
|
|
74
|
+
const threshold = resolveThreshold(options);
|
|
75
|
+
const byStatus = statusSuppression(memory.status);
|
|
76
|
+
if (byStatus !== null)
|
|
77
|
+
return byStatus;
|
|
78
|
+
const byValidity = validitySuppression(memory, nowMs);
|
|
79
|
+
if (byValidity !== null)
|
|
80
|
+
return byValidity;
|
|
81
|
+
const byConfidence = confidenceSuppression(memory, threshold);
|
|
82
|
+
if (byConfidence !== null)
|
|
83
|
+
return byConfidence;
|
|
84
|
+
return NOT_SUPPRESSED;
|
|
85
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ConversationId, MemoryId, MemoryReviewerId, MemoryScope, MemoryStatus, MemoryType } from "@oscharko-dev/keiko-contracts/memory";
|
|
2
|
+
export interface GovernanceContext {
|
|
3
|
+
readonly reviewerId: MemoryReviewerId;
|
|
4
|
+
readonly nowMs: number;
|
|
5
|
+
}
|
|
6
|
+
export type ForgetSelector = {
|
|
7
|
+
readonly kind: "by-id";
|
|
8
|
+
readonly memoryId: MemoryId;
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: "by-scope";
|
|
11
|
+
readonly scope: MemoryScope;
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: "by-type";
|
|
14
|
+
readonly scope: MemoryScope;
|
|
15
|
+
readonly type: MemoryType;
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: "by-source-conversation";
|
|
18
|
+
readonly scope: MemoryScope;
|
|
19
|
+
readonly sourceConversationId: ConversationId;
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: "by-time-window";
|
|
22
|
+
readonly scope: MemoryScope;
|
|
23
|
+
readonly olderThanMs: number;
|
|
24
|
+
};
|
|
25
|
+
export type ForgetSelectorKind = ForgetSelector["kind"];
|
|
26
|
+
export interface StatusTransition {
|
|
27
|
+
readonly memoryId: MemoryId;
|
|
28
|
+
readonly from: MemoryStatus;
|
|
29
|
+
readonly to: MemoryStatus;
|
|
30
|
+
readonly transitionedAt: number;
|
|
31
|
+
}
|
|
32
|
+
export type ConflictReason = "negation-flip" | "polarity-mismatch" | "value-mismatch";
|
|
33
|
+
export interface ConflictPair {
|
|
34
|
+
readonly hasConflict: boolean;
|
|
35
|
+
readonly reason?: ConflictReason;
|
|
36
|
+
}
|
|
37
|
+
export interface ConflictResolution {
|
|
38
|
+
readonly winner: MemoryId;
|
|
39
|
+
readonly losers: readonly MemoryId[];
|
|
40
|
+
}
|
|
41
|
+
export interface SelectMemoriesForForgetOptions {
|
|
42
|
+
readonly nowMs: number;
|
|
43
|
+
readonly protectPinned?: boolean;
|
|
44
|
+
readonly protectArchived?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface BuildForgetOperationsOptions {
|
|
47
|
+
readonly writeTombstone: boolean;
|
|
48
|
+
readonly reason?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare const FORGET_SELECTOR_KINDS: readonly ForgetSelectorKind[];
|
|
51
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,UAAU,EACX,MAAM,sCAAsC,CAAC;AAO9C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAWD,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACpF;IACE,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,cAAc,CAAC;CAC/C,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;AAOxD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAGD,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAEtF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC;AAMD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;CACtC;AAOD,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,4BAA4B;IAM3C,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAuBD,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAMrD,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Public type surface for @oscharko-dev/keiko-memory-governance (Epic #204 child #209).
|
|
2
|
+
// Pure types only — no IO, no clock, no randomness. Every function exported from this
|
|
3
|
+
// package consumes a `GovernanceContext` instead of reading the wall clock or generating
|
|
4
|
+
// a reviewer id internally; the caller (BFF route handler, MemoriaViva UI, workflow
|
|
5
|
+
// orchestrator) is the authoritative source of both.
|
|
6
|
+
// ─── Correction options ───────────────────────────────────────────────────────
|
|
7
|
+
// `buildCorrection` produces both a `correction`-type MemoryProposal AND a
|
|
8
|
+
// MemorySupersession linking the old MemoryId to the new one. The caller persists the
|
|
9
|
+
// proposal first (mint a new MemoryId at acceptance) and then applies the supersession
|
|
10
|
+
// once it knows the freshly-minted id.
|
|
11
|
+
//
|
|
12
|
+
// We require the caller to supply `newMemoryIdHint`: the supersession envelope needs the
|
|
13
|
+
// NEW memory id at construction time. The "correct" architecture would be a two-phase
|
|
14
|
+
// commit — propose, accept-and-mint, supersede — but a single function returning both
|
|
15
|
+
// envelopes is the operating contract #209 asks for. The hint is a placeholder that the
|
|
16
|
+
// caller MUST replace with the real minted id before sending the supersession to the
|
|
17
|
+
// audit ledger; the GovernanceError("supersession-needs-real-id") at the storage seam
|
|
18
|
+
// catches a caller that forgets.
|
|
19
|
+
//
|
|
20
|
+
// The proposal carries a `proposalId` distinct from `newMemoryIdHint`; both flow through
|
|
21
|
+
// the caller-supplied `newProposalId` and `newMemoryIdHint` factories so the builder
|
|
22
|
+
// stays pure.
|
|
23
|
+
// ─── Re-export the selector kind list at runtime ──────────────────────────────
|
|
24
|
+
// Frozen at the value level so a downstream switch can iterate it without re-deriving the
|
|
25
|
+
// literal set.
|
|
26
|
+
export const FORGET_SELECTOR_KINDS = [
|
|
27
|
+
"by-id",
|
|
28
|
+
"by-scope",
|
|
29
|
+
"by-type",
|
|
30
|
+
"by-source-conversation",
|
|
31
|
+
"by-time-window",
|
|
32
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,+BAA+B,EAAG,OAAgB,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const KEIKO_MEMORY_GOVERNANCE_VERSION = "0.1.0";
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oscharko-dev/keiko-memory-governance",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"description": "MemoriaViva — Internal memory-governance package (Epic #204 child #209): pure-function envelope builders for user-driven corrections, conflict resolution, selective forgetting, expiration, pinning and archiving over Governed Enterprise Memory Vault records. Every public function returns a contracts-validated operation envelope (MemoryProposal / MemorySupersession / MemoryUpdate / MemoryForget / MemoryPin / MemoryUnpin / MemoryArchive) or a StatusTransition; the caller (vault #206, audit #214, MemoriaViva UI #211, retrieval #210) materialises the persistence side. Pinned memories cannot be silently selected for forget. No IO, no clock, no randomness (caller supplies nowMs). ADR-0019 direction rule 3i (governance may depend only on keiko-contracts and keiko-security). Not published independently.",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -b tsconfig.json",
|
|
17
|
+
"typecheck": "tsc -b tsconfig.json",
|
|
18
|
+
"test": "vitest run"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@oscharko-dev/keiko-contracts": "0.2.0",
|
|
29
|
+
"@oscharko-dev/keiko-security": "0.2.0"
|
|
30
|
+
}
|
|
31
|
+
}
|