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.
Files changed (139) hide show
  1. package/.onto/authority/core-lexicon.yaml +1 -1
  2. package/.onto/authority/supported-models.yaml +153 -0
  3. package/.onto/domains/accounting-kr/competency_qs.md +153 -153
  4. package/.onto/processes/reconstruct/obligation-coverage-ledger.yaml +842 -0
  5. package/.onto/processes/reconstruct/obligation-coverage-recorded.yaml +225 -0
  6. package/.onto/processes/reconstruct/ontology-seeding-and-maturation-design.md +93 -54
  7. package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +202 -49
  8. package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +72 -1
  9. package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +35 -0
  10. package/.onto/processes/review/nesting-batch-worker-contract.md +1 -1
  11. package/.onto/processes/review/productized-live-path.md +9 -5
  12. package/.onto/processes/review/prompt-execution-runner-contract.md +32 -8
  13. package/.onto/processes/review/review-target-profile-contract.md +47 -4
  14. package/.onto/processes/shared/pipeline-execution-ledger-contract.md +11 -0
  15. package/.onto/processes/shared/target-material-kind-contract.md +1 -1
  16. package/README.md +64 -1
  17. package/dist/cli.js +11 -1
  18. package/dist/core-api/reconstruct-api.js +679 -18
  19. package/dist/core-api/review-api.js +70 -5
  20. package/dist/core-api/review-progress.js +7 -0
  21. package/dist/core-api/runtime-observation.js +7 -0
  22. package/dist/core-runtime/artifact-io.js +131 -0
  23. package/dist/core-runtime/cli/claude-code-review-unit-executor.js +21 -9
  24. package/dist/core-runtime/cli/claude-nesting-batch-worker.js +4 -2
  25. package/dist/core-runtime/cli/materialize-review-prompt-packets.js +68 -14
  26. package/dist/core-runtime/cli/prepare-review-session.js +34 -1
  27. package/dist/core-runtime/cli/render-review-final-output.js +2 -1
  28. package/dist/core-runtime/cli/run-review-prompt-execution.js +758 -48
  29. package/dist/core-runtime/cli/run-seats.js +18 -0
  30. package/dist/core-runtime/cli/runtime-submit-context.js +10 -2
  31. package/dist/core-runtime/cli/unit-resubmit.js +269 -0
  32. package/dist/core-runtime/cli/worker-structured-output.js +80 -2
  33. package/dist/core-runtime/discovery/host-detection.js +71 -22
  34. package/dist/core-runtime/discovery/review-cert-assemble.js +208 -0
  35. package/dist/core-runtime/discovery/review-cert-record.js +442 -0
  36. package/dist/core-runtime/discovery/review-execution-units.js +22 -0
  37. package/dist/core-runtime/discovery/seat-inventory.js +167 -0
  38. package/dist/core-runtime/discovery/settings-chain.js +311 -52
  39. package/dist/core-runtime/discovery/supported-models.js +289 -25
  40. package/dist/core-runtime/discovery/synthesize-cert-assemble.js +197 -0
  41. package/dist/core-runtime/discovery/synthesize-cert-capsule.js +399 -0
  42. package/dist/core-runtime/discovery/synthesize-cert-judge.js +340 -0
  43. package/dist/core-runtime/discovery/synthesize-cert-loop.js +234 -0
  44. package/dist/core-runtime/discovery/synthesize-cert-mutation.js +117 -0
  45. package/dist/core-runtime/discovery/synthesize-cert-packet.js +182 -0
  46. package/dist/core-runtime/discovery/synthesize-cert-record.js +831 -0
  47. package/dist/core-runtime/discovery/synthesize-cert-sampler.js +336 -0
  48. package/dist/core-runtime/effort-calibration-ingest.js +326 -0
  49. package/dist/core-runtime/effort-calibration-reconstruct.js +47 -0
  50. package/dist/core-runtime/effort-calibration-review.js +22 -0
  51. package/dist/core-runtime/effort-calibration-sweep.js +110 -0
  52. package/dist/core-runtime/effort-frontier.js +134 -0
  53. package/dist/core-runtime/llm/claude-bin.js +77 -0
  54. package/dist/core-runtime/llm/dispatch-breaker.js +412 -0
  55. package/dist/core-runtime/llm/dispatch-fallback-adapter-capabilities.js +33 -0
  56. package/dist/core-runtime/llm/llm-caller.js +316 -35
  57. package/dist/core-runtime/llm/mock-llm-realization.js +35 -4
  58. package/dist/core-runtime/llm/model-switcher.js +1 -1
  59. package/dist/core-runtime/llm/openai-responses-incomplete-error.js +46 -0
  60. package/dist/core-runtime/llm/sealed-dispatch-capability.js +359 -0
  61. package/dist/core-runtime/llm/structured-dispatch-error.js +15 -0
  62. package/dist/core-runtime/onboard/claude-profile-scan.js +65 -0
  63. package/dist/core-runtime/onboard/cli-host.js +5 -2
  64. package/dist/core-runtime/onboard/configure-provider.js +33 -1
  65. package/dist/core-runtime/onboard/host-target.js +28 -3
  66. package/dist/core-runtime/onboard/register.js +54 -12
  67. package/dist/core-runtime/pipeline-execution-ledger.js +10 -0
  68. package/dist/core-runtime/reconstruct/artifact-types.js +37 -0
  69. package/dist/core-runtime/reconstruct/benchmark-evidence.js +16 -0
  70. package/dist/core-runtime/reconstruct/claim-projection-validation.js +19 -5
  71. package/dist/core-runtime/reconstruct/competency-projection-contract.js +63 -0
  72. package/dist/core-runtime/reconstruct/comprehension-artifact.js +321 -0
  73. package/dist/core-runtime/reconstruct/comprehension-reduce.js +367 -0
  74. package/dist/core-runtime/reconstruct/comprehension-semantic-map.js +771 -0
  75. package/dist/core-runtime/reconstruct/contract-registry.js +20 -0
  76. package/dist/core-runtime/reconstruct/directive-validation.js +4 -3
  77. package/dist/core-runtime/reconstruct/dispatch-fallback-artifacts.js +640 -0
  78. package/dist/core-runtime/reconstruct/execution-telemetry.js +84 -9
  79. package/dist/core-runtime/reconstruct/final-output-sections.js +89 -0
  80. package/dist/core-runtime/reconstruct/governing-snapshot.js +36 -1
  81. package/dist/core-runtime/reconstruct/leaf-reader.js +305 -0
  82. package/dist/core-runtime/reconstruct/llm-dispatch-failure.js +270 -0
  83. package/dist/core-runtime/reconstruct/llm-touch-fingerprint.js +94 -0
  84. package/dist/core-runtime/reconstruct/material-admission-validation.js +20 -5
  85. package/dist/core-runtime/reconstruct/material-profile-validation.js +24 -6
  86. package/dist/core-runtime/reconstruct/materialize-preparation.js +380 -23
  87. package/dist/core-runtime/reconstruct/maturation-validation.js +1522 -67
  88. package/dist/core-runtime/reconstruct/mock-llm-realization.js +120 -1
  89. package/dist/core-runtime/reconstruct/obligation-assertion.js +18 -0
  90. package/dist/core-runtime/reconstruct/ontology-seed-validation.js +39 -7
  91. package/dist/core-runtime/reconstruct/output-budget.js +6 -0
  92. package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +112 -5
  93. package/dist/core-runtime/reconstruct/post-seed-validation.js +122 -11
  94. package/dist/core-runtime/reconstruct/proof-authority-validation.js +2 -6
  95. package/dist/core-runtime/reconstruct/purpose-authority-validation.js +119 -7
  96. package/dist/core-runtime/reconstruct/record.js +49 -3
  97. package/dist/core-runtime/reconstruct/registry-verification-validation.js +41 -5
  98. package/dist/core-runtime/reconstruct/run-control-validation.js +1019 -37
  99. package/dist/core-runtime/reconstruct/run.js +5409 -517
  100. package/dist/core-runtime/reconstruct/seed-authoring-readiness-validation.js +56 -8
  101. package/dist/core-runtime/reconstruct/semantic-quality-gate.js +112 -7
  102. package/dist/core-runtime/reconstruct/source-observation-delta-validation.js +53 -5
  103. package/dist/core-runtime/reconstruct/source-observations.js +166 -0
  104. package/dist/core-runtime/reconstruct/source-safety-validation.js +77 -188
  105. package/dist/core-runtime/reconstruct/source-scout-pack-validation.js +50 -6
  106. package/dist/core-runtime/reconstruct/terminal-validation.js +145 -13
  107. package/dist/core-runtime/review/continuation-plan.js +12 -5
  108. package/dist/core-runtime/review/issue-artifact-runtime.js +4 -1
  109. package/dist/core-runtime/review/materializers.js +100 -11
  110. package/dist/core-runtime/review/nesting-batch.js +6 -2
  111. package/dist/core-runtime/review/obligation-shardability.js +138 -0
  112. package/dist/core-runtime/review/pipeline-execution-ledger.js +42 -2
  113. package/dist/core-runtime/review/review-artifact-utils.js +219 -7
  114. package/dist/core-runtime/review/review-execution-steps.js +32 -8
  115. package/dist/core-runtime/review/review-progress-contract.js +8 -0
  116. package/dist/core-runtime/review/review-prompt-budget.js +97 -0
  117. package/dist/core-runtime/review/semantic-quality-gate.js +33 -7
  118. package/dist/core-runtime/review/spreadsheet-review-disposition.js +94 -0
  119. package/dist/core-runtime/route-identity.js +182 -0
  120. package/dist/core-runtime/spreadsheet-header-escalation.js +204 -0
  121. package/dist/core-runtime/spreadsheet-structure-observer.js +2689 -0
  122. package/dist/core-runtime/target-material-kind.js +58 -0
  123. package/dist/mcp/server.js +27 -5
  124. package/dist/mcp/tool-schemas.js +8 -0
  125. package/dist/tui/app.js +167 -0
  126. package/dist/tui/data/event-follower.js +116 -0
  127. package/dist/tui/data/node-detail.js +42 -0
  128. package/dist/tui/data/projection-poll.js +26 -0
  129. package/dist/tui/data/session-discovery.js +65 -0
  130. package/dist/tui/index.js +108 -0
  131. package/dist/tui/screens/log.js +25 -0
  132. package/dist/tui/screens/node-detail.js +17 -0
  133. package/dist/tui/screens/session-selector.js +26 -0
  134. package/dist/tui/screens/workflow-tree.js +90 -0
  135. package/dist/tui/view-model/reconstruct-adapter.js +162 -0
  136. package/dist/tui/view-model/review-adapter.js +270 -0
  137. package/dist/tui/view-model/tree-view-model.js +19 -0
  138. package/package.json +20 -3
  139. package/settings.example.json +77 -16
