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
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { parse as parseYaml
|
|
5
|
-
import {
|
|
4
|
+
import { parse as parseYaml } from "yaml";
|
|
5
|
+
import { assertArrayField, atomicWriteYamlDocument as writeYamlDocument } from "../artifact-io.js";
|
|
6
|
+
import { RECONSTRUCT_STAGE_IDS, WITNESS_LESS_CONDITIONAL_STAGE_IDS } from "./artifact-types.js";
|
|
6
7
|
import { loadReconstructContractRegistry, } from "./contract-registry.js";
|
|
7
8
|
import { validateReconstructRunGoverningSnapshot } from "./governing-snapshot.js";
|
|
9
|
+
import { assertObligation } from "./obligation-assertion.js";
|
|
8
10
|
function isoNow() {
|
|
9
11
|
return new Date().toISOString();
|
|
10
12
|
}
|
|
@@ -24,10 +26,6 @@ async function exists(ref) {
|
|
|
24
26
|
return false;
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
|
-
async function writeYamlDocument(filePath, value) {
|
|
28
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
29
|
-
await fs.writeFile(filePath, stringifyYaml(value), "utf8");
|
|
30
|
-
}
|
|
31
29
|
async function readYamlDocument(filePath) {
|
|
32
30
|
return parseYaml(await fs.readFile(filePath, "utf8"));
|
|
33
31
|
}
|
|
@@ -48,8 +46,13 @@ const SELF_VALIDATION_OUTPUT_REFS = new Set([
|
|
|
48
46
|
"pre_handoff_run_manifest_validation",
|
|
49
47
|
"post_publication_run_manifest_validation",
|
|
50
48
|
]);
|
|
49
|
+
// The witness-less conditional stages permitted `skip_kind: "legit_conditional"` on a
|
|
50
|
+
// graceful-terminal manifest (canonical set in artifact-types.ts, shared with the builder).
|
|
51
|
+
const WITNESS_LESS_CONDITIONAL_STAGES = new Set(WITNESS_LESS_CONDITIONAL_STAGE_IDS);
|
|
51
52
|
export async function validateReconstructRunManifest(args) {
|
|
53
|
+
assertArrayField(args.manifest.steps, "run-manifest", "steps");
|
|
52
54
|
const violations = [];
|
|
55
|
+
const assertedObligationIds = [];
|
|
53
56
|
const stepById = new Map(args.manifest.steps.map((step) => [step.step_id, step]));
|
|
54
57
|
for (const stageId of RECONSTRUCT_STAGE_IDS) {
|
|
55
58
|
if (!stepById.has(stageId)) {
|
|
@@ -60,6 +63,27 @@ export async function validateReconstructRunManifest(args) {
|
|
|
60
63
|
}));
|
|
61
64
|
}
|
|
62
65
|
}
|
|
66
|
+
// W3 review W3-004: missing-only checking was fail-OPEN for extra/duplicate steps — a
|
|
67
|
+
// misregistered or duplicated step id validated green. Exact-set both directions.
|
|
68
|
+
const knownStageIds = new Set(RECONSTRUCT_STAGE_IDS);
|
|
69
|
+
const seenStepIds = new Set();
|
|
70
|
+
for (const step of args.manifest.steps) {
|
|
71
|
+
if (!knownStageIds.has(step.step_id)) {
|
|
72
|
+
violations.push(violation({
|
|
73
|
+
code: "manifest_step_unknown",
|
|
74
|
+
message: `manifest carries unknown stage ${step.step_id}`,
|
|
75
|
+
subjectId: step.step_id,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
if (seenStepIds.has(step.step_id)) {
|
|
79
|
+
violations.push(violation({
|
|
80
|
+
code: "manifest_step_duplicate",
|
|
81
|
+
message: `manifest carries duplicate stage ${step.step_id}`,
|
|
82
|
+
subjectId: step.step_id,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
seenStepIds.add(step.step_id);
|
|
86
|
+
}
|
|
63
87
|
for (const step of args.manifest.steps) {
|
|
64
88
|
if (step.status !== "completed")
|
|
65
89
|
continue;
|
|
@@ -75,21 +99,33 @@ export async function validateReconstructRunManifest(args) {
|
|
|
75
99
|
}
|
|
76
100
|
if (SELF_VALIDATION_OUTPUT_REFS.has(step.step_id))
|
|
77
101
|
continue;
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
const refExistence = await Promise.all(step.artifact_refs.map((ref) => exists(ref)));
|
|
103
|
+
step.artifact_refs.forEach((ref, index) => {
|
|
104
|
+
if (!refExistence[index]) {
|
|
80
105
|
violations.push(violation({
|
|
81
106
|
code: "manifest_artifact_missing",
|
|
82
107
|
message: `manifest step ${step.step_id} references a missing artifact: ${ref}`,
|
|
83
108
|
subjectId: step.step_id,
|
|
84
109
|
}));
|
|
85
110
|
}
|
|
86
|
-
}
|
|
111
|
+
});
|
|
87
112
|
}
|
|
88
113
|
if (args.projectRoot &&
|
|
89
114
|
args.registryPath &&
|
|
90
115
|
args.contractRegistry &&
|
|
91
116
|
args.selectedSourceProfiles &&
|
|
92
117
|
args.lensIds) {
|
|
118
|
+
// AUTHORITY-GATED record (slice 28): the governing-snapshot drift check rebuilds the expected
|
|
119
|
+
// snapshot from the live registry/profile/lens authority and compares each recorded field by exact
|
|
120
|
+
// value, so it only runs when that authority is supplied. The four recorded snapshot-freeze
|
|
121
|
+
// obligations (selected reference-standard / pattern-catalog ids resolve to the registry projection;
|
|
122
|
+
// their version/snapshot maps carry an entry per selected id) are stamped INSIDE the callee, at the
|
|
123
|
+
// per-field `checks` loop — past the missing-snapshot and registry-hash early-returns — so they
|
|
124
|
+
// record only when the comparisons actually run. The remaining 23 obligations stay PARKED (see
|
|
125
|
+
// obligation-coverage-ledger.yaml): shared-field obligations cannot bind a single one, the canonical
|
|
126
|
+
// URI obligation names a registry policy the rebuild never reads, "allowed/supported/contains" are
|
|
127
|
+
// enforced at snapshot-build time, the p2/p3 non-promotion policy and governed-seed/previous-id
|
|
128
|
+
// closures are not compared fields, and the registry ref+hash presence overlaps the hash-match path.
|
|
93
129
|
violations.push(...await validateReconstructRunGoverningSnapshot({
|
|
94
130
|
projectRoot: args.projectRoot,
|
|
95
131
|
registryPath: args.registryPath,
|
|
@@ -98,6 +134,7 @@ export async function validateReconstructRunManifest(args) {
|
|
|
98
134
|
lensIds: args.lensIds,
|
|
99
135
|
admittedDomainIds: args.admittedDomainIds ?? [],
|
|
100
136
|
snapshot: args.manifest.governing_snapshot,
|
|
137
|
+
assertedObligationIds,
|
|
101
138
|
}));
|
|
102
139
|
}
|
|
103
140
|
else if (!args.manifest.governing_snapshot) {
|
|
@@ -107,6 +144,75 @@ export async function validateReconstructRunManifest(args) {
|
|
|
107
144
|
subjectId: "governing_snapshot",
|
|
108
145
|
}));
|
|
109
146
|
}
|
|
147
|
+
// Graceful-terminal reachability rules (design v2 §4). Enforced ONLY when the manifest is
|
|
148
|
+
// an explicit graceful terminal — a completed run has no graceful_terminal field, so this
|
|
149
|
+
// whole block is skipped and completed-path validation stays byte-identical. Authority for
|
|
150
|
+
// "did a witness-less conditional stage run and legitimately produce nothing" is an
|
|
151
|
+
// INDEPENDENT reachability witness (census) read here; the manifest builder cannot
|
|
152
|
+
// self-declare a legit no-op the witness does not confirm (closes the v1 membership-only hole).
|
|
153
|
+
if (args.manifest.graceful_terminal) {
|
|
154
|
+
// legitNoOpByStage: stage -> legit_no_op flag, for witness-less stages that RAN and produced
|
|
155
|
+
// nothing. ranStages: every witness-less stage the census shows ran (produced or not).
|
|
156
|
+
const legitNoOpByStage = new Map();
|
|
157
|
+
const ranStages = new Set();
|
|
158
|
+
const witnessRef = args.manifest.graceful_terminal.reachability_witness_ref;
|
|
159
|
+
if (witnessRef) {
|
|
160
|
+
const census = await readYamlDocumentIfPresent(witnessRef);
|
|
161
|
+
if (!census) {
|
|
162
|
+
violations.push(violation({
|
|
163
|
+
code: "manifest_reachability_witness_missing",
|
|
164
|
+
message: `graceful manifest references a reachability witness that does not exist: ${witnessRef}`,
|
|
165
|
+
subjectId: "reachability_witness_ref",
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
for (const w of census.stage_witnesses) {
|
|
170
|
+
ranStages.add(w.step_id); // present in the census only because the stage ran
|
|
171
|
+
if (!w.produced)
|
|
172
|
+
legitNoOpByStage.set(w.step_id, w.legit_no_op);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const step of args.manifest.steps) {
|
|
177
|
+
if (step.status !== "skipped")
|
|
178
|
+
continue; // completed already ref-checked; failed out of scope
|
|
179
|
+
if (step.step_id === "invocation_binding")
|
|
180
|
+
continue;
|
|
181
|
+
if (step.skip_kind === undefined) {
|
|
182
|
+
// M5: a bare skipped step under a graceful terminal is a masking surface (a not-reached
|
|
183
|
+
// bug hiding as a healthy pre-handoff-style skip). Require the typed discriminant.
|
|
184
|
+
violations.push(violation({
|
|
185
|
+
code: "manifest_untyped_graceful_skip",
|
|
186
|
+
message: `graceful manifest skipped step lacks skip_kind: ${step.step_id}`,
|
|
187
|
+
subjectId: step.step_id,
|
|
188
|
+
}));
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (step.skip_kind === "legit_conditional") {
|
|
192
|
+
// M2: authorized by the WITNESS (ran-and-legit-no-op), not by allowlist membership. Only
|
|
193
|
+
// the witness-less lineage stages carry this witness; any other stage claiming it, or one
|
|
194
|
+
// the witness does not confirm ran-and-legit-no-op, is a masking attempt.
|
|
195
|
+
if (!WITNESS_LESS_CONDITIONAL_STAGES.has(step.step_id) ||
|
|
196
|
+
legitNoOpByStage.get(step.step_id) !== true) {
|
|
197
|
+
violations.push(violation({
|
|
198
|
+
code: "manifest_unwitnessed_conditional_skip",
|
|
199
|
+
message: `legit_conditional skip for ${step.step_id} is not confirmed by the reachability witness (must be a witness-less lineage stage that ran and legitimately produced nothing)`,
|
|
200
|
+
subjectId: step.step_id,
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (step.skip_kind === "not_reached") {
|
|
205
|
+
// A witness proving the stage RAN contradicts not_reached = masking attempt.
|
|
206
|
+
if (ranStages.has(step.step_id)) {
|
|
207
|
+
violations.push(violation({
|
|
208
|
+
code: "manifest_reached_stage_masked",
|
|
209
|
+
message: `${step.step_id} is marked not_reached but the reachability witness shows it ran`,
|
|
210
|
+
subjectId: step.step_id,
|
|
211
|
+
}));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
110
216
|
const completedStepCount = args.manifest.steps.filter((step) => step.status === "completed").length;
|
|
111
217
|
const skippedStepCount = args.manifest.steps.filter((step) => step.status === "skipped").length;
|
|
112
218
|
return {
|
|
@@ -120,6 +226,7 @@ export async function validateReconstructRunManifest(args) {
|
|
|
120
226
|
validation_results: violations.length === 0
|
|
121
227
|
? ["reconstruct_run_manifest_valid"]
|
|
122
228
|
: ["reconstruct_run_manifest_invalid"],
|
|
229
|
+
asserted_obligation_ids: assertedObligationIds,
|
|
123
230
|
violations,
|
|
124
231
|
};
|
|
125
232
|
}
|
|
@@ -223,6 +330,10 @@ function validationArtifactStatuses(args) {
|
|
|
223
330
|
"source-scout-pack-validation.post-maturation.yaml",
|
|
224
331
|
statusOf(args.sourceScoutPackPostMaturationValidation),
|
|
225
332
|
],
|
|
333
|
+
[
|
|
334
|
+
"semantic-map-resume-validation.yaml",
|
|
335
|
+
statusOf(args.semanticMapResumeValidation),
|
|
336
|
+
],
|
|
226
337
|
[
|
|
227
338
|
"material-admission-ledger-validation.yaml",
|
|
228
339
|
statusOf(args.materialAdmissionLedgerValidation),
|
|
@@ -797,6 +908,15 @@ export function validateHandoffDecision(args) {
|
|
|
797
908
|
gate.validation_status,
|
|
798
909
|
]));
|
|
799
910
|
const violations = [];
|
|
911
|
+
// G(a) obligation recorder (INV-OBLIGATION-COVERAGE-1): record that control reached the
|
|
912
|
+
// active-gate consumption loop below. Unconditional, before the per-gate guard so a zero-gate
|
|
913
|
+
// input still stamps. Only the two ACTIVE-gate obligations are recorded — every PLANNED-gate
|
|
914
|
+
// obligation is parked because planned_validation_gate_catalog is never loaded into the runtime
|
|
915
|
+
// registry (projectGateStatusesOnce iterates validation_gate_catalog only); see
|
|
916
|
+
// obligation-coverage-ledger.yaml.
|
|
917
|
+
const assertedObligationIds = [];
|
|
918
|
+
assertObligation(assertedObligationIds, "consume_all_active_validation_gate_statuses_emitted_by_runtime");
|
|
919
|
+
assertObligation(assertedObligationIds, "project_missing_active_validation_artifact_as_blocked");
|
|
800
920
|
for (const gate of gateProjection) {
|
|
801
921
|
if (gate.applicability === "not_applicable" || gate.applicability === "self_validation_output") {
|
|
802
922
|
continue;
|
|
@@ -858,13 +978,15 @@ export function validateHandoffDecision(args) {
|
|
|
858
978
|
validation_results: violations.length === 0
|
|
859
979
|
? ["handoff_decision_valid"]
|
|
860
980
|
: ["handoff_decision_invalid"],
|
|
981
|
+
asserted_obligation_ids: assertedObligationIds,
|
|
861
982
|
violations,
|
|
862
983
|
};
|
|
863
984
|
}
|
|
864
985
|
export async function writeReconstructRunManifestValidationArtifact(args) {
|
|
865
986
|
const manifest = await readYamlDocument(args.manifestPath);
|
|
866
987
|
const [contractRegistry, targetMaterialProfile] = await Promise.all([
|
|
867
|
-
|
|
988
|
+
args.contractRegistry ??
|
|
989
|
+
loadReconstructContractRegistry({ registryPath: args.registryPath }),
|
|
868
990
|
readYamlDocument(args.targetMaterialProfilePath),
|
|
869
991
|
]);
|
|
870
992
|
const validation = await validateReconstructRunManifest({
|
|
@@ -882,7 +1004,8 @@ export async function writeReconstructRunManifestValidationArtifact(args) {
|
|
|
882
1004
|
}
|
|
883
1005
|
export async function writePostMaturationGateProjectionValidationArtifact(args) {
|
|
884
1006
|
const [contractRegistry, sourceScoutPackPostMaturationValidation] = await Promise.all([
|
|
885
|
-
|
|
1007
|
+
args.contractRegistry ??
|
|
1008
|
+
loadReconstructContractRegistry({ registryPath: args.registryPath }),
|
|
886
1009
|
readYamlDocumentIfPresent(args.sourceScoutPackPostMaturationValidationPath),
|
|
887
1010
|
]);
|
|
888
1011
|
const validation = validatePostMaturationGateProjection({
|
|
@@ -900,10 +1023,11 @@ export async function writeHandoffDecisionValidationArtifact(args) {
|
|
|
900
1023
|
readYamlDocument(args.stopDecisionPath),
|
|
901
1024
|
readYamlDocument(args.manifestValidationPath),
|
|
902
1025
|
readYamlDocument(args.metricsPath),
|
|
903
|
-
|
|
1026
|
+
args.contractRegistry ??
|
|
1027
|
+
loadReconstructContractRegistry({ registryPath: args.registryPath }),
|
|
904
1028
|
]);
|
|
905
1029
|
const manifest = await readYamlDocumentIfPresent(manifestValidation.reconstruct_run_manifest_ref);
|
|
906
|
-
const [runControlValidation, registryVerificationEvidenceValidation, targetMaterialProfileValidation, sourceObservationDirectiveValidation, sourceObservationLineageIndexValidation, sourceSafetyLedgerValidation, sourceScoutPackValidation, sourceScoutPackPreSeedValidation, sourceScoutPackPostMaturationValidation, materialAdmissionLedgerValidation, seedAuthoringReadinessValidation, sourceFrontierValidation, sourcePurposeCandidatesValidation, purposeConfirmationValidation, candidateDispositionValidation, ontologySeed, ontologySeedValidation, claimRealizationMapValidation, competencyQuestionsValidation, competencyQuestionAssessment, competencyQuestionAssessmentValidation, seedConfirmationValidation, failureClassificationValidation, revisionProposalValidation,] = await Promise.all([
|
|
1030
|
+
const [runControlValidation, registryVerificationEvidenceValidation, targetMaterialProfileValidation, sourceObservationDirectiveValidation, sourceObservationLineageIndexValidation, sourceSafetyLedgerValidation, sourceScoutPackValidation, sourceScoutPackPreSeedValidation, sourceScoutPackPostMaturationValidation, semanticMapResumeValidation, materialAdmissionLedgerValidation, seedAuthoringReadinessValidation, sourceFrontierValidation, sourcePurposeCandidatesValidation, purposeConfirmationValidation, candidateDispositionValidation, ontologySeed, ontologySeedValidation, claimRealizationMapValidation, competencyQuestionsValidation, competencyQuestionAssessment, competencyQuestionAssessmentValidation, seedConfirmationValidation, failureClassificationValidation, revisionProposalValidation,] = await Promise.all([
|
|
907
1031
|
args.runControlValidationPath
|
|
908
1032
|
? readYamlDocumentIfPresent(args.runControlValidationPath)
|
|
909
1033
|
: Promise.resolve(null),
|
|
@@ -927,6 +1051,9 @@ export async function writeHandoffDecisionValidationArtifact(args) {
|
|
|
927
1051
|
args.sourceScoutPackPostMaturationValidationPath
|
|
928
1052
|
? readYamlDocumentIfPresent(args.sourceScoutPackPostMaturationValidationPath)
|
|
929
1053
|
: Promise.resolve(null),
|
|
1054
|
+
args.semanticMapResumeValidationPath
|
|
1055
|
+
? readYamlDocumentIfPresent(args.semanticMapResumeValidationPath)
|
|
1056
|
+
: Promise.resolve(null),
|
|
930
1057
|
args.materialAdmissionLedgerValidationPath
|
|
931
1058
|
? readYamlDocumentIfPresent(args.materialAdmissionLedgerValidationPath)
|
|
932
1059
|
: Promise.resolve(null),
|
|
@@ -985,6 +1112,7 @@ export async function writeHandoffDecisionValidationArtifact(args) {
|
|
|
985
1112
|
sourceScoutPackPostMaturationValidation
|
|
986
1113
|
? args.sourceScoutPackPostMaturationValidationPath
|
|
987
1114
|
: null,
|
|
1115
|
+
semanticMapResumeValidation ? args.semanticMapResumeValidationPath : null,
|
|
988
1116
|
materialAdmissionLedgerValidation
|
|
989
1117
|
? args.materialAdmissionLedgerValidationPath
|
|
990
1118
|
: null,
|
|
@@ -1041,6 +1169,9 @@ export async function writeHandoffDecisionValidationArtifact(args) {
|
|
|
1041
1169
|
"source-scout-pack-validation.post-maturation.yaml": sourceScoutPackPostMaturationValidation
|
|
1042
1170
|
? args.sourceScoutPackPostMaturationValidationPath
|
|
1043
1171
|
: null,
|
|
1172
|
+
"semantic-map-resume-validation.yaml": semanticMapResumeValidation
|
|
1173
|
+
? args.semanticMapResumeValidationPath
|
|
1174
|
+
: null,
|
|
1044
1175
|
"material-admission-ledger-validation.yaml": materialAdmissionLedgerValidation
|
|
1045
1176
|
? args.materialAdmissionLedgerValidationPath
|
|
1046
1177
|
: null,
|
|
@@ -1093,6 +1224,7 @@ export async function writeHandoffDecisionValidationArtifact(args) {
|
|
|
1093
1224
|
sourceScoutPackValidation,
|
|
1094
1225
|
sourceScoutPackPreSeedValidation,
|
|
1095
1226
|
sourceScoutPackPostMaturationValidation,
|
|
1227
|
+
semanticMapResumeValidation,
|
|
1096
1228
|
materialAdmissionLedgerValidation,
|
|
1097
1229
|
seedAuthoringReadinessValidation,
|
|
1098
1230
|
sourceFrontierValidation,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isTrustedLedgerUnit } from "../pipeline-execution-ledger.js";
|
|
1
|
+
import { isResolvedLedgerUnit, isTrustedLedgerUnit, } from "../pipeline-execution-ledger.js";
|
|
2
2
|
function lensIdFromUnit(unit) {
|
|
3
3
|
if (unit.unitKind === "lens")
|
|
4
4
|
return unit.unitId;
|
|
@@ -21,13 +21,15 @@ function toContinuationUnit(unit, dispatchDecision, reason) {
|
|
|
21
21
|
reason,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
+
/** Upstream-satisfied set: trusted outputs plus terminally resolved units
|
|
25
|
+
* (a demoted unit's downstream consumed the disclosed gap, not its output). */
|
|
24
26
|
function trustedUnitIds(ledger) {
|
|
25
27
|
return new Set(ledger.units
|
|
26
|
-
.filter((unit) =>
|
|
28
|
+
.filter((unit) => isResolvedLedgerUnit(unit))
|
|
27
29
|
.map((unit) => unit.unitId));
|
|
28
30
|
}
|
|
29
31
|
function isFrontierUnit(unit, trustedIds) {
|
|
30
|
-
if (
|
|
32
|
+
if (isResolvedLedgerUnit(unit))
|
|
31
33
|
return false;
|
|
32
34
|
return unit.upstreamUnitIds.every((unitId) => trustedIds.has(unitId));
|
|
33
35
|
}
|
|
@@ -76,6 +78,11 @@ function targetRejectedUnits(args) {
|
|
|
76
78
|
toContinuationUnit(unit, "reject", "Target unit is already trusted and completed; completed outputs are reuse-only."),
|
|
77
79
|
];
|
|
78
80
|
}
|
|
81
|
+
if (isResolvedLedgerUnit(unit)) {
|
|
82
|
+
return [
|
|
83
|
+
toContinuationUnit(unit, "reject", "Target unit is terminally resolved (demoted complete-with-failure); its gap is disclosed downstream and it owes no further dispatch."),
|
|
84
|
+
];
|
|
85
|
+
}
|
|
79
86
|
if (!args.naturalFrontierUnitIds.has(unitId)) {
|
|
80
87
|
return [
|
|
81
88
|
toContinuationUnit(unit, "reject", "Target unit is not the current continuation frontier; continue from the earliest untrusted unit first."),
|
|
@@ -102,7 +109,7 @@ export function buildReviewContinuationPlan(params) {
|
|
|
102
109
|
const allRejectedTargets = [...rejectedTargets, ...rejectedMissingFrontierTargets];
|
|
103
110
|
const targetFrontier = requestedTargetSet.size === 0
|
|
104
111
|
? naturalFrontier
|
|
105
|
-
: params.ledger.units.filter((unit) => requestedTargetSet.has(unit.unitId) && !
|
|
112
|
+
: params.ledger.units.filter((unit) => requestedTargetSet.has(unit.unitId) && !isResolvedLedgerUnit(unit));
|
|
106
113
|
const frontierUnits = allRejectedTargets.length > 0
|
|
107
114
|
? allRejectedTargets
|
|
108
115
|
: targetFrontier.map((unit) => toContinuationUnit(unit, "run", requestedTargetSet.size === 0
|
|
@@ -116,7 +123,7 @@ export function buildReviewContinuationPlan(params) {
|
|
|
116
123
|
frontierUnitIds,
|
|
117
124
|
});
|
|
118
125
|
const downstreamUnits = params.ledger.units
|
|
119
|
-
.filter((unit) => downstreamIds.has(unit.unitId) && !
|
|
126
|
+
.filter((unit) => downstreamIds.has(unit.unitId) && !isResolvedLedgerUnit(unit))
|
|
120
127
|
.map((unit) => toContinuationUnit(unit, "run", "Downstream unit must be recomputed after the continuation frontier."));
|
|
121
128
|
const preservedArtifactRefs = params.ledger.units
|
|
122
129
|
.filter((unit) => isTrustedLedgerUnit(unit))
|
|
@@ -3072,7 +3072,10 @@ export async function writeIssueStanceMatrixFromResponses(args) {
|
|
|
3072
3072
|
session_id: args.executionPlan.session_id,
|
|
3073
3073
|
issues,
|
|
3074
3074
|
validation: {
|
|
3075
|
-
missing_stances: []
|
|
3075
|
+
missing_stances: (args.demotedLensIds ?? []).map((lensId) => ({
|
|
3076
|
+
lens_id: lensId,
|
|
3077
|
+
reason: "stance_validation_failed",
|
|
3078
|
+
})),
|
|
3076
3079
|
},
|
|
3077
3080
|
});
|
|
3078
3081
|
await validateIssueArtifactOnDisk({
|
|
@@ -7,7 +7,9 @@ import { ensureDirectory, isoNow, normalizeDomainValue, renderReviewTargetMateri
|
|
|
7
7
|
import { ISSUE_ARTIFACT_IDS, issueArtifactConsumerId, issueArtifactSpec, issueStanceConsumerId, } from "./issue-artifact-runtime.js";
|
|
8
8
|
import { lensSidecarArtifactPath } from "./lens-sidecar-artifact.js";
|
|
9
9
|
import { deliberationResolutionPath } from "./controlled-lens-deliberation.js";
|
|
10
|
-
import { detectTargetMaterialKind, reviewMaterialSupportStatus, } from "../target-material-kind.js";
|
|
10
|
+
import { detectTargetMaterialKind, isSpreadsheetRef, reviewMaterialGoals, reviewMaterialSupportStatus, } from "../target-material-kind.js";
|
|
11
|
+
import { observeSpreadsheetSource, } from "../spreadsheet-structure-observer.js";
|
|
12
|
+
import { computeSpreadsheetDisposition, } from "./spreadsheet-review-disposition.js";
|
|
11
13
|
import { semanticQualityEvidenceForArtifactGeneration } from "./artifact-generation-realization.js";
|
|
12
14
|
/**
|
|
13
15
|
* Load {projectRoot}/.onto/settings.json into the narrow subset used by
|
|
@@ -79,7 +81,7 @@ function derivePlanTimeLlmResolution(config) {
|
|
|
79
81
|
plan.base_url = baseUrl;
|
|
80
82
|
return Object.keys(plan).length > 0 ? plan : undefined;
|
|
81
83
|
}
|
|
82
|
-
function resolveReviewExecutionSettingsForArtifacts(config) {
|
|
84
|
+
export function resolveReviewExecutionSettingsForArtifacts(config) {
|
|
83
85
|
const defaults = defaultReviewExecution();
|
|
84
86
|
const execution = config.review?.execution;
|
|
85
87
|
if (!execution)
|
|
@@ -655,6 +657,12 @@ export async function bootstrapInvocationBindingArtifacts(params) {
|
|
|
655
657
|
effective_boundary_state: effectiveBoundaryState,
|
|
656
658
|
max_concurrent_lenses: maxConcurrentLenses,
|
|
657
659
|
minimum_participating_lenses: params.resolvedLensIds.length,
|
|
660
|
+
// Stage 1: persist the window-proportional embed budget so the packet stage
|
|
661
|
+
// reads it without re-resolving. Omitted when unresolved (model-unaware run)
|
|
662
|
+
// → packet stage falls back to the DEFAULT budget (no regression).
|
|
663
|
+
...(params.maxEmbedLines !== undefined
|
|
664
|
+
? { max_embed_lines: params.maxEmbedLines }
|
|
665
|
+
: {}),
|
|
658
666
|
};
|
|
659
667
|
const actorInvocationProfiles = {
|
|
660
668
|
schema_version: "1",
|
|
@@ -944,7 +952,7 @@ function requireExecutionPreparationSessionDomain(value) {
|
|
|
944
952
|
}
|
|
945
953
|
return normalizeDomainValue(value);
|
|
946
954
|
}
|
|
947
|
-
async function buildReviewTargetProfileArtifact(params) {
|
|
955
|
+
async function buildReviewTargetProfileArtifact(params, inventoryByRef, materializedRefs) {
|
|
948
956
|
const sessionRoot = path.resolve(params.sessionRoot);
|
|
949
957
|
const sessionId = path.basename(sessionRoot);
|
|
950
958
|
const resolvedRefs = params.resolvedTargetRefs.map((ref) => path.resolve(ref));
|
|
@@ -966,19 +974,82 @@ async function buildReviewTargetProfileArtifact(params) {
|
|
|
966
974
|
inputKind,
|
|
967
975
|
primaryRole: roles.primary,
|
|
968
976
|
});
|
|
977
|
+
// SINGLE SOURCE OF TRUTH: one disposition per rendered spreadsheet ref, computed once
|
|
978
|
+
// over the UNION of resolved + materialized refs from the shared observation. Every
|
|
979
|
+
// honesty surface below (support_status, target_refs[].inspectable/.sha256, review_goal)
|
|
980
|
+
// PROJECTS from this map instead of re-deriving "is this workbook backed?" from a proxy.
|
|
981
|
+
const unionSpreadsheetRefs = uniqueStrings([...resolvedRefs, ...(materializedRefs ?? [])].filter(isSpreadsheetRef));
|
|
982
|
+
const dispositionByRef = new Map();
|
|
983
|
+
for (const ref of unionSpreadsheetRefs) {
|
|
984
|
+
dispositionByRef.set(ref, computeSpreadsheetDisposition(inventoryByRef?.get(ref), ref));
|
|
985
|
+
}
|
|
969
986
|
const targetRefs = [];
|
|
970
987
|
for (const [index, ref] of resolvedRefs.entries()) {
|
|
971
988
|
const kind = await targetRefKind(ref, sessionRoot);
|
|
989
|
+
// Per-ref inspectability + sha256 PROJECT from the ref's disposition (spreadsheet-only).
|
|
990
|
+
// `inspectable` is the renderable-structure axis — a clean data CSV is inspectable even
|
|
991
|
+
// though it backs no structural obligation. sha256 reuses the single observation's
|
|
992
|
+
// content hash (no raw re-read; null when the observer declined to read the file).
|
|
993
|
+
const isSpreadsheet = isSpreadsheetRef(ref);
|
|
994
|
+
const disposition = isSpreadsheet ? dispositionByRef.get(ref) : undefined;
|
|
972
995
|
targetRefs.push({
|
|
973
996
|
ref,
|
|
974
997
|
role: index === 0 ? "primary" : "supporting",
|
|
975
998
|
kind: kind.kind,
|
|
976
999
|
exists: kind.exists,
|
|
977
1000
|
sha256: kind.exists
|
|
978
|
-
?
|
|
1001
|
+
? isSpreadsheet
|
|
1002
|
+
? (disposition?.sha256 ?? null)
|
|
1003
|
+
: await targetRefSha256(ref, kind.kind, params.directoryListingOptions)
|
|
979
1004
|
: null,
|
|
1005
|
+
...(isSpreadsheet
|
|
1006
|
+
? { inspectable: disposition?.inspectable ?? false }
|
|
1007
|
+
: {}),
|
|
980
1008
|
});
|
|
981
1009
|
}
|
|
1010
|
+
// SUPPORT-STATUS GATE — projects from the disposition set over the UNION of rendered
|
|
1011
|
+
// spreadsheet refs. It runs UNCONDITIONALLY (not only when the resolved kind is
|
|
1012
|
+
// spreadsheet) because materialized-input renders materializedRefs regardless of the
|
|
1013
|
+
// resolved kind (F1): a code-resolved target carrying a materialized workbook the
|
|
1014
|
+
// observer could not read must not stay `supported`. reviewMaterialSupportStatus is the
|
|
1015
|
+
// KIND-level baseline; any rendered workbook ref that is not inspectable downgrades it to
|
|
1016
|
+
// partial, naming each ref's honest cause (full path, deduped on path+cause).
|
|
1017
|
+
let supportStatus = materialSupport.status;
|
|
1018
|
+
let supportReason = materialSupport.reason;
|
|
1019
|
+
let materialGoals = reviewMaterialGoals(materialDetection.target_material_kind);
|
|
1020
|
+
const unionDispositions = unionSpreadsheetRefs.map((ref) => dispositionByRef.get(ref));
|
|
1021
|
+
const uninspected = unionDispositions.filter((d) => !d.inspectable);
|
|
1022
|
+
if (uninspected.length > 0) {
|
|
1023
|
+
supportStatus = "partial";
|
|
1024
|
+
// Each uninspected disposition carries a non-null `reason` by construction (disposition
|
|
1025
|
+
// invariant: !inspectable ⇒ reason is set); `?? d.ref` only satisfies the string|null
|
|
1026
|
+
// type and is never actually taken.
|
|
1027
|
+
supportReason = `spreadsheet review inspects structure only; ${uninspected.length} of ${unionDispositions.length} workbook ref(s) were not inspected (${uniqueStrings(uninspected.map((d) => d.reason ?? d.ref)).join("; ")})`;
|
|
1028
|
+
}
|
|
1029
|
+
// review_goal spreadsheet obligations = union of backed_goals across the RESOLVED
|
|
1030
|
+
// spreadsheet refs (kind stays the trigger per the approved F1 scope: only support_status
|
|
1031
|
+
// reflects the materialized union). backed_goals is the POSITIVE rule — a goal is carried
|
|
1032
|
+
// only when its specific evidence was rendered for that ref, so an obligation never
|
|
1033
|
+
// outruns its backing (a plain data CSV carries none; a macro-only workbook carries only
|
|
1034
|
+
// access_and_protection_hygiene).
|
|
1035
|
+
if (materialDetection.target_material_kind === "spreadsheet") {
|
|
1036
|
+
materialGoals = uniqueStrings(resolvedRefs
|
|
1037
|
+
.filter(isSpreadsheetRef)
|
|
1038
|
+
.flatMap((ref) => dispositionByRef.get(ref)?.backed_goals ?? []));
|
|
1039
|
+
// No directly-inspectable workbook ref at all — e.g. a directory aggregated as
|
|
1040
|
+
// spreadsheet with no workbook ref, or every ref uninspectable. Nothing backs an
|
|
1041
|
+
// obligation and the render shows only a listing/unsupported note, so a kind-level
|
|
1042
|
+
// `supported` would be dishonest.
|
|
1043
|
+
const anyInspectable = unionDispositions.some((d) => d.inspectable);
|
|
1044
|
+
if (!anyInspectable) {
|
|
1045
|
+
materialGoals = [];
|
|
1046
|
+
if (supportStatus === "supported") {
|
|
1047
|
+
supportStatus = "partial";
|
|
1048
|
+
supportReason =
|
|
1049
|
+
"spreadsheet target has no directly-inspectable workbook ref (no inventory-backed structural detail rendered)";
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
982
1053
|
return {
|
|
983
1054
|
schema_version: "1",
|
|
984
1055
|
session_id: sessionId,
|
|
@@ -1000,6 +1071,7 @@ async function buildReviewTargetProfileArtifact(params) {
|
|
|
1000
1071
|
...goalsForRole(roles.primary),
|
|
1001
1072
|
...roles.secondary.flatMap(goalsForRole),
|
|
1002
1073
|
...domainGoalAdditions(sessionDomain),
|
|
1074
|
+
...materialGoals,
|
|
1003
1075
|
]),
|
|
1004
1076
|
closure_obligation_policy: [
|
|
1005
1077
|
"must_close_in_target",
|
|
@@ -1012,8 +1084,8 @@ async function buildReviewTargetProfileArtifact(params) {
|
|
|
1012
1084
|
material_profile: {
|
|
1013
1085
|
target_material_kind: materialDetection.target_material_kind,
|
|
1014
1086
|
target_material_kind_candidates: materialDetection.target_material_kind_candidates,
|
|
1015
|
-
support_status:
|
|
1016
|
-
unsupported_reason:
|
|
1087
|
+
support_status: supportStatus,
|
|
1088
|
+
unsupported_reason: supportReason,
|
|
1017
1089
|
detection: {
|
|
1018
1090
|
owner: "runtime_heuristic",
|
|
1019
1091
|
confidence: materialDetection.confidence,
|
|
@@ -1045,17 +1117,34 @@ export async function materializeReviewExecutionPreparationArtifacts(params) {
|
|
|
1045
1117
|
const reviewTargetProfilePath = path.join(executionPreparationRoot, "review-target-profile.yaml");
|
|
1046
1118
|
const contextCandidateAssemblyPath = path.join(executionPreparationRoot, "context-candidate-assembly.yaml");
|
|
1047
1119
|
await ensureDirectory(executionPreparationRoot);
|
|
1120
|
+
const resolvedTargetRefs = params.resolvedTargetRefs.map((ref) => path.resolve(ref));
|
|
1048
1121
|
const materializedRefs = params.materializedRefs && params.materializedRefs.length > 0
|
|
1049
1122
|
? params.materializedRefs.map((ref) => path.resolve(ref))
|
|
1050
|
-
:
|
|
1123
|
+
: resolvedTargetRefs;
|
|
1124
|
+
// Observe each spreadsheet ref ONCE and share the inventory across the profile and
|
|
1125
|
+
// both renders (design §3.2 "single observation"): a workbook would otherwise be
|
|
1126
|
+
// parsed up to three times (target-snapshot + materialized-input + profile
|
|
1127
|
+
// inspectability). The map feeds per-target inspectability and the rendered detail.
|
|
1128
|
+
const spreadsheetRefs = [
|
|
1129
|
+
...new Set([...resolvedTargetRefs, ...materializedRefs].filter(isSpreadsheetRef)),
|
|
1130
|
+
];
|
|
1131
|
+
// Observe SEQUENTIALLY (not Promise.all): observeSpreadsheetSource reads each source
|
|
1132
|
+
// fully into a Buffer (up to the 1 GiB pre-read limit) before streaming-unzip, so
|
|
1133
|
+
// observing every ref of a multi-workbook bundle at once could exhaust host memory
|
|
1134
|
+
// before any artifact is written. Sequential keeps peak memory at one workbook while
|
|
1135
|
+
// still observing — and sharing — each inventory exactly once.
|
|
1136
|
+
const inventoryByRef = new Map();
|
|
1137
|
+
for (const ref of spreadsheetRefs) {
|
|
1138
|
+
inventoryByRef.set(ref, await observeSpreadsheetSource(ref));
|
|
1139
|
+
}
|
|
1051
1140
|
const targetSnapshotManifest = {
|
|
1052
1141
|
review_target_scope_kind: params.scopeKind,
|
|
1053
|
-
resolved_target_refs:
|
|
1142
|
+
resolved_target_refs: resolvedTargetRefs,
|
|
1054
1143
|
review_target_profile_ref: reviewTargetProfilePath,
|
|
1055
1144
|
captured_at: isoNow(),
|
|
1056
1145
|
capture_reason: "prompt-backed review execution",
|
|
1057
1146
|
};
|
|
1058
|
-
const reviewTargetProfile = await buildReviewTargetProfileArtifact(params);
|
|
1147
|
+
const reviewTargetProfile = await buildReviewTargetProfileArtifact(params, inventoryByRef, materializedRefs);
|
|
1059
1148
|
const contextCandidateAssembly = {
|
|
1060
1149
|
system_purpose_refs: params.systemPurposeRefs ?? [],
|
|
1061
1150
|
domain_context_refs: params.domainContextRefs ?? [],
|
|
@@ -1063,10 +1152,10 @@ export async function materializeReviewExecutionPreparationArtifacts(params) {
|
|
|
1063
1152
|
execution_rule_refs: params.executionRuleRefs ?? [],
|
|
1064
1153
|
};
|
|
1065
1154
|
await Promise.all([
|
|
1066
|
-
fs.writeFile(targetSnapshotPath, await renderTargetSnapshot(
|
|
1155
|
+
fs.writeFile(targetSnapshotPath, await renderTargetSnapshot(resolvedTargetRefs, params.directoryListingOptions, inventoryByRef, params.inventoryPromptCaps), "utf8"),
|
|
1067
1156
|
writeYamlDocument(targetSnapshotManifestPath, targetSnapshotManifest),
|
|
1068
1157
|
writeYamlDocument(reviewTargetProfilePath, reviewTargetProfile),
|
|
1069
|
-
fs.writeFile(materializedInputPath, await renderReviewTargetMaterializedInput(params.materializedKind, materializedRefs, params.directoryListingOptions), "utf8"),
|
|
1158
|
+
fs.writeFile(materializedInputPath, await renderReviewTargetMaterializedInput(params.materializedKind, materializedRefs, params.directoryListingOptions, inventoryByRef, params.inventoryPromptCaps), "utf8"),
|
|
1070
1159
|
writeYamlDocument(contextCandidateAssemblyPath, contextCandidateAssembly),
|
|
1071
1160
|
]);
|
|
1072
1161
|
return executionPreparationRoot;
|
|
@@ -104,7 +104,7 @@ export function buildNestingBatchScript(descriptor) {
|
|
|
104
104
|
const auditPath = path.join(outputDir, `.${safeId}.nested-stderr.log`);
|
|
105
105
|
const statRef = `"$TMPDIR/u${index}.status"`;
|
|
106
106
|
const okJson = `{"unit_id":"${jsonEscape(unit.unit_id)}","status":"ok"}`;
|
|
107
|
-
const failFmt = `{"unit_id":"${jsonEscape(unit.unit_id)}","status":"fail","error":"exit=%s size=%s"}`;
|
|
107
|
+
const failFmt = `{"unit_id":"${jsonEscape(unit.unit_id)}","status":"fail","error":"exit=%s size=%s log_tail=%s"}`;
|
|
108
108
|
const fallbackJson = `{"unit_id":"${jsonEscape(unit.unit_id)}","status":"fail","error":"no status reported"}`;
|
|
109
109
|
const unitArgs = [
|
|
110
110
|
"--unit-id",
|
|
@@ -136,7 +136,11 @@ export function buildNestingBatchScript(descriptor) {
|
|
|
136
136
|
' if [ "$EC" = "0" ] && [ "$SIZE" -gt 0 ]; then',
|
|
137
137
|
` printf '%s' ${shellQuote(okJson)} > ${statRef}`,
|
|
138
138
|
" else",
|
|
139
|
-
|
|
139
|
+
' ERROR_HINT=""',
|
|
140
|
+
' if [ -f "$LOG" ]; then',
|
|
141
|
+
` ERROR_HINT=$(tail -n 20 "$LOG" 2>/dev/null | tr '\\n\\r\\t' ' ' | tr '\\000-\\010\\013\\014\\016-\\037\\177' ' ' | cut -c1-500 | sed 's/\\\\/\\\\\\\\/g; s/"/\\\\"/g')`,
|
|
142
|
+
" fi",
|
|
143
|
+
` printf ${shellQuote(failFmt)} "$EC" "$SIZE" "$ERROR_HINT" > ${statRef}`,
|
|
140
144
|
" fi",
|
|
141
145
|
") &",
|
|
142
146
|
].join("\n"));
|