@unson/brainbase-mcp 0.5.0 → 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 (92) hide show
  1. package/README.md +8 -0
  2. package/contracts/judgment-dag/digest.json +2 -2
  3. package/dist/canonical-task-contract.d.ts +9 -0
  4. package/dist/canonical-task-contract.js +39 -0
  5. package/dist/canonical-task-principal.d.ts +16 -0
  6. package/dist/canonical-task-principal.js +36 -0
  7. package/dist/canonical-task-service.d.ts +251 -0
  8. package/dist/canonical-task-service.js +809 -0
  9. package/dist/company-os-evaluation.d.ts +193 -0
  10. package/dist/company-os-evaluation.js +1150 -0
  11. package/dist/company-os-impact-review.d.ts +248 -0
  12. package/dist/company-os-impact-review.js +663 -0
  13. package/dist/company-os-learning-adoption.d.ts +288 -0
  14. package/dist/company-os-learning-adoption.js +944 -0
  15. package/dist/company-os-objectives.d.ts +52 -0
  16. package/dist/company-os-objectives.js +197 -0
  17. package/dist/company-os-receipt-adapter.d.ts +109 -0
  18. package/dist/company-os-receipt-adapter.js +636 -0
  19. package/dist/constraint-exception-store.d.ts +23 -0
  20. package/dist/constraint-exception-store.js +108 -0
  21. package/dist/constraint-resolution.d.ts +175 -0
  22. package/dist/constraint-resolution.js +922 -0
  23. package/dist/decision-adapter.d.ts +145 -0
  24. package/dist/decision-adapter.js +586 -0
  25. package/dist/durable-wait-http.d.ts +51 -0
  26. package/dist/durable-wait-http.js +497 -0
  27. package/dist/durable-waits.d.ts +234 -0
  28. package/dist/durable-waits.js +944 -0
  29. package/dist/execution-authority-http.d.ts +28 -0
  30. package/dist/execution-authority-http.js +359 -0
  31. package/dist/execution-authority.d.ts +201 -0
  32. package/dist/execution-authority.js +634 -0
  33. package/dist/foundation-catalog.d.ts +26 -0
  34. package/dist/foundation-catalog.js +206 -0
  35. package/dist/foundation-constraint-store.d.ts +50 -0
  36. package/dist/foundation-constraint-store.js +215 -0
  37. package/dist/foundation-http.d.ts +90 -0
  38. package/dist/foundation-http.js +439 -0
  39. package/dist/foundation-store.d.ts +132 -0
  40. package/dist/foundation-store.js +654 -0
  41. package/dist/judgment-dag-composition.d.ts +224 -0
  42. package/dist/judgment-dag-composition.js +731 -0
  43. package/dist/judgment-dag.d.ts +2 -0
  44. package/dist/judgment-dag.js +1 -0
  45. package/dist/judgment-problem-snapshot.d.ts +185 -0
  46. package/dist/judgment-problem-snapshot.js +777 -0
  47. package/dist/judgment-view-http.d.ts +22 -0
  48. package/dist/judgment-view-http.js +128 -0
  49. package/dist/judgment-view.d.ts +222 -0
  50. package/dist/judgment-view.js +627 -0
  51. package/dist/knowledge-adapter.d.ts +112 -0
  52. package/dist/knowledge-adapter.js +691 -0
  53. package/dist/ontology-foundation.d.ts +209 -0
  54. package/dist/ontology-foundation.js +1000 -0
  55. package/dist/ontology.d.ts +13 -0
  56. package/dist/ontology.js +14 -0
  57. package/dist/organization-connection.d.ts +164 -0
  58. package/dist/organization-connection.js +428 -0
  59. package/dist/personal-knowledge.d.ts +120 -0
  60. package/dist/personal-knowledge.js +750 -0
  61. package/dist/problem-candidates.d.ts +149 -0
  62. package/dist/problem-candidates.js +898 -0
  63. package/dist/problem-selection.d.ts +238 -0
  64. package/dist/problem-selection.js +995 -0
  65. package/dist/resource-reservation-http.d.ts +31 -0
  66. package/dist/resource-reservation-http.js +371 -0
  67. package/dist/resource-reservations.d.ts +221 -0
  68. package/dist/resource-reservations.js +577 -0
  69. package/dist/server.d.ts +97 -0
  70. package/dist/server.js +180 -1
  71. package/dist/ssot.d.ts +6 -1
  72. package/dist/ssot.js +63 -5
  73. package/dist/streamable-http.d.ts +42 -0
  74. package/dist/streamable-http.js +288 -0
  75. package/dist/types.d.ts +20 -0
  76. package/dist/world-model.d.ts +181 -0
  77. package/dist/world-model.js +873 -0
  78. package/package.json +145 -3
  79. package/ui/icons/mana/LICENSE.tabler.txt +21 -0
  80. package/ui/icons/mana/affiliate.svg +20 -0
  81. package/ui/icons/mana/brand-github.svg +15 -0
  82. package/ui/icons/mana/brand-google-drive.svg +17 -0
  83. package/ui/icons/mana/brand-slack.svg +18 -0
  84. package/ui/icons/mana/cpu.svg +24 -0
  85. package/ui/judgment-view.css +238 -0
  86. package/ui/judgment-view.js +508 -0
  87. package/ui/objective-editor.css +180 -0
  88. package/ui/objective-editor.js +1139 -0
  89. package/ui/outcome-knowledge.css +365 -0
  90. package/ui/outcome-knowledge.js +1570 -0
  91. package/ui/outcome-mana.css +255 -0
  92. package/ui/outcome-mana.js +2325 -0