@@ -3,6 +3,44 @@ import { ontologySeedClaimProjections } from "./seed-claim-projections.js";
3
3
  export const RECONSTRUCT_MOCK_REALIZATION_ENV = REVIEW_MOCK_REALIZATION_ENV;
4
4
  export const RECONSTRUCT_MOCK_AUTHOR_ID = "reconstruct-mock-semantic-author";
5
5
  export const RECONSTRUCT_MOCK_CONFIRMATION_PROVIDER_ID = "reconstruct-mock-confirmation-provider";
6
+ /**
7
+ * Layer-2 semantic-map author capability — MOCK realization (wiring design 20260702 §7-W5).
8
+ *
9
+ * Wraps a directive author with the deterministic capability PAIR (the production direct-call
10
+ * author deliberately does NOT implement it — real-LLM authoring is a separate owner-approved
11
+ * cut, so the live path stays default-off). Pure functions of their input:
12
+ * - synthesize: one boundary at the node's first value-shape seam when one exists (reconciled
13
+ * anchored) plus ALWAYS one at row_start — emission is unconditional; the deterministic
14
+ * reconcile CLASSIFIES it (unanchored → adversarial verify path — whenever no seam lies
15
+ * within ±1 of row_start, which holds for every non-seam-adjacent region start);
16
+ * - verify: confirmed on even rows, refuted on odd (exercises kept AND disclosed dispositions).
17
+ * The two-path description above is the mock's FUNCTION CONTRACT given seam-ful input; the W5
18
+ * E2E fixture is seam-less through the production observer (adversary F1, probe-confirmed), so
19
+ * the E2E itself traverses only the unanchored→refuted path — anchored/confirmed execution
20
+ * coverage lives in semantic-map-stage.test.ts.
21
+ * Mock output verifies wiring/contracts only — never product semantic quality.
22
+ */
23
+ export function withMockSemanticMapCapability(author) {
24
+ return {
25
+ ...author,
26
+ async synthesizeSemanticMapNode(input) {
27
+ const seam = input.value_shape_seams[0];
28
+ return {
29
+ semantic_summary: `mock ${input.node_ref.sheet}#${input.node_ref.column_index}:` +
30
+ `${input.node_ref.row_start}-${input.node_ref.row_end} kids=${input.child_summaries.length}`,
31
+ boundaries: [
32
+ ...(seam
33
+ ? [{ row: seam.row, character_before: "seam-prev", character_after: "seam-next" }]
34
+ : []),
35
+ { row: input.node_ref.row_start, character_before: "prev", character_after: "next" },
36
+ ],
37
+ };
38
+ },
39
+ async verifySemanticMapBoundary(input) {
40
+ return input.boundary.row % 2 === 0 ? "adversarial_confirmed" : "adversarial_refuted";
41
+ },
42
+ };
43
+ }
6
44
  export function isReconstructMockLlmRealizationEnabled(env = process.env) {
7
45
  return env[RECONSTRUCT_MOCK_REALIZATION_ENV] === "1";
8
46
  }
