@unson/brainbase-mcp 0.43.0 → 0.44.1
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/contracts/canonical-task/operation-schema.sql +58 -0
- package/contracts/canonical-task/search-indexes.sql +10 -0
- package/contracts/canonical-task/store-schema.sql +77 -0
- package/dist/automation-run.d.ts +213 -0
- package/dist/automation-run.js +479 -0
- package/dist/canonical-task-operations.d.ts +205 -0
- package/dist/canonical-task-operations.js +700 -0
- package/dist/canonical-task-postgres.d.ts +139 -0
- package/dist/canonical-task-postgres.js +554 -0
- package/dist/canonical-task-service.d.ts +13 -0
- package/dist/canonical-task-service.js +55 -3
- package/dist/canonical-task-store-config.d.ts +31 -0
- package/dist/canonical-task-store-config.js +53 -0
- package/dist/config-parser.d.ts +298 -0
- package/dist/config-parser.js +593 -0
- package/dist/connected-onboarding.d.ts +57 -0
- package/dist/connected-onboarding.js +37 -0
- package/dist/durable-wait-http.d.ts +3 -1
- package/dist/durable-wait-http.js +73 -6
- package/dist/durable-waits.d.ts +93 -3
- package/dist/durable-waits.js +320 -8
- package/dist/honcho.d.ts +25 -0
- package/dist/honcho.js +81 -0
- package/dist/judgment-event-adapter.d.ts +72 -0
- package/dist/judgment-event-adapter.js +114 -0
- package/dist/judgment-event-outbox.d.ts +182 -0
- package/dist/judgment-event-outbox.js +568 -0
- package/dist/judgment-execution-outcome.d.ts +46 -0
- package/dist/judgment-execution-outcome.js +149 -0
- package/dist/judgment-host.d.ts +18 -7
- package/dist/judgment-host.js +82 -34
- package/dist/judgment-lifecycle-core.d.ts +198 -0
- package/dist/judgment-lifecycle-core.js +464 -0
- package/dist/judgment-node-evidence.d.ts +57 -0
- package/dist/judgment-node-evidence.js +297 -0
- package/dist/judgment-runtime-resolution.d.ts +264 -0
- package/dist/judgment-runtime-resolution.js +1248 -0
- package/dist/judgment-runtime-resolution.public.d.ts +255 -0
- package/dist/knowledge-event.d.ts +28 -0
- package/dist/knowledge-event.js +114 -0
- package/dist/mcp-runtime.d.ts +75 -0
- package/dist/mcp-runtime.js +188 -0
- package/dist/meeting-automation-runtime.d.ts +102 -0
- package/dist/meeting-automation-runtime.js +249 -0
- package/dist/meeting-automation.d.ts +155 -0
- package/dist/meeting-automation.js +341 -0
- package/dist/meeting-minutes-context-receipt.d.ts +91 -0
- package/dist/meeting-minutes-context-receipt.js +280 -0
- package/dist/meeting-source-sync.d.ts +89 -0
- package/dist/meeting-source-sync.js +230 -0
- package/dist/mesh.d.ts +58 -0
- package/dist/mesh.js +134 -0
- package/dist/onboarding-runtime.d.ts +47 -0
- package/dist/onboarding-runtime.js +4719 -0
- package/dist/routine-cycle.d.ts +51 -0
- package/dist/routine-cycle.js +153 -0
- package/dist/routine-liveness.d.ts +49 -0
- package/dist/routine-liveness.js +227 -0
- package/dist/routine-runtime.d.ts +101 -0
- package/dist/routine-runtime.js +237 -0
- package/dist/routines.d.ts +3 -0
- package/dist/routines.js +3 -0
- package/dist/run-receipt.d.ts +40 -0
- package/dist/run-receipt.js +635 -0
- package/dist/runtime-host.d.ts +64 -0
- package/dist/runtime-host.js +70 -0
- package/dist/world-work.d.ts +16 -0
- package/package.json +115 -3
- package/ui/meeting-minutes.css +122 -0
- package/ui/meeting-minutes.js +316 -0
- package/ui/objective-editor.js +47 -11
- package/ui/world/world-district.js +18 -3
- package/ui/world/world-placement.js +13 -0
- package/ui/world/world-work-rail.js +7 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { verifyMeetingReviewPackage, type MeetingReviewPackage, type VerifiedMeetingReviewPackage } from './meeting-automation.js';
|
|
2
|
+
export declare const MEETING_AUTOMATION_RUNTIME_VERSION: "brainbase.meeting-automation-runtime.v1";
|
|
3
|
+
type UnknownRecord = Record<string, unknown>;
|
|
4
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
+
export interface MeetingAutomationRuntimeInput {
|
|
6
|
+
readonly org_id: string;
|
|
7
|
+
readonly project_id: string;
|
|
8
|
+
readonly review_package: MeetingReviewPackage;
|
|
9
|
+
readonly loop_intent_repository: Parameters<typeof verifyMeetingReviewPackage>[0]['repository'];
|
|
10
|
+
readonly source_event?: UnknownRecord;
|
|
11
|
+
readonly case_scope?: string | null;
|
|
12
|
+
readonly actor_id?: string | null;
|
|
13
|
+
readonly idempotency_key?: string | null;
|
|
14
|
+
readonly evidence_refs?: readonly unknown[];
|
|
15
|
+
}
|
|
16
|
+
export interface MeetingAutomationRuntimeRecord {
|
|
17
|
+
readonly record_id: string;
|
|
18
|
+
readonly idempotency_key: string;
|
|
19
|
+
/** Fingerprint of the normalized package before owner resolution. */
|
|
20
|
+
readonly input_fingerprint?: string;
|
|
21
|
+
readonly fingerprint: string;
|
|
22
|
+
readonly org_id: string;
|
|
23
|
+
readonly project_id: string;
|
|
24
|
+
readonly state: 'waiting_human';
|
|
25
|
+
readonly review_package: UnknownRecord;
|
|
26
|
+
readonly verified_loop_intents: readonly string[];
|
|
27
|
+
readonly created_at: string;
|
|
28
|
+
readonly actor_id: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface MeetingAutomationRuntimeExecution {
|
|
31
|
+
readonly record: MeetingAutomationRuntimeRecord;
|
|
32
|
+
readonly attempts: number;
|
|
33
|
+
readonly workflow: UnknownRecord | null;
|
|
34
|
+
readonly knowledge: UnknownRecord | null;
|
|
35
|
+
}
|
|
36
|
+
export interface MeetingAutomationRuntimeClaimRequest {
|
|
37
|
+
readonly idempotency_key: string;
|
|
38
|
+
readonly fingerprint: string;
|
|
39
|
+
readonly scope: {
|
|
40
|
+
readonly org_id: string;
|
|
41
|
+
readonly project_id: string;
|
|
42
|
+
};
|
|
43
|
+
readonly execute: () => MaybePromise<MeetingAutomationRuntimeExecution>;
|
|
44
|
+
}
|
|
45
|
+
export interface MeetingAutomationRuntimeClaimResult {
|
|
46
|
+
readonly status: 'persisted' | 'replayed';
|
|
47
|
+
readonly execution: MeetingAutomationRuntimeExecution;
|
|
48
|
+
}
|
|
49
|
+
export interface MeetingAutomationRuntimePorts {
|
|
50
|
+
readonly ledger: {
|
|
51
|
+
/**
|
|
52
|
+
* Atomically claims an idempotency key, executes the complete workflow,
|
|
53
|
+
* and returns the durable execution on both the winner and replayers.
|
|
54
|
+
* The host must back this with a durable transaction/claim, not a local
|
|
55
|
+
* in-memory lock.
|
|
56
|
+
*/
|
|
57
|
+
readonly claimOrReplay: (request: MeetingAutomationRuntimeClaimRequest) => MaybePromise<MeetingAutomationRuntimeClaimResult>;
|
|
58
|
+
findByIdempotencyKey?: (key: string, scope: {
|
|
59
|
+
org_id: string;
|
|
60
|
+
project_id: string;
|
|
61
|
+
}) => MaybePromise<MeetingAutomationRuntimeRecord | null>;
|
|
62
|
+
save: (record: MeetingAutomationRuntimeRecord) => MaybePromise<MeetingAutomationRuntimeRecord | void>;
|
|
63
|
+
readonly readback: (recordId: string, scope: {
|
|
64
|
+
org_id: string;
|
|
65
|
+
project_id: string;
|
|
66
|
+
}) => MaybePromise<MeetingAutomationRuntimeRecord | null>;
|
|
67
|
+
};
|
|
68
|
+
readonly resolveTaskOwners?: (input: UnknownRecord, context: UnknownRecord) => MaybePromise<UnknownRecord>;
|
|
69
|
+
readonly prepareWorkflow?: (input: UnknownRecord) => MaybePromise<UnknownRecord | void>;
|
|
70
|
+
readonly bridgeKnowledge?: (input: UnknownRecord) => MaybePromise<UnknownRecord | void>;
|
|
71
|
+
/**
|
|
72
|
+
* The host implements this with a durable post-commit outbox/effect ledger.
|
|
73
|
+
* It must persist the effect key across worker restarts; a process-local
|
|
74
|
+
* mutex is not sufficient for knowledge bridge idempotency.
|
|
75
|
+
*/
|
|
76
|
+
readonly runOnce?: <T>(effectKey: string, effect: () => MaybePromise<T>) => MaybePromise<T>;
|
|
77
|
+
readonly now?: () => Date;
|
|
78
|
+
readonly max_attempts?: number;
|
|
79
|
+
readonly is_retryable?: (error: unknown) => boolean;
|
|
80
|
+
}
|
|
81
|
+
export declare class MeetingAutomationRuntimeError extends Error {
|
|
82
|
+
readonly code: string;
|
|
83
|
+
readonly details: UnknownRecord;
|
|
84
|
+
constructor(code: string, message: string, details?: UnknownRecord);
|
|
85
|
+
}
|
|
86
|
+
export interface MeetingAutomationRuntimeResult {
|
|
87
|
+
readonly status: 'persisted' | 'replayed';
|
|
88
|
+
readonly idempotent: boolean;
|
|
89
|
+
readonly attempts: number;
|
|
90
|
+
readonly record: MeetingAutomationRuntimeRecord;
|
|
91
|
+
readonly readback: MeetingAutomationRuntimeRecord;
|
|
92
|
+
readonly verified: VerifiedMeetingReviewPackage;
|
|
93
|
+
readonly workflow: UnknownRecord | null;
|
|
94
|
+
readonly knowledge: UnknownRecord | null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Provider-independent orchestration for meeting review package ingestion.
|
|
98
|
+
* The host owns workflow, Graph, identity and durable ledger ports; this core
|
|
99
|
+
* owns validation, normalization, replay keys, retry and persisted readback.
|
|
100
|
+
*/
|
|
101
|
+
export declare function runMeetingAutomationRuntime(input: MeetingAutomationRuntimeInput, ports: MeetingAutomationRuntimePorts): Promise<MeetingAutomationRuntimeResult>;
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { assertMeetingCandidatesInput, normalizeDecisionCandidates, normalizeFollowUpDraft, normalizeTaskCandidates, verifyMeetingReviewPackage, } from './meeting-automation.js';
|
|
3
|
+
export const MEETING_AUTOMATION_RUNTIME_VERSION = 'brainbase.meeting-automation-runtime.v1';
|
|
4
|
+
export class MeetingAutomationRuntimeError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
details;
|
|
7
|
+
constructor(code, message, details = {}) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'MeetingAutomationRuntimeError';
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function stable(value) {
|
|
15
|
+
if (Array.isArray(value))
|
|
16
|
+
return value.map(stable);
|
|
17
|
+
if (!value || typeof value !== 'object')
|
|
18
|
+
return value;
|
|
19
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]));
|
|
20
|
+
}
|
|
21
|
+
function digest(value) {
|
|
22
|
+
return createHash('sha256').update(JSON.stringify(stable(value))).digest('hex');
|
|
23
|
+
}
|
|
24
|
+
function requireScope(value, field) {
|
|
25
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
26
|
+
throw new MeetingAutomationRuntimeError('invalid_scope', `${field} is required`, { field });
|
|
27
|
+
}
|
|
28
|
+
return value.trim();
|
|
29
|
+
}
|
|
30
|
+
function retryable(error, ports) {
|
|
31
|
+
return ports.is_retryable?.(error) ?? Boolean(error?.retryable);
|
|
32
|
+
}
|
|
33
|
+
function normalizeReviewPackage(input) {
|
|
34
|
+
const reviewPackage = input.review_package;
|
|
35
|
+
assertMeetingCandidatesInput(reviewPackage);
|
|
36
|
+
const caseScope = input.case_scope ?? (typeof reviewPackage.case_scope === 'string' ? reviewPackage.case_scope : null);
|
|
37
|
+
const evidenceRefs = Array.isArray(input.evidence_refs) ? [...input.evidence_refs] : [];
|
|
38
|
+
const normalizedTaskCandidates = normalizeTaskCandidates(reviewPackage.task_candidates, {
|
|
39
|
+
caseScope,
|
|
40
|
+
evidenceRefs,
|
|
41
|
+
});
|
|
42
|
+
const normalizedDecisionCandidates = normalizeDecisionCandidates(reviewPackage.decision_candidates, {
|
|
43
|
+
caseScope,
|
|
44
|
+
evidenceRefs,
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
...reviewPackage,
|
|
48
|
+
task_candidates: normalizedTaskCandidates,
|
|
49
|
+
decision_candidates: normalizedDecisionCandidates,
|
|
50
|
+
follow_up_draft: normalizeFollowUpDraft(reviewPackage.follow_up_draft),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function saveWithRetry(record, ports) {
|
|
54
|
+
const maxAttempts = Math.max(1, Math.min(5, ports.max_attempts ?? 2));
|
|
55
|
+
let attempts = 0;
|
|
56
|
+
let lastError;
|
|
57
|
+
while (attempts < maxAttempts) {
|
|
58
|
+
attempts += 1;
|
|
59
|
+
try {
|
|
60
|
+
const saved = await ports.ledger.save(record);
|
|
61
|
+
return { record: saved ?? record, attempts };
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
lastError = error;
|
|
65
|
+
if (!retryable(error, ports) || attempts >= maxAttempts)
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw new MeetingAutomationRuntimeError('persist_failed', 'meeting automation record could not be persisted', {
|
|
70
|
+
attempts,
|
|
71
|
+
cause: lastError instanceof Error ? lastError.message : String(lastError),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Provider-independent orchestration for meeting review package ingestion.
|
|
76
|
+
* The host owns workflow, Graph, identity and durable ledger ports; this core
|
|
77
|
+
* owns validation, normalization, replay keys, retry and persisted readback.
|
|
78
|
+
*/
|
|
79
|
+
export async function runMeetingAutomationRuntime(input, ports) {
|
|
80
|
+
const orgId = requireScope(input.org_id, 'org_id');
|
|
81
|
+
const projectId = requireScope(input.project_id, 'project_id');
|
|
82
|
+
if (!ports?.ledger || typeof ports.ledger.save !== 'function') {
|
|
83
|
+
throw new MeetingAutomationRuntimeError('invalid_ports', 'a meeting review ledger save port is required');
|
|
84
|
+
}
|
|
85
|
+
if (typeof ports.ledger.claimOrReplay !== 'function' || typeof ports.ledger.readback !== 'function') {
|
|
86
|
+
throw new MeetingAutomationRuntimeError('invalid_ports', 'meeting review ledger claimOrReplay and durable readback ports are required');
|
|
87
|
+
}
|
|
88
|
+
const normalizedPackage = normalizeReviewPackage(input);
|
|
89
|
+
// Keep the incoming contract separate from the persisted post-owner
|
|
90
|
+
// fingerprint. Owner resolution may add fields, while an explicit
|
|
91
|
+
// idempotency key must still reject a replay carrying a different input
|
|
92
|
+
// package. Ingestion time is intentionally excluded.
|
|
93
|
+
const inputFingerprint = digest({ org_id: orgId, project_id: projectId, review_package: normalizedPackage });
|
|
94
|
+
// An explicit key can be replayed before owner/Graph work. This keeps a
|
|
95
|
+
// duplicate delivery from doing any host-side resolution while the atomic
|
|
96
|
+
// claim below remains the authority for a concurrent miss.
|
|
97
|
+
const explicitIdempotencyKey = typeof input.idempotency_key === 'string' && input.idempotency_key.trim()
|
|
98
|
+
? input.idempotency_key.trim()
|
|
99
|
+
: null;
|
|
100
|
+
const earlyReplay = explicitIdempotencyKey && ports.ledger.findByIdempotencyKey
|
|
101
|
+
? await ports.ledger.findByIdempotencyKey(explicitIdempotencyKey, { org_id: orgId, project_id: projectId })
|
|
102
|
+
: null;
|
|
103
|
+
if (earlyReplay) {
|
|
104
|
+
const readback = await ports.ledger.readback(earlyReplay.record_id, { org_id: orgId, project_id: projectId });
|
|
105
|
+
if (!readback) {
|
|
106
|
+
throw new MeetingAutomationRuntimeError('readback_mismatch', 'meeting automation ledger replay was not durable', {
|
|
107
|
+
record_id: earlyReplay.record_id,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (readback.input_fingerprint && readback.input_fingerprint !== inputFingerprint) {
|
|
111
|
+
throw new MeetingAutomationRuntimeError('idempotency_conflict', 'meeting automation replay input differs from the claimed key', {
|
|
112
|
+
idempotency_key: explicitIdempotencyKey,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const replayPackage = readback.review_package;
|
|
116
|
+
const verified = verifyMeetingReviewPackage({
|
|
117
|
+
repository: input.loop_intent_repository,
|
|
118
|
+
reviewPackage: replayPackage,
|
|
119
|
+
orgId,
|
|
120
|
+
projectId,
|
|
121
|
+
});
|
|
122
|
+
if (readback.idempotency_key !== explicitIdempotencyKey) {
|
|
123
|
+
throw new MeetingAutomationRuntimeError('idempotency_conflict', 'idempotency key replay returned a different key', {
|
|
124
|
+
idempotency_key: explicitIdempotencyKey,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const knowledge = await runKnowledgeBridge({
|
|
128
|
+
ports,
|
|
129
|
+
orgId,
|
|
130
|
+
projectId,
|
|
131
|
+
reviewPackage: replayPackage,
|
|
132
|
+
record: readback,
|
|
133
|
+
idempotencyKey: explicitIdempotencyKey,
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
status: 'replayed',
|
|
137
|
+
idempotent: true,
|
|
138
|
+
attempts: 0,
|
|
139
|
+
record: readback,
|
|
140
|
+
readback,
|
|
141
|
+
verified,
|
|
142
|
+
workflow: null,
|
|
143
|
+
knowledge,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const ownerResolved = ports.resolveTaskOwners
|
|
147
|
+
? await ports.resolveTaskOwners({ task_candidates: normalizedPackage.task_candidates }, { org_id: orgId, project_id: projectId })
|
|
148
|
+
: null;
|
|
149
|
+
const reviewPackageWithOwners = ownerResolved?.task_candidates
|
|
150
|
+
? { ...normalizedPackage, task_candidates: ownerResolved.task_candidates }
|
|
151
|
+
: normalizedPackage;
|
|
152
|
+
// Owner resolution is an injected host port. Re-run the candidate input
|
|
153
|
+
// contract after it returns so a resolver cannot replace the normalized
|
|
154
|
+
// package with an invalid candidate shape before the review verification.
|
|
155
|
+
assertMeetingCandidatesInput(reviewPackageWithOwners);
|
|
156
|
+
const verified = verifyMeetingReviewPackage({
|
|
157
|
+
repository: input.loop_intent_repository,
|
|
158
|
+
// Owner resolution changes the contract being persisted. Verify the
|
|
159
|
+
// resolved package itself so an injected/host resolver cannot bypass the
|
|
160
|
+
// review-package contract.
|
|
161
|
+
reviewPackage: reviewPackageWithOwners,
|
|
162
|
+
orgId,
|
|
163
|
+
projectId,
|
|
164
|
+
});
|
|
165
|
+
const fingerprint = digest({ org_id: orgId, project_id: projectId, review_package: reviewPackageWithOwners });
|
|
166
|
+
const idempotencyKey = explicitIdempotencyKey
|
|
167
|
+
? explicitIdempotencyKey
|
|
168
|
+
: `meeting-review:${orgId}:${projectId}:${fingerprint}`;
|
|
169
|
+
const scope = { org_id: orgId, project_id: projectId };
|
|
170
|
+
const claim = await ports.ledger.claimOrReplay({
|
|
171
|
+
idempotency_key: idempotencyKey,
|
|
172
|
+
fingerprint,
|
|
173
|
+
scope,
|
|
174
|
+
execute: async () => {
|
|
175
|
+
const workflow = await ports.prepareWorkflow?.({
|
|
176
|
+
org_id: orgId,
|
|
177
|
+
project_id: projectId,
|
|
178
|
+
review_package: reviewPackageWithOwners,
|
|
179
|
+
idempotency_key: idempotencyKey,
|
|
180
|
+
}) ?? null;
|
|
181
|
+
const now = (ports.now ?? (() => new Date()))().toISOString();
|
|
182
|
+
const record = {
|
|
183
|
+
record_id: `mrev_${fingerprint.slice(0, 32)}`,
|
|
184
|
+
idempotency_key: idempotencyKey,
|
|
185
|
+
input_fingerprint: inputFingerprint,
|
|
186
|
+
fingerprint,
|
|
187
|
+
org_id: orgId,
|
|
188
|
+
project_id: projectId,
|
|
189
|
+
state: 'waiting_human',
|
|
190
|
+
review_package: reviewPackageWithOwners,
|
|
191
|
+
verified_loop_intents: verified.loopIntents.map(({ loop_intent }) => String(loop_intent.id ?? '')),
|
|
192
|
+
created_at: now,
|
|
193
|
+
actor_id: input.actor_id ?? null,
|
|
194
|
+
};
|
|
195
|
+
const persisted = await saveWithRetry(record, ports);
|
|
196
|
+
return {
|
|
197
|
+
record: persisted.record,
|
|
198
|
+
attempts: persisted.attempts,
|
|
199
|
+
workflow,
|
|
200
|
+
knowledge: null,
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
const execution = claim.execution;
|
|
205
|
+
if (execution.record.input_fingerprint && execution.record.input_fingerprint !== inputFingerprint) {
|
|
206
|
+
throw new MeetingAutomationRuntimeError('idempotency_conflict', 'meeting automation claim returned a different input package', {
|
|
207
|
+
idempotency_key: idempotencyKey,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const readback = await ports.ledger.readback(execution.record.record_id, scope);
|
|
211
|
+
if (!readback || readback.fingerprint !== execution.record.fingerprint) {
|
|
212
|
+
throw new MeetingAutomationRuntimeError('readback_mismatch', 'meeting automation ledger readback did not match the persisted record', {
|
|
213
|
+
record_id: execution.record.record_id,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const knowledge = await runKnowledgeBridge({
|
|
217
|
+
ports,
|
|
218
|
+
orgId,
|
|
219
|
+
projectId,
|
|
220
|
+
reviewPackage: execution.record.review_package,
|
|
221
|
+
record: readback,
|
|
222
|
+
idempotencyKey,
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
status: claim.status,
|
|
226
|
+
idempotent: claim.status === 'replayed',
|
|
227
|
+
attempts: claim.status === 'replayed' ? 0 : execution.attempts,
|
|
228
|
+
record: execution.record,
|
|
229
|
+
readback,
|
|
230
|
+
verified,
|
|
231
|
+
workflow: claim.status === 'replayed' ? null : execution.workflow,
|
|
232
|
+
knowledge,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async function runKnowledgeBridge({ ports, orgId, projectId, reviewPackage, record, idempotencyKey, }) {
|
|
236
|
+
if (!ports.bridgeKnowledge)
|
|
237
|
+
return null;
|
|
238
|
+
if (!ports.runOnce) {
|
|
239
|
+
throw new MeetingAutomationRuntimeError('invalid_ports', 'meeting automation knowledge bridge requires a durable post-commit runOnce port');
|
|
240
|
+
}
|
|
241
|
+
const knowledge = await ports.runOnce(`meeting-review:${idempotencyKey}:knowledge-bridge`, () => ports.bridgeKnowledge?.({
|
|
242
|
+
org_id: orgId,
|
|
243
|
+
project_id: projectId,
|
|
244
|
+
review_package: reviewPackage,
|
|
245
|
+
record,
|
|
246
|
+
idempotency_key: idempotencyKey,
|
|
247
|
+
}) ?? null);
|
|
248
|
+
return (knowledge ?? null);
|
|
249
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
declare const EXTERNAL_RUNTIME_CANDIDATE_SOURCE = "external_meeting_runtime";
|
|
2
|
+
type RecordValue = Record<string, unknown>;
|
|
3
|
+
export interface MeetingCandidate {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: 'candidate';
|
|
7
|
+
source: typeof EXTERNAL_RUNTIME_CANDIDATE_SOURCE;
|
|
8
|
+
case_scope: string | null;
|
|
9
|
+
owner_hint?: string | null;
|
|
10
|
+
due_hint?: string | null;
|
|
11
|
+
decision_type?: string;
|
|
12
|
+
source_excerpt?: string | null;
|
|
13
|
+
evidence_refs: unknown[];
|
|
14
|
+
}
|
|
15
|
+
export interface FollowUpDraft {
|
|
16
|
+
status: 'draft_only';
|
|
17
|
+
external_send_required_approval: true;
|
|
18
|
+
body: string;
|
|
19
|
+
}
|
|
20
|
+
export interface MeetingLoopIntent {
|
|
21
|
+
id?: string;
|
|
22
|
+
org_id: string;
|
|
23
|
+
project_id: string;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface MeetingLoopIntentRepository {
|
|
27
|
+
getLoopIntent(loopIntentId: string): MeetingLoopIntent | null | undefined;
|
|
28
|
+
}
|
|
29
|
+
export interface MeetingReviewPackage {
|
|
30
|
+
meeting_note_summary: unknown;
|
|
31
|
+
task_candidates: unknown;
|
|
32
|
+
decision_candidates: unknown;
|
|
33
|
+
follow_up_draft: unknown;
|
|
34
|
+
promotion_candidates: unknown;
|
|
35
|
+
loop_intent_ids: Record<string, unknown>;
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
}
|
|
38
|
+
export interface VerifyMeetingReviewPackageInput {
|
|
39
|
+
repository: MeetingLoopIntentRepository;
|
|
40
|
+
reviewPackage: MeetingReviewPackage;
|
|
41
|
+
orgId: string;
|
|
42
|
+
projectId: string;
|
|
43
|
+
}
|
|
44
|
+
export interface MeetingReviewLoopIntentEntry {
|
|
45
|
+
key: string;
|
|
46
|
+
loop_intent: MeetingLoopIntent;
|
|
47
|
+
}
|
|
48
|
+
export interface VerifiedMeetingReviewPackage {
|
|
49
|
+
loopIntents: MeetingReviewLoopIntentEntry[];
|
|
50
|
+
loopIntentByKey: Map<string, MeetingLoopIntent>;
|
|
51
|
+
}
|
|
52
|
+
export declare class MeetingAutomationContractError extends Error {
|
|
53
|
+
readonly code = "validation_error";
|
|
54
|
+
readonly statusCode = 400;
|
|
55
|
+
readonly status = 400;
|
|
56
|
+
readonly timestamp: string;
|
|
57
|
+
readonly details: RecordValue;
|
|
58
|
+
constructor(message: string, details?: RecordValue);
|
|
59
|
+
toJSON(): {
|
|
60
|
+
error: {
|
|
61
|
+
code: string;
|
|
62
|
+
message: string;
|
|
63
|
+
timestamp: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export declare function assertMeetingCandidatesInput(input: unknown): asserts input is RecordValue;
|
|
68
|
+
export declare function normalizeTaskCandidates(rawCandidates: unknown, { caseScope, evidenceRefs }?: {
|
|
69
|
+
caseScope?: string | null;
|
|
70
|
+
evidenceRefs?: unknown[];
|
|
71
|
+
}): MeetingCandidate[];
|
|
72
|
+
export declare function normalizeDecisionCandidates(rawCandidates: unknown, { caseScope, evidenceRefs }?: {
|
|
73
|
+
caseScope?: string | null;
|
|
74
|
+
evidenceRefs?: unknown[];
|
|
75
|
+
}): MeetingCandidate[];
|
|
76
|
+
export declare function normalizeFollowUpDraft(rawDraft: unknown): FollowUpDraft;
|
|
77
|
+
export declare const MEETING_REVIEW_OUTPUT_DEFINITIONS: readonly [{
|
|
78
|
+
readonly id: "meeting_note_draft";
|
|
79
|
+
readonly title: "議事録ドラフト";
|
|
80
|
+
readonly type: "meeting_note_draft";
|
|
81
|
+
readonly package_key: "meeting_note_summary";
|
|
82
|
+
readonly loop_intent_key: "transcript_to_meeting_note";
|
|
83
|
+
readonly write_back_target: "meeting_note_draft";
|
|
84
|
+
}, {
|
|
85
|
+
readonly id: "task_candidates";
|
|
86
|
+
readonly title: "Task候補";
|
|
87
|
+
readonly type: "task_candidates";
|
|
88
|
+
readonly package_key: "task_candidates";
|
|
89
|
+
readonly loop_intent_key: "meeting_note_to_tasks";
|
|
90
|
+
readonly write_back_target: "task_store";
|
|
91
|
+
}, {
|
|
92
|
+
readonly id: "decision_candidates";
|
|
93
|
+
readonly title: "Decision候補";
|
|
94
|
+
readonly type: "decision_candidates";
|
|
95
|
+
readonly package_key: "decision_candidates";
|
|
96
|
+
readonly loop_intent_key: "meeting_note_to_decisions";
|
|
97
|
+
readonly write_back_target: "graph_ssot_decision";
|
|
98
|
+
}, {
|
|
99
|
+
readonly id: "follow_up_draft";
|
|
100
|
+
readonly title: "フォローアップ文面ドラフト";
|
|
101
|
+
readonly type: "message_draft";
|
|
102
|
+
readonly package_key: "follow_up_draft";
|
|
103
|
+
readonly loop_intent_key: "post_meeting_follow_up_message";
|
|
104
|
+
readonly write_back_target: "external_message_draft";
|
|
105
|
+
}, {
|
|
106
|
+
readonly id: "promotion_candidates";
|
|
107
|
+
readonly title: "Graph / Learning昇格候補";
|
|
108
|
+
readonly type: "promotion_candidates";
|
|
109
|
+
readonly package_key: "promotion_candidates";
|
|
110
|
+
readonly loop_intent_key: "meeting_note_to_decisions";
|
|
111
|
+
readonly write_back_target: "candidate_store";
|
|
112
|
+
}];
|
|
113
|
+
export declare const MEETING_REVIEW_HUMAN_STEP_DEFINITIONS: readonly [{
|
|
114
|
+
readonly id: "approve_meeting_note_publish";
|
|
115
|
+
readonly step_type: "approval";
|
|
116
|
+
readonly prompt: "議事録ドラフトの公開可否を確認してください";
|
|
117
|
+
readonly reason: "required_before_publish";
|
|
118
|
+
readonly protects: readonly ["meeting_note_publish"];
|
|
119
|
+
readonly write_back_target: "meeting_note_draft";
|
|
120
|
+
readonly loop_intent_key: "transcript_to_meeting_note";
|
|
121
|
+
}, {
|
|
122
|
+
readonly id: "approve_task_candidates";
|
|
123
|
+
readonly step_type: "approval";
|
|
124
|
+
readonly prompt: "Task候補を作成してよいか確認してください";
|
|
125
|
+
readonly reason: "required_before_task_create";
|
|
126
|
+
readonly protects: readonly ["task_create"];
|
|
127
|
+
readonly write_back_target: "task_store";
|
|
128
|
+
readonly loop_intent_key: "meeting_note_to_tasks";
|
|
129
|
+
}, {
|
|
130
|
+
readonly id: "approve_decision_candidates";
|
|
131
|
+
readonly step_type: "approval";
|
|
132
|
+
readonly prompt: "Decision候補をGraph SSOTへ昇格してよいか確認してください";
|
|
133
|
+
readonly reason: "required_before_graph_promotion";
|
|
134
|
+
readonly protects: readonly ["decision_promotion", "graph_promotion"];
|
|
135
|
+
readonly write_back_target: "graph_ssot_decision";
|
|
136
|
+
readonly loop_intent_key: "meeting_note_to_decisions";
|
|
137
|
+
}, {
|
|
138
|
+
readonly id: "approve_follow_up_draft";
|
|
139
|
+
readonly step_type: "approval";
|
|
140
|
+
readonly prompt: "フォローアップ文面を外部送信してよいか確認してください";
|
|
141
|
+
readonly reason: "required_before_external_send";
|
|
142
|
+
readonly protects: readonly ["external_send"];
|
|
143
|
+
readonly write_back_target: "external_message_draft";
|
|
144
|
+
readonly loop_intent_key: "post_meeting_follow_up_message";
|
|
145
|
+
}, {
|
|
146
|
+
readonly id: "approve_promotion_candidates";
|
|
147
|
+
readonly step_type: "approval";
|
|
148
|
+
readonly prompt: "Graph / Learning昇格候補を次の審査へ回してよいか確認してください";
|
|
149
|
+
readonly reason: "required_before_candidate_promotion";
|
|
150
|
+
readonly protects: readonly ["graph_candidate_promotion", "learning_candidate_promotion"];
|
|
151
|
+
readonly write_back_target: "candidate_store";
|
|
152
|
+
readonly loop_intent_key: "meeting_note_to_decisions";
|
|
153
|
+
}];
|
|
154
|
+
export declare function verifyMeetingReviewPackage({ repository, reviewPackage, orgId, projectId }: VerifyMeetingReviewPackageInput): VerifiedMeetingReviewPackage;
|
|
155
|
+
export {};
|