@unson/brainbase-mcp 0.23.2 → 0.23.4

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.
@@ -18,6 +18,17 @@ export type JudgmentFrameRole = 'constraint' | 'criterion' | 'prediction';
18
18
  export type JudgmentFrameConstraintVerdict = 'satisfied' | 'violated' | 'tension';
19
19
  /** Each kind is used in exactly one way inside an option evaluation. */
20
20
  export declare const JUDGMENT_FRAME_ROLE_BY_KIND: Readonly<Record<JudgmentFrameKind, JudgmentFrameRole>>;
21
+ /**
22
+ * A caller-provided summary that may be projected to an owner-only history.
23
+ * Core never derives this value from an answer, tool response, or body.
24
+ */
25
+ export interface JudgmentFramePublicFrame {
26
+ readonly summary: string;
27
+ readonly reason: string;
28
+ }
29
+ export interface JudgmentFramePublicFrameResponse extends JudgmentFramePublicFrame {
30
+ readonly digest: `sha256:${string}`;
31
+ }
21
32
  export interface JudgmentFrameSourceRecord {
22
33
  readonly id: string;
23
34
  readonly entity_type: string;
@@ -70,8 +81,10 @@ export interface JudgmentFrameRecord {
70
81
  readonly none?: Partial<Record<JudgmentFrameKind, string>>;
71
82
  readonly options: readonly JudgmentFrameOption[];
72
83
  readonly chosen_option: string;
84
+ /** Explicit opt-in for the future owner-only public projection. */
85
+ readonly public_frame?: JudgmentFramePublicFrame;
73
86
  }
74
- export type JudgmentFrameIssueCode = 'frame_record_invalid' | 'frame_catalog_mismatch' | 'frame_ref_unknown' | 'frame_kind_mismatch' | 'frame_selection_duplicate' | 'frame_kind_unaddressed' | 'frame_kind_contradiction' | 'frame_use_unselected' | 'frame_role_mismatch' | 'frame_verdict_missing' | 'frame_selection_unused' | 'frame_chosen_unknown';
87
+ export type JudgmentFrameIssueCode = 'frame_record_invalid' | 'frame_catalog_mismatch' | 'frame_ref_unknown' | 'frame_kind_mismatch' | 'frame_selection_duplicate' | 'frame_kind_unaddressed' | 'frame_kind_contradiction' | 'frame_use_unselected' | 'frame_role_mismatch' | 'frame_verdict_missing' | 'frame_selection_unused' | 'frame_chosen_unknown' | 'frame_public_invalid';
75
88
  export interface JudgmentFrameIssue {
76
89
  readonly code: JudgmentFrameIssueCode;
77
90
  readonly path: string;
@@ -88,6 +101,18 @@ export interface JudgmentFrameValidation {
88
101
  readonly issues: readonly JudgmentFrameIssue[];
89
102
  readonly escalations: readonly JudgmentFrameEscalation[];
90
103
  }
104
+ /**
105
+ * Compute the digest for the exact two-field public projection.
106
+ * The response adds this digest; it is intentionally separate from the
107
+ * full-record digest returned alongside the projection.
108
+ */
109
+ export declare function judgmentFramePublicFrameDigest(value: JudgmentFramePublicFrame): `sha256:${string}`;
110
+ /**
111
+ * Compute the stable digest returned with an accepted frame record.
112
+ * The explicit public frame is part of the digest so a changed projection
113
+ * cannot be acknowledged as the same judgment.
114
+ */
115
+ export declare function judgmentFrameRecordDigest(value: JudgmentFrameRecord): `sha256:${string}`;
91
116
  /**
92
117
  * Build the compact catalog shown to the model on a judgment-bearing turn.
93
118
  * Excluded records are returned with a reason so a shrinking catalog is visible.
@@ -25,6 +25,7 @@ const MAX_NOTE = 2_000;
25
25
  const MAX_SELECTIONS = 24;
26
26
  const MAX_OPTIONS = 8;
27
27
  const MAX_USES = 32;
28
+ const MAX_PUBLIC_FRAME_TEXT = 2_000;
28
29
  const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
29
30
  const text = (value) => typeof value === 'string' && value.trim() ? value.trim() : undefined;
30
31
  const nonEmpty = (value, max) => typeof value === 'string' && value.trim().length > 0 && value.length <= max;
@@ -40,6 +41,45 @@ function canonicalJson(value) {
40
41
  }
41
42
  return JSON.stringify(value);
42
43
  }
44
+ const PUBLIC_FRAME_KEYS = ['summary', 'reason'];
45
+ const PUBLIC_FRAME_SECRET_PATTERNS = [
46
+ /(?:^|[\s([{])Bearer\s+[A-Za-z0-9._~+\/-]{8,}(?=$|[\s)\]}.,;])/iu,
47
+ /\b(?:sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_-]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AIza[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16})\b/u,
48
+ /(?:access[_-]?token|refresh[_-]?token|api[_-]?key|client[_-]?secret|secret|password|credential|authorization|cookie)\s*(?:=|:)\s*[^\s&#;,]+/iu,
49
+ /\b[a-z][a-z0-9+.-]*:\/\/[^\s/?#:@]+:[^\s/@]+@/iu,
50
+ /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/u,
51
+ ];
52
+ const PUBLIC_FRAME_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
53
+ function containsPublicFrameCredential(value) {
54
+ return PUBLIC_FRAME_SECRET_PATTERNS.some((pattern) => pattern.test(value));
55
+ }
56
+ function publicFrameRecord(value) {
57
+ return {
58
+ record_version: value.record_version,
59
+ catalog_digest: value.catalog_digest,
60
+ selections: value.selections,
61
+ ...(value.none === undefined ? {} : { none: value.none }),
62
+ options: value.options,
63
+ chosen_option: value.chosen_option,
64
+ ...(value.public_frame === undefined ? {} : { public_frame: value.public_frame }),
65
+ };
66
+ }
67
+ /**
68
+ * Compute the digest for the exact two-field public projection.
69
+ * The response adds this digest; it is intentionally separate from the
70
+ * full-record digest returned alongside the projection.
71
+ */
72
+ export function judgmentFramePublicFrameDigest(value) {
73
+ return `sha256:${createHash('sha256').update(canonicalJson({ summary: value.summary, reason: value.reason }), 'utf8').digest('hex')}`;
74
+ }
75
+ /**
76
+ * Compute the stable digest returned with an accepted frame record.
77
+ * The explicit public frame is part of the digest so a changed projection
78
+ * cannot be acknowledged as the same judgment.
79
+ */
80
+ export function judgmentFrameRecordDigest(value) {
81
+ return `sha256:${createHash('sha256').update(canonicalJson(publicFrameRecord(value)), 'utf8').digest('hex')}`;
82
+ }
43
83
  function itemText(kind, payload) {
44
84
  const foundation = isRecord(payload.foundation) ? payload.foundation : {};
45
85
  if (kind === 'philosophy') {
@@ -146,6 +186,31 @@ export function validateJudgmentFrameRecord(value, catalog) {
146
186
  issue('frame_record_invalid', '$', `record_version must be ${JUDGMENT_FRAME_RECORD_VERSION}`);
147
187
  return { valid: false, issues, escalations: [] };
148
188
  }
189
+ if (value.public_frame !== undefined) {
190
+ if (!isRecord(value.public_frame)) {
191
+ issue('frame_public_invalid', 'public_frame', 'public_frame must be an object with summary and reason');
192
+ }
193
+ else {
194
+ for (const key of Object.keys(value.public_frame)) {
195
+ if (!PUBLIC_FRAME_KEYS.includes(key)) {
196
+ issue('frame_public_invalid', `public_frame.${key}`, 'public_frame contains an unknown field');
197
+ }
198
+ }
199
+ for (const key of PUBLIC_FRAME_KEYS) {
200
+ const candidate = value.public_frame[key];
201
+ if (!nonEmpty(candidate, MAX_PUBLIC_FRAME_TEXT)) {
202
+ issue('frame_public_invalid', `public_frame.${key}`, `${key} must be a non-empty string of at most ${MAX_PUBLIC_FRAME_TEXT} characters`);
203
+ continue;
204
+ }
205
+ if (PUBLIC_FRAME_CONTROL_CHARACTERS.test(candidate)) {
206
+ issue('frame_public_invalid', `public_frame.${key}`, `${key} contains control characters`);
207
+ }
208
+ if (containsPublicFrameCredential(candidate)) {
209
+ issue('frame_public_invalid', `public_frame.${key}`, `${key} contains a credential-like value`);
210
+ }
211
+ }
212
+ }
213
+ }
149
214
  if (value.catalog_digest !== catalog.digest) {
150
215
  issue('frame_catalog_mismatch', 'catalog_digest', 'catalog_digest does not match the catalog shown on this turn');
151
216
  }
@@ -264,6 +329,15 @@ const frameUseSchema = {
264
329
  },
265
330
  required: ['ref', 'role', 'note'],
266
331
  };
332
+ const publicFrameSchema = {
333
+ type: 'object',
334
+ additionalProperties: false,
335
+ properties: {
336
+ summary: { type: 'string', minLength: 1, maxLength: MAX_PUBLIC_FRAME_TEXT },
337
+ reason: { type: 'string', minLength: 1, maxLength: MAX_PUBLIC_FRAME_TEXT },
338
+ },
339
+ required: [...PUBLIC_FRAME_KEYS],
340
+ };
267
341
  export const judgmentFrameTools = [{
268
342
  name: 'brainbase_judgment_frame_catalog',
269
343
  description: 'On a judgment-bearing turn, read the catalog of philosophy, objectives, and world models visible to you. Select only what bears on this decision. Status is a label (draft objectives and adopted_unverified models are still usable as hypotheses); it is not a reason to skip them. Then call brainbase_judgment_frame_record with the returned catalog_digest.',
@@ -271,7 +345,7 @@ export const judgmentFrameTools = [{
271
345
  annotations: { readOnlyHint: true, destructiveHint: false },
272
346
  }, {
273
347
  name: 'brainbase_judgment_frame_record',
274
- description: 'Record the judgment frame: which catalog references you selected and why, and for each evaluated option how each selected reference was used. Philosophy is a constraint (give verdict satisfied, violated, or tension), an objective is a criterion, a world model is a prediction. Every selection must be used by at least one option. For a kind with no applicable reference, give the reason in none instead of selecting. Name the option you chose. The tool rejects references outside the catalog; it does not judge semantic quality. If escalations are returned, ask the human before acting on the chosen option.',
348
+ description: 'Record the judgment frame: which catalog references you selected and why, and for each evaluated option how each selected reference was used. Philosophy is a constraint (give verdict satisfied, violated, or tension), an objective is a criterion, a world model is a prediction. Every selection must be used by at least one option. For a kind with no applicable reference, give the reason in none instead of selecting. Name the option you chose. The tool rejects references outside the catalog; it does not judge semantic quality. If escalations are returned, ask the human before acting on the chosen option. Include public_frame only when the caller explicitly intends this exact summary and reason for the future owner-only projection; Core never derives it from an answer, tool response, or internal reasoning. public_frame accepts only non-empty safe summary and reason strings up to 2000 characters.',
275
349
  inputSchema: {
276
350
  type: 'object',
277
351
  additionalProperties: false,
@@ -312,6 +386,7 @@ export const judgmentFrameTools = [{
312
386
  },
313
387
  },
314
388
  chosen_option: { type: 'string', minLength: 1, maxLength: 400 },
389
+ public_frame: publicFrameSchema,
315
390
  },
316
391
  required: ['record_version', 'catalog_digest', 'selections', 'options', 'chosen_option'],
317
392
  },
@@ -378,6 +453,13 @@ export async function handleJudgmentFrameToolCall(name, args, dependencies) {
378
453
  option_count: args.options.length,
379
454
  chosen_option: args.chosen_option,
380
455
  escalations: validation.escalations,
456
+ ...(args.public_frame === undefined ? {} : {
457
+ public_frame: {
458
+ ...args.public_frame,
459
+ digest: judgmentFramePublicFrameDigest(args.public_frame),
460
+ },
461
+ }),
462
+ digest: judgmentFrameRecordDigest(args),
381
463
  },
382
464
  };
383
465
  }
@@ -0,0 +1,18 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { createJudgmentHistoryReader, type JudgmentHistoryFeedbackWriter, type JudgmentHistoryReader } from './judgment-history.js';
3
+ export declare const JUDGMENT_HISTORY_HTTP_VERSION: "judgment-history-http.v1";
4
+ export declare const JUDGMENT_HISTORY_HTTP_PREFIX: "/api/judgment-history";
5
+ export declare const JUDGMENT_HISTORY_FEEDBACK_BODY_LIMIT_BYTES: number;
6
+ export interface JudgmentHistoryHttpOptions {
7
+ readonly reader: JudgmentHistoryReader;
8
+ readonly basePath?: string;
9
+ /** Host-owned authorization callback. Browser input never selects its owner. */
10
+ readonly assertWriteAllowed?: (request: IncomingMessage) => void | Promise<void>;
11
+ /** Append-only writer; GET-only compositions can omit this seam. */
12
+ readonly writeFeedback?: JudgmentHistoryFeedbackWriter;
13
+ }
14
+ export type JudgmentHistoryHttpHandler = (request: IncomingMessage, response: ServerResponse) => Promise<boolean>;
15
+ /** Node-style GET route for the common normal-judgment history contract. */
16
+ export declare function createJudgmentHistoryHttpHandler(options: JudgmentHistoryHttpOptions): JudgmentHistoryHttpHandler;
17
+ /** Convenience composition seam for adapters that want the HTTP contract without a local journal. */
18
+ export declare function createJudgmentHistoryHttpReader(options: Parameters<typeof createJudgmentHistoryReader>[0]): JudgmentHistoryReader;
@@ -0,0 +1,170 @@
1
+ import { JUDGMENT_HISTORY_ENTRYPOINTS, createJudgmentHistoryReader, JudgmentHistoryFeedbackConflictError } from './judgment-history.js';
2
+ import { LocalWebHttpError, readJsonObjectBody, writeJson } from './local-web-security.js';
3
+ export const JUDGMENT_HISTORY_HTTP_VERSION = 'judgment-history-http.v1';
4
+ export const JUDGMENT_HISTORY_HTTP_PREFIX = '/api/judgment-history';
5
+ export const JUDGMENT_HISTORY_FEEDBACK_BODY_LIMIT_BYTES = 64 * 1024;
6
+ function methodNotAllowed() {
7
+ const error = new Error('Use GET or POST');
8
+ error.statusCode = 405;
9
+ error.code = 'method_not_allowed';
10
+ return error;
11
+ }
12
+ function matchRoute(pathname, basePath) {
13
+ if (pathname === `${basePath}/home`)
14
+ return { name: 'home' };
15
+ if (pathname === `${basePath}/feedback`)
16
+ return { name: 'feedback' };
17
+ if (!pathname.startsWith(`${basePath}/records/`))
18
+ return null;
19
+ const encoded = pathname.slice(`${basePath}/records/`.length);
20
+ if (!encoded || encoded.includes('/'))
21
+ return null;
22
+ let recordId;
23
+ try {
24
+ recordId = decodeURIComponent(encoded);
25
+ }
26
+ catch {
27
+ const error = new Error('record_id is not valid percent-encoding');
28
+ error.statusCode = 400;
29
+ error.code = 'invalid_record_id';
30
+ throw error;
31
+ }
32
+ return { name: 'detail', recordId };
33
+ }
34
+ function queryValue(url, key) {
35
+ const value = url.searchParams.get(key);
36
+ return value === null ? undefined : value;
37
+ }
38
+ function parseLimit(value) {
39
+ if (value === undefined)
40
+ return undefined;
41
+ if (!/^\d+$/u.test(value))
42
+ throw readerError(400, 'invalid_limit', 'limit must be between 1 and 100');
43
+ return Number(value);
44
+ }
45
+ function readerError(statusCode, code, message) {
46
+ const error = new Error(message);
47
+ error.statusCode = statusCode;
48
+ error.code = code;
49
+ return error;
50
+ }
51
+ function parseQuery(url) {
52
+ const allowed = new Set(['period', 'project', 'entrypoint', 'cursor', 'limit']);
53
+ for (const key of url.searchParams.keys()) {
54
+ if (!allowed.has(key))
55
+ throw readerError(400, 'unknown_query', `Unknown query parameter: ${key}`);
56
+ }
57
+ const periodValue = queryValue(url, 'period');
58
+ const period = periodValue === undefined ? undefined : periodValue;
59
+ const entrypointValue = queryValue(url, 'entrypoint');
60
+ const entrypoint = entrypointValue === undefined ? undefined : entrypointValue;
61
+ if (period !== undefined && period !== 'week' && period !== 'past30days' && period !== 'all') {
62
+ throw readerError(400, 'invalid_period', 'period is invalid');
63
+ }
64
+ if (entrypoint !== undefined && !JUDGMENT_HISTORY_ENTRYPOINTS.includes(entrypoint)) {
65
+ throw readerError(400, 'invalid_entrypoint', 'entrypoint is invalid');
66
+ }
67
+ const project = queryValue(url, 'project');
68
+ const cursor = queryValue(url, 'cursor');
69
+ const limit = parseLimit(queryValue(url, 'limit'));
70
+ return {
71
+ ...(period === undefined ? {} : { period }),
72
+ ...(project === undefined ? {} : { project }),
73
+ ...(entrypoint === undefined ? {} : { entrypoint }),
74
+ ...(cursor === undefined ? {} : { cursor }),
75
+ ...(limit === undefined ? {} : { limit })
76
+ };
77
+ }
78
+ function toError(error) {
79
+ if (error && typeof error === 'object'
80
+ && typeof error.statusCode === 'number'
81
+ && typeof error.code === 'string') {
82
+ return error;
83
+ }
84
+ return readerError(500, 'judgment_history_failed', error instanceof Error ? error.message : 'Judgment history read failed');
85
+ }
86
+ /** Node-style GET route for the common normal-judgment history contract. */
87
+ export function createJudgmentHistoryHttpHandler(options) {
88
+ if (!options?.reader || typeof options.reader.home !== 'function' || typeof options.reader.detail !== 'function') {
89
+ throw new TypeError('reader is required');
90
+ }
91
+ const basePath = (options.basePath ?? JUDGMENT_HISTORY_HTTP_PREFIX).replace(/\/+$/u, '');
92
+ const reader = options.reader;
93
+ return async (request, response) => {
94
+ const url = new URL(request.url ?? '/', 'http://localhost');
95
+ let route;
96
+ try {
97
+ route = matchRoute(url.pathname, basePath);
98
+ }
99
+ catch (error) {
100
+ const normalized = toError(error);
101
+ writeJson(response, normalized.statusCode, {
102
+ error: { code: normalized.code, message: normalized.message }
103
+ });
104
+ return true;
105
+ }
106
+ if (!route)
107
+ return false;
108
+ try {
109
+ if (route.name === 'feedback') {
110
+ if (request.method !== 'POST')
111
+ throw methodNotAllowed();
112
+ if (!options.assertWriteAllowed) {
113
+ throw new LocalWebHttpError(403, 'feedback_write_unconfigured', 'Feedback writes are not configured for this host');
114
+ }
115
+ if (!options.writeFeedback) {
116
+ throw new LocalWebHttpError(503, 'feedback_write_unavailable', 'Feedback writes are unavailable');
117
+ }
118
+ await options.assertWriteAllowed(request);
119
+ const input = await readJsonObjectBody(request, JUDGMENT_HISTORY_FEEDBACK_BODY_LIMIT_BYTES);
120
+ const result = await options.writeFeedback(input);
121
+ const responseBody = {
122
+ status: result.status,
123
+ saved: true,
124
+ created: result.created,
125
+ feedback_event: result.event,
126
+ ...result.event
127
+ };
128
+ writeJson(response, result.created ? 201 : 200, responseBody);
129
+ }
130
+ else {
131
+ if (request.method !== 'GET')
132
+ throw methodNotAllowed();
133
+ if (route.name === 'home') {
134
+ writeJson(response, 200, await reader.home(parseQuery(url)));
135
+ }
136
+ else {
137
+ const result = await reader.detail(route.recordId);
138
+ if (result.status === 'unavailable') {
139
+ writeJson(response, 200, result);
140
+ }
141
+ else if (result.status === 'available' && !result.record) {
142
+ throw readerError(404, 'judgment_history_not_found', 'No judgment history record matches this id');
143
+ }
144
+ else {
145
+ writeJson(response, 200, result);
146
+ }
147
+ }
148
+ }
149
+ }
150
+ catch (error) {
151
+ const normalized = toError(error);
152
+ if (error instanceof JudgmentHistoryFeedbackConflictError) {
153
+ writeJson(response, normalized.statusCode, {
154
+ error: { code: normalized.code, message: normalized.message },
155
+ feedback_event: error.existing
156
+ });
157
+ }
158
+ else {
159
+ writeJson(response, normalized.statusCode, {
160
+ error: { code: normalized.code, message: normalized.message }
161
+ });
162
+ }
163
+ }
164
+ return true;
165
+ };
166
+ }
167
+ /** Convenience composition seam for adapters that want the HTTP contract without a local journal. */
168
+ export function createJudgmentHistoryHttpReader(options) {
169
+ return createJudgmentHistoryReader(options);
170
+ }
@@ -0,0 +1,178 @@
1
+ /** Public normal-judgment history contract. Value-proof records use a separate contract. */
2
+ export declare const JUDGMENT_HISTORY_RECORD_SCHEMA: "brainbase-judgment-history-record-v1";
3
+ export declare const JUDGMENT_HISTORY_CONTRACT_VERSION: "brainbase.judgment-history.v1";
4
+ export declare const JUDGMENT_HISTORY_FEEDBACK_SCHEMA: "brainbase-judgment-history-feedback-v1";
5
+ export declare const JUDGMENT_HISTORY_ENTRYPOINTS: readonly ["codex", "claude_code", "mana", "company_os", "unknown"];
6
+ export type JudgmentHistoryEntrypoint = typeof JUDGMENT_HISTORY_ENTRYPOINTS[number];
7
+ export type JudgmentHistoryStatus = 'available' | 'partial' | 'unavailable';
8
+ export type JudgmentHistoryStorage = 'local' | 'server';
9
+ export type JudgmentHistoryPeriod = 'week' | 'past30days' | 'all';
10
+ export type JudgmentHistoryReferenceAvailability = 'recorded' | 'permission_denied' | 'unavailable' | 'unknown';
11
+ export type JudgmentHistoryExecutionStatus = 'pending' | 'completed' | 'failed' | 'held' | 'cancelled' | 'unknown';
12
+ export type JudgmentHistoryOutcomeStatus = 'unconfirmed' | 'confirmed' | 'unknown';
13
+ export type JudgmentHistoryFeedbackKind = 'feedback' | 'result' | 'correction';
14
+ export interface JudgmentHistoryFeedbackContent {
15
+ readonly summary: string;
16
+ readonly outcome_status?: JudgmentHistoryOutcomeStatus;
17
+ }
18
+ /** Public feedback event. Storage timestamps and digests are deliberately omitted. */
19
+ export interface JudgmentHistoryFeedbackEvent {
20
+ readonly record_id: string;
21
+ readonly event_id: string;
22
+ readonly kind: JudgmentHistoryFeedbackKind;
23
+ readonly content: JudgmentHistoryFeedbackContent;
24
+ }
25
+ export interface JudgmentHistoryFeedbackWriteResult {
26
+ readonly event: JudgmentHistoryFeedbackEvent;
27
+ readonly created: boolean;
28
+ readonly status: 'saved' | 'already_saved';
29
+ }
30
+ export interface JudgmentHistoryReference {
31
+ readonly ref: string;
32
+ readonly kind: string | null;
33
+ readonly version: string | null;
34
+ readonly digest: string | null;
35
+ readonly why: string | null;
36
+ readonly usage: string | null;
37
+ readonly availability: JudgmentHistoryReferenceAvailability;
38
+ }
39
+ export interface JudgmentHistoryAlternative {
40
+ readonly label: string;
41
+ readonly evaluation: string | null;
42
+ readonly adopted: boolean | null;
43
+ }
44
+ export interface JudgmentHistoryJudgment {
45
+ readonly status: 'resolved' | 'needs_clarification' | 'unknown';
46
+ readonly summary: string | null;
47
+ readonly reason: string | null;
48
+ readonly selected_references: readonly JudgmentHistoryReference[] | null;
49
+ readonly alternatives: readonly JudgmentHistoryAlternative[] | null;
50
+ }
51
+ export interface JudgmentHistoryExecution {
52
+ readonly status: JudgmentHistoryExecutionStatus;
53
+ readonly result_summary: string | null;
54
+ readonly outcome_status: JudgmentHistoryOutcomeStatus;
55
+ }
56
+ export interface JudgmentHistoryRecord {
57
+ readonly schema_version: typeof JUDGMENT_HISTORY_RECORD_SCHEMA;
58
+ readonly record_id: string;
59
+ readonly entrypoint: JudgmentHistoryEntrypoint;
60
+ readonly recorded_at: string;
61
+ readonly project_code: string | null;
62
+ readonly turn_ref: string;
63
+ readonly judgment: JudgmentHistoryJudgment;
64
+ readonly execution: JudgmentHistoryExecution;
65
+ readonly missing_fields: readonly string[];
66
+ /** Append-only result/correction events linked to this normal record. */
67
+ readonly feedback_events?: readonly JudgmentHistoryFeedbackEvent[];
68
+ }
69
+ export interface JudgmentHistorySourceInfo {
70
+ readonly entrypoint: JudgmentHistoryEntrypoint;
71
+ readonly status: JudgmentHistoryStatus;
72
+ readonly reason: string | null;
73
+ }
74
+ export interface JudgmentHistoryCoverage {
75
+ readonly complete: boolean;
76
+ readonly storage: JudgmentHistoryStorage;
77
+ readonly reason: string | null;
78
+ readonly sources: readonly JudgmentHistorySourceInfo[];
79
+ /** Null means the adapter cannot prove the total under this scope/filter. */
80
+ readonly total: number | null;
81
+ }
82
+ export interface JudgmentHistorySourceSnapshot {
83
+ readonly status: JudgmentHistoryStatus;
84
+ readonly records: readonly JudgmentHistoryRecord[] | null;
85
+ readonly coverage: JudgmentHistoryCoverage;
86
+ /** Stable source revision used to bind pagination cursors. */
87
+ readonly snapshot_id?: string;
88
+ }
89
+ export interface JudgmentHistorySource {
90
+ readonly storage: JudgmentHistoryStorage;
91
+ readonly read: () => Promise<JudgmentHistorySourceSnapshot>;
92
+ }
93
+ export interface JudgmentHistoryQuery {
94
+ readonly period?: JudgmentHistoryPeriod;
95
+ readonly project?: string;
96
+ readonly entrypoint?: JudgmentHistoryEntrypoint;
97
+ readonly cursor?: string;
98
+ readonly limit?: number;
99
+ }
100
+ export interface JudgmentHistoryFilters {
101
+ readonly period: JudgmentHistoryPeriod;
102
+ readonly project: string | null;
103
+ readonly entrypoint: JudgmentHistoryEntrypoint | null;
104
+ }
105
+ export interface JudgmentHistoryPagination {
106
+ readonly cursor: string | null;
107
+ readonly next_cursor: string | null;
108
+ readonly limit: number;
109
+ readonly has_more: boolean;
110
+ }
111
+ export interface JudgmentHistoryHome {
112
+ readonly contract_version: typeof JUDGMENT_HISTORY_CONTRACT_VERSION;
113
+ readonly status: JudgmentHistoryStatus;
114
+ readonly records: readonly JudgmentHistoryRecord[] | null;
115
+ readonly coverage: JudgmentHistoryCoverage;
116
+ readonly pagination: JudgmentHistoryPagination;
117
+ readonly filters: JudgmentHistoryFilters;
118
+ }
119
+ export interface JudgmentHistoryDetail {
120
+ readonly contract_version: typeof JUDGMENT_HISTORY_CONTRACT_VERSION;
121
+ readonly status: JudgmentHistoryStatus;
122
+ readonly record: JudgmentHistoryRecord | null;
123
+ readonly coverage: JudgmentHistoryCoverage;
124
+ }
125
+ export interface JudgmentHistoryReaderOptions {
126
+ readonly source: JudgmentHistorySource;
127
+ readonly now?: () => Date;
128
+ /** Organization adapters provide trusted scope authorization here. */
129
+ readonly authorizeProject?: (project: string) => boolean | Promise<boolean>;
130
+ }
131
+ export interface JudgmentHistoryReader {
132
+ readonly home: (query?: JudgmentHistoryQuery) => Promise<JudgmentHistoryHome>;
133
+ readonly detail: (recordId: string) => Promise<JudgmentHistoryDetail>;
134
+ }
135
+ export declare class JudgmentHistoryReaderError extends Error {
136
+ readonly statusCode: number;
137
+ readonly code: string;
138
+ constructor(statusCode: number, code: string, message: string);
139
+ }
140
+ export interface LocalJudgmentHistorySourceOptions {
141
+ readonly root: string;
142
+ readonly entrypoint?: JudgmentHistoryEntrypoint;
143
+ /** Maximum number of candidate journal files inspected in one read. */
144
+ readonly max_files?: number;
145
+ /** Maximum size of one journal artifact, in bytes. */
146
+ readonly max_record_bytes?: number;
147
+ }
148
+ export interface LocalJudgmentHistoryFeedbackWriterOptions {
149
+ readonly root: string;
150
+ readonly reader: JudgmentHistoryReader;
151
+ readonly now?: () => Date;
152
+ }
153
+ export type JudgmentHistoryFeedbackWriter = (input: unknown) => Promise<JudgmentHistoryFeedbackWriteResult>;
154
+ export declare class JudgmentHistoryFeedbackError extends Error {
155
+ readonly statusCode: number;
156
+ readonly code: string;
157
+ constructor(statusCode: number, code: string, message: string);
158
+ }
159
+ export declare class JudgmentHistoryFeedbackConflictError extends JudgmentHistoryFeedbackError {
160
+ readonly existing: JudgmentHistoryFeedbackEvent;
161
+ constructor(existing: JudgmentHistoryFeedbackEvent);
162
+ }
163
+ export declare const DEFAULT_LOCAL_JUDGMENT_HISTORY_SCAN_CAP = 4096;
164
+ export declare const DEFAULT_LOCAL_JUDGMENT_HISTORY_RECORD_BYTES: number;
165
+ export declare function canonicalJson(value: unknown): string;
166
+ /** Reads only the configured local owner journal; it never searches or uploads another journal. */
167
+ export declare function createLocalJudgmentHistorySource(options: LocalJudgmentHistorySourceOptions): JudgmentHistorySource;
168
+ /**
169
+ * Append-only local feedback writer for normal judgment records. It writes a
170
+ * separate immutable event file below the configured journal and always
171
+ * confirms the event through the same reader before returning success.
172
+ */
173
+ export declare function createLocalJudgmentHistoryFeedbackWriter(options: LocalJudgmentHistoryFeedbackWriterOptions): JudgmentHistoryFeedbackWriter;
174
+ export declare function appendLocalJudgmentHistoryFeedback(options: LocalJudgmentHistoryFeedbackWriterOptions & {
175
+ readonly input: unknown;
176
+ }): Promise<JudgmentHistoryFeedbackWriteResult>;
177
+ /** Reader shared by local, organization, Mana, and Company OS adapters. */
178
+ export declare function createJudgmentHistoryReader(options: JudgmentHistoryReaderOptions): JudgmentHistoryReader;