Files
confidence-engine/docs/orchestrator-contract.md
T

114 lines
7.5 KiB
Markdown

# Orchestrator Contract — Confidence Engine v0.4
## 1. Exported Function Signatures & Shape (JavaScript)
### lib/analysis.js
```js
export async function analyseScenario(scenario, opts = {})
// @param {string} scenario
// @param {{ promptVersion?: "v0.2" | "v0.3" }} [opts]
// @returns {Promise<{ success: boolean, validationStatus: "valid"|"invalid",
// modelName: string|null, responseDurationMs: number, rawResponse: string|null,
// promptVersion: string|null, inputClassification: object|null, reconstruction: object|null,
// evidence: object[]|undefined, nextQuestion: string|undefined, errors: string[]|undefined,
// error: string|undefined, statusCode: number|undefined }>}
export const PROMPT_VERSIONS // { [key: string]: string }
export const DEFAULT_PROMPT_VERSION // "v0.2"
```
### lib/graph/schema.js
```js
export const SituationKind // { observation, reported_claim, metric, state, transition, relationship, assumption, unknown, conclusion }
export const SituationStatus // { known, unknown, provisional, supported, weakened, contradicted, resolved }
export const ConfidenceLevel // { low, medium, high }
export const SituationRelationship // { supports, weakens, contradicts, depends_on, causes, may_cause, measures, compares_with, updates, other }
export const situationNodeSchema // Zod → {@typedef SituationNode}
export const situationEdgeSchema // Zod → {@typedef SituationEdge}
export const situationGraphSchema // Zod → {@typedef SituationGraph}
export const graphUpdateSchema // Zod → {@typedef GraphUpdate}
export const startCaseRequestSchema // { scenario: string (1-10000), promptVersion?: string }
export const updateCaseRequestSchema// { situationGraph: SituationGraph, previousQuestion: string, answer: string (1-5000), promptVersion?: string }
/** @param {string} label */ /** @returns {string} */ export function makeNodeId(label)
/** @param {{ id?, label, description, kind?, status?, confidence?, value?, unit?, ... }} opts */ /** @returns {SituationNode} */ export function makeNode(opts)
/** @param {{ id?, fromNodeId, toNodeId, relationship?, confidence?, description? }} opts */ /** @returns {SituationEdge} */ export function makeEdge(opts)
/** @param {{ centralStatement?, nodes?, edges?, activeUnknownNodeId?, resolvedNodeIds?, currentSummary? }} opts */ /** @returns {SituationGraph} */ export function makeGraph(opts)
```
### lib/graph/utils.js
```js
export function validateGraphReferences(graph) // → { valid: boolean, errors: string[] }
export function detectDuplicateNodeIds(nodes) // → { nodeId, count }[]
export function detectDuplicateEdges(edges) // { edgeId, fromNodeId, toNodeId, relationship }[]
export function findDependentNodes(graph, nodeId) // → string[] (transitive)
export function findAffectedNodes(graph, nodeId) // → string[] (direct + indirect via affects/dependsOn)
/** @param {SituationGraph} graph */ /** @param {string} nodeId */ /** @param {string} newStatus */ /** @param {*} newValue */ /** @param {string} reason */
export function resolveUnknownNode(graph, nodeId, newStatus, newValue, reason) // → { success, error?, previousStatus?, newStatus?, previousValue?, newValue?, reason?, affectedNodes? }
export function selectActiveUnknownCandidate(graph, resolvedNodeIds) // → { nodeId, label, score } | null
/** @param {SituationGraph} graph */ /** @param {GraphUpdate} update */
export function applyGraphUpdate(graph, update) // → { success: boolean, errors?, nodes?, edges?, resolvedNodeIds? }
/** @param {SituationGraph} graph */ /** @param {GraphUpdate} update */
export function validateGraphUpdate(graph, update) // → { valid: boolean, errors: string[] }
```
### lib/graph/builder.js
```js
export function buildInitialGraph(analysisData) // @param {{ reconstruction, evidence? }} → { nodes: SituationNode[], edges: SituationEdge[] }
export function buildMinimalGraph(scenario) // @param {string} → { nodes, edges }
export function describeGraph(graph) // @param {{ nodes, edges }} → string (summary text)
```
## 2. Dependencies Between Files
```
lib/analysis.js
├── getConfig() from lib/config.js
├── getProvider() from lib/llm/provider.js [EXTERNAL]
├── buildPrompt() from lib/reconstruction/prompt.js
└── reconstructionV2/V1Schema from lib/reconstruction/schema.js
lib/graph/utils.js ← imports situationNodeSchema, situationEdgeSchema, situationGraphSchema from schema.js
lib/graph/builder.js ← imports situationNodeSchema, situationEdgeSchema, makeNodeId from schema.js
docs/archive/v0.4-handoff.md → references CaseOrchestrator.startCase()/updateCase() (not in any inspected file)
```
## 3. Side Effects (LLM Calls)
| Function | LLM Call? | Details |
|---|---|---|
| `analyseScenario()` | **Yes** | `provider.generateReconstruction(prompt, model)` — POST to configured LLM. Prompt from `buildPrompt(scenario, version)`. |
| All graph functions (`schema.js`, `utils.js`, `builder.js`) | No | Pure/deterministic only. |
| `startCase()` / `updateCase()` (per docs/archive/v0.4-handoff.md) | **Yes** | startCase: calls analyseScenario. updateCase: calls LLM via buildUpdatePrompt context + provider for GraphUpdate, then applyGraphUpdate(). |
## 4. Minimal Proposed Contract for API Functions
### startCase(body)
- **Input:** `{ scenario: string (1-10000), promptVersion?: string }` — validated by `startCaseRequestSchema`.
- **Flow:** validate → `analyseScenario()` → if ok, `buildInitialGraph(result)`; on failure return minimal graph via `buildMinimalGraph()`.
- **Output (success):** `{ success: true, graphSummary: string, nodeCount: number, edgeCount: number, activeUnknownNodeId: string|undefined, nextQuestion: string }`
- **Output (failure):** `{ success: false, error: string, graphSummary: string, nodeCount: number, edgeCount: number }`
### updateCase(body)
- **Input:** `{ situationGraph: SituationGraph, previousQuestion: string (1+), answer: string (1-5000), promptVersion?: string }` — validated by `updateCaseRequestSchema`.
- **Flow:** validate → `buildUpdatePrompt(ctx)` → LLM call for GraphUpdate proposal → `validateGraphUpdate()``applyGraphUpdate()` → resolve unknowns via `resolveUnknownNode()` → pick next candidate via `selectActiveUnknownCandidate()`.
- **Output (success):** `{ success: true, graphSummary: string, nodeChanges: { added, updated, removed }, edgeChanges: { added, removed }, resolvedNodes: string[], nextQuestion: string|null }`
- **Output (failure):** `{ success: false, error: string, graphSummary: string, nodeChanges: {}, edgeChanges: {}, resolvedNodes: [], nextQuestion: null }`
## 5. Missing Interfaces — TODO
1. **[TODO]** `CaseOrchestrator` class described in handoff but absent from all five inspected files. startCase()/updateCase() wrappers need implementation per above contract.
2. **[TODO]** `buildUpdatePrompt(ctx)` (per handoff lives in prompt-builder.js) — not reviewed; input/output needs a separate doc once the file is available.
3. **[TODO]** LLM provider interface (`getProvider()`, `generateReconstruction(prompt, model)`) — external dependency. Assumes rawResponse is parseable JSON matching v0.2/v0.1 schema; needs explicit contract.
4. **[TODO]** Error handling for updateCase() on malformed LLM JSON — handoff notes "generic 500"; needs structured retry/error contract.
5. **[TODO]** Completion heuristic `getCompletionStatus()` referenced in handoff but absent; needs contract (e.g., "complete" when no unresolved unknown nodes).
---
*End of contract.*