@@ -0,0 +1,288 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { createServer as createHttpServer } from 'node:http';
3
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
+ const DEFAULT_BODY_LIMIT_BYTES = 1024 * 1024;
5
+ const DEFAULT_MCP_PATH = '/mcp';
6
+ const DEFAULT_HEALTH_PATH = '/health';
7
+ class BodyLimitError extends Error {
8
+ constructor() {
9
+ super('Request body exceeds the configured limit');
10
+ this.name = 'BodyLimitError';
11
+ }
12
+ }
13
+ class InvalidJsonError extends Error {
14
+ constructor() {
15
+ super('Parse error: Invalid JSON');
16
+ this.name = 'InvalidJsonError';
17
+ }
18
+ }
19
+ function jsonRpcError(code, message) {
20
+ return {
21
+ jsonrpc: '2.0',
22
+ error: { code, message },
23
+ id: null
24
+ };
25
+ }
26
+ function writeJson(response, statusCode, body, headers = {}) {
27
+ if (response.headersSent)
28
+ return;
29
+ response.statusCode = statusCode;
30
+ response.setHeader('Content-Type', 'application/json');
31
+ for (const [name, value] of Object.entries(headers))
32
+ response.setHeader(name, value);
33
+ response.end(JSON.stringify(body));
34
+ }
35
+ function requestPath(request) {
36
+ try {
37
+ return new URL(request.url ?? '/', 'http://localhost').pathname;
38
+ }
39
+ catch {
40
+ return '/';
41
+ }
42
+ }
43
+ function headerValue(request, name) {
44
+ const value = request.headers[name.toLowerCase()];
45
+ return Array.isArray(value) ? value[0] : value;
46
+ }
47
+ async function readJsonBody(request, limitBytes) {
48
+ const contentLengthHeader = headerValue(request, 'content-length');
49
+ if (contentLengthHeader !== undefined) {
50
+ const contentLength = Number(contentLengthHeader);
51
+ if (Number.isFinite(contentLength) && contentLength > limitBytes) {
52
+ request.resume();
53
+ throw new BodyLimitError();
54
+ }
55
+ }
56
+ const chunks = [];
57
+ let totalBytes = 0;
58
+ await new Promise((resolve, reject) => {
59
+ let settled = false;
60
+ const cleanup = () => {
61
+ request.removeListener('data', onData);
62
+ request.removeListener('end', onEnd);
63
+ request.removeListener('error', onError);
64
+ request.removeListener('aborted', onAborted);
65
+ };
66
+ const finish = (error) => {
67
+ if (settled)
68
+ return;
69
+ settled = true;
70
+ cleanup();
71
+ if (error)
72
+ reject(error);
73
+ else
74
+ resolve();
75
+ };
76
+ const onData = (chunk) => {
77
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
78
+ totalBytes += buffer.byteLength;
79
+ if (totalBytes > limitBytes) {
80
+ request.resume();
81
+ finish(new BodyLimitError());
82
+ return;
83
+ }
84
+ chunks.push(buffer);
85
+ };
86
+ const onEnd = () => finish();
87
+ const onError = () => finish(new Error('Request body could not be read'));
88
+ const onAborted = () => finish(new Error('Request was aborted'));
89
+ request.on('data', onData);
90
+ request.once('end', onEnd);
91
+ request.once('error', onError);
92
+ request.once('aborted', onAborted);
93
+ });
94
+ if (chunks.length === 0)
95
+ throw new InvalidJsonError();
96
+ try {
97
+ return JSON.parse(Buffer.concat(chunks).toString('utf8'));
98
+ }
99
+ catch {
100
+ throw new InvalidJsonError();
101
+ }
102
+ }
103
+ function assignAuth(request, auth) {
104
+ const authenticatedRequest = request;
105
+ if (auth !== undefined)
106
+ authenticatedRequest.auth = auth;
107
+ return authenticatedRequest;
108
+ }
109
+ export function createStreamableHttpHandler(dependencies) {
110
+ const bodyLimitBytes = dependencies.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES;
111
+ const mcpPath = dependencies.mcpPath ?? DEFAULT_MCP_PATH;
112
+ const healthPath = dependencies.healthPath ?? DEFAULT_HEALTH_PATH;
113
+ if (!Number.isInteger(bodyLimitBytes) || bodyLimitBytes <= 0) {
114
+ throw new Error('bodyLimitBytes must be a positive integer');
115
+ }
116
+ const sessions = new Map();
117
+ const closeServer = async (session) => {
118
+ if (session.serverClosePromise)
119
+ return session.serverClosePromise;
120
+ session.serverCloseStarted = true;
121
+ session.serverClosePromise = session.server.close();
122
+ await session.serverClosePromise;
123
+ };
124
+ const disposeSession = async (session) => {
125
+ if (session.id)
126
+ sessions.delete(session.id);
127
+ if (session.closed && session.serverCloseStarted) {
128
+ await session.serverClosePromise;
129
+ return;
130
+ }
131
+ session.closed = true;
132
+ try {
133
+ await session.transport.close();
134
+ }
135
+ finally {
136
+ await closeServer(session);
137
+ }
138
+ };
139
+ const createSession = async (scope) => {
140
+ const server = await dependencies.createServer(scope);
141
+ let session;
142
+ const transport = new StreamableHTTPServerTransport({
143
+ sessionIdGenerator: randomUUID,
144
+ enableJsonResponse: true,
145
+ onsessioninitialized: (id) => {
146
+ session.id = id;
147
+ sessions.set(id, session);
148
+ },
149
+ onsessionclosed: (id) => {
150
+ sessions.delete(id);
151
+ session.closed = true;
152
+ }
153
+ });
154
+ session = {
155
+ server,
156
+ transport,
157
+ closed: false,
158
+ serverCloseStarted: false
159
+ };
160
+ transport.onclose = () => {
161
+ session.closed = true;
162
+ if (session.id)
163
+ sessions.delete(session.id);
164
+ void closeServer(session).catch(() => undefined);
165
+ };
166
+ await server.connect(transport);
167
+ return session;
168
+ };
169
+ const resolveScope = async (request, auth, sessionId, requestId) => {
170
+ const base = {
171
+ requestId,
172
+ method: request.method ?? 'GET',
173
+ path: requestPath(request),
174
+ ...(auth === undefined ? {} : { auth }),
175
+ ...(sessionId === undefined ? {} : { sessionId })
176
+ };
177
+ const custom = await dependencies.requestScope?.({ request, requestId, auth, sessionId });
178
+ return custom ? { ...base, ...custom } : base;
179
+ };
180
+ const handle = async (request, response) => {
181
+ const path = requestPath(request);
182
+ const requestId = randomUUID();
183
+ if (path === healthPath && request.method === 'GET') {
184
+ try {
185
+ const result = await dependencies.health?.({ request, requestId });
186
+ writeJson(response, 200, result ?? { status: 'ok' });
187
+ }
188
+ catch {
189
+ writeJson(response, 503, { status: 'unavailable' });
190
+ }
191
+ return;
192
+ }
193
+ if (path !== mcpPath) {
194
+ writeJson(response, 404, { error: 'Not Found' });
195
+ return;
196
+ }
197
+ if (request.method === 'GET') {
198
+ writeJson(response, 405, jsonRpcError(-32000, 'GET is not supported'), { Allow: 'POST, DELETE' });
199
+ return;
200
+ }
201
+ if (request.method !== 'POST' && request.method !== 'DELETE') {
202
+ writeJson(response, 405, jsonRpcError(-32000, 'Method not allowed'), { Allow: 'POST, DELETE' });
203
+ return;
204
+ }
205
+ let auth;
206
+ if (dependencies.authenticate) {
207
+ try {
208
+ const authenticated = await dependencies.authenticate(request);
209
+ if (authenticated === null) {
210
+ writeJson(response, 401, jsonRpcError(-32000, 'Unauthorized'), { 'WWW-Authenticate': 'Bearer' });
211
+ return;
212
+ }
213
+ auth = authenticated;
214
+ }
215
+ catch {
216
+ writeJson(response, 401, jsonRpcError(-32000, 'Unauthorized'), { 'WWW-Authenticate': 'Bearer' });
217
+ return;
218
+ }
219
+ }
220
+ const sessionId = headerValue(request, 'mcp-session-id');
221
+ let session = sessionId ? sessions.get(sessionId) : undefined;
222
+ if (sessionId && !session) {
223
+ writeJson(response, 404, jsonRpcError(-32001, 'Session not found'));
224
+ return;
225
+ }
226
+ try {
227
+ const body = request.method === 'POST' ? await readJsonBody(request, bodyLimitBytes) : undefined;
228
+ const scope = await resolveScope(request, auth, sessionId, requestId);
229
+ if (!session)
230
+ session = await createSession(scope);
231
+ let aborted = false;
232
+ const onClose = () => {
233
+ if (!response.writableFinished) {
234
+ aborted = true;
235
+ if (session)
236
+ void disposeSession(session).catch(() => undefined);
237
+ }
238
+ };
239
+ response.once('close', onClose);
240
+ try {
241
+ await session.transport.handleRequest(assignAuth(request, auth), response, body);
242
+ }
243
+ finally {
244
+ response.removeListener('close', onClose);
245
+ }
246
+ // An uninitialized, stateless request creates no session and must not leak
247
+ // its server. Initialized sessions remain available for list/call/delete.
248
+ if (!session.transport.sessionId && !sessionId && !aborted)
249
+ await disposeSession(session);
250
+ }
251
+ catch (error) {
252
+ if (response.headersSent) {
253
+ if (!response.writableEnded)
254
+ response.destroy();
255
+ return;
256
+ }
257
+ if (error instanceof BodyLimitError) {
258
+ writeJson(response, 413, jsonRpcError(-32013, error.message));
259
+ return;
260
+ }
261
+ if (error instanceof InvalidJsonError) {
262
+ writeJson(response, 400, jsonRpcError(-32700, error.message));
263
+ return;
264
+ }
265
+ writeJson(response, 500, jsonRpcError(-32603, 'Internal server error'));
266
+ }
267
+ };
268
+ return {
269
+ handle,
270
+ close: async () => {
271
+ await Promise.all([...sessions.values()].map((session) => disposeSession(session)));
272
+ sessions.clear();
273
+ },
274
+ get activeSessionCount() {
275
+ return sessions.size;
276
+ }
277
+ };
278
+ }
279
+ export function createStreamableHttpServer(dependencies) {
280
+ const handler = createStreamableHttpHandler(dependencies);
281
+ const server = createHttpServer((request, response) => {
282
+ void handler.handle(request, response);
283
+ });
284
+ server.once('close', () => {
285
+ void handler.close().catch(() => undefined);
286
+ });
287
+ return server;
288
+ }
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { FoundationDefinition, FoundationRelationReference, FoundationRevision } from './ontology-foundation.js';
1
2
  export type EntityKind = 'person' | 'org' | 'project' | 'relationship' | 'decision';
