@unson/brainbase-mcp 0.7.0 → 0.9.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 (91) hide show
  1. package/README.md +1 -1
  2. package/contracts/foundation/graph-history.sql +634 -0
  3. package/contracts/judgment-dag/digest.json +2 -2
  4. package/contracts/judgment-value-proof/schema.json +43 -1
  5. package/dist/canonical-task-service.js +16 -5
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +107 -0
  8. package/dist/company-os-objectives.d.ts +11 -0
  9. package/dist/company-os-objectives.js +84 -47
  10. package/dist/foundation-authenticated-tools.d.ts +56 -0
  11. package/dist/foundation-authenticated-tools.js +347 -0
  12. package/dist/foundation-graph-http.d.ts +43 -0
  13. package/dist/foundation-graph-http.js +243 -0
  14. package/dist/foundation-graph-write.d.ts +90 -0
  15. package/dist/foundation-graph-write.js +447 -0
  16. package/dist/foundation-public-provider.d.ts +140 -0
  17. package/dist/foundation-public-provider.js +192 -0
  18. package/dist/graph-corrections.d.ts +157 -0
  19. package/dist/graph-corrections.js +620 -0
  20. package/dist/graph-foundation-reader.d.ts +60 -0
  21. package/dist/graph-foundation-reader.js +494 -0
  22. package/dist/graph-retrieval.d.ts +6 -1
  23. package/dist/graph-revision-reader.d.ts +80 -0
  24. package/dist/graph-revision-reader.js +246 -0
  25. package/dist/graph-web-http.d.ts +26 -0
  26. package/dist/graph-web-http.js +215 -0
  27. package/dist/graph-web.d.ts +364 -0
  28. package/dist/graph-web.js +639 -0
  29. package/dist/judgment-problem-snapshot.d.ts +30 -2
  30. package/dist/judgment-problem-snapshot.js +302 -6
  31. package/dist/judgment-value-proof-review.d.ts +166 -0
  32. package/dist/judgment-value-proof-review.js +437 -0
  33. package/dist/judgment-value-proof.d.ts +28 -1
  34. package/dist/judgment-value-proof.js +53 -8
  35. package/dist/knowledge-continuation.d.ts +127 -0
  36. package/dist/knowledge-continuation.js +446 -0
  37. package/dist/knowledge-lookup.d.ts +178 -0
  38. package/dist/knowledge-lookup.js +758 -0
  39. package/dist/local-web-fetch-bridge.d.ts +5 -0
  40. package/dist/local-web-fetch-bridge.js +37 -0
  41. package/dist/local-web-host.d.ts +109 -0
  42. package/dist/local-web-host.js +688 -0
  43. package/dist/local-web-security.d.ts +25 -0
  44. package/dist/local-web-security.js +95 -0
  45. package/dist/organization-graph.d.ts +15 -0
  46. package/dist/organization-graph.js +24 -4
  47. package/dist/personal-knowledge.d.ts +12 -0
  48. package/dist/personal-knowledge.js +29 -0
  49. package/dist/personal-memory-handover.d.ts +108 -0
  50. package/dist/personal-memory-handover.js +369 -0
  51. package/dist/philosophy-revision-reader.d.ts +85 -0
  52. package/dist/philosophy-revision-reader.js +241 -0
  53. package/dist/portable-graph.d.ts +24 -0
  54. package/dist/portable-graph.js +77 -0
  55. package/dist/server.d.ts +7 -2
  56. package/dist/server.js +9 -6
  57. package/dist/value-proof-review-http.d.ts +25 -0
  58. package/dist/value-proof-review-http.js +185 -0
  59. package/dist/world-model.d.ts +21 -3
  60. package/dist/world-model.js +94 -12
  61. package/package.json +94 -6
  62. package/ui/brainbase-tokens.css +56 -0
  63. package/ui/graph-own-share.js +367 -0
  64. package/ui/graph-projects-view.css +23 -0
  65. package/ui/graph-projects-view.js +730 -0
  66. package/ui/graph-registry-view.css +101 -0
  67. package/ui/graph-registry-view.js +804 -0
  68. package/ui/graph-view-shared.css +522 -0
  69. package/ui/graph-view-shared.js +1227 -0
  70. package/ui/judgment-view.css +119 -45
  71. package/ui/local-web-shell.css +396 -0
  72. package/ui/local-web-shell.js +378 -0
  73. package/ui/objective-editor-http-port.js +154 -0
  74. package/ui/objective-editor.css +180 -74
  75. package/ui/objective-editor.js +490 -43
  76. package/ui/outcome-knowledge.css +50 -14
  77. package/ui/outcome-knowledge.js +15 -1
  78. package/ui/value-proof-review.css +504 -0
  79. package/ui/value-proof-review.js +1104 -0
  80. package/ui/workspace-kit.css +485 -0
  81. package/ui/workspace-kit.js +229 -0
  82. package/ui/world-model-view.css +188 -0
  83. package/ui/world-model-view.js +486 -0
  84. package/ui/icons/mana/LICENSE.tabler.txt +0 -21
  85. package/ui/icons/mana/affiliate.svg +0 -20
  86. package/ui/icons/mana/brand-github.svg +0 -15
  87. package/ui/icons/mana/brand-google-drive.svg +0 -17
  88. package/ui/icons/mana/brand-slack.svg +0 -18
  89. package/ui/icons/mana/cpu.svg +0 -24
  90. package/ui/outcome-mana.css +0 -255
  91. package/ui/outcome-mana.js +0 -2325