@@ -805,8 +843,52 @@ export function callReconstructMockLlm(systemPrompt, userPrompt) {
805
843
  });
806
844
  }
807
845
  else if (systemPrompt.includes("Author answer-support-ledger.yaml")) {
846
+ // Defect-3 G4: derive a deterministic direct_authority cluster from the
847
+ // prompt's frontier questions + prompt-visible observations. With the shared
848
+ // empty-frontier mock (questions:[]) this yields [] so the ~12 full-pipeline
849
+ // completion tests are unaffected; a non-empty-frontier fixture exercises the
850
+ // real G1/G2/G3 per-evidence-ref path (the path the empty mock hid).
851
+ const frontierQuestions = (input.questions ?? []);
852
+ const promptVisibleObservationIds = (input.prompt_visible_observation_ids ?? []);
853
+ const questionRefs = frontierQuestions
854
+ .map((question) => question.question_id)
855
+ .filter((id) => typeof id === "string" && id.length > 0);
856
+ if (questionRefs.length === 0 || promptVisibleObservationIds.length === 0) {
857
+ text = JSON.stringify({ evidence_clusters: [] });
858
+ }
859
+ else {
860
+ text = JSON.stringify({
861
+ evidence_clusters: [
862
+ {
863
+ evidence_cluster_id: "mock-evidence-cluster-1",
864
+ question_refs: questionRefs,
865
+ support_mode: "direct_authority",
866
+ proposed_answer_summary: "Mock direct-authority support derived from the observed runtime-target source.",
867
+ evidence_observation_ids: [promptVisibleObservationIds[0]],
868
+ proof_refs: [],
869
+ user_confirmation_refs: [],
870
+ authority_response_refs: [],
871
+ independence_basis: "Deterministic mock structural observation of the runtime-target source.",
872
+ contradiction_refs: [],
873
+ limitation_refs: [],
874
+ },
875
+ ],
876
+ });
877
+ }
878
+ }
879
+ else if (systemPrompt.includes("Author answer-support-judgment.yaml")) {
880
+ // Mirrors the judge author payload shape: per-cluster
881
+ // {evidence_cluster_id, evidence_observation_ids}. Returns one supported
882
+ // judgment per cited evidence to exercise the supported path deterministically.
883
+ const judgeClusters = (input.evidence_clusters ?? []);
808
884
  text = JSON.stringify({
809
- evidence_clusters: [],
885
+ judgments: judgeClusters.flatMap((cluster) => (cluster.evidence_observation_ids ?? []).map((observationId, index) => ({
886
+ judgment_id: `${cluster.evidence_cluster_id}-judgment-${index + 1}`,
887
+ evidence_cluster_ref: cluster.evidence_cluster_id,
888
+ evidence_observation_id: observationId,
889
+ supports: "supported",
890
+ rationale_ref: `rationale:${cluster.evidence_cluster_id}:${observationId}`,
891
+ }))),
810
892
  });
811
893
  }
