onto-mcp 0.4.11 → 0.4.13
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/.onto/authority/core-lexicon.yaml +1 -1
- package/.onto/authority/supported-models.yaml +153 -0
- package/.onto/domains/accounting-kr/competency_qs.md +153 -153
- package/.onto/processes/reconstruct/obligation-coverage-ledger.yaml +842 -0
- package/.onto/processes/reconstruct/obligation-coverage-recorded.yaml +225 -0
- package/.onto/processes/reconstruct/ontology-seeding-and-maturation-design.md +93 -54
- package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +202 -49
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +72 -1
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +35 -0
- package/.onto/processes/review/nesting-batch-worker-contract.md +1 -1
- package/.onto/processes/review/productized-live-path.md +9 -5
- package/.onto/processes/review/prompt-execution-runner-contract.md +32 -8
- package/.onto/processes/review/review-target-profile-contract.md +47 -4
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +11 -0
- package/.onto/processes/shared/target-material-kind-contract.md +1 -1
- package/README.md +64 -1
- package/dist/cli.js +11 -1
- package/dist/core-api/reconstruct-api.js +679 -18
- package/dist/core-api/review-api.js +70 -5
- package/dist/core-api/review-progress.js +7 -0
- package/dist/core-api/runtime-observation.js +7 -0
- package/dist/core-runtime/artifact-io.js +131 -0
- package/dist/core-runtime/cli/claude-code-review-unit-executor.js +21 -9
- package/dist/core-runtime/cli/claude-nesting-batch-worker.js +4 -2
- package/dist/core-runtime/cli/materialize-review-prompt-packets.js +68 -14
- package/dist/core-runtime/cli/prepare-review-session.js +34 -1
- package/dist/core-runtime/cli/render-review-final-output.js +2 -1
- package/dist/core-runtime/cli/run-review-prompt-execution.js +758 -48
- package/dist/core-runtime/cli/run-seats.js +18 -0
- package/dist/core-runtime/cli/runtime-submit-context.js +10 -2
- package/dist/core-runtime/cli/unit-resubmit.js +269 -0
- package/dist/core-runtime/cli/worker-structured-output.js +80 -2
- package/dist/core-runtime/discovery/host-detection.js +71 -22
- package/dist/core-runtime/discovery/review-cert-assemble.js +208 -0
- package/dist/core-runtime/discovery/review-cert-record.js +442 -0
- package/dist/core-runtime/discovery/review-execution-units.js +22 -0
- package/dist/core-runtime/discovery/seat-inventory.js +167 -0
- package/dist/core-runtime/discovery/settings-chain.js +311 -52
- package/dist/core-runtime/discovery/supported-models.js +289 -25
- package/dist/core-runtime/discovery/synthesize-cert-assemble.js +197 -0
- package/dist/core-runtime/discovery/synthesize-cert-capsule.js +399 -0
- package/dist/core-runtime/discovery/synthesize-cert-judge.js +340 -0
- package/dist/core-runtime/discovery/synthesize-cert-loop.js +234 -0
- package/dist/core-runtime/discovery/synthesize-cert-mutation.js +117 -0
- package/dist/core-runtime/discovery/synthesize-cert-packet.js +182 -0
- package/dist/core-runtime/discovery/synthesize-cert-record.js +831 -0
- package/dist/core-runtime/discovery/synthesize-cert-sampler.js +336 -0
- package/dist/core-runtime/effort-calibration-ingest.js +326 -0
- package/dist/core-runtime/effort-calibration-reconstruct.js +47 -0
- package/dist/core-runtime/effort-calibration-review.js +22 -0
- package/dist/core-runtime/effort-calibration-sweep.js +110 -0
- package/dist/core-runtime/effort-frontier.js +134 -0
- package/dist/core-runtime/llm/claude-bin.js +77 -0
- package/dist/core-runtime/llm/dispatch-breaker.js +412 -0
- package/dist/core-runtime/llm/dispatch-fallback-adapter-capabilities.js +33 -0
- package/dist/core-runtime/llm/llm-caller.js +316 -35
- package/dist/core-runtime/llm/mock-llm-realization.js +35 -4
- package/dist/core-runtime/llm/model-switcher.js +1 -1
- package/dist/core-runtime/llm/openai-responses-incomplete-error.js +46 -0
- package/dist/core-runtime/llm/sealed-dispatch-capability.js +359 -0
- package/dist/core-runtime/llm/structured-dispatch-error.js +15 -0
- package/dist/core-runtime/onboard/claude-profile-scan.js +65 -0
- package/dist/core-runtime/onboard/cli-host.js +5 -2
- package/dist/core-runtime/onboard/configure-provider.js +33 -1
- package/dist/core-runtime/onboard/host-target.js +28 -3
- package/dist/core-runtime/onboard/register.js +54 -12
- package/dist/core-runtime/pipeline-execution-ledger.js +10 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +37 -0
- package/dist/core-runtime/reconstruct/benchmark-evidence.js +16 -0
- package/dist/core-runtime/reconstruct/claim-projection-validation.js +19 -5
- package/dist/core-runtime/reconstruct/competency-projection-contract.js +63 -0
- package/dist/core-runtime/reconstruct/comprehension-artifact.js +321 -0
- package/dist/core-runtime/reconstruct/comprehension-reduce.js +367 -0
- package/dist/core-runtime/reconstruct/comprehension-semantic-map.js +771 -0
- package/dist/core-runtime/reconstruct/contract-registry.js +20 -0
- package/dist/core-runtime/reconstruct/directive-validation.js +4 -3
- package/dist/core-runtime/reconstruct/dispatch-fallback-artifacts.js +640 -0
- package/dist/core-runtime/reconstruct/execution-telemetry.js +84 -9
- package/dist/core-runtime/reconstruct/final-output-sections.js +89 -0
- package/dist/core-runtime/reconstruct/governing-snapshot.js +36 -1
- package/dist/core-runtime/reconstruct/leaf-reader.js +305 -0
- package/dist/core-runtime/reconstruct/llm-dispatch-failure.js +270 -0
- package/dist/core-runtime/reconstruct/llm-touch-fingerprint.js +94 -0
- package/dist/core-runtime/reconstruct/material-admission-validation.js +20 -5
- package/dist/core-runtime/reconstruct/material-profile-validation.js +24 -6
- package/dist/core-runtime/reconstruct/materialize-preparation.js +380 -23
- package/dist/core-runtime/reconstruct/maturation-validation.js +1522 -67
- package/dist/core-runtime/reconstruct/mock-llm-realization.js +120 -1
- package/dist/core-runtime/reconstruct/obligation-assertion.js +18 -0
- package/dist/core-runtime/reconstruct/ontology-seed-validation.js +39 -7
- package/dist/core-runtime/reconstruct/output-budget.js +6 -0
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +112 -5
- package/dist/core-runtime/reconstruct/post-seed-validation.js +122 -11
- package/dist/core-runtime/reconstruct/proof-authority-validation.js +2 -6
- package/dist/core-runtime/reconstruct/purpose-authority-validation.js +119 -7
- package/dist/core-runtime/reconstruct/record.js +49 -3
- package/dist/core-runtime/reconstruct/registry-verification-validation.js +41 -5
- package/dist/core-runtime/reconstruct/run-control-validation.js +1019 -37
- package/dist/core-runtime/reconstruct/run.js +5409 -517
- package/dist/core-runtime/reconstruct/seed-authoring-readiness-validation.js +56 -8
- package/dist/core-runtime/reconstruct/semantic-quality-gate.js +112 -7
- package/dist/core-runtime/reconstruct/source-observation-delta-validation.js +53 -5
- package/dist/core-runtime/reconstruct/source-observations.js +166 -0
- package/dist/core-runtime/reconstruct/source-safety-validation.js +77 -188
- package/dist/core-runtime/reconstruct/source-scout-pack-validation.js +50 -6
- package/dist/core-runtime/reconstruct/terminal-validation.js +145 -13
- package/dist/core-runtime/review/continuation-plan.js +12 -5
- package/dist/core-runtime/review/issue-artifact-runtime.js +4 -1
- package/dist/core-runtime/review/materializers.js +100 -11
- package/dist/core-runtime/review/nesting-batch.js +6 -2
- package/dist/core-runtime/review/obligation-shardability.js +138 -0
- package/dist/core-runtime/review/pipeline-execution-ledger.js +42 -2
- package/dist/core-runtime/review/review-artifact-utils.js +219 -7
- package/dist/core-runtime/review/review-execution-steps.js +32 -8
- package/dist/core-runtime/review/review-progress-contract.js +8 -0
- package/dist/core-runtime/review/review-prompt-budget.js +97 -0
- package/dist/core-runtime/review/semantic-quality-gate.js +33 -7
- package/dist/core-runtime/review/spreadsheet-review-disposition.js +94 -0
- package/dist/core-runtime/route-identity.js +182 -0
- package/dist/core-runtime/spreadsheet-header-escalation.js +204 -0
- package/dist/core-runtime/spreadsheet-structure-observer.js +2689 -0
- package/dist/core-runtime/target-material-kind.js +58 -0
- package/dist/mcp/server.js +27 -5
- package/dist/mcp/tool-schemas.js +8 -0
- package/dist/tui/app.js +167 -0
- package/dist/tui/data/event-follower.js +116 -0
- package/dist/tui/data/node-detail.js +42 -0
- package/dist/tui/data/projection-poll.js +26 -0
- package/dist/tui/data/session-discovery.js +65 -0
- package/dist/tui/index.js +108 -0
- package/dist/tui/screens/log.js +25 -0
- package/dist/tui/screens/node-detail.js +17 -0
- package/dist/tui/screens/session-selector.js +26 -0
- package/dist/tui/screens/workflow-tree.js +90 -0
- package/dist/tui/view-model/reconstruct-adapter.js +162 -0
- package/dist/tui/view-model/review-adapter.js +270 -0
- package/dist/tui/view-model/tree-view-model.js +19 -0
- package/package.json +20 -3
- package/settings.example.json +77 -16
|
@@ -3,24 +3,206 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parse as parseYaml } from "yaml";
|
|
5
5
|
import { RECONSTRUCT_STAGE_IDS, } from "../core-runtime/reconstruct/artifact-types.js";
|
|
6
|
-
import { materializeReconstructPreparationArtifacts, } from "../core-runtime/reconstruct/materialize-preparation.js";
|
|
6
|
+
import { deriveDocumentExcerptProjectionBudget, DOCUMENT_EXCERPT_PROJECTION_FLOOR, materializeReconstructPreparationArtifacts, } from "../core-runtime/reconstruct/materialize-preparation.js";
|
|
7
7
|
import { writeTargetMaterialProfileValidationArtifact, } from "../core-runtime/reconstruct/material-profile-validation.js";
|
|
8
|
-
import { assembleReconstructRecord, } from "../core-runtime/reconstruct/record.js";
|
|
8
|
+
import { assembleReconstructRecord, reconstructTerminalStatus, } from "../core-runtime/reconstruct/record.js";
|
|
9
|
+
export { reconstructTerminalStatus, } from "../core-runtime/reconstruct/record.js";
|
|
9
10
|
import { createDirectCallReconstructConfirmationProvider, createDirectCallReconstructDirectiveAuthor, runReconstruct, } from "../core-runtime/reconstruct/run.js";
|
|
11
|
+
import { RECONSTRUCT_SEMANTIC_AUTHOR_MAX_BASE_OUTPUT_TOKENS, } from "../core-runtime/reconstruct/output-budget.js";
|
|
10
12
|
// Explicit reconstruct mock realization switch point (INV-MOCK-1 boundary;
|
|
11
13
|
// allowlisted in scripts/check-import-boundary.ts). Active only when
|
|
12
14
|
// ONTO_LLM_MOCK=1; mock runs record mock actor ids in the run manifest.
|
|
13
15
|
import { RECONSTRUCT_MOCK_AUTHOR_ID, RECONSTRUCT_MOCK_CONFIRMATION_PROVIDER_ID, callReconstructMockLlm, isReconstructMockLlmRealizationEnabled, } from "../core-runtime/reconstruct/mock-llm-realization.js";
|
|
14
|
-
import { assertSettingsModelsSupported, resolveSettingsChain, resolveReconstructActorLlmSettings, } from "../core-runtime/discovery/settings-chain.js";
|
|
16
|
+
import { assertSettingsModelsSupported, completeDispatchBreakerSettings, isReconstructSemanticMapAuthoringEnabled, resolveOptionalReconstructActorLlmSettings, resolveSettingsChain, resolveReconstructActorLlmSettings, resolveReconstructSemanticAuthorLlmRuntimeSettings, } from "../core-runtime/discovery/settings-chain.js";
|
|
17
|
+
import { assertDispatchFallbackSessionAdmission } from "../core-runtime/reconstruct/dispatch-fallback-artifacts.js";
|
|
18
|
+
import { normalizeLlmModelSwitcher, } from "../core-runtime/llm/model-switcher.js";
|
|
15
19
|
import { resolveOntoHome, } from "../core-runtime/discovery/onto-home.js";
|
|
16
|
-
import {
|
|
20
|
+
import { isSupportedModelRoute, loadSupportedModelRegistry, supportedModelMaxOutputTokens, } from "../core-runtime/discovery/supported-models.js";
|
|
21
|
+
import { applyOpenAIResponsesOutputHeadroom, resolveLlmProviderConfig, } from "../core-runtime/llm/llm-caller.js";
|
|
22
|
+
import { createSealedDispatchCapability, SemanticMapDispatchAccounting, } from "../core-runtime/llm/sealed-dispatch-capability.js";
|
|
23
|
+
import { createReconstructExecutionTelemetryCollector } from "../core-runtime/reconstruct/execution-telemetry.js";
|
|
17
24
|
import { writeOntologySeedValidationArtifact, writeCandidateDispositionValidationArtifact, } from "../core-runtime/reconstruct/ontology-seed-validation.js";
|
|
18
25
|
import { writeSourceObservationDirectiveValidationArtifact, } from "../core-runtime/reconstruct/directive-validation.js";
|
|
19
26
|
import { loadReconstructSourceProfiles, } from "../core-runtime/reconstruct/source-profiles.js";
|
|
20
27
|
import { assertReconstructDomainId, } from "../core-runtime/reconstruct/domain-id.js";
|
|
21
|
-
import { buildReconstructPipelineExecutionLedger, } from "../core-runtime/reconstruct/pipeline-execution-ledger.js";
|
|
28
|
+
import { buildReconstructPipelineExecutionLedger, reconstructStageIdForArtifactRef, reconstructStageOwner, } from "../core-runtime/reconstruct/pipeline-execution-ledger.js";
|
|
29
|
+
import { reconcileReconstructLlmDispatchFailures, } from "../core-runtime/reconstruct/run-control-validation.js";
|
|
30
|
+
import { isReconstructLlmDispatchFailureRef, projectReconstructLlmDispatchFailureSummary, readReconstructLlmDispatchFailureArtifactWithHash, readReconstructLlmDispatchFailureError, } from "../core-runtime/reconstruct/llm-dispatch-failure.js";
|
|
22
31
|
import { spawnRuntimeWatcherPane, } from "../core-runtime/cli/spawn-watcher.js";
|
|
32
|
+
import { assertPathInsideRoot } from "../core-runtime/path-boundary.js";
|
|
23
33
|
import { appendRuntimeStatusEventSync, runWithRuntimeObservationContext, } from "../core-runtime/observability/runtime-stream-observation.js";
|
|
34
|
+
function failedReconstructProgress(failure, completedStageRefs) {
|
|
35
|
+
return {
|
|
36
|
+
executionProfile: null,
|
|
37
|
+
currentStageId: failure.unit_id,
|
|
38
|
+
stageCount: RECONSTRUCT_STAGE_IDS.length,
|
|
39
|
+
liveness: {
|
|
40
|
+
state: "halted_or_partial",
|
|
41
|
+
recommendedPollIntervalMs: null,
|
|
42
|
+
},
|
|
43
|
+
countSummary: {
|
|
44
|
+
sourceObservationCount: null,
|
|
45
|
+
selectedObservationCount: null,
|
|
46
|
+
semanticClaimCount: null,
|
|
47
|
+
confirmedClaimCount: null,
|
|
48
|
+
partialClaimCount: null,
|
|
49
|
+
deferredClaimCount: null,
|
|
50
|
+
competencyQuestionCount: null,
|
|
51
|
+
assessmentCount: null,
|
|
52
|
+
failureCount: null,
|
|
53
|
+
revisionProposalCount: null,
|
|
54
|
+
unresolvedCount: null,
|
|
55
|
+
passRate: null,
|
|
56
|
+
},
|
|
57
|
+
answerabilitySummary: null,
|
|
58
|
+
stages: RECONSTRUCT_STAGE_IDS.map((stageId) => ({
|
|
59
|
+
stageId,
|
|
60
|
+
state: stageId === failure.unit_id
|
|
61
|
+
? "halted"
|
|
62
|
+
: completedStageRefs.has(stageId)
|
|
63
|
+
? "completed"
|
|
64
|
+
: "pending",
|
|
65
|
+
owner: stageId === failure.unit_id
|
|
66
|
+
? reconstructStageOwner(stageId)
|
|
67
|
+
: null,
|
|
68
|
+
artifactRefs: stageId === failure.unit_id
|
|
69
|
+
? [failure.failure_artifact_ref]
|
|
70
|
+
: [...(completedStageRefs.get(stageId) ?? [])],
|
|
71
|
+
reason: stageId === failure.unit_id ? failure.failure_code : null,
|
|
72
|
+
authorityImpact: stageId === failure.unit_id
|
|
73
|
+
? "The provider output ceiling stopped the owning actor before a canonical stage artifact was accepted."
|
|
74
|
+
: null,
|
|
75
|
+
})),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function isRegularRefInsideSession(sessionRoot, artifactRef) {
|
|
79
|
+
const relative = path.relative(sessionRoot, path.resolve(artifactRef));
|
|
80
|
+
if (relative.startsWith("..") || path.isAbsolute(relative))
|
|
81
|
+
return false;
|
|
82
|
+
try {
|
|
83
|
+
const stat = await fs.lstat(artifactRef);
|
|
84
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
85
|
+
return false;
|
|
86
|
+
const [realSessionRoot, realArtifactRef] = await Promise.all([
|
|
87
|
+
fs.realpath(sessionRoot),
|
|
88
|
+
fs.realpath(artifactRef),
|
|
89
|
+
]);
|
|
90
|
+
const realRelative = path.relative(realSessionRoot, realArtifactRef);
|
|
91
|
+
return !realRelative.startsWith("..") && !path.isAbsolute(realRelative);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function collectFailedStatusArtifactEvidence(args) {
|
|
98
|
+
const reusable = new Set();
|
|
99
|
+
const completedStageRefs = new Map();
|
|
100
|
+
const addStageRef = (stageId, ref) => {
|
|
101
|
+
const refs = completedStageRefs.get(stageId) ?? [];
|
|
102
|
+
if (!refs.includes(ref))
|
|
103
|
+
refs.push(ref);
|
|
104
|
+
completedStageRefs.set(stageId, refs);
|
|
105
|
+
};
|
|
106
|
+
for (const transaction of args.runControl.write_transactions) {
|
|
107
|
+
if (transaction.owner_attempt_id !== args.ownerAttemptId ||
|
|
108
|
+
transaction.transaction_status !== "committed" ||
|
|
109
|
+
!transaction.committed_hash ||
|
|
110
|
+
isReconstructLlmDispatchFailureRef(args.sessionRoot, transaction.artifact_ref) ||
|
|
111
|
+
!(await isRegularRefInsideSession(args.sessionRoot, transaction.artifact_ref))) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const bytes = await fs.readFile(transaction.artifact_ref);
|
|
115
|
+
const observedHash = crypto.createHash("sha256").update(bytes).digest("hex");
|
|
116
|
+
if (observedHash !== transaction.committed_hash)
|
|
117
|
+
continue;
|
|
118
|
+
reusable.add(transaction.artifact_ref);
|
|
119
|
+
const stageId = reconstructStageIdForArtifactRef(transaction.artifact_ref);
|
|
120
|
+
if (stageId)
|
|
121
|
+
addStageRef(stageId, transaction.artifact_ref);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
reusableArtifactRefs: [...reusable].sort(),
|
|
125
|
+
completedStageRefs,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async function trustedFailedSessionStatus(args) {
|
|
129
|
+
if (!args.reconciliation)
|
|
130
|
+
return null;
|
|
131
|
+
const runControl = args.reconciliation.runControl;
|
|
132
|
+
const validation = args.reconciliation.validation ??
|
|
133
|
+
await readYamlArtifactIfPresent(args.runControlValidationRef);
|
|
134
|
+
const latestAttempt = runControl.attempt_rows.at(-1) ?? null;
|
|
135
|
+
if (latestAttempt?.attempt_status !== "failed")
|
|
136
|
+
return null;
|
|
137
|
+
const failureTransactions = runControl.write_transactions.filter((row) => row.owner_attempt_id === latestAttempt.attempt_id &&
|
|
138
|
+
row.transaction_status === "committed" &&
|
|
139
|
+
isReconstructLlmDispatchFailureRef(args.sessionRoot, row.artifact_ref));
|
|
140
|
+
const failureTransaction = failureTransactions.length === 1
|
|
141
|
+
? failureTransactions[0]
|
|
142
|
+
: null;
|
|
143
|
+
if (!validation ||
|
|
144
|
+
validation.validation_status !== "valid" ||
|
|
145
|
+
validation.current_attempt_id !== latestAttempt.attempt_id ||
|
|
146
|
+
!failureTransaction) {
|
|
147
|
+
throw new Error(`reconstruct session has no trusted failed terminal: ${args.sessionRoot}`);
|
|
148
|
+
}
|
|
149
|
+
const failureRead = await readReconstructLlmDispatchFailureArtifactWithHash({
|
|
150
|
+
sessionRoot: args.sessionRoot,
|
|
151
|
+
artifactRef: failureTransaction.artifact_ref,
|
|
152
|
+
});
|
|
153
|
+
if (failureTransaction.prepared_content_hash !==
|
|
154
|
+
failureTransaction.committed_hash ||
|
|
155
|
+
failureRead.sha256 !== failureTransaction.committed_hash ||
|
|
156
|
+
failureRead.artifact.session_id !== runControl.session_id ||
|
|
157
|
+
failureRead.artifact.owner_attempt_id !== latestAttempt.attempt_id) {
|
|
158
|
+
throw new Error(`trusted failed terminal changed after validation: ${failureTransaction.artifact_ref}`);
|
|
159
|
+
}
|
|
160
|
+
const failure = projectReconstructLlmDispatchFailureSummary(failureRead.artifact, failureTransaction.artifact_ref);
|
|
161
|
+
const artifactEvidence = await collectFailedStatusArtifactEvidence({
|
|
162
|
+
sessionRoot: args.sessionRoot,
|
|
163
|
+
runControl,
|
|
164
|
+
ownerAttemptId: latestAttempt.attempt_id,
|
|
165
|
+
});
|
|
166
|
+
artifactEvidence.completedStageRefs.set("run_control", [args.runControlRef]);
|
|
167
|
+
artifactEvidence.completedStageRefs.set("run_control_validation", [
|
|
168
|
+
args.runControlValidationRef,
|
|
169
|
+
]);
|
|
170
|
+
return {
|
|
171
|
+
sessionId: runControl.session_id,
|
|
172
|
+
sessionRoot: args.sessionRoot,
|
|
173
|
+
status: "failed",
|
|
174
|
+
artifactRefs: {
|
|
175
|
+
reconstruct_run_control: args.runControlRef,
|
|
176
|
+
reconstruct_run_control_validation: args.runControlValidationRef,
|
|
177
|
+
},
|
|
178
|
+
claimProjection: null,
|
|
179
|
+
claimProjectionValidation: null,
|
|
180
|
+
progress: failedReconstructProgress(failure, artifactEvidence.completedStageRefs),
|
|
181
|
+
reconstructRecord: null,
|
|
182
|
+
runControlRef: args.runControlRef,
|
|
183
|
+
runControlValidationRef: args.runControlValidationRef,
|
|
184
|
+
failure,
|
|
185
|
+
reusableArtifactRefs: artifactEvidence.reusableArtifactRefs,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
export async function recoverReconstructFailedRunStatus(args) {
|
|
189
|
+
const typedFailure = readReconstructLlmDispatchFailureError(args.error);
|
|
190
|
+
if (!typedFailure)
|
|
191
|
+
return null;
|
|
192
|
+
const runControlRef = path.join(args.sessionRoot, "reconstruct-run-control.yaml");
|
|
193
|
+
const runControlValidationRef = path.join(args.sessionRoot, "reconstruct-run-control-validation.yaml");
|
|
194
|
+
const reconciliation = await reconcileReconstructLlmDispatchFailures({
|
|
195
|
+
sessionRoot: args.sessionRoot,
|
|
196
|
+
runControlPath: runControlRef,
|
|
197
|
+
validationOutputPath: runControlValidationRef,
|
|
198
|
+
});
|
|
199
|
+
return trustedFailedSessionStatus({
|
|
200
|
+
sessionRoot: args.sessionRoot,
|
|
201
|
+
reconciliation,
|
|
202
|
+
runControlRef,
|
|
203
|
+
runControlValidationRef,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
24
206
|
async function directoryExists(directoryPath) {
|
|
25
207
|
try {
|
|
26
208
|
const stat = await fs.stat(directoryPath);
|
|
@@ -35,6 +217,128 @@ function resolveFromBase(basePath, maybeRelativePath) {
|
|
|
35
217
|
? path.resolve(maybeRelativePath)
|
|
36
218
|
: path.resolve(basePath, maybeRelativePath);
|
|
37
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Pure adopt-vs-degrade decision for the opt-in answer-support judge config.
|
|
222
|
+
* The judge keeps the semantic author's config except for the requested
|
|
223
|
+
* overrides. A judgeModelCandidate (already resolved on the author's provider,
|
|
224
|
+
* so its credentials/adapter match the author) is adopted only when it is a
|
|
225
|
+
* benchmark-verified route (INV-MODEL-1) AND keeps the author's provider; any
|
|
226
|
+
* other case degrades to the author model with a recorded note. Effort always
|
|
227
|
+
* INHERITS the author's effective effort (e.g. a pinned `--effort`) unless
|
|
228
|
+
* judgeLlmEffort explicitly overrides it — never the model candidate's raw
|
|
229
|
+
* settings effort, which could otherwise silently run the judge weaker than the
|
|
230
|
+
* author. Returns `undefined` config when nothing was requested (caller inherits
|
|
231
|
+
* the author config — zero change).
|
|
232
|
+
*/
|
|
233
|
+
export function resolveJudgeLlmConfig(args) {
|
|
234
|
+
if (!args.judgeLlmEffort && !args.judgeModelCandidate) {
|
|
235
|
+
return { judgeLlmConfig: undefined, note: null };
|
|
236
|
+
}
|
|
237
|
+
const judge = { ...args.authorLlmConfig };
|
|
238
|
+
const authorEffort = args.authorLlmConfig.reasoning_effort;
|
|
239
|
+
let note = null;
|
|
240
|
+
const candidate = args.judgeModelCandidate;
|
|
241
|
+
if (candidate) {
|
|
242
|
+
// INV-MODEL-1 is keyed by MODEL provider (e.g. openai/gpt-5.5), not the
|
|
243
|
+
// runtime adapter provider (OpenAI OAuth normalizes to codex). Check the
|
|
244
|
+
// model provider so a supported judge model is not spuriously degraded.
|
|
245
|
+
const supported = isSupportedModelRoute(args.judgeModelProvider, candidate.model_id, args.registry,
|
|
246
|
+
// Judge adoption is a NAMED non-settings dispatch (design §2.3): a
|
|
247
|
+
// role-restricted entry (e.g. synthesize-only) must not be adoptable
|
|
248
|
+
// as the answer-support judge.
|
|
249
|
+
{ kind: "request_judge" });
|
|
250
|
+
// Credential safety: the candidate resolves on the author's provider, so its
|
|
251
|
+
// runtime provider must match the author's (guarantees api_key_env/adapter
|
|
252
|
+
// never cross providers). Uses the runtime provider, not the model provider.
|
|
253
|
+
const sameProvider = candidate.provider === args.authorLlmConfig.provider;
|
|
254
|
+
if (supported && sameProvider) {
|
|
255
|
+
Object.assign(judge, candidate);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
note = `answer-support judge model override (${args.judgeModelProvider ?? "(unresolved provider)"}/${candidate.model_id ?? "(unresolved model)"}) ${supported
|
|
259
|
+
? "requires a different provider than the semantic author"
|
|
260
|
+
: "is not a benchmark-verified route"}; degraded to the semantic-author model`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Effort = explicit judge override, else the author's effective effort. This
|
|
264
|
+
// wins over any reasoning_effort Object.assign copied from the model candidate
|
|
265
|
+
// (the candidate is resolved without the author's effort pin, so its raw
|
|
266
|
+
// settings effort can diverge from the author's pinned effort).
|
|
267
|
+
if (args.judgeLlmEffort)
|
|
268
|
+
judge.reasoning_effort = args.judgeLlmEffort;
|
|
269
|
+
else if (authorEffort !== undefined)
|
|
270
|
+
judge.reasoning_effort = authorEffort;
|
|
271
|
+
else
|
|
272
|
+
delete judge.reasoning_effort;
|
|
273
|
+
const judgeLlmConfig = args.outputHeadroom
|
|
274
|
+
? applyOpenAIResponsesOutputHeadroom({
|
|
275
|
+
config: judge,
|
|
276
|
+
selection: args.outputHeadroom.selection,
|
|
277
|
+
headroomTokens: args.outputHeadroom.headroomTokens,
|
|
278
|
+
maxBaseOutputTokens: RECONSTRUCT_SEMANTIC_AUTHOR_MAX_BASE_OUTPUT_TOKENS,
|
|
279
|
+
modelMaxOutputTokens: supportedModelMaxOutputTokens(args.registry, args.judgeModelProvider ?? "", judge.model_id ?? ""),
|
|
280
|
+
})
|
|
281
|
+
: judge;
|
|
282
|
+
return { judgeLlmConfig, note };
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Mock-safe IDENTITY projection of the optional synthesize seat (design §5.4):
|
|
286
|
+
* carries only the dispatch-identity axes the reuse fold and census read
|
|
287
|
+
* (provider/model/effort/base_url) — deliberately NOT resolveLlmProviderConfig,
|
|
288
|
+
* which validates provider/auth combinations and resolves credentials that a
|
|
289
|
+
* mock run must not require. The identity is deterministic per seat edit, so
|
|
290
|
+
* P3's fold-rotation assertions hold under mock without any live material.
|
|
291
|
+
* (No execution_adapter under mock — the canonical fold serializes it as
|
|
292
|
+
* "default"; live runs fold the real adapter.)
|
|
293
|
+
*/
|
|
294
|
+
export function synthesizeSeatIdentityProjection(selection) {
|
|
295
|
+
return {
|
|
296
|
+
...(selection.provider !== undefined
|
|
297
|
+
? { provider: selection.provider }
|
|
298
|
+
: {}),
|
|
299
|
+
...(selection.model !== undefined ? { model_id: selection.model } : {}),
|
|
300
|
+
...(selection.effort !== undefined
|
|
301
|
+
? { reasoning_effort: selection.effort }
|
|
302
|
+
: {}),
|
|
303
|
+
...(selection.base_url !== undefined
|
|
304
|
+
? { base_url: selection.base_url }
|
|
305
|
+
: {}),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* The ONE deterministic seam from post-chain settings to the factory's
|
|
310
|
+
* semantic-map wiring (design §5.4/§5.5): opt-in read, single seat read
|
|
311
|
+
* (resolveOptionalReconstructActorLlmSettings), live provider completion vs
|
|
312
|
+
* mock identity projection, and the dormant-seat honesty note. Coverage is
|
|
313
|
+
* two-layered: unit tests exercise this function over resolved settings, and
|
|
314
|
+
* the seam→factory CONSUMPTION edge is bound by the mock E2Es — the dormant
|
|
315
|
+
* branch via the N11 note, the active branch via the P3 census
|
|
316
|
+
* synthesize_model_identity assertion (dropping either factory spread at the
|
|
317
|
+
* runReconstruct call site fails P3).
|
|
318
|
+
*/
|
|
319
|
+
export function resolveSemanticMapSynthesizeWiring(args) {
|
|
320
|
+
const enabled = isReconstructSemanticMapAuthoringEnabled(args.settings);
|
|
321
|
+
const seat = resolveOptionalReconstructActorLlmSettings(args.settings, "semantic_map_synthesize");
|
|
322
|
+
if (seat === undefined)
|
|
323
|
+
return { enableSemanticMapAuthoring: enabled };
|
|
324
|
+
if (!enabled) {
|
|
325
|
+
return {
|
|
326
|
+
enableSemanticMapAuthoring: false,
|
|
327
|
+
dormantSeatNote: "semantic_map_synthesize seat is configured but reconstruct.execution.semantic_map_authoring is off — the seat is dormant (no synthesize dispatch, not gate-validated) until the opt-in is enabled",
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
enableSemanticMapAuthoring: true,
|
|
332
|
+
semanticMapSynthesizeLlmConfig: args.mockRealizationEnabled
|
|
333
|
+
? synthesizeSeatIdentityProjection(seat)
|
|
334
|
+
: resolveLlmProviderConfig({
|
|
335
|
+
config: { llm: seat },
|
|
336
|
+
...(args.llmEffortOverride
|
|
337
|
+
? { cliOverrides: args.llmEffortOverride }
|
|
338
|
+
: {}),
|
|
339
|
+
}),
|
|
340
|
+
};
|
|
341
|
+
}
|
|
38
342
|
function dateStamp() {
|
|
39
343
|
return new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
40
344
|
}
|
|
@@ -118,15 +422,20 @@ function deriveReconstructProgress(args) {
|
|
|
118
422
|
});
|
|
119
423
|
const lastReachedStage = [...stages].reverse().find((stage) => stage.state !== "pending") ??
|
|
120
424
|
stages[0];
|
|
425
|
+
// Terminality (completed / graceful-blocked / graceful-limited) is judged once, via the single
|
|
426
|
+
// projection (design §16.7). A graceful terminal is terminal for polling (stop) but not
|
|
427
|
+
// "completed" — its liveness state stays "halted_or_partial" while the poll interval goes null.
|
|
428
|
+
const terminalStatus = reconstructTerminalStatus(args.record);
|
|
429
|
+
const isCompleted = terminalStatus === "completed";
|
|
430
|
+
const isGracefulTerminal = terminalStatus === "blocked" || terminalStatus === "limited";
|
|
431
|
+
const isTerminal = isCompleted || isGracefulTerminal;
|
|
121
432
|
return {
|
|
122
433
|
executionProfile: args.runManifest?.execution_profile ?? null,
|
|
123
434
|
currentStageId: lastReachedStage.stageId,
|
|
124
435
|
stageCount: RECONSTRUCT_STAGE_IDS.length,
|
|
125
436
|
liveness: {
|
|
126
|
-
state:
|
|
127
|
-
|
|
128
|
-
: "halted_or_partial",
|
|
129
|
-
recommendedPollIntervalMs: args.record.record_stage === "completed" ? null : 1000,
|
|
437
|
+
state: isCompleted ? "completed" : "halted_or_partial",
|
|
438
|
+
recommendedPollIntervalMs: isTerminal ? null : 1000,
|
|
130
439
|
},
|
|
131
440
|
countSummary: {
|
|
132
441
|
sourceObservationCount: args.metrics?.source_observation_count ?? null,
|
|
@@ -171,6 +480,23 @@ function recordArtifactRefsFromPreparation(refs) {
|
|
|
171
480
|
source_observations: refs.source_observations,
|
|
172
481
|
};
|
|
173
482
|
}
|
|
483
|
+
export async function tryCreateEligiblePrimarySealedDispatchCapability(args) {
|
|
484
|
+
const selection = normalizeLlmModelSwitcher(args.llm);
|
|
485
|
+
if (!selection ||
|
|
486
|
+
selection.auth !== "api_key" ||
|
|
487
|
+
selection.execution_route !== "direct_model_call" ||
|
|
488
|
+
(selection.execution_adapter !== "openai_sdk" &&
|
|
489
|
+
selection.execution_adapter !== "anthropic_sdk") ||
|
|
490
|
+
selection.base_url !== undefined) {
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
return await createSealedDispatchCapability(args);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
return undefined;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
174
500
|
export function createOntoReconstructCoreApi(options = {}) {
|
|
175
501
|
const ontoHome = resolveOntoHome(options.ontoHome);
|
|
176
502
|
return {
|
|
@@ -187,6 +513,11 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
187
513
|
const sessionRoot = request.sessionRoot
|
|
188
514
|
? resolveFromBase(projectRoot, request.sessionRoot)
|
|
189
515
|
: createDefaultSessionRoot(projectRoot);
|
|
516
|
+
await assertPathInsideRoot({
|
|
517
|
+
root: projectRoot,
|
|
518
|
+
candidate: sessionRoot,
|
|
519
|
+
label: "reconstruct sessionRoot",
|
|
520
|
+
});
|
|
190
521
|
const profilesRoot = await resolveProfilesRoot({
|
|
191
522
|
projectRoot,
|
|
192
523
|
...(request.profilesRoot
|
|
@@ -233,6 +564,11 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
233
564
|
const sessionRoot = request.sessionRoot
|
|
234
565
|
? resolveFromBase(projectRoot, request.sessionRoot)
|
|
235
566
|
: createDefaultSessionRoot(projectRoot);
|
|
567
|
+
await assertPathInsideRoot({
|
|
568
|
+
root: projectRoot,
|
|
569
|
+
candidate: sessionRoot,
|
|
570
|
+
label: "reconstruct sessionRoot",
|
|
571
|
+
});
|
|
236
572
|
const profilesRoot = await resolveProfilesRoot({
|
|
237
573
|
projectRoot,
|
|
238
574
|
...(request.profilesRoot
|
|
@@ -242,6 +578,10 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
242
578
|
});
|
|
243
579
|
const targetRefs = request.targetRefs.map((targetRef) => resolveFromBase(projectRoot, targetRef));
|
|
244
580
|
const settings = await resolveSettingsChain(ontoHome ?? projectRoot, projectRoot);
|
|
581
|
+
await assertDispatchFallbackSessionAdmission({
|
|
582
|
+
sessionRoot,
|
|
583
|
+
enabled: settings.reconstruct?.execution?.dispatch_fallback?.enabled === true,
|
|
584
|
+
});
|
|
245
585
|
const semanticAuthorRealization = request.semanticAuthorRealization ?? "direct_call";
|
|
246
586
|
const confirmationProviderRealization = request.confirmationProviderRealization ?? "direct_call";
|
|
247
587
|
if (request.domain) {
|
|
@@ -261,14 +601,20 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
261
601
|
const llmEffortOverride = request.llmEffort
|
|
262
602
|
? { reasoning_effort: request.llmEffort }
|
|
263
603
|
: undefined;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
604
|
+
// The semantic_author actor settings (non-mock). The MODEL provider here
|
|
605
|
+
// (e.g. "openai") is the supported-models registry key, DISTINCT from the
|
|
606
|
+
// resolved RUNTIME provider (openai OAuth resolves to "codex"). The document
|
|
607
|
+
// projection-budget lookup keys on the model provider so the default
|
|
608
|
+
// gpt-5.5 OAuth seat resolves (see deriveDocumentExcerptProjectionBudget).
|
|
609
|
+
const semanticAuthorActorLlm = mockRealizationEnabled
|
|
610
|
+
? null
|
|
611
|
+
: resolveReconstructActorLlmSettings(settings, "semantic_author");
|
|
612
|
+
let semanticAuthorLlmConfig = semanticAuthorActorLlm
|
|
613
|
+
? resolveLlmProviderConfig({
|
|
614
|
+
config: { llm: semanticAuthorActorLlm },
|
|
270
615
|
...(llmEffortOverride ? { cliOverrides: llmEffortOverride } : {}),
|
|
271
|
-
})
|
|
616
|
+
})
|
|
617
|
+
: {};
|
|
272
618
|
const confirmationProviderLlmConfig = mockRealizationEnabled
|
|
273
619
|
? {}
|
|
274
620
|
: resolveLlmProviderConfig({
|
|
@@ -277,8 +623,240 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
277
623
|
},
|
|
278
624
|
...(llmEffortOverride ? { cliOverrides: llmEffortOverride } : {}),
|
|
279
625
|
});
|
|
626
|
+
// The supported-models registry (non-mock only): loaded once and shared by
|
|
627
|
+
// the judge-override support check and the document projection-budget
|
|
628
|
+
// lookup. Mock realization makes no real provider calls, so it stays
|
|
629
|
+
// decoupled from the install authority file (C6).
|
|
630
|
+
const supportedModelRegistry = mockRealizationEnabled
|
|
631
|
+
? null
|
|
632
|
+
: loadSupportedModelRegistry();
|
|
633
|
+
const semanticAuthorLlmRuntime = mockRealizationEnabled
|
|
634
|
+
? undefined
|
|
635
|
+
: resolveReconstructSemanticAuthorLlmRuntimeSettings(settings);
|
|
636
|
+
if (semanticAuthorLlmRuntime && semanticAuthorActorLlm) {
|
|
637
|
+
const selection = normalizeLlmModelSwitcher(semanticAuthorActorLlm);
|
|
638
|
+
if (!selection) {
|
|
639
|
+
throw new Error("semantic_author output headroom requires a resolved LLM selection.");
|
|
640
|
+
}
|
|
641
|
+
semanticAuthorLlmConfig = applyOpenAIResponsesOutputHeadroom({
|
|
642
|
+
config: semanticAuthorLlmConfig,
|
|
643
|
+
selection,
|
|
644
|
+
headroomTokens: semanticAuthorLlmRuntime.openai_responses_output_headroom_tokens,
|
|
645
|
+
maxBaseOutputTokens: RECONSTRUCT_SEMANTIC_AUTHOR_MAX_BASE_OUTPUT_TOKENS,
|
|
646
|
+
modelMaxOutputTokens: supportedModelMaxOutputTokens(supportedModelRegistry, selection.model_provider, semanticAuthorLlmConfig.model_id ?? selection.model_id ?? ""),
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
// Semantic-map authoring opt-in + optional synthesize seat (INV-MODEL-1
|
|
650
|
+
// role-aware design §5.4/§5.5): ONE deterministic seam owns the wiring
|
|
651
|
+
// (resolveSemanticMapSynthesizeWiring) — live completes the seat into a
|
|
652
|
+
// provider config (own auth/adapter, cross-provider; the request
|
|
653
|
+
// llmEffort pin applies as cliOverrides, so pin > seat effort), mock
|
|
654
|
+
// takes an identity-only projection (no auth material required).
|
|
655
|
+
const semanticMapWiring = resolveSemanticMapSynthesizeWiring({
|
|
656
|
+
settings,
|
|
657
|
+
mockRealizationEnabled,
|
|
658
|
+
llmEffortOverride,
|
|
659
|
+
});
|
|
660
|
+
// Single seed-stage document projection budget (chars), derived once from
|
|
661
|
+
// the semantic author's MODEL window.
|
|
662
|
+
const documentExcerptProjectionBudget = supportedModelRegistry
|
|
663
|
+
? deriveDocumentExcerptProjectionBudget({
|
|
664
|
+
...(semanticAuthorActorLlm?.provider
|
|
665
|
+
? { provider: semanticAuthorActorLlm.provider }
|
|
666
|
+
: {}),
|
|
667
|
+
...(semanticAuthorLlmConfig.model_id
|
|
668
|
+
? { modelId: semanticAuthorLlmConfig.model_id }
|
|
669
|
+
: {}),
|
|
670
|
+
}, supportedModelRegistry)
|
|
671
|
+
: DOCUMENT_EXCERPT_PROJECTION_FLOOR;
|
|
672
|
+
const dispatchFallbackSettings = settings.reconstruct?.execution?.dispatch_fallback;
|
|
673
|
+
const dispatchBreakerSettings = completeDispatchBreakerSettings(settings.reconstruct?.execution?.dispatch_breaker);
|
|
674
|
+
if (semanticAuthorLlmRuntime &&
|
|
675
|
+
dispatchFallbackSettings?.enabled === true) {
|
|
676
|
+
throw new Error("reconstruct output headroom cannot be combined with dispatch_fallback until the sealed semantic-map route preserves the same output-budget and typed-incomplete contract.");
|
|
677
|
+
}
|
|
678
|
+
let dispatchFallbackRuntime;
|
|
679
|
+
let dispatchFallbackTelemetry;
|
|
680
|
+
if (dispatchFallbackSettings?.enabled === true) {
|
|
681
|
+
if (!dispatchBreakerSettings.enabled) {
|
|
682
|
+
throw new Error("reconstruct dispatch_fallback requires reconstruct.execution.dispatch_breaker.enabled=true.");
|
|
683
|
+
}
|
|
684
|
+
if (mockRealizationEnabled) {
|
|
685
|
+
throw new Error("reconstruct dispatch_fallback requires the live sealed SDK path; mock realization is not product evidence.");
|
|
686
|
+
}
|
|
687
|
+
if (!semanticMapWiring.enableSemanticMapAuthoring) {
|
|
688
|
+
throw new Error("reconstruct dispatch_fallback requires reconstruct.execution.semantic_map_authoring=true.");
|
|
689
|
+
}
|
|
690
|
+
const effectiveEffort = request.llmEffort;
|
|
691
|
+
const primarySynthesizeLlm = {
|
|
692
|
+
...(resolveOptionalReconstructActorLlmSettings(settings, "semantic_map_synthesize") ?? resolveReconstructActorLlmSettings(settings, "semantic_author")),
|
|
693
|
+
...(effectiveEffort ? { effort: effectiveEffort } : {}),
|
|
694
|
+
};
|
|
695
|
+
const primaryVerifyLlm = {
|
|
696
|
+
...resolveReconstructActorLlmSettings(settings, "semantic_author"),
|
|
697
|
+
...(effectiveEffort ? { effort: effectiveEffort } : {}),
|
|
698
|
+
};
|
|
699
|
+
const fallbackLlm = {
|
|
700
|
+
...dispatchFallbackSettings.llm,
|
|
701
|
+
...(effectiveEffort ? { effort: effectiveEffort } : {}),
|
|
702
|
+
};
|
|
703
|
+
const [primarySynthesize, primaryVerify, fallbackSynthesize, fallbackVerify] = await Promise.all([
|
|
704
|
+
tryCreateEligiblePrimarySealedDispatchCapability({
|
|
705
|
+
llm: primarySynthesizeLlm,
|
|
706
|
+
operation: "semantic_map_synthesize",
|
|
707
|
+
}),
|
|
708
|
+
tryCreateEligiblePrimarySealedDispatchCapability({
|
|
709
|
+
llm: primaryVerifyLlm,
|
|
710
|
+
operation: "semantic_map_verify",
|
|
711
|
+
}),
|
|
712
|
+
createSealedDispatchCapability({
|
|
713
|
+
llm: fallbackLlm,
|
|
714
|
+
operation: "semantic_map_synthesize",
|
|
715
|
+
}),
|
|
716
|
+
createSealedDispatchCapability({
|
|
717
|
+
llm: fallbackLlm,
|
|
718
|
+
operation: "semantic_map_verify",
|
|
719
|
+
}),
|
|
720
|
+
]);
|
|
721
|
+
const eligiblePrimaryCapabilities = [
|
|
722
|
+
primarySynthesize,
|
|
723
|
+
primaryVerify,
|
|
724
|
+
].filter((capability) => capability !== undefined);
|
|
725
|
+
if (eligiblePrimaryCapabilities.length === 0) {
|
|
726
|
+
throw new Error("reconstruct dispatch_fallback requires at least one eligible sealed primary semantic-map operation.");
|
|
727
|
+
}
|
|
728
|
+
const eligiblePrimaryProviders = new Set(eligiblePrimaryCapabilities.map((capability) => capability.public_descriptor.model_provider));
|
|
729
|
+
if ([...eligiblePrimaryProviders].every((provider) => provider === fallbackSynthesize.public_descriptor.model_provider) ||
|
|
730
|
+
fallbackSynthesize.public_descriptor.model_provider !==
|
|
731
|
+
fallbackVerify.public_descriptor.model_provider) {
|
|
732
|
+
throw new Error("reconstruct dispatch_fallback requires one alternate provider for the complete fallback pair.");
|
|
733
|
+
}
|
|
734
|
+
const accounting = new SemanticMapDispatchAccounting();
|
|
735
|
+
dispatchFallbackTelemetry =
|
|
736
|
+
createReconstructExecutionTelemetryCollector({
|
|
737
|
+
nullMixedRouteProjection: true,
|
|
738
|
+
});
|
|
739
|
+
const fallbackLlmConfig = resolveLlmProviderConfig({
|
|
740
|
+
config: { llm: fallbackLlm },
|
|
741
|
+
});
|
|
742
|
+
const fallbackDirectiveAuthor = createDirectCallReconstructDirectiveAuthor({
|
|
743
|
+
llmConfig: fallbackLlmConfig,
|
|
744
|
+
semanticMapSynthesizeLlmConfig: fallbackLlmConfig,
|
|
745
|
+
enableSemanticMapAuthoring: true,
|
|
746
|
+
semanticMapDispatchCapabilities: {
|
|
747
|
+
synthesize: fallbackSynthesize,
|
|
748
|
+
verify: fallbackVerify,
|
|
749
|
+
accounting,
|
|
750
|
+
executionSource: "fallback",
|
|
751
|
+
allowParseRepair: false,
|
|
752
|
+
maxTransportAttempts: 1,
|
|
753
|
+
},
|
|
754
|
+
documentExcerptProjectionBudget,
|
|
755
|
+
executionTelemetry: dispatchFallbackTelemetry,
|
|
756
|
+
});
|
|
757
|
+
dispatchFallbackRuntime = {
|
|
758
|
+
accounting,
|
|
759
|
+
primary: {
|
|
760
|
+
...(primarySynthesize ? { synthesize: primarySynthesize } : {}),
|
|
761
|
+
...(primaryVerify ? { verify: primaryVerify } : {}),
|
|
762
|
+
},
|
|
763
|
+
fallback: {
|
|
764
|
+
synthesize: fallbackSynthesize,
|
|
765
|
+
verify: fallbackVerify,
|
|
766
|
+
directiveAuthor: fallbackDirectiveAuthor,
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
// Opt-in per-stage JUDGE config (semantic-independence lever). Default =
|
|
771
|
+
// inherit the semantic-author config (judgeLlmConfig undefined → no change,
|
|
772
|
+
// zero regression). A judgeModel override resolves ON THE AUTHOR'S PROVIDER
|
|
773
|
+
// (same credentials/route), so it is adopted only when the resulting
|
|
774
|
+
// (author provider, judgeModel) pair is benchmark-verified, otherwise it
|
|
775
|
+
// degrades. resolveJudgeLlmConfig owns the adopt-vs-degrade decision.
|
|
776
|
+
const judgeOverrideRequested = Boolean(request.judgeLlmEffort || request.judgeModel);
|
|
777
|
+
let judgeConfigNote = null;
|
|
778
|
+
if (judgeOverrideRequested && mockRealizationEnabled) {
|
|
779
|
+
judgeConfigNote =
|
|
780
|
+
"answer-support judge override ignored under mock realization (no real provider calls)";
|
|
781
|
+
}
|
|
782
|
+
// A judgeModel candidate is resolved on the SAME actor settings as the
|
|
783
|
+
// author (no provider override), so api_key_env / execution_adapter /
|
|
784
|
+
// base_url stay the author provider's — consistent, never cross-provider.
|
|
785
|
+
const judgeAuthorActorLlm = !mockRealizationEnabled && request.judgeModel
|
|
786
|
+
? resolveReconstructActorLlmSettings(settings, "semantic_author")
|
|
787
|
+
: null;
|
|
788
|
+
const judgeModelCandidateBase = judgeAuthorActorLlm
|
|
789
|
+
? resolveLlmProviderConfig({
|
|
790
|
+
config: { llm: judgeAuthorActorLlm },
|
|
791
|
+
cliOverrides: { model: request.judgeModel },
|
|
792
|
+
})
|
|
793
|
+
: null;
|
|
794
|
+
const judgeResolution = mockRealizationEnabled
|
|
795
|
+
? { judgeLlmConfig: undefined, note: judgeConfigNote }
|
|
796
|
+
: resolveJudgeLlmConfig({
|
|
797
|
+
authorLlmConfig: semanticAuthorLlmConfig,
|
|
798
|
+
...(request.judgeLlmEffort
|
|
799
|
+
? { judgeLlmEffort: request.judgeLlmEffort }
|
|
800
|
+
: {}),
|
|
801
|
+
judgeModelCandidate: judgeModelCandidateBase,
|
|
802
|
+
// Registry key is the MODEL provider (e.g. openai), not the runtime
|
|
803
|
+
// adapter (openai OAuth → codex). The judge uses the author's provider.
|
|
804
|
+
...(judgeAuthorActorLlm?.provider
|
|
805
|
+
? { judgeModelProvider: judgeAuthorActorLlm.provider }
|
|
806
|
+
: {}),
|
|
807
|
+
...(judgeAuthorActorLlm && semanticAuthorLlmRuntime
|
|
808
|
+
? {
|
|
809
|
+
outputHeadroom: {
|
|
810
|
+
selection: normalizeLlmModelSwitcher(judgeAuthorActorLlm),
|
|
811
|
+
headroomTokens: semanticAuthorLlmRuntime
|
|
812
|
+
.openai_responses_output_headroom_tokens,
|
|
813
|
+
},
|
|
814
|
+
}
|
|
815
|
+
: {}),
|
|
816
|
+
// Non-null in this branch: both this and supportedModelRegistry gate on
|
|
817
|
+
// the same mockRealizationEnabled check.
|
|
818
|
+
registry: supportedModelRegistry,
|
|
819
|
+
});
|
|
820
|
+
const judgeLlmConfig = judgeResolution.judgeLlmConfig;
|
|
821
|
+
if (!mockRealizationEnabled)
|
|
822
|
+
judgeConfigNote = judgeResolution.note;
|
|
280
823
|
const directiveAuthor = createDirectCallReconstructDirectiveAuthor({
|
|
281
824
|
llmConfig: semanticAuthorLlmConfig,
|
|
825
|
+
...(judgeLlmConfig ? { judgeLlmConfig } : {}),
|
|
826
|
+
// Production opt-in + per-role synthesize override (design §5.5/§5.2)
|
|
827
|
+
// from the single wiring seam. Opt-in absent/false = pair not
|
|
828
|
+
// attached, stage skips — byte-parity with today. A dormant seat
|
|
829
|
+
// (configured, opt-in off) is surfaced via the honest note below.
|
|
830
|
+
...(semanticMapWiring.enableSemanticMapAuthoring
|
|
831
|
+
? { enableSemanticMapAuthoring: true }
|
|
832
|
+
: {}),
|
|
833
|
+
...(semanticMapWiring.semanticMapSynthesizeLlmConfig
|
|
834
|
+
? {
|
|
835
|
+
semanticMapSynthesizeLlmConfig: semanticMapWiring.semanticMapSynthesizeLlmConfig,
|
|
836
|
+
}
|
|
837
|
+
: {}),
|
|
838
|
+
documentExcerptProjectionBudget,
|
|
839
|
+
...(dispatchFallbackRuntime
|
|
840
|
+
? {
|
|
841
|
+
semanticMapDispatchCapabilities: {
|
|
842
|
+
...(dispatchFallbackRuntime.primary.synthesize
|
|
843
|
+
? {
|
|
844
|
+
synthesize: dispatchFallbackRuntime.primary.synthesize,
|
|
845
|
+
}
|
|
846
|
+
: {}),
|
|
847
|
+
...(dispatchFallbackRuntime.primary.verify
|
|
848
|
+
? { verify: dispatchFallbackRuntime.primary.verify }
|
|
849
|
+
: {}),
|
|
850
|
+
accounting: dispatchFallbackRuntime.accounting,
|
|
851
|
+
executionSource: "primary",
|
|
852
|
+
allowParseRepair: true,
|
|
853
|
+
maxTransportAttempts: 3,
|
|
854
|
+
},
|
|
855
|
+
}
|
|
856
|
+
: {}),
|
|
857
|
+
...(dispatchFallbackTelemetry
|
|
858
|
+
? { executionTelemetry: dispatchFallbackTelemetry }
|
|
859
|
+
: {}),
|
|
282
860
|
...(mockRealizationEnabled
|
|
283
861
|
? {
|
|
284
862
|
llmCall: callReconstructMockLlm,
|
|
@@ -304,6 +882,37 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
304
882
|
: "reconstruct session starting",
|
|
305
883
|
stageId: "start",
|
|
306
884
|
});
|
|
885
|
+
if (judgeConfigNote) {
|
|
886
|
+
// Honest accounting: the operator opted into a judge override that was
|
|
887
|
+
// not used (unsupported model degraded to the author model, or ignored
|
|
888
|
+
// under mock), so the rubber-stamp mitigation did NOT take effect. The
|
|
889
|
+
// judge's actual model/effort is independently recorded in the judge
|
|
890
|
+
// step execution telemetry. Emitted BEFORE the run so it survives a
|
|
891
|
+
// run failure — the degrade decision is independent of the run outcome.
|
|
892
|
+
appendRuntimeStatusEventSync({
|
|
893
|
+
pipeline: "reconstruct",
|
|
894
|
+
sessionRoot,
|
|
895
|
+
sourceLabel: "onto_reconstruct",
|
|
896
|
+
message: judgeConfigNote,
|
|
897
|
+
stageId: "answer_support_judgment",
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
if (semanticMapWiring.dormantSeatNote) {
|
|
901
|
+
// Honest accounting (design §5.4, N11 / judge-note precedent): the
|
|
902
|
+
// operator configured a synthesize seat but the semantic-map authoring
|
|
903
|
+
// opt-in is off, so the seat is DORMANT — no synthesize dispatch will
|
|
904
|
+
// use it and the gate deliberately excludes it (U6). Emitted BEFORE the
|
|
905
|
+
// run so the inert config is never a silent no-op. This emission binds
|
|
906
|
+
// the seam's DORMANT branch to the live path (N11); the ACTIVE branch
|
|
907
|
+
// is bound by the P3 census-identity assertion on the factory spreads.
|
|
908
|
+
appendRuntimeStatusEventSync({
|
|
909
|
+
pipeline: "reconstruct",
|
|
910
|
+
sessionRoot,
|
|
911
|
+
sourceLabel: "onto_reconstruct",
|
|
912
|
+
message: semanticMapWiring.dormantSeatNote,
|
|
913
|
+
stageId: "start",
|
|
914
|
+
});
|
|
915
|
+
}
|
|
307
916
|
const watcherResult = spawnRuntimeWatcherPane(projectRoot, sessionRoot, ontoHome);
|
|
308
917
|
appendRuntimeStatusEventSync({
|
|
309
918
|
pipeline: "reconstruct",
|
|
@@ -334,6 +943,17 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
334
943
|
confirmationProviderRealization,
|
|
335
944
|
directiveAuthor,
|
|
336
945
|
confirmationProvider,
|
|
946
|
+
// 설계 B: settings가 유일 권위(INV-CFG-1) — 기본 OFF, 완성값은
|
|
947
|
+
// settings chain이 채운다.
|
|
948
|
+
dispatchBreaker: dispatchBreakerSettings,
|
|
949
|
+
...(settings.reconstruct?.execution?.dispatch_fallback
|
|
950
|
+
? {
|
|
951
|
+
dispatchFallback: settings.reconstruct.execution.dispatch_fallback,
|
|
952
|
+
}
|
|
953
|
+
: {}),
|
|
954
|
+
...(dispatchFallbackRuntime
|
|
955
|
+
? { dispatchFallbackRuntime }
|
|
956
|
+
: {}),
|
|
337
957
|
filesystemAllowedRoots: request.filesystemAllowedRoots?.map((root) => resolveFromBase(projectRoot, root)) ??
|
|
338
958
|
[projectRoot],
|
|
339
959
|
}));
|
|
@@ -354,6 +974,12 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
354
974
|
message: `reconstruct session failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
355
975
|
stageId: "complete",
|
|
356
976
|
});
|
|
977
|
+
const failedStatus = await recoverReconstructFailedRunStatus({
|
|
978
|
+
sessionRoot,
|
|
979
|
+
error,
|
|
980
|
+
});
|
|
981
|
+
if (failedStatus)
|
|
982
|
+
return failedStatus;
|
|
357
983
|
throw error;
|
|
358
984
|
}
|
|
359
985
|
},
|
|
@@ -400,7 +1026,33 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
400
1026
|
},
|
|
401
1027
|
async getRunStatus(sessionRoot) {
|
|
402
1028
|
const resolvedSessionRoot = path.resolve(sessionRoot);
|
|
403
|
-
const
|
|
1029
|
+
const runControlRef = path.join(resolvedSessionRoot, "reconstruct-run-control.yaml");
|
|
1030
|
+
const runControlValidationRef = path.join(resolvedSessionRoot, "reconstruct-run-control-validation.yaml");
|
|
1031
|
+
const reconciliation = await reconcileReconstructLlmDispatchFailures({
|
|
1032
|
+
sessionRoot: resolvedSessionRoot,
|
|
1033
|
+
runControlPath: runControlRef,
|
|
1034
|
+
validationOutputPath: runControlValidationRef,
|
|
1035
|
+
});
|
|
1036
|
+
const blockedPartialWrite = reconciliation
|
|
1037
|
+
? [...reconciliation.runControl.resume_rows].reverse().find((row) => row.resume_decision === "blocked_partial_write")
|
|
1038
|
+
: undefined;
|
|
1039
|
+
if (blockedPartialWrite) {
|
|
1040
|
+
throw new Error(`reconstruct session is blocked by a partial failure write: ${blockedPartialWrite.stale_artifact_refs.join(",") || "unknown ref"}`);
|
|
1041
|
+
}
|
|
1042
|
+
const failedStatus = await trustedFailedSessionStatus({
|
|
1043
|
+
sessionRoot: resolvedSessionRoot,
|
|
1044
|
+
reconciliation,
|
|
1045
|
+
runControlRef,
|
|
1046
|
+
runControlValidationRef,
|
|
1047
|
+
});
|
|
1048
|
+
if (failedStatus)
|
|
1049
|
+
return failedStatus;
|
|
1050
|
+
const reconstructRecord = await readYamlArtifactIfPresent(path.join(resolvedSessionRoot, "reconstruct-record.yaml"));
|
|
1051
|
+
if (!reconstructRecord) {
|
|
1052
|
+
throw new Error(reconciliation
|
|
1053
|
+
? `reconstruct session has no readable terminal record or trusted failed terminal: ${resolvedSessionRoot}`
|
|
1054
|
+
: `reconstruct session has neither a record nor run-control: ${resolvedSessionRoot}`);
|
|
1055
|
+
}
|
|
404
1056
|
const reconstructRunManifest = await readYamlArtifactIfPresent(reconstructRecord.artifact_refs.reconstruct_run_manifest);
|
|
405
1057
|
const reconstructMetrics = await readYamlArtifactIfPresent(reconstructRecord.artifact_refs.reconstruct_metrics);
|
|
406
1058
|
const claimProjection = await readYamlArtifactIfPresent(reconstructRecord.artifact_refs.claim_projection);
|
|
@@ -416,7 +1068,7 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
416
1068
|
return {
|
|
417
1069
|
sessionId: path.basename(resolvedSessionRoot),
|
|
418
1070
|
sessionRoot: resolvedSessionRoot,
|
|
419
|
-
status: reconstructRecord
|
|
1071
|
+
status: reconstructTerminalStatus(reconstructRecord),
|
|
420
1072
|
artifactRefs: reconstructRecord.artifact_refs,
|
|
421
1073
|
claimProjection,
|
|
422
1074
|
claimProjectionValidation,
|
|
@@ -431,6 +1083,15 @@ export function createOntoReconstructCoreApi(options = {}) {
|
|
|
431
1083
|
},
|
|
432
1084
|
async getRunResult(sessionRoot) {
|
|
433
1085
|
const status = await this.getRunStatus(sessionRoot);
|
|
1086
|
+
if (status.status === "failed") {
|
|
1087
|
+
return {
|
|
1088
|
+
...status,
|
|
1089
|
+
finalOutputPath: null,
|
|
1090
|
+
finalOutputText: null,
|
|
1091
|
+
reconstructRunManifestPath: null,
|
|
1092
|
+
reconstructRunManifest: null,
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
434
1095
|
const finalOutputPath = status.reconstructRecord.artifact_refs.final_output;
|
|
435
1096
|
const reconstructRunManifestPath = status.reconstructRecord.artifact_refs.reconstruct_run_manifest;
|
|
436
1097
|
return {
|