@@ -0,0 +1,90 @@
1
+ import type { FoundationDefinition, FoundationScope, FoundationType } from './ontology-foundation.js';
2
+ /**
3
+ * Contract for preparing a Foundation draft for the canonical Graph writer.
4
+ *
5
+ * This module deliberately stops at a pure, fail-closed validation boundary.
6
+ * It does not issue Graph queries, mutate a catalog, or infer a tenant from
7
+ * any value in the payload. The host must provide the already-authenticated
8
+ * principal, selected project, and current revision.
9
+ */
10
+ export declare const FOUNDATION_GRAPH_WRITE_CONTRACT_VERSION: "foundation-graph-draft-write.v1";
11
+ export type FoundationGraphWriteOperation = 'create' | 'update';
12
+ export type FoundationGraphWriteIssueCode = 'INVALID_INPUT' | 'INVALID_IDENTITY' | 'ROW_DEFINITION_MISMATCH' | 'REVISION_CONFLICT' | 'CURRENT_DEFINITION_REQUIRED' | 'DEFINITION_INVALID' | 'DRAFT_ADOPTION_REQUIRED' | 'CANDIDATE_STORAGE_REQUIRED' | 'DRAFT_AUTHORIZATION_REQUIRED' | 'PROVENANCE_REQUIRED' | 'OWNER_MISMATCH' | 'ACL_CHANGE_FORBIDDEN' | 'WRITER_NOT_AUTHORIZED' | 'SCOPE_VIOLATION' | 'PROJECT_MISMATCH';
13
+ export interface FoundationGraphWriteIssue {
14
+ readonly code: FoundationGraphWriteIssueCode;
15
+ readonly path: string;
16
+ readonly message: string;
17
+ }
18
+ /** Trusted context resolved before this pure contract is called. */
19
+ export interface FoundationGraphWriteContext {
20
+ /** Host auth boundary value; callers should pass `access.personId`. */
21
+ readonly principal: string;
22
+ /** Selected canonical project code, never taken from the candidate payload. */
23
+ readonly projectCode: string;
24
+ /** Optional trusted subject/time scope for the selected project. */
25
+ readonly scope?: FoundationScope;
26
+ }
27
+ /**
28
+ * The host's Graph row shape. `type` is the canonical API name; `entityType`
29
+ * is accepted as a compatibility alias for adapters that mirror SQL rows.
30
+ */
31
+ export interface FoundationGraphWriteRow {
32
+ readonly id: string;
33
+ readonly type?: string;
34
+ readonly entityType?: string;
35
+ readonly revision: string;
36
+ readonly projectCode: string;
37
+ readonly payload: {
38
+ readonly foundation: unknown;
39
+ };
40
+ }
41
+ export interface FoundationGraphWriteInput {
42
+ readonly context: FoundationGraphWriteContext;
43
+ readonly row: FoundationGraphWriteRow;
44
+ readonly expectedNextRevision: string;
45
+ readonly currentDefinition?: unknown;
46
+ }
47
+ export interface FoundationGraphWriteResult {
48
+ readonly contractVersion: typeof FOUNDATION_GRAPH_WRITE_CONTRACT_VERSION;
49
+ readonly operation: FoundationGraphWriteOperation;
50
+ readonly projectCode: string;
51
+ readonly row: {
52
+ readonly id: string;
53
+ readonly type: FoundationType;
54
+ readonly revision: string;
55
+ readonly projectCode: string;
56
+ readonly payload: {
57
+ readonly foundation: FoundationDefinition;
58
+ };
59
+ };
60
+ readonly definition: FoundationDefinition;
61
+ }
62
+ export interface FoundationGraphWriteValidationResult {
63
+ readonly valid: boolean;
64
+ readonly status: 'valid' | 'invalid';
65
+ readonly operation?: FoundationGraphWriteOperation;
66
+ readonly issues: readonly FoundationGraphWriteIssue[];
67
+ readonly normalized?: FoundationGraphWriteResult;
68
+ }
69
+ /**
70
+ * Error thrown by the throwing normalizer. The non-throwing validator should
71
+ * be used at HTTP/MCP boundaries when callers need to render all issues.
72
+ */
73
+ export declare class FoundationGraphWriteError extends Error {
74
+ readonly code: FoundationGraphWriteIssueCode;
75
+ readonly issues: readonly FoundationGraphWriteIssue[];
76
+ constructor(issues: readonly FoundationGraphWriteIssue[]);
77
+ }
78
+ /**
79
+ * Validate and normalize an untrusted Graph upsert candidate.
80
+ *
81
+ * A successful result is safe to hand to a canonical Graph writer only after
82
+ * that writer also enforces its transaction/RLS boundary. This function proves
83
+ * the payload contract, identity, current ACL authorization, scope, and
84
+ * revision identity without performing any I/O.
85
+ */
86
+ export declare function validateFoundationGraphWrite(input: unknown): FoundationGraphWriteValidationResult;
87
+ /** Normalize a valid candidate or throw with the complete validation issues. */
88
+ export declare function normalizeFoundationGraphWrite(input: unknown): FoundationGraphWriteResult;
89
+ /** Descriptive alias for callers that use the validation/normalization pair. */
90
+ export declare const validateAndNormalizeFoundationGraphWrite: typeof normalizeFoundationGraphWrite;
@@ -0,0 +1,447 @@
1
+ import { cloneFoundationDefinition, nextFoundationRevision } from './foundation-catalog.js';
2
+ import { validateFoundationDefinition } from './ontology-foundation.js';
3
+ /**
4
+ * Contract for preparing a Foundation draft for the canonical Graph writer.
5
+ *
6
+ * This module deliberately stops at a pure, fail-closed validation boundary.
7
+ * It does not issue Graph queries, mutate a catalog, or infer a tenant from
8
+ * any value in the payload. The host must provide the already-authenticated
9
+ * principal, selected project, and current revision.
10
+ */
11
+ export const FOUNDATION_GRAPH_WRITE_CONTRACT_VERSION = 'foundation-graph-draft-write.v1';
12
+ const FOUNDATION_TYPES = ['objective', 'variable', 'model', 'constraint'];
13
+ const REVISION_PATTERN = /^[1-9]\d*$/u;
14
+ const FOUNDATION_USES_DRAFT = ['draft'];
15
+ /**
16
+ * Error thrown by the throwing normalizer. The non-throwing validator should
17
+ * be used at HTTP/MCP boundaries when callers need to render all issues.
18
+ */
19
+ export class FoundationGraphWriteError extends Error {
20
+ code;
21
+ issues;
22
+ constructor(issues) {
23
+ const first = issues[0] ?? {
24
+ code: 'INVALID_INPUT',
25
+ path: 'input',
26
+ message: 'Foundation Graph write input is invalid.'
27
+ };
28
+ super(first.message);
29
+ this.name = 'FoundationGraphWriteError';
30
+ this.code = first.code;
31
+ this.issues = issues;
32
+ }
33
+ }
34
+ /**
35
+ * Validate and normalize an untrusted Graph upsert candidate.
36
+ *
37
+ * A successful result is safe to hand to a canonical Graph writer only after
38
+ * that writer also enforces its transaction/RLS boundary. This function proves
39
+ * the payload contract, identity, current ACL authorization, scope, and
40
+ * revision identity without performing any I/O.
41
+ */
42
+ export function validateFoundationGraphWrite(input) {
43
+ const issues = [];
44
+ if (!isRecord(input)) {
45
+ return invalid(issues, {
46
+ code: 'INVALID_INPUT',
47
+ path: 'input',
48
+ message: 'Foundation Graph write input must be an object.'
49
+ });
50
+ }
51
+ const context = input.context;
52
+ const row = input.row;
53
+ if (!isRecord(context)) {
54
+ issues.push({ code: 'INVALID_INPUT', path: 'context', message: 'A trusted write context is required.' });
55
+ }
56
+ if (!isRecord(row)) {
57
+ issues.push({ code: 'INVALID_INPUT', path: 'row', message: 'A Graph row is required.' });
58
+ }
59
+ if (issues.length > 0)
60
+ return invalid(issues);
61
+ const trustedContext = context;
62
+ const graphRow = row;
63
+ validateContext(trustedContext, issues);
64
+ validateGraphRow(graphRow, issues);
65
+ if (isNonEmptyString(graphRow.projectCode)
66
+ && isNonEmptyString(trustedContext.projectCode)
67
+ && graphRow.projectCode !== trustedContext.projectCode) {
68
+ issues.push({
69
+ code: 'PROJECT_MISMATCH',
70
+ path: 'row.projectCode',
71
+ message: 'Graph row projectCode must match the trusted selected project.'
72
+ });
73
+ }
74
+ const expectedNextRevision = input.expectedNextRevision;
75
+ if (!isCanonicalRevision(expectedNextRevision)) {
76
+ issues.push({
77
+ code: 'INVALID_IDENTITY',
78
+ path: 'expectedNextRevision',
79
+ message: 'expectedNextRevision must be a positive canonical decimal revision.'
80
+ });
81
+ }
82
+ if (issues.length > 0)
83
+ return invalid(issues);
84
+ const rowType = resolveRowType(graphRow);
85
+ const rowId = graphRow.id;
86
+ const rowRevision = graphRow.revision;
87
+ const candidate = unwrapFoundation(graphRow.payload.foundation);
88
+ const definitionResult = validateFoundationDefinition(candidate, { use: 'draft' });
89
+ appendDefinitionIssues(issues, 'row.payload.foundation', definitionResult.issues);
90
+ if (!definitionResult.valid)
91
+ return invalid(issues);
92
+ if (!isFoundationDefinitionRecord(candidate)) {
93
+ issues.push({
94
+ code: 'DEFINITION_INVALID',
95
+ path: 'row.payload.foundation',
96
+ message: 'payload.foundation must be an object containing a registered Foundation definition.'
97
+ });
98
+ }
99
+ if (rowType !== undefined && isFoundationDefinitionRecord(candidate)) {
100
+ if (candidate.type !== rowType) {
101
+ issues.push({
102
+ code: 'ROW_DEFINITION_MISMATCH',
103
+ path: 'row.type',
104
+ message: `Graph row type ${rowType} does not match payload.foundation.type ${String(candidate.type)}.`
105
+ });
106
+ }
107
+ }
108
+ if (isFoundationDefinitionRecord(candidate)) {
109
+ if (candidate.id !== rowId) {
110
+ issues.push({
111
+ code: 'ROW_DEFINITION_MISMATCH',
112
+ path: 'row.id',
113
+ message: `Graph row id ${rowId} does not match payload.foundation.id ${String(candidate.id)}.`
114
+ });
115
+ }
116
+ if (candidate.revision !== rowRevision) {
117
+ issues.push({
118
+ code: 'ROW_DEFINITION_MISMATCH',
119
+ path: 'row.revision',
120
+ message: `Graph row revision ${rowRevision} does not match payload.foundation.revision ${String(candidate.revision)}.`
121
+ });
122
+ }
123
+ if (expectedNextRevision !== rowRevision) {
124
+ issues.push({
125
+ code: 'REVISION_CONFLICT',
126
+ path: 'expectedNextRevision',
127
+ message: `expectedNextRevision ${expectedNextRevision} must equal row.revision ${rowRevision}.`
128
+ });
129
+ }
130
+ validateDraftWriteInvariants(candidate, issues);
131
+ validateCandidateScope(candidate, trustedContext, issues);
132
+ }
133
+ const hasCurrentDefinition = input.currentDefinition !== undefined;
134
+ const operation = hasCurrentDefinition ? 'update' : 'create';
135
+ if (hasCurrentDefinition) {
136
+ const current = unwrapFoundation(input.currentDefinition);
137
+ validateCurrentDefinition(current, candidate, rowId, rowType, trustedContext, issues);
138
+ if (isFoundationDefinitionRecord(current) && isCanonicalRevision(current.revision) && isCanonicalRevision(rowRevision)) {
139
+ let expectedRevision;
140
+ try {
141
+ expectedRevision = nextFoundationRevision(current.revision);
142
+ }
143
+ catch {
144
+ expectedRevision = '';
145
+ }
146
+ if (expectedRevision !== rowRevision || expectedNextRevision !== expectedRevision) {
147
+ issues.push({
148
+ code: 'REVISION_CONFLICT',
149
+ path: 'row.revision',
150
+ message: `An update must append revision ${expectedRevision}; received row ${rowRevision} and expectedNextRevision ${expectedNextRevision}.`
151
+ });
152
+ }
153
+ }
154
+ }
155
+ else {
156
+ if (rowRevision !== '1' || expectedNextRevision !== '1') {
157
+ issues.push({
158
+ code: 'REVISION_CONFLICT',
159
+ path: 'row.revision',
160
+ message: 'A new Foundation Graph row must start at revision 1.'
161
+ });
162
+ }
163
+ if (isFoundationDefinitionRecord(candidate) && candidate.acl.ownerId !== trustedContext.principal) {
164
+ issues.push({
165
+ code: 'OWNER_MISMATCH',
166
+ path: 'row.payload.foundation.acl.ownerId',
167
+ message: 'A new draft must be owned by the trusted principal.'
168
+ });
169
+ }
170
+ }
171
+ if (issues.length > 0 || !isFoundationDefinitionRecord(candidate) || !rowType) {
172
+ return invalid(issues, undefined, operation);
173
+ }
174
+ const normalizedDefinition = cloneFoundationDefinition(candidate);
175
+ // These assignments are intentionally explicit even after validation. They
176
+ // make the invariant visible in the object handed to the Host writer.
177
+ normalizedDefinition.adoptionState = 'draft';
178
+ normalizedDefinition.storage = 'candidate';
179
+ normalizedDefinition.authorizedUses = [...FOUNDATION_USES_DRAFT];
180
+ const normalized = {
181
+ contractVersion: FOUNDATION_GRAPH_WRITE_CONTRACT_VERSION,
182
+ operation,
183
+ projectCode: trustedContext.projectCode,
184
+ row: {
185
+ id: rowId,
186
+ type: rowType,
187
+ revision: rowRevision,
188
+ projectCode: trustedContext.projectCode,
189
+ payload: { foundation: normalizedDefinition }
190
+ },
191
+ definition: normalizedDefinition
192
+ };
193
+ return {
194
+ valid: true,
195
+ status: 'valid',
196
+ operation,
197
+ issues: [],
198
+ normalized
199
+ };
200
+ }
201
+ /** Normalize a valid candidate or throw with the complete validation issues. */
202
+ export function normalizeFoundationGraphWrite(input) {
203
+ const result = validateFoundationGraphWrite(input);
204
+ if (!result.valid || !result.normalized)
205
+ throw new FoundationGraphWriteError(result.issues);
206
+ return result.normalized;
207
+ }
208
+ /** Descriptive alias for callers that use the validation/normalization pair. */
209
+ export const validateAndNormalizeFoundationGraphWrite = normalizeFoundationGraphWrite;
210
+ function validateContext(context, issues) {
211
+ if (!isNonEmptyString(context.principal)) {
212
+ issues.push({ code: 'INVALID_INPUT', path: 'context.principal', message: 'context.principal must be a non-empty trusted identifier.' });
213
+ }
214
+ if (!isNonEmptyString(context.projectCode)) {
215
+ issues.push({ code: 'INVALID_INPUT', path: 'context.projectCode', message: 'context.projectCode must be a non-empty selected project code.' });
216
+ }
217
+ if (context.scope !== undefined && !isScope(context.scope)) {
218
+ issues.push({ code: 'INVALID_INPUT', path: 'context.scope', message: 'context.scope must be a valid trusted scope.' });
219
+ }
220
+ else if (context.scope !== undefined && context.scope.subjectIds.length === 0) {
221
+ issues.push({ code: 'INVALID_INPUT', path: 'context.scope.subjectIds', message: 'context.scope must contain at least one trusted subject.' });
222
+ }
223
+ }
224
+ function validateGraphRow(row, issues) {
225
+ if (!isNonEmptyString(row.id)) {
226
+ issues.push({ code: 'INVALID_IDENTITY', path: 'row.id', message: 'Graph row id must be a non-empty string.' });
227
+ }
228
+ const rowType = resolveRowType(row);
229
+ if (!rowType || !isFoundationType(rowType)) {
230
+ issues.push({ code: 'INVALID_IDENTITY', path: 'row.type', message: 'Graph row type must be one of objective, variable, model, or constraint.' });
231
+ }
232
+ if (row.type !== undefined && row.entityType !== undefined && row.type !== row.entityType) {
233
+ issues.push({ code: 'ROW_DEFINITION_MISMATCH', path: 'row.type', message: 'row.type and row.entityType must identify the same type.' });
234
+ }
235
+ if (!isCanonicalRevision(row.revision)) {
236
+ issues.push({ code: 'INVALID_IDENTITY', path: 'row.revision', message: 'Graph row revision must be a positive canonical decimal.' });
237
+ }
238
+ if (!isNonEmptyString(row.projectCode)) {
239
+ issues.push({ code: 'INVALID_INPUT', path: 'row.projectCode', message: 'Graph row projectCode must be a non-empty string.' });
240
+ }
241
+ if (!isRecord(row.payload) || !('foundation' in row.payload)) {
242
+ issues.push({ code: 'INVALID_INPUT', path: 'row.payload.foundation', message: 'Graph row payload.foundation is required.' });
243
+ }
244
+ }
245
+ function validateDraftWriteInvariants(definition, issues) {
246
+ if (definition.adoptionState !== 'draft') {
247
+ issues.push({ code: 'DRAFT_ADOPTION_REQUIRED', path: 'row.payload.foundation.adoptionState', message: 'Foundation Graph write accepts draft definitions only.' });
248
+ }
249
+ if (definition.storage !== 'candidate') {
250
+ issues.push({ code: 'CANDIDATE_STORAGE_REQUIRED', path: 'row.payload.foundation.storage', message: 'Foundation Graph draft writes require storage=candidate.' });
251
+ }
252
+ if (!sameStringArray(definition.authorizedUses, FOUNDATION_USES_DRAFT)) {
253
+ issues.push({ code: 'DRAFT_AUTHORIZATION_REQUIRED', path: 'row.payload.foundation.authorizedUses', message: 'Foundation Graph draft writes require authorizedUses=[draft].' });
254
+ }
255
+ if (!Array.isArray(definition.provenance) || definition.provenance.length === 0) {
256
+ issues.push({ code: 'PROVENANCE_REQUIRED', path: 'row.payload.foundation.provenance', message: 'At least one non-empty source provenance entry is required.' });
257
+ }
258
+ else {
259
+ for (const [index, item] of definition.provenance.entries()) {
260
+ if (!isRecord(item) || !isNonEmptyString(item.sourceId)) {
261
+ issues.push({ code: 'PROVENANCE_REQUIRED', path: `row.payload.foundation.provenance[${index}].sourceId`, message: 'Each provenance entry requires a non-empty sourceId.' });
262
+ }
263
+ }
264
+ }
265
+ }
266
+ function validateCandidateScope(definition, context, issues) {
267
+ const scope = definition.scope;
268
+ if (!isScope(scope) || scope.subjectIds.length === 0) {
269
+ issues.push({ code: 'SCOPE_VIOLATION', path: 'row.payload.foundation.scope.subjectIds', message: 'A draft Graph write must identify at least one scoped subject.' });
270
+ return;
271
+ }
272
+ if (context.scope !== undefined) {
273
+ if (!isScope(context.scope) || context.scope.subjectIds.length === 0 || !scopeWithin(scope, context.scope)) {
274
+ issues.push({ code: 'SCOPE_VIOLATION', path: 'row.payload.foundation.scope', message: 'Foundation scope exceeds the trusted principal/project scope.' });
275
+ }
276
+ return;
277
+ }
278
+ if (!scope.subjectIds.every((subject) => subject === context.projectCode)) {
279
+ issues.push({ code: 'SCOPE_VIOLATION', path: 'row.payload.foundation.scope.subjectIds', message: 'Without a trusted scope, the draft scope must contain only the selected projectCode.' });
280
+ }
281
+ }
282
+ function validateCurrentDefinition(current, candidate, rowId, rowType, context, issues) {
283
+ if (!isFoundationDefinitionRecord(current)) {
284
+ issues.push({ code: 'CURRENT_DEFINITION_REQUIRED', path: 'currentDefinition', message: 'An update requires the current Foundation definition.' });
285
+ return;
286
+ }
287
+ const currentValidation = validateFoundationDefinition(current, { use: 'draft' });
288
+ appendDefinitionIssues(issues, 'currentDefinition', currentValidation.issues);
289
+ if (!currentValidation.valid)
290
+ return;
291
+ if (current.id !== rowId || (rowType !== undefined && current.type !== rowType)) {
292
+ issues.push({ code: 'ROW_DEFINITION_MISMATCH', path: 'currentDefinition', message: 'currentDefinition identity must match the Graph row.' });
293
+ }
294
+ if (isFoundationDefinitionRecord(candidate) && (current.id !== candidate.id || current.type !== candidate.type)) {
295
+ issues.push({ code: 'ROW_DEFINITION_MISMATCH', path: 'currentDefinition', message: 'currentDefinition identity must match the candidate definition.' });
296
+ }
297
+ if (current.acl.ownerId !== candidateAclOwner(candidate)) {
298
+ issues.push({ code: 'OWNER_MISMATCH', path: 'row.payload.foundation.acl.ownerId', message: 'An update must preserve the current owner.' });
299
+ }
300
+ const canWrite = current.acl.ownerId === context.principal || current.acl.writerIds.includes(context.principal);
301
+ if (!canWrite) {
302
+ issues.push({ code: 'WRITER_NOT_AUTHORIZED', path: 'currentDefinition.acl', message: 'The trusted principal is not an owner or writer in the current ACL.' });
303
+ }
304
+ if (isFoundationDefinitionRecord(candidate) && candidate.acl.ownerId !== current.acl.ownerId) {
305
+ issues.push({ code: 'OWNER_MISMATCH', path: 'row.payload.foundation.acl.ownerId', message: 'An update cannot transfer ownership through a draft write.' });
306
+ }
307
+ if (isFoundationDefinitionRecord(candidate) && isFoundationAcl(candidate.acl)
308
+ && !sameAcl(current.acl, candidate.acl)
309
+ && current.acl.ownerId !== context.principal) {
310
+ issues.push({
311
+ code: 'ACL_CHANGE_FORBIDDEN',
312
+ path: 'row.payload.foundation.acl',
313
+ message: 'Only the current owner may change ACL fields during a draft update.'
314
+ });
315
+ }
316
+ validateCandidateScope(current, context, issues);
317
+ }
318
+ function candidateAclOwner(value) {
319
+ return isRecord(value) && isRecord(value.acl) && typeof value.acl.ownerId === 'string'
320
+ ? value.acl.ownerId
321
+ : undefined;
322
+ }
323
+ function isFoundationAcl(value) {
324
+ return isRecord(value)
325
+ && isNonEmptyString(value.ownerId)
326
+ && (value.visibility === 'private'
327
+ || value.visibility === 'project'
328
+ || value.visibility === 'organization'
329
+ || value.visibility === 'public')
330
+ && Array.isArray(value.readerIds)
331
+ && value.readerIds.every(isNonEmptyString)
332
+ && Array.isArray(value.writerIds)
333
+ && value.writerIds.every(isNonEmptyString);
334
+ }
335
+ function sameAcl(left, right) {
336
+ return left.ownerId === right.ownerId
337
+ && left.visibility === right.visibility
338
+ && sameStringArray(left.readerIds, right.readerIds)
339
+ && sameStringArray(left.writerIds, right.writerIds);
340
+ }
341
+ function appendDefinitionIssues(issues, prefix, validationIssues) {
342
+ for (const issue of validationIssues) {
343
+ issues.push({
344
+ code: 'DEFINITION_INVALID',
345
+ path: `${prefix}.${issue.path}`,
346
+ message: issue.message
347
+ });
348
+ }
349
+ }
350
+ function invalid(issues, first, operation) {
351
+ if (first)
352
+ issues.unshift(first);
353
+ return {
354
+ valid: false,
355
+ status: 'invalid',
356
+ ...(operation === undefined ? {} : { operation }),
357
+ issues
358
+ };
359
+ }
360
+ function resolveRowType(row) {
361
+ const candidate = row.type ?? row.entityType;
362
+ return isFoundationType(candidate) ? candidate : undefined;
363
+ }
364
+ function isFoundationDefinitionRecord(value) {
365
+ return isRecord(value)
366
+ && isNonEmptyString(value.id)
367
+ && isFoundationType(value.type)
368
+ && isNonEmptyString(value.revision);
369
+ }
370
+ function unwrapFoundation(value) {
371
+ if (isRecord(value) && isRecord(value.foundation))
372
+ return value.foundation;
373
+ return value;
374
+ }
375
+ function isFoundationType(value) {
376
+ return typeof value === 'string' && FOUNDATION_TYPES.includes(value);
377
+ }
378
+ function isCanonicalRevision(value) {
379
+ return typeof value === 'string' && REVISION_PATTERN.test(value);
380
+ }
381
+ function isNonEmptyString(value) {
382
+ return typeof value === 'string' && value.trim().length > 0;
383
+ }
384
+ function isRecord(value) {
385
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
386
+ }
387
+ function isScope(value) {
388
+ if (!isRecord(value) || !Array.isArray(value.subjectIds) || !value.subjectIds.every(isNonEmptyString))
389
+ return false;
390
+ if (!isNonEmptyString(value.validFrom) || !isRfc3339(value.validFrom))
391
+ return false;
392
+ if (value.validUntil !== undefined && (!isNonEmptyString(value.validUntil) || !isRfc3339(value.validUntil)))
393
+ return false;
394
+ if (value.validUntil === undefined)
395
+ return true;
396
+ return parseRfc3339(value.validUntil) > parseRfc3339(value.validFrom);
397
+ }
398
+ function scopeWithin(inner, outer) {
399
+ if (!inner.subjectIds.every((subject) => outer.subjectIds.includes(subject)))
400
+ return false;
401
+ const innerFrom = parseRfc3339(inner.validFrom);
402
+ const outerFrom = parseRfc3339(outer.validFrom);
403
+ if (innerFrom === undefined || outerFrom === undefined || innerFrom < outerFrom)
404
+ return false;
405
+ if (inner.validUntil === undefined)
406
+ return outer.validUntil === undefined;
407
+ const innerUntil = parseRfc3339(inner.validUntil);
408
+ if (innerUntil === undefined || outer.validUntil === undefined)
409
+ return innerUntil !== undefined && outer.validUntil === undefined;
410
+ const outerUntil = parseRfc3339(outer.validUntil);
411
+ return outerUntil !== undefined && innerUntil <= outerUntil;
412
+ }
413
+ function sameStringArray(left, right) {
414
+ return Array.isArray(left) && left.length === right.length && left.every((item, index) => item === right[index]);
415
+ }
416
+ function isRfc3339(value) {
417
+ return parseRfc3339(value) !== undefined;
418
+ }
419
+ function parseRfc3339(value) {
420
+ const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?(Z|[+-]\d{2}:\d{2})$/u.exec(value);
421
+ if (!match)
422
+ return undefined;
423
+ const year = Number(match[1]);
424
+ const month = Number(match[2]);
425
+ const day = Number(match[3]);
426
+ const hour = Number(match[4]);
427
+ const minute = Number(match[5]);
428
+ const second = Number(match[6]);
429
+ if (month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month) || hour > 23 || minute > 59 || second > 59)
430
+ return undefined;
431
+ const zone = match[8];
432
+ let offsetMinutes = 0;
433
+ if (zone !== 'Z') {
434
+ const offsetHour = Number(zone.slice(1, 3));
435
+ const offsetMinute = Number(zone.slice(4, 6));
436
+ if (offsetHour > 23 || offsetMinute > 59)
437
+ return undefined;
438
+ offsetMinutes = (zone[0] === '-' ? -1 : 1) * (offsetHour * 60 + offsetMinute);
439
+ }
440
+ const milliseconds = Number(((match[7] ?? '') + '000').slice(0, 3));
441
+ return Date.UTC(year, month - 1, day, hour, minute, second, milliseconds) - offsetMinutes * 60_000;
442
+ }
443
+ function daysInMonth(year, month) {
444
+ if (month === 2)
445
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28;
446
+ return [4, 6, 9, 11].includes(month) ? 30 : 31;
447
+ }
@@ -0,0 +1,140 @@
1
+ import { type PhilosophyRevisionReader } from './philosophy-revision-reader.js';
2
+ import type { FoundationRevisionStore, FoundationStoreContext } from './foundation-store.js';
3
+ import { type JudgmentProblemReferenceProvider } from './judgment-problem-snapshot.js';
4
+ import type { FoundationHttpRoute } from './foundation-http.js';
5
+ export declare const FOUNDATION_PUBLIC_CONTRACT_VERSION: "foundation-public.v1";
6
+ /** The host owns canonical storage and authentication. No body can supply either. */
7
+ export declare function createFoundationPublicProvider(options: {
8
+ store: Pick<FoundationRevisionStore, 'read'>;
9
+ philosophyReader?: PhilosophyRevisionReader;
10
+ /** Canonical Observation/authority/etc. ports; cannot override Foundation or philosophy. */
11
+ resolveOther?: JudgmentProblemReferenceProvider['resolve'];
12
+ }): {
13
+ describe(): {
14
+ contractVersion: "foundation-public.v1";
15
+ foundation: import("./ontology-foundation.js").JudgmentFoundationContract;
16
+ connection: string;
17
+ storage: string;
18
+ philosophy: {
19
+ kind: string;
20
+ canonicalSource: string;
21
+ connected: boolean;
22
+ immutableRevisionRequired: boolean;
23
+ };
24
+ historicalRead: string;
25
+ executionPermission: string;
26
+ };
27
+ read(raw: unknown, context: FoundationStoreContext): Promise<import("./types.js").FoundationCatalogRecord | import("./philosophy-revision-reader.js").PhilosophyRevisionRecord>;
28
+ validate(raw: unknown, context: FoundationStoreContext): Promise<import("./judgment-problem-snapshot.js").JudgmentProblemReferenceResolution>;
29
+ validateProblem(raw: unknown, context: FoundationStoreContext): Promise<{
30
+ status: "resolved";
31
+ executionPermission: "none";
32
+ }>;
33
+ };
34
+ export type FoundationPublicProvider = ReturnType<typeof createFoundationPublicProvider>;
35
+ export interface FoundationPublicConnection {
36
+ provider: FoundationPublicProvider;
37
+ resolveContext(): FoundationStoreContext | null | Promise<FoundationStoreContext | null>;
38
+ }
39
+ export declare const foundationPublicToolDefinitions: readonly [{
40
+ readonly name: "foundation_describe";
41
+ readonly description: "Describe the connected versioned judgment foundation contract.";
42
+ readonly inputSchema: {
43
+ readonly type: "object";
44
+ readonly properties: {};
45
+ readonly additionalProperties: false;
46
+ };
47
+ }, {
48
+ readonly name: "foundation_read";
49
+ readonly description: "Read an exact canonical foundation revision under current access rights.";
50
+ readonly inputSchema: {
51
+ readonly type: "object";
52
+ readonly required: readonly ["type", "id", "revision"];
53
+ readonly additionalProperties: false;
54
+ readonly properties: {
55
+ readonly type: {
56
+ readonly type: "string";
57
+ readonly enum: readonly ["objective", "variable", "model", "constraint", "philosophy"];
58
+ };
59
+ readonly id: {
60
+ readonly type: "string";
61
+ };
62
+ readonly revision: {
63
+ readonly type: "string";
64
+ };
65
+ readonly digest: {
66
+ readonly type: "string";
67
+ };
68
+ };
69
+ };
70
+ }, {
71
+ readonly name: "foundation_validate_reference";
72
+ readonly description: "Validate an exact foundation or philosophy reference for judgment, including its dependencies.";
73
+ readonly inputSchema: {
74
+ readonly type: "object";
75
+ readonly required: readonly ["reference"];
76
+ readonly additionalProperties: false;
77
+ readonly properties: {
78
+ readonly reference: {
79
+ readonly type: "object";
80
+ readonly required: readonly ["kind", "id", "revision", "digest", "scope", "valid_from"];
81
+ readonly additionalProperties: false;
82
+ readonly properties: {
83
+ readonly kind: {
84
+ readonly type: "string";
85
+ readonly enum: readonly ["objective", "variable", "model", "constraint", "philosophy"];
86
+ };
87
+ readonly id: {
88
+ readonly type: "string";
89
+ };
90
+ readonly revision: {
91
+ readonly type: "string";
92
+ };
93
+ readonly digest: {
94
+ readonly type: "string";
95
+ };
96
+ readonly scope: {
97
+ readonly type: "object";
98
+ readonly required: readonly ["type", "id"];
99
+ readonly additionalProperties: false;
100
+ readonly properties: {
101
+ readonly type: {
102
+ readonly type: "string";
103
+ readonly enum: readonly ["personal", "project", "organization"];
104
+ };
105
+ readonly id: {
106
+ readonly type: "string";
107
+ };
108
+ };
109
+ };
110
+ readonly valid_from: {
111
+ readonly type: "string";
112
+ };
113
+ readonly valid_to: {
114
+ readonly type: readonly ["string", "null"];
115
+ };
116
+ };
117
+ };
118
+ readonly phase: {
119
+ readonly type: "string";
120
+ readonly enum: readonly ["read", "historical_read"];
121
+ };
122
+ };
123
+ };
124
+ }, {
125
+ readonly name: "foundation_validate_problem";
126
+ readonly description: "Validate a complete judgment snapshot and canonical observation measurement conditions. Grants no execution permission.";
127
+ readonly inputSchema: {
128
+ readonly type: "object";
129
+ readonly required: readonly ["snapshot"];
130
+ readonly properties: {
131
+ readonly snapshot: {
132
+ readonly type: "object";
133
+ };
134
+ };
135
+ readonly additionalProperties: false;
136
+ };
137
+ }];
138
+ export declare function callFoundationPublicTool(name: string, args: unknown, connection?: FoundationPublicConnection): Promise<unknown>;
139
+ /** Mounted with createFoundationHttpRouter, whose host resolves auth and CSRF. */
140
+ export declare function createFoundationPublicRoute(provider: FoundationPublicProvider): FoundationHttpRoute;