2
3
  export type CanonicalEntityKind = 'person' | 'org' | 'project' | 'decision';
3
4
  export type CoreRelation = 'member_of' | 'participates_in' | 'accountable_for' | 'owned_by' | 'governs' | 'supersedes';
@@ -43,6 +44,24 @@ export interface CanonicalEdge {
43
44
  evidenceHash?: string;
44
45
  };
45
46
  }
47
+ /**
48
+ * Versioned definitions that extend the historical Graph v2 contract.
49
+ *
50
+ * This is deliberately an extension of the canonical aggregate rather than a
51
+ * second objectives/world-model file. The old Graph entities and edges keep
52
+ * their historical interpretation; foundation records are validated by their
53
+ * own shared ontology contract.
54
+ */
55
+ export interface FoundationCatalogRecord {
56
+ definition: FoundationDefinition;
57
+ digest: string;
58
+ }
59
+ export interface FoundationCatalog {
60
+ version: 1;
61
+ records: FoundationCatalogRecord[];
62
+ latest: Record<string, FoundationRevision>;
63
+ relations: FoundationRelationReference[];
64
+ }
46
65
  export interface GraphFileV2 {
47
66
  version: 2;
48
67
  ontology: {
@@ -57,6 +76,7 @@ export interface GraphFileV2 {
57
76
  };
58
77
  entities: CanonicalEntity[];
59
78
  edges: CanonicalEdge[];
79
+ foundation?: FoundationCatalog;
60
80
  }
61
81
  export type GraphFile = GraphFileV1 | GraphFileV2;
62
82
  export type CanonicalGraphFile = GraphFile;
@@ -0,0 +1,181 @@
1
+ import { type FoundationDefinition, type FoundationAcl, type FoundationAdoptionState, type FoundationEpistemicState, type FoundationPeriod, type FoundationProvenance, type FoundationRevision, type FoundationUse, type FoundationValidationResult, type DecisionRevision, type ModelDefinition, type VariableDefinition } from './ontology-foundation.js';
2
+ /**
3
+ * The world-model helpers are deliberately independent of storage. Definitions
4
+ * belong to the shared foundation catalog; observations and adoption records are
5
+ * values that reference an exact definition revision. A caller can therefore
6
+ * pass these records through the canonical SSOT transaction without introducing
7
+ * a second lock or definition authority.
8
+ */
9
+ export declare const WORLD_MODEL_CONTRACT_VERSION: "0.1.0";
10
+ export declare const WORLD_MODEL_RECORD_CATALOG_VERSION: 1;
11
+ /** Evidence records are sidecar data committed with the canonical aggregate. */
12
+ export declare const WORLD_MODEL_EVIDENCE_SIDECAR: "evidence/world-model.json";
13
+ export type WorldModelScalar = string | number | boolean;
14
+ export type WorldModelValue = WorldModelScalar | readonly WorldModelValue[] | {
15
+ readonly [key: string]: WorldModelValue;
16
+ };
17
+ export interface WorldModelObservationInput {
18
+ id: string;
19
+ variableRef: FoundationRevision;
20
+ subjectId: string;
21
+ value: WorldModelValue;
22
+ /** When the observed event happened. */
23
+ occurredAt: string;
24
+ /** The interval for which the value is valid, which may differ from occurredAt. */
25
+ period: FoundationPeriod;
26
+ /** When Brainbase recorded the observation. */
27
+ recordedAt: string;
28
+ sourceRef: FoundationProvenance;
29
+ /** A correction creates a new observation and points at the old one. */
30
+ supersedes?: string;
31
+ }
32
+ export interface WorldModelObservation extends WorldModelObservationInput {
33
+ readonly id: string;
34
+ readonly variableRef: FoundationRevision;
35
+ readonly subjectId: string;
36
+ readonly value: WorldModelValue;
37
+ readonly occurredAt: string;
38
+ readonly period: FoundationPeriod;
39
+ readonly recordedAt: string;
40
+ readonly sourceRef: FoundationProvenance;
41
+ readonly supersedes?: string;
42
+ }
43
+ export type WorldModelValidationIssueCode = 'MISSING_FIELD' | 'INVALID_FIELD' | 'INVALID_TIMESTAMP' | 'INVALID_PERIOD' | 'INVALID_VARIABLE_REFERENCE' | 'VARIABLE_VALUE_KIND_MISMATCH' | 'OBSERVATION_SCOPE_MISMATCH' | 'OBSERVATION_PERIOD_MISMATCH' | 'RECORDED_BEFORE_OCCURRED' | 'INVALID_CORRECTION_REFERENCE' | 'MISSING_SOURCE' | 'MODEL_CONTRACT_INVALID';
44
+ export interface WorldModelValidationIssue {
45
+ readonly code: WorldModelValidationIssueCode;
46
+ readonly path: string;
47
+ readonly message: string;
48
+ }
49
+ export interface WorldModelValidationResult {
50
+ readonly valid: boolean;
51
+ readonly status: 'valid' | 'invalid';
52
+ readonly issues: readonly WorldModelValidationIssue[];
53
+ }
54
+ /**
55
+ * A candidate snapshot is intentionally not a FoundationDefinition. It
56
+ * captures the candidate-store state at the moment a model is proposed so that
57
+ * adopting a model never overwrites the original hypothesis or ACL.
58
+ */
59
+ export interface CandidateModelSnapshot {
60
+ readonly candidateId: string;
61
+ readonly hypothesis: string;
62
+ readonly evidenceIds: readonly string[];
63
+ readonly acl: FoundationAcl;
64
+ readonly epistemicState: Extract<FoundationEpistemicState, 'unverified' | 'hypothesis'>;
65
+ }
66
+ export interface ModelAdoptionInput {
67
+ readonly adoptionId: string;
68
+ readonly modelRef: FoundationRevision;
69
+ readonly candidate: CandidateModelSnapshot;
70
+ readonly adoptionState: Extract<FoundationAdoptionState, 'proposed' | 'approved'>;
71
+ readonly authorizedUse: FoundationUse;
72
+ readonly adoptedAt: string;
73
+ readonly approvalRef?: DecisionRevision;
74
+ }
75
+ export interface ModelAdoptionRecord extends ModelAdoptionInput {
76
+ readonly modelRef: FoundationRevision;
77
+ readonly candidate: CandidateModelSnapshot;
78
+ readonly adoptionState: Extract<FoundationAdoptionState, 'proposed' | 'approved'>;
79
+ readonly authorizedUse: FoundationUse;
80
+ readonly adoptedAt: string;
81
+ readonly approvalRef?: DecisionRevision;
82
+ }
83
+ /**
84
+ * This is an evidence-sidecar catalog, not part of the canonical Graph
85
+ * aggregate. Variable and Model definitions continue to be resolved by the
86
+ * foundation catalog, while this catalog holds immutable observations and
87
+ * candidate adoption references that point back to exact definition revisions.
88
+ */
89
+ export interface WorldModelRecordCatalog {
90
+ readonly version: typeof WORLD_MODEL_RECORD_CATALOG_VERSION;
91
+ readonly observations: readonly WorldModelObservation[];
92
+ readonly adoptions: readonly ModelAdoptionRecord[];
93
+ }
94
+ export interface WorldModelStoreContext {
95
+ /** Identity resolved by the trusted auth boundary. */
96
+ readonly principal: string;
97
+ }
98
+ export interface WorldModelFoundationRecord {
99
+ readonly definition: FoundationDefinition;
100
+ readonly digest: string;
101
+ }
102
+ /**
103
+ * Structural contract implemented by the shared FoundationRevisionStore. It
104
+ * is local to this module so world-model can depend on the small public store
105
+ * surface without introducing a second definition catalog. Transactional
106
+ * foundation resolution is implemented below from the aggregate already held
107
+ * by mutatePersonalOsWithSidecar; the normal read method must not be
108
+ * re-entered while that lock is held.
109
+ */
110
+ export interface WorldModelFoundationStore {
111
+ create(definition: FoundationDefinition, context: WorldModelStoreContext): Promise<FoundationRevision & {
112
+ readonly digest: string;
113
+ }>;
114
+ read(reference: FoundationRevision, context: WorldModelStoreContext): Promise<WorldModelFoundationRecord | null>;
115
+ }
116
+ export interface WorldModelObservationQuery {
117
+ readonly variableRef?: FoundationRevision;
118
+ readonly subjectId?: string;
119
+ readonly supersedes?: string;
120
+ }
121
+ export type ModelAdoptionStoreInput = Omit<ModelAdoptionInput, 'candidate' | 'modelRef'>;
122
+ export type WorldModelStoreErrorCode = 'invalid_input' | 'not_found' | 'revision_conflict' | 'authorization_denied' | 'unsupported_graph' | 'corrupt_record' | 'readback_mismatch';
123
+ export declare class WorldModelStoreError extends Error {
124
+ readonly code: WorldModelStoreErrorCode;
125
+ constructor(code: WorldModelStoreErrorCode, message: string);
126
+ }
127
+ export interface WorldModelRecordStore {
128
+ createVariable(variable: VariableDefinition, context: WorldModelStoreContext): Promise<FoundationRevision & {
129
+ readonly digest: string;
130
+ }>;
131
+ createModel(model: ModelDefinition, context: WorldModelStoreContext): Promise<FoundationRevision & {
132
+ readonly digest: string;
133
+ }>;
134
+ readModel(reference: FoundationRevision, context: WorldModelStoreContext): Promise<ModelDefinition | null>;
135
+ saveObservation(input: WorldModelObservationInput, context: WorldModelStoreContext): Promise<WorldModelObservation>;
136
+ readObservation(id: string, context: WorldModelStoreContext): Promise<WorldModelObservation | null>;
137
+ listObservations(query: WorldModelObservationQuery | undefined, context: WorldModelStoreContext): Promise<readonly WorldModelObservation[]>;
138
+ saveModelAdoption(candidate: CandidateModelSnapshot, modelRef: FoundationRevision, adoption: ModelAdoptionStoreInput, context: WorldModelStoreContext): Promise<ModelAdoptionRecord>;
139
+ readModelAdoption(adoptionId: string, context: WorldModelStoreContext): Promise<ModelAdoptionRecord | null>;
140
+ listModelAdoptions(context: WorldModelStoreContext): Promise<readonly ModelAdoptionRecord[]>;
141
+ }
142
+ export declare class WorldModelValidationError extends Error {
143
+ readonly issues: readonly WorldModelValidationIssue[];
144
+ constructor(issues: readonly WorldModelValidationIssue[]);
145
+ }
146
+ /**
147
+ * Validates and clones an observation before it crosses a storage boundary.
148
+ * The returned value is deeply frozen, while the input remains untouched.
149
+ */
150
+ export declare function normalizeWorldModelObservation(input: WorldModelObservationInput): WorldModelObservation;
151
+ /**
152
+ * Checks whether an already normalized observation is compatible with the
153
+ * exact Variable definition it references. This does not infer a value or
154
+ * upgrade an observation from inferred to observed.
155
+ */
156
+ export declare function validateWorldModelObservation(observation: WorldModelObservation, variable: VariableDefinition): WorldModelValidationResult;
157
+ /**
158
+ * Delegates Model validation to the shared ontology contract. The wrapper
159
+ * keeps world-model callers from importing ontology internals while retaining
160
+ * the contract's distinction between draft, judgment, evaluation, and
161
+ * execution use.
162
+ */
163
+ export declare function validateWorldModelModel(model: ModelDefinition, use?: FoundationUse): FoundationValidationResult;
164
+ /**
165
+ * Creates a durable adoption record without mutating the candidate or Model.
166
+ * A candidate may only produce an unverified/hypothesis Model record; adopting
167
+ * it cannot silently turn it into a verified claim.
168
+ */
169
+ export declare function retainCandidateModel(candidate: CandidateModelSnapshot, model: ModelDefinition, adoption: Omit<ModelAdoptionInput, 'candidate' | 'modelRef'> & {
170
+ modelRef?: FoundationRevision;
171
+ }): ModelAdoptionRecord;
172
+ /**
173
+ * Creates a world-model record store over the existing canonical aggregate.
174
+ * Foundation definitions are delegated to the shared revision store. The
175
+ * observation/adoption evidence catalog is committed as a sidecar in the same
176
+ * SSOT transaction, so the canonical Graph remains definition-only.
177
+ */
178
+ export declare function createWorldModelStore(options: {
179
+ dataDir: string;
180
+ foundationStore: WorldModelFoundationStore;
181
+ }): WorldModelRecordStore;