812
894
  else if (systemPrompt.includes("Author maturation-answer-claims.yaml")) {
@@ -819,6 +901,43 @@ export function callReconstructMockLlm(systemPrompt, userPrompt) {
819
901
  expansions: [],
820
902
  });
821
903
  }
904
+ else if (systemPrompt.includes("Read provisional column labels for a low-confidence")) {
905
+ // P1-C2-A §11 R10 / P1-C2-B′ §3: the leaf-reader (CAPTURE) fixture branch. Returns one
906
+ // provisional label per known column PLUS a deterministic capture (role/note) so the generalized
907
+ // capture path is exercised. The mock model_id is a constant ("reconstruct-mock-model" in the
908
+ // result below), so the model-identity-rotation test must mutate the PRODUCTION LlmCallConfig,
909
+ // never this constant (avoids CG-2 contamination).
910
+ const columns = (input.columns ?? []);
911
+ // Deterministic role rotation across the bounded vocabulary (mock only — no domain meaning).
912
+ const mockRoles = ["category", "measure", "identifier", "free_text", "reference"];
913
+ text = JSON.stringify({
914
+ labels: columns.map((column, i) => ({
915
+ column_index: column.column_index,
916
+ tentative_label: `provisional column ${column.column_index}`,
917
+ semantic_role: mockRoles[i % mockRoles.length],
918
+ captured_note: `mock capture for column ${column.column_index}`,
919
+ })),
920
+ unread_columns: [],
921
+ });
922
+ }
923
+ else if (systemPrompt.includes("Select spreadsheet cell locations")) {
924
+ // Maturation value-read location pick (design §15.4). Echo the FIRST allowed grid scope so an
925
+ // incidental value-read exercises the cell-read path; an empty allowed set yields no pick (honest).
926
+ const allowed = (input.allowed_locations ?? []);
927
+ text = JSON.stringify({
928
+ picked_locations: allowed.length > 0 ? [allowed[0]] : [],
929
+ });
930
+ }
931
+ else if (systemPrompt.includes("Judge whether read spreadsheet cell values")) {
932
+ // Value-read judgment (design §15.4). Default INCONCLUSIVE so an incidental value-read in an
933
+ // existing full mock run discharges nothing (regression-0 / byte-parity — never flips a row to
934
+ // value_resolved). A dedicated value-read E2E drives `satisfied` via a stub llmCall, not this
935
+ // dispatcher. Honest "ran but discharged zero".
936
+ text = JSON.stringify({
937
+ satisfaction_status: "inconclusive",
938
+ rationale: "mock value-read judgment: read values do not decide the limitation",
939
+ });
940
+ }
822
941
  else if (systemPrompt.includes("writing the final reconstruct result")) {
823
942
  text = [
824
943
  "# Reconstruct Result",
@@ -0,0 +1,18 @@
1
+ /**
2
+ * G(a) — obligation recorder (INV-OBLIGATION-COVERAGE-1).
3
+ *
4
+ * A validator calls `assertObligation(acc, id)` at an UNCONDITIONAL position before each
5
+ * check-block's guard, accumulating the obligation ids whose enforcer block was reached.
6
+ * The accumulator is emitted as `asserted_obligation_ids: string[]` on the validation
7
+ * artifact (off the reuse-hash five). The obligation-coverage harvest test re-derives this
8
+ * set dynamically (deleting the call reds the harvest) and the gate proves every active
9
+ * `(validator_id, obligation_id)` is either recorded here or parked in the pending ledger.
10
+ *
11
+ * Scope honesty: this records that control REACHED the enforcer block — NOT that the
12
+ * enforcer is semantically correct. Idempotent: a repeat id is not pushed twice.
13
+ */
14
+ export function assertObligation(asserted, obligationId) {
15
+ if (!asserted.includes(obligationId)) {
16
+ asserted.push(obligationId);
17
+ }
18
+ }
@@ -1,7 +1,9 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { assertArrayField, atomicWriteYamlDocument as writeYamlDocument } from "../artifact-io.js";
4
5
  import { loadReconstructContractRegistry, } from "./contract-registry.js";
6
+ import { assertObligation } from "./obligation-assertion.js";
5
7
  function isoNow() {
6
8
  return new Date().toISOString();
7
9
  }
@@ -88,6 +90,7 @@ function normalizeSourceRef(ref) {
88
90
  return path.resolve(ref);
89
91
  }
90
92
  function evidenceObservationById(sourceObservations) {
93
+ assertArrayField(sourceObservations.observations, "source-observations", "observations");
91
94
  return new Map(sourceObservations.observations.map((observation) => [
92
95
  observation.observation_id,
93
96
  observation,
@@ -179,9 +182,11 @@ function readEvidenceRefs(args) {
179
182
  return evidenceRefs;
180
183
  }
181
184
  function registryCandidateKindIds(registry) {
185
+ assertArrayField(registry.candidate_kind_registry, "contract-registry", "candidate_kind_registry");
182
186
  return new Set(registry.candidate_kind_registry.map((record) => record.candidate_kind_id));
183
187
  }
184
188
  function registryCandidateDispositionIds(registry) {
189
+ assertArrayField(registry.candidate_disposition_registry, "contract-registry", "candidate_disposition_registry");
185
190
  return new Set(registry.candidate_disposition_registry.map((record) => record.disposition_id));
186
191
  }
187
192
  function candidateValidationViolation(args) {
@@ -193,7 +198,19 @@ function candidateValidationViolation(args) {
193
198
  };
194
199
  }
195
200
  export function validateCandidateDisposition(args) {
201
+ assertArrayField(args.sourceObservations.observations, "source-observations", "observations");
196
202
  const violations = [];
203
+ // G(a) obligation recorder (INV-OBLIGATION-COVERAGE-1): record that control reached the
204
+ // per-candidate / per-disposition enforcement loops below. Unconditional, before any per-row
205
+ // guard so a zero-candidate/zero-disposition input still stamps. Only the four obligations with a
206
+ // distinct, name-matching enforcer are recorded; salience-scoped and surface/purpose/limitation/
207
+ // frontier obligations are PARKED (this validator is salience-blind and takes no purpose-frame or
208
+ // surface input) — see obligation-coverage-ledger.yaml.
209
+ const assertedObligationIds = [];
210
+ assertObligation(assertedObligationIds, "validate_candidate_inventory_candidate_kind_against_candidate_kind_registry");
211
+ assertObligation(assertedObligationIds, "validate_candidate_disposition_against_candidate_disposition_registry");
212
+ assertObligation(assertedObligationIds, "require_rationale_and_evidence_refs_for_each_disposition");
213
+ assertObligation(assertedObligationIds, "validate_promoted_candidate_target_seed_refs_are_declared_for_promoted_dispositions");
197
214
  const addShapeViolation = (_code, message) => {
198
215
  violations.push(candidateValidationViolation({
199
216
  code: "schema_shape_invalid",
@@ -382,6 +399,7 @@ export function validateCandidateDisposition(args) {
382
399
  validation_results: violations.length === 0
383
400
  ? ["candidate_disposition_valid"]
384
401
  : ["candidate_disposition_invalid"],
402
+ asserted_obligation_ids: assertedObligationIds,
385
403
  violations,
386
404
  };
387
405
  }
@@ -726,10 +744,25 @@ function checkSourceRefs(args) {
726
744
  }
727
745
  }
728
746
  export function validateOntologySeed(args) {
747
+ assertArrayField(args.sourceObservations.observations, "source-observations", "observations");
748
+ assertArrayField(args.registry.coverage_axis_registry, "contract-registry", "coverage_axis_registry");
729
749
  const violations = [];
730
750
  const addShapeViolation = (_code, message) => {
731
751
  violations.push(seedValidationViolation({ code: "schema_shape_invalid", message }));
732
752
  };
753
+ // G(a) slice 26: record the six obligations this validator FULLY enforces with a distinct,
754
+ // name-matching site (stamped before the per-root/per-row guards so a zero-row seed still records).
755
+ // Parked (see obligation-coverage-ledger.yaml notes): surface_dimension_closure / closure_status /
756
+ // mixed-member-lineage / dynamic_boundaries name fields this function never reads; the three
757
+ // purpose-projection/confirmation obligations are activation_gated_dormant (their conditional inputs
758
+ // — source-purpose-candidates-validation / purpose-confirmation-validation — are never received here).
759
+ const assertedObligationIds = [];
760
+ assertObligation(assertedObligationIds, "require_static_kinetic_dynamic_actionability_coverage_axes");
761
+ assertObligation(assertedObligationIds, "validate_purpose_required_element_seed_ref_refs_against_known_seed_refs");
762
+ assertObligation(assertedObligationIds, "validate_promoted_candidate_target_seed_refs_are_realized");
763
+ assertObligation(assertedObligationIds, "validate_instance_assertion_mapping_status");
764
+ assertObligation(assertedObligationIds, "require_limitation_ref_when_instance_availability_status_is_absent_or_unknown");
765
+ assertObligation(assertedObligationIds, "require_ready_ontology_handoff_mappings_to_have_substantive_content_or_limitation_refs");
733
766
  const seed = readRecord(args.ontologySeed, "ontology_seed", addShapeViolation);
734
767
  const disposition = readRecord(args.candidateDisposition, "candidate_disposition", addShapeViolation);
735
768
  const sessionId = optionalString(disposition?.session_id) ??
@@ -1907,22 +1940,20 @@ export function validateOntologySeed(args) {
1907
1940
  validation_results: violations.length === 0
1908
1941
  ? ["ontology_seed_valid"]
1909
1942
  : ["ontology_seed_invalid"],
1943
+ asserted_obligation_ids: assertedObligationIds,
1910
1944
  violations,
1911
1945
  };
1912
1946
  }
1913
1947
  async function readYamlDocument(filePath) {
1914
1948
  return parseYaml(await fs.readFile(filePath, "utf8"));
1915
1949
  }
1916
- async function writeYamlDocument(filePath, value) {
1917
- await fs.mkdir(path.dirname(filePath), { recursive: true });
1918
- await fs.writeFile(filePath, stringifyYaml(value), "utf8");
1919
- }
1920
1950
  export async function writeCandidateDispositionValidationArtifact(args) {
1921
1951
  const [candidateInventory, candidateDisposition, sourceObservations, registry] = await Promise.all([
1922
1952
  readYamlDocument(args.candidateInventoryPath),
1923
1953
  readYamlDocument(args.candidateDispositionPath),
1924
1954
  readYamlDocument(args.sourceObservationsPath),
1925
- loadReconstructContractRegistry({ registryPath: args.registryPath }),
1955
+ args.contractRegistry ??
1956
+ loadReconstructContractRegistry({ registryPath: args.registryPath }),
1926
1957
  ]);
1927
1958
  const validation = validateCandidateDisposition({
1928
1959
  candidateInventory,
@@ -1942,7 +1973,8 @@ export async function writeOntologySeedValidationArtifact(args) {
1942
1973
  readYamlDocument(args.ontologySeedPath),
1943
1974
  readYamlDocument(args.candidateDispositionPath),
1944
1975
  readYamlDocument(args.sourceObservationsPath),
1945
- loadReconstructContractRegistry({ registryPath: args.registryPath }),
1976
+ args.contractRegistry ??
1977
+ loadReconstructContractRegistry({ registryPath: args.registryPath }),
1946
1978
  ]);
1947
1979
  const validation = validateOntologySeed({
1948
1980
  ontologySeed,
@@ -0,0 +1,6 @@
1
+ export const RECONSTRUCT_SEMANTIC_AUTHOR_OUTPUT_CEILINGS = {
2
+ candidate_disposition: 4_000,
3
+ ontology_seed: 9_000,
4
+ json_parse_repair: 16_000,
5
+ };
6
+ export const RECONSTRUCT_SEMANTIC_AUTHOR_MAX_BASE_OUTPUT_TOKENS = Math.max(...Object.values(RECONSTRUCT_SEMANTIC_AUTHOR_OUTPUT_CEILINGS));
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { parse as parseYaml } from "yaml";
4
4
  import { PIPELINE_EXECUTION_LEDGER_SCHEMA_VERSION, buildLedgerTrust, buildOutputHashes, isTrustedLedgerUnit, normalizeLedgerRefs, } from "../pipeline-execution-ledger.js";
5
5
  import { terminalFailureMessageFromTelemetry } from "./execution-telemetry.js";
6
+ import { DispatchFallbackOutcomeSchema, projectDispatchFallbackRecordBlock, } from "./dispatch-fallback-artifacts.js";
6
7
  const RECONSTRUCT_LEDGER_STAGE_SPECS = [
7
8
  {
8
9
  unitId: "run_control",
@@ -193,6 +194,23 @@ const RECONSTRUCT_LEDGER_STAGE_SPECS = [
193
194
  "source_observation_reentry_validation",
194
195
  ],
195
196
  },
197
+ {
198
+ // Layer-2 semantic_map stage (W3 review: codex W3-002 ≡ onto issue-001/002/006 — 4-lens
199
+ // convergence on audit-graph registration). The LIVE run does not consume this ledger (it is a
200
+ // post-hoc audit projection derived from the record), so this row is descriptive evidence, not
201
+ // continuation authority. Authored-artifact reuse still folds the stage fingerprint into the
202
+ // seed key; breaker recovery is stage-local and consumes dispatch-incomplete.yaml only after
203
+ // semantic-map-resume-validation.yaml validates retained census/sidecar rows. unitKind is NOT
204
+ // "semantic_map" — that kind name is already taken by claim_realization (pre-existing vocabulary
205
+ // collision).
206
+ unitId: "semantic_map",
207
+ unitKind: "semantic_map_accumulation",
208
+ owner: "host_llm",
209
+ artifactKey: "semantic_map_census",
210
+ // DATA dependency (ultracode audit E: the earlier lineage-validation edge was a false/temporal
211
+ // edge — the stage reads source_observations' inventory tiles, nothing from the lineage index).
212
+ upstreamUnitIds: ["source_observation"],
213
+ },
196
214
  {
197
215
  unitId: "source_purpose_candidates",
198
216
  unitKind: "semantic_source_purpose",
@@ -286,6 +304,16 @@ const RECONSTRUCT_LEDGER_STAGE_SPECS = [
286
304
  artifactKey: "seed_authoring_readiness_validation",
287
305
  upstreamUnitIds: ["seed_authoring_readiness"],
288
306
  },
307
+ {
308
+ // M3c: runtime snapshot of the pre-maturation seed-stage projected observations,
309
+ // captured at the seed-authoring gate; the conserved authority the resume truncation
310
+ // fallback measures. Runtime-owned, derived from the source-observation unit.
311
+ unitId: "seed_stage_prompt_source_observations",
312
+ unitKind: "source_observation_snapshot",
313
+ owner: "runtime",
314
+ artifactKey: "seed_stage_prompt_source_observations",
315
+ upstreamUnitIds: ["source_observation", "seed_authoring_readiness_validation"],
316
+ },
289
317
  {
290
318
  unitId: "ontology_seed",
291
319
  unitKind: "semantic_ontology_seed",
@@ -575,19 +603,40 @@ const RECONSTRUCT_LEDGER_STAGE_SPECS = [
575
603
  "source_safety_validation",
576
604
  ],
577
605
  },
606
+ {
607
+ unitId: "answer_support_judgment",
608
+ unitKind: "semantic_answer_support_judgment",
609
+ owner: "host_llm",
610
+ artifactKey: "answer_support_judgment",
611
+ upstreamUnitIds: ["answer_support_ledger_validation"],
612
+ },
613
+ {
614
+ unitId: "answer_support_judgment_validation",
615
+ unitKind: "runtime_validation",
616
+ owner: "runtime",
617
+ artifactKey: "answer_support_judgment_validation",
618
+ upstreamUnitIds: [
619
+ "answer_support_judgment",
620
+ "answer_support_ledger_validation",
621
+ ],
622
+ },
578
623
  {
579
624
  unitId: "maturation_answer_claims",
580
625
  unitKind: "semantic_answer_claims",
581
626
  owner: "host_llm",
582
627
  artifactKey: "maturation_answer_claims",
583
- upstreamUnitIds: ["answer_support_ledger_validation"],
628
+ upstreamUnitIds: ["answer_support_judgment_validation"],
584
629
  },
585
630
  {
586
631
  unitId: "maturation_answer_claims_validation",
587
632
  unitKind: "runtime_validation",
588
633
  owner: "runtime",
589
634
  artifactKey: "maturation_answer_claims_validation",
590
- upstreamUnitIds: ["maturation_answer_claims", "answer_support_ledger_validation"],
635
+ upstreamUnitIds: [
636
+ "maturation_answer_claims",
637
+ "answer_support_judgment_validation",
638
+ "answer_support_ledger_validation",
639
+ ],
591
640
  },
592
641
  {
593
642
  unitId: "ontology_expansion",
@@ -612,6 +661,7 @@ const RECONSTRUCT_LEDGER_STAGE_SPECS = [
612
661
  "baseline_actionability_matrix_validation",
613
662
  "maturation_answer_claims_validation",
614
663
  "ontology_expansion_validation",
664
+ "maturation_question_frontier_validation",
615
665
  ],
616
666
  },
617
667
  {
@@ -624,6 +674,7 @@ const RECONSTRUCT_LEDGER_STAGE_SPECS = [
624
674
  "maturation_baseline_validation",
625
675
  "maturation_answer_claims_validation",
626
676
  "ontology_expansion_validation",
677
+ "maturation_question_frontier_validation",
627
678
  ],
628
679
  },
629
680
  {
@@ -821,6 +872,19 @@ const RECONSTRUCT_LEDGER_STAGE_SPECS = [
821
872
  upstreamUnitIds: ["record_assembly"],
822
873
  },
823
874
  ];
875
+ export function reconstructStageIdForArtifactRef(artifactRef) {
876
+ const artifactKey = path.basename(artifactRef, path.extname(artifactRef))
877
+ .replaceAll("-", "_");
878
+ return RECONSTRUCT_LEDGER_STAGE_SPECS.find((spec) => spec.artifactKey === artifactKey)?.unitId ?? null;
879
+ }
880
+ export function reconstructStageOwner(stageId) {
881
+ const owner = RECONSTRUCT_LEDGER_STAGE_SPECS.find((spec) => spec.unitId === stageId)?.owner;
882
+ if (owner === "runtime" || owner === "host_llm")
883
+ return owner;
884
+ if (owner === "user_or_host_mediated")
885
+ return "host_or_user";
886
+ return null;
887
+ }
824
888
  const VALIDATION_GATE_BY_AUTHORED_UNIT = new Map([
825
889
  ["observation_directive", "observation_directive_validation"],
826
890
  ["source_frontier", "source_frontier_validation"],
@@ -837,6 +901,7 @@ const VALIDATION_GATE_BY_AUTHORED_UNIT = new Map([
837
901
  ["maturation_question_frontier", "maturation_question_frontier_validation"],
838
902
  ["maturation_closure_frontier", "maturation_closure_frontier_validation"],
839
903
  ["answer_support_ledger", "answer_support_ledger_validation"],
904
+ ["answer_support_judgment", "answer_support_judgment_validation"],
840
905
  ["maturation_answer_claims", "maturation_answer_claims_validation"],
841
906
  ["ontology_expansion", "ontology_expansion_validation"],
842
907
  ["maturation_source_delta", "maturation_source_delta_validation"],
@@ -907,6 +972,7 @@ const PRESENCE_INPUTS_BY_RUNTIME_VALIDATION = new Map([
907
972
  ["maturation_authority_response"],
908
973
  ],
909
974
  ["answer_support_ledger_validation", ["answer_support_ledger"]],
975
+ ["answer_support_judgment_validation", ["answer_support_judgment"]],
910
976
  ["maturation_answer_claims_validation", ["maturation_answer_claims"]],
911
977
  ["ontology_expansion_validation", ["ontology_expansion"]],
912
978
  [
@@ -1070,6 +1136,31 @@ export async function buildReconstructPipelineExecutionLedger(params) {
1070
1136
  }),
1071
1137
  ]),
1072
1138
  ]));
1139
+ const dispatchFallback = params.reconstructRecord.dispatch_fallback;
1140
+ if (dispatchFallback) {
1141
+ const semanticMapManifestStep = manifestStepByUnitId.get("semantic_map");
1142
+ if (!semanticMapManifestStep?.artifact_refs.includes(dispatchFallback.outcome_ref)) {
1143
+ throw new Error("dispatch fallback record/manifest mismatch: semantic_map step must consume the completed outcome ref.");
1144
+ }
1145
+ const parsedOutcome = DispatchFallbackOutcomeSchema.safeParse(parseYaml(await fs.readFile(dispatchFallback.outcome_ref, "utf8")));
1146
+ if (!parsedOutcome.success || parsedOutcome.data.status !== "completed") {
1147
+ throw new Error("dispatch fallback record/ledger mismatch: outcome artifact is not a valid completed canonical outcome.");
1148
+ }
1149
+ const canonicalBlock = projectDispatchFallbackRecordBlock({
1150
+ outcome: parsedOutcome.data,
1151
+ outcomeIntegrity: {
1152
+ path: dispatchFallback.outcome_ref,
1153
+ sha256: dispatchFallback.outcome_sha256,
1154
+ },
1155
+ });
1156
+ if (Object.entries(canonicalBlock).some(([key, value]) => JSON.stringify(dispatchFallback[key]) !== JSON.stringify(value))) {
1157
+ throw new Error("dispatch fallback record/ledger mismatch: record block is not the canonical outcome projection.");
1158
+ }
1159
+ artifactRefsByUnitId.set("semantic_map", normalizeLedgerRefs([
1160
+ ...(artifactRefsByUnitId.get("semantic_map") ?? []),
1161
+ dispatchFallback.outcome_ref,
1162
+ ]));
1163
+ }
1073
1164
  const sourceDeltaFrontierKind = await sourceObservationDeltaFrontierKind(artifactRefsByUnitId.get("source_observation_delta") ?? []);
1074
1165
  const sourceObservationReentryPresent = (artifactRefsByUnitId.get("source_observation_reentry_validation") ?? [])
1075
1166
  .length > 0;
@@ -1088,6 +1179,12 @@ export async function buildReconstructPipelineExecutionLedger(params) {
1088
1179
  const outputRefs = artifactRefsByUnitId.get(spec.unitId) ?? [];
1089
1180
  const outputHashes = await buildOutputHashes(outputRefs);
1090
1181
  outputHashesByUnitId.set(spec.unitId, outputHashes);
1182
+ if (spec.unitId === "semantic_map" &&
1183
+ dispatchFallback &&
1184
+ outputHashes[dispatchFallback.outcome_ref] !==
1185
+ dispatchFallback.outcome_sha256) {
1186
+ throw new Error("dispatch fallback record/ledger mismatch: outcome file hash does not match the completed record block.");
1187
+ }
1091
1188
  if (spec.unitKind === "runtime_validation") {
1092
1189
  validationStatusesByUnitId.set(spec.unitId, await runtimeValidationOutputStatus(outputRefs));
1093
1190
  }
@@ -1114,12 +1211,22 @@ export async function buildReconstructPipelineExecutionLedger(params) {
1114
1211
  }
1115
1212
  return trustedUnitIds.has(unitId);
1116
1213
  });
1214
+ // Pre-stage sessions (ultracode audit E, read-path): when a manifest IS provided but carries
1215
+ // NO step for this unit, the run predates the unit's registration — the terminal validator
1216
+ // (manifest_step_missing, W3-004) forces every CURRENT manifest to carry every stage, so an
1217
+ // absent step can only mean "this run never had the stage". Reporting it "missing" would raise
1218
+ // a false defect signal on every historical session each time a stage is added.
1219
+ const predatesUnit = params.reconstructRunManifest != null &&
1220
+ manifestStatus(params.reconstructRunManifest, spec.unitId) == null &&
1221
+ !manifestStepByUnitId.has(spec.unitId);
1117
1222
  const status = manifestStatus(params.reconstructRunManifest, spec.unitId) ??
1118
1223
  (outputPresent
1119
1224
  ? "completed"
1120
- : upstreamTrusted
1121
- ? "missing"
1122
- : "not_reached");
1225
+ : predatesUnit
1226
+ ? "not_reached"
1227
+ : upstreamTrusted
1228
+ ? "missing"
1229
+ : "not_reached");
1123
1230
  const trust = trustForReconstructUnit({
1124
1231
  spec,
1125
1232
  status,