onto-mcp 0.3.0 → 0.3.2

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 (61) hide show
  1. package/.onto/authority/core-lexicon.yaml +12 -0
  2. package/.onto/domains/software-engineering/competency_qs.md +192 -63
  3. package/.onto/domains/software-engineering/concepts.md +67 -5
  4. package/.onto/domains/software-engineering/conciseness_rules.md +22 -2
  5. package/.onto/domains/software-engineering/dependency_rules.md +78 -8
  6. package/.onto/domains/software-engineering/domain_scope.md +181 -150
  7. package/.onto/domains/software-engineering/extension_cases.md +318 -542
  8. package/.onto/domains/software-engineering/logic_rules.md +75 -3
  9. package/.onto/domains/software-engineering/problem_framing_profile.md +29 -2
  10. package/.onto/domains/software-engineering/prompt_interface.md +122 -0
  11. package/.onto/domains/software-engineering/structure_spec.md +53 -4
  12. package/.onto/principles/llm-native-development-guideline.md +20 -0
  13. package/.onto/principles/productization-charter.md +6 -0
  14. package/.onto/processes/evolve/material-kind-adapter-contract.md +6 -0
  15. package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +468 -81
  16. package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +177 -0
  17. package/.onto/processes/reconstruct/source-profile-contract.md +39 -6
  18. package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +387 -0
  19. package/.onto/processes/review/binding-contract.md +8 -0
  20. package/.onto/processes/review/lens-registry.md +16 -0
  21. package/.onto/processes/review/pre-dispatch-contracts.md +34 -13
  22. package/.onto/processes/review/productized-live-path.md +3 -1
  23. package/.onto/processes/shared/pipeline-execution-ledger-contract.md +185 -0
  24. package/.onto/processes/shared/target-material-kind-contract.md +24 -2
  25. package/.onto/roles/axiology.md +7 -2
  26. package/AGENTS.md +4 -2
  27. package/README.md +52 -29
  28. package/dist/core-api/reconstruct-api.js +92 -5
  29. package/dist/core-api/review-api.js +1744 -371
  30. package/dist/core-runtime/cli/mock-review-unit-executor.js +17 -0
  31. package/dist/core-runtime/cli/render-review-final-output.js +9 -0
  32. package/dist/core-runtime/cli/review-invoke.js +387 -55
  33. package/dist/core-runtime/cli/run-review-prompt-execution.js +361 -90
  34. package/dist/core-runtime/path-boundary.js +58 -0
  35. package/dist/core-runtime/pipeline-execution-ledger.js +100 -0
  36. package/dist/core-runtime/reconstruct/artifact-types.js +33 -1
  37. package/dist/core-runtime/reconstruct/materialize-preparation.js +54 -4
  38. package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +342 -0
  39. package/dist/core-runtime/reconstruct/post-seed-validation.js +630 -0
  40. package/dist/core-runtime/reconstruct/record.js +105 -1
  41. package/dist/core-runtime/reconstruct/run.js +1594 -38
  42. package/dist/core-runtime/reconstruct/seed-candidate-validation.js +29 -0
  43. package/dist/core-runtime/review/continuation-plan.js +160 -0
  44. package/dist/core-runtime/review/execution-plan-boundary.js +123 -0
  45. package/dist/core-runtime/review/materializers.js +8 -3
  46. package/dist/core-runtime/review/pipeline-execution-ledger.js +250 -0
  47. package/dist/core-runtime/review/review-artifact-utils.js +15 -2
  48. package/dist/core-runtime/review/review-invocation-runner.js +604 -0
  49. package/dist/core-runtime/target-material-kind.js +43 -5
  50. package/dist/mcp/server.js +289 -59
  51. package/dist/mcp/tool-schemas.js +28 -2
  52. package/package.json +4 -2
  53. package/.onto/domains/llm-native-development/competency_qs.md +0 -430
  54. package/.onto/domains/llm-native-development/concepts.md +0 -242
  55. package/.onto/domains/llm-native-development/conciseness_rules.md +0 -163
  56. package/.onto/domains/llm-native-development/dependency_rules.md +0 -216
  57. package/.onto/domains/llm-native-development/domain_scope.md +0 -197
  58. package/.onto/domains/llm-native-development/extension_cases.md +0 -474
  59. package/.onto/domains/llm-native-development/logic_rules.md +0 -123
  60. package/.onto/domains/llm-native-development/prompt_interface.md +0 -49
  61. package/.onto/domains/llm-native-development/structure_spec.md +0 -245
@@ -91,6 +91,16 @@ function readEvidenceRef(value, claimId) {
91
91
  violations,
92
92
  };
93
93
  }
94
+ function isGenericClaimName(name, groupName) {
95
+ const normalized = name.trim().toLowerCase().replace(/[_\s-]+/g, "_");
96
+ const singularGroup = groupName.endsWith("ies")
97
+ ? groupName.slice(0, -3) + "y"
98
+ : groupName.endsWith("s")
99
+ ? groupName.slice(0, -1)
100
+ : groupName;
101
+ const normalizedGroup = singularGroup.toLowerCase().replace(/[_\s-]+/g, "_");
102
+ return new RegExp(`^${normalizedGroup}_?\\d+$`).test(normalized);
103
+ }
94
104
  function readClaim(value, groupName) {
95
105
  const violations = [];
96
106
  if (!isRecord(value)) {
@@ -109,6 +119,24 @@ function readClaim(value, groupName) {
109
119
  message: `${groupName} claim_id is required`,
110
120
  }));
111
121
  }
122
+ const rawName = value.name;
123
+ const name = typeof rawName === "string" && rawName.trim().length > 0
124
+ ? rawName.trim()
125
+ : null;
126
+ if (!name) {
127
+ violations.push(violation({
128
+ code: "claim_name_missing",
129
+ message: `${groupName} name is required`,
130
+ claimId,
131
+ }));
132
+ }
133
+ else if (isGenericClaimName(name, groupName)) {
134
+ violations.push(violation({
135
+ code: "claim_name_generic",
136
+ message: `${groupName} name must be a meaningful user-facing label, not a numbered placeholder`,
137
+ claimId,
138
+ }));
139
+ }
112
140
  const rawStatement = value.statement;
113
141
  const statement = typeof rawStatement === "string" ? rawStatement : "";
114
142
  const rawEvidenceRefs = value.evidence_refs;
@@ -125,6 +153,7 @@ function readClaim(value, groupName) {
125
153
  return {
126
154
  claim: {
127
155
  claim_id: claimId ?? `${groupName}:missing-claim-id`,
156
+ name: name ?? "",
128
157
  statement,
129
158
  evidence_refs: evidenceRefs,
130
159
  },
@@ -0,0 +1,160 @@
1
+ import { isTrustedLedgerUnit } from "../pipeline-execution-ledger.js";
2
+ function normalizeRequestedTargetUnitId(unitId) {
3
+ if (unitId.startsWith("lens:"))
4
+ return unitId.slice("lens:".length);
5
+ if (unitId.startsWith("deliberation:")) {
6
+ return `deliberation-${unitId.slice("deliberation:".length)}`;
7
+ }
8
+ if (unitId.startsWith("issue-artifact:")) {
9
+ return unitId.slice("issue-artifact:".length);
10
+ }
11
+ if (unitId === "controlled-lens-deliberation") {
12
+ return "controlled-deliberation";
13
+ }
14
+ return unitId;
15
+ }
16
+ function lensIdFromUnit(unit) {
17
+ if (unit.unitKind === "lens")
18
+ return unit.unitId;
19
+ if (unit.unitId.startsWith("deliberation-")) {
20
+ return unit.unitId.slice("deliberation-".length) || null;
21
+ }
22
+ return null;
23
+ }
24
+ function toContinuationUnit(unit, dispatchDecision, reason) {
25
+ const lensId = lensIdFromUnit(unit);
26
+ return {
27
+ unitId: unit.unitId,
28
+ unitKind: unit.unitKind,
29
+ ...(lensId !== null ? { lensId } : {}),
30
+ packetPath: unit.packetRef ?? null,
31
+ outputPath: unit.outputRefs[0] ?? null,
32
+ priorStatus: unit.status,
33
+ dispatchDecision,
34
+ reason,
35
+ };
36
+ }
37
+ function trustedUnitIds(ledger) {
38
+ return new Set(ledger.units
39
+ .filter((unit) => isTrustedLedgerUnit(unit))
40
+ .map((unit) => unit.unitId));
41
+ }
42
+ function isFrontierUnit(unit, trustedIds) {
43
+ if (isTrustedLedgerUnit(unit))
44
+ return false;
45
+ return unit.upstreamUnitIds.every((unitId) => trustedIds.has(unitId));
46
+ }
47
+ function reachableDownstreamUnitIds(args) {
48
+ const byId = new Map(args.ledger.units.map((unit) => [unit.unitId, unit]));
49
+ const result = new Set();
50
+ const queue = [...args.frontierUnitIds];
51
+ while (queue.length > 0) {
52
+ const unitId = queue.shift();
53
+ if (!unitId)
54
+ continue;
55
+ const unit = byId.get(unitId);
56
+ if (!unit)
57
+ continue;
58
+ for (const downstreamUnitId of unit.downstreamUnitIds) {
59
+ if (args.frontierUnitIds.has(downstreamUnitId))
60
+ continue;
61
+ if (result.has(downstreamUnitId))
62
+ continue;
63
+ result.add(downstreamUnitId);
64
+ queue.push(downstreamUnitId);
65
+ }
66
+ }
67
+ return result;
68
+ }
69
+ function targetRejectedUnits(args) {
70
+ const byId = new Map(args.ledger.units.map((unit) => [unit.unitId, unit]));
71
+ return args.targetUnits.flatMap((unitId) => {
72
+ const unit = byId.get(unitId);
73
+ if (!unit) {
74
+ return [
75
+ {
76
+ unitId,
77
+ unitKind: "unknown",
78
+ packetPath: null,
79
+ outputPath: null,
80
+ priorStatus: "missing",
81
+ dispatchDecision: "reject",
82
+ reason: "Target unit is not present in the pipeline execution ledger.",
83
+ },
84
+ ];
85
+ }
86
+ if (isTrustedLedgerUnit(unit)) {
87
+ return [
88
+ toContinuationUnit(unit, "reject", "Target unit is already trusted and completed; completed outputs are reuse-only."),
89
+ ];
90
+ }
91
+ if (!args.naturalFrontierUnitIds.has(unitId)) {
92
+ return [
93
+ toContinuationUnit(unit, "reject", "Target unit is not the current continuation frontier; continue from the earliest untrusted unit first."),
94
+ ];
95
+ }
96
+ return [];
97
+ });
98
+ }
99
+ export function buildReviewContinuationPlan(params) {
100
+ const trustedIds = trustedUnitIds(params.ledger);
101
+ const requestedTargets = (params.targetUnits ?? []).map(normalizeRequestedTargetUnitId);
102
+ const naturalFrontier = params.ledger.units.filter((unit) => isFrontierUnit(unit, trustedIds));
103
+ const naturalFrontierUnitIds = new Set(naturalFrontier.map((unit) => unit.unitId));
104
+ const rejectedTargets = targetRejectedUnits({
105
+ ledger: params.ledger,
106
+ targetUnits: requestedTargets,
107
+ naturalFrontierUnitIds,
108
+ });
109
+ const requestedTargetSet = new Set(requestedTargets);
110
+ const missingFrontierTargets = requestedTargetSet.size === 0 || rejectedTargets.length > 0
111
+ ? []
112
+ : naturalFrontier.filter((unit) => !requestedTargetSet.has(unit.unitId));
113
+ const rejectedMissingFrontierTargets = missingFrontierTargets.map((unit) => toContinuationUnit(unit, "reject", "Target units must match the current continuation frontier so no untrusted sibling unit is skipped."));
114
+ const allRejectedTargets = [...rejectedTargets, ...rejectedMissingFrontierTargets];
115
+ const targetFrontier = requestedTargetSet.size === 0
116
+ ? naturalFrontier
117
+ : params.ledger.units.filter((unit) => requestedTargetSet.has(unit.unitId) && !isTrustedLedgerUnit(unit));
118
+ const frontierUnits = allRejectedTargets.length > 0
119
+ ? allRejectedTargets
120
+ : targetFrontier.map((unit) => toContinuationUnit(unit, "run", requestedTargetSet.size === 0
121
+ ? "Earliest untrusted unit whose upstream units are trusted."
122
+ : "Requested untrusted target unit."));
123
+ const frontierUnitIds = new Set(frontierUnits
124
+ .filter((unit) => unit.dispatchDecision === "run")
125
+ .map((unit) => unit.unitId));
126
+ const downstreamIds = reachableDownstreamUnitIds({
127
+ ledger: params.ledger,
128
+ frontierUnitIds,
129
+ });
130
+ const downstreamUnits = params.ledger.units
131
+ .filter((unit) => downstreamIds.has(unit.unitId) && !isTrustedLedgerUnit(unit))
132
+ .map((unit) => toContinuationUnit(unit, "run", "Downstream unit must be recomputed after the continuation frontier."));
133
+ const preservedArtifactRefs = params.ledger.units
134
+ .filter((unit) => isTrustedLedgerUnit(unit))
135
+ .flatMap((unit) => unit.producedArtifactRefs);
136
+ const supersededArtifactRefs = [...frontierUnits, ...downstreamUnits]
137
+ .filter((unit) => unit.dispatchDecision === "run" && unit.outputPath !== null)
138
+ .map((unit) => unit.outputPath)
139
+ .filter((outputPath) => preservedArtifactRefs.includes(outputPath) === false);
140
+ const eligible = allRejectedTargets.length === 0 &&
141
+ (frontierUnits.length > 0 || downstreamUnits.length > 0);
142
+ const ineligibleReason = eligible
143
+ ? null
144
+ : allRejectedTargets.length > 0
145
+ ? "One or more requested target units cannot be continued."
146
+ : "No untrusted continuation frontier remains.";
147
+ return {
148
+ schemaVersion: "1",
149
+ sessionId: params.ledger.sessionId,
150
+ eligible,
151
+ ineligibleReason,
152
+ sourceRefs: params.ledger.sourceRefs,
153
+ validationRefs: params.ledger.sourceRefs,
154
+ unitLedger: params.ledger,
155
+ frontierUnits,
156
+ downstreamUnits,
157
+ preservedArtifactRefs,
158
+ supersededArtifactRefs: [...new Set(supersededArtifactRefs)].sort(),
159
+ };
160
+ }
@@ -0,0 +1,123 @@
1
+ import path from "node:path";
2
+ import { assertPathInsideRoot, realpathIfExists } from "../path-boundary.js";
3
+ async function assertSamePath(args) {
4
+ const expected = path.resolve(args.expected);
5
+ const actual = path.resolve(args.actual);
6
+ if (expected === actual)
7
+ return;
8
+ const realExpected = await realpathIfExists(expected);
9
+ const realActual = await realpathIfExists(actual);
10
+ if (realExpected && realActual && path.resolve(realExpected) === path.resolve(realActual)) {
11
+ return;
12
+ }
13
+ throw new Error(`${args.label} mismatch: expected ${expected}, received ${actual}`);
14
+ }
15
+ async function assertExecutionPlanRefInsideSession(args) {
16
+ const sessionRoot = path.resolve(args.sessionRoot);
17
+ const resolvedRef = path.isAbsolute(args.ref)
18
+ ? path.resolve(args.ref)
19
+ : path.resolve(sessionRoot, args.ref);
20
+ try {
21
+ await assertPathInsideRoot({
22
+ root: sessionRoot,
23
+ candidate: resolvedRef,
24
+ label: args.label,
25
+ });
26
+ }
27
+ catch (error) {
28
+ const message = (error instanceof Error ? error.message : String(error))
29
+ .replace("parent realpath escapes allowed root", "parent realpath escapes the session root")
30
+ .replace("realpath escapes allowed root", "realpath escapes the session root")
31
+ .replace("escapes allowed root", "escapes the session root");
32
+ throw new Error(`Review execution blocked because ${message}`);
33
+ }
34
+ }
35
+ export async function assertReviewExecutionPlanSessionBoundary(args) {
36
+ const { executionPlan, sessionRoot } = args;
37
+ const plannedSessionRoot = path.isAbsolute(executionPlan.session_root)
38
+ ? executionPlan.session_root
39
+ : path.resolve(sessionRoot, executionPlan.session_root);
40
+ await assertSamePath({
41
+ label: "ReviewExecutionPlan.session_root",
42
+ expected: sessionRoot,
43
+ actual: plannedSessionRoot,
44
+ });
45
+ const refs = [
46
+ { label: "interpretation_artifact_path", ref: executionPlan.interpretation_artifact_path },
47
+ { label: "binding_output_path", ref: executionPlan.binding_output_path },
48
+ { label: "session_metadata_path", ref: executionPlan.session_metadata_path },
49
+ { label: "execution_preparation_root", ref: executionPlan.execution_preparation_root },
50
+ { label: "round1_root", ref: executionPlan.round1_root },
51
+ { label: "prompt_packets_root", ref: executionPlan.prompt_packets_root },
52
+ {
53
+ label: "teamlead_deliberation_prompt_packet_path",
54
+ ref: executionPlan.teamlead_deliberation_prompt_packet_path,
55
+ },
56
+ { label: "synthesize_prompt_packet_path", ref: executionPlan.synthesize_prompt_packet_path },
57
+ { label: "actor_invocation_profiles_path", ref: executionPlan.actor_invocation_profiles_path },
58
+ { label: "actor_consumer_bindings_path", ref: executionPlan.actor_consumer_bindings_path },
59
+ { label: "domain_binding_path", ref: executionPlan.domain_binding_path },
60
+ { label: "review_target_profile_path", ref: executionPlan.review_target_profile_path },
61
+ {
62
+ label: "review_value_alignment_criteria_path",
63
+ ref: executionPlan.review_value_alignment_criteria_path,
64
+ },
65
+ { label: "review_context_manifest_path", ref: executionPlan.review_context_manifest_path },
66
+ { label: "synthesis_output_path", ref: executionPlan.synthesis_output_path },
67
+ { label: "finding_ledger_path", ref: executionPlan.finding_ledger_path },
68
+ {
69
+ label: "finding_relation_graph_path",
70
+ ref: executionPlan.finding_relation_graph_path,
71
+ },
72
+ { label: "issue_ledger_path", ref: executionPlan.issue_ledger_path },
73
+ { label: "issue_stance_matrix_path", ref: executionPlan.issue_stance_matrix_path },
74
+ { label: "deliberation_plan_path", ref: executionPlan.deliberation_plan_path },
75
+ { label: "problem_framing_path", ref: executionPlan.problem_framing_path },
76
+ { label: "lens_completion_barrier_path", ref: executionPlan.lens_completion_barrier_path },
77
+ { label: "deliberation_root_path", ref: executionPlan.deliberation_root_path },
78
+ { label: "deliberation_output_path", ref: executionPlan.deliberation_output_path },
79
+ { label: "execution_result_path", ref: executionPlan.execution_result_path },
80
+ { label: "error_log_path", ref: executionPlan.error_log_path },
81
+ { label: "final_output_path", ref: executionPlan.final_output_path },
82
+ { label: "review_record_path", ref: executionPlan.review_record_path },
83
+ ...executionPlan.lens_execution_seats.map((seat) => ({
84
+ label: `lens_execution_seats.${seat.lens_id}.output_path`,
85
+ ref: seat.output_path,
86
+ })),
87
+ ...executionPlan.lens_prompt_packet_seats.flatMap((seat) => [
88
+ {
89
+ label: `lens_prompt_packet_seats.${seat.lens_id}.packet_path`,
90
+ ref: seat.packet_path,
91
+ },
92
+ {
93
+ label: `lens_prompt_packet_seats.${seat.lens_id}.output_path`,
94
+ ref: seat.output_path,
95
+ },
96
+ ]),
97
+ ...executionPlan.issue_artifact_prompt_packet_seats.flatMap((seat) => [
98
+ {
99
+ label: `issue_artifact_prompt_packet_seats.${seat.artifact_id}.packet_path`,
100
+ ref: seat.packet_path,
101
+ },
102
+ {
103
+ label: `issue_artifact_prompt_packet_seats.${seat.artifact_id}.output_path`,
104
+ ref: seat.output_path,
105
+ },
106
+ ]),
107
+ ...executionPlan.lens_deliberation_prompt_packet_seats.flatMap((seat) => [
108
+ {
109
+ label: `lens_deliberation_prompt_packet_seats.${seat.lens_id}.packet_path`,
110
+ ref: seat.packet_path,
111
+ },
112
+ {
113
+ label: `lens_deliberation_prompt_packet_seats.${seat.lens_id}.output_path`,
114
+ ref: seat.output_path,
115
+ },
116
+ ]),
117
+ ];
118
+ for (const { label, ref } of refs) {
119
+ if (!ref)
120
+ continue;
121
+ await assertExecutionPlanRefInsideSession({ sessionRoot, ref, label });
122
+ }
123
+ }
@@ -773,9 +773,14 @@ function goalsForRole(role) {
773
773
  function domainGoalAdditions(domain) {
774
774
  switch (normalizeDomainValue(domain)) {
775
775
  case "software-engineering":
776
- return ["runtime_contract", "test_evidence", "error_path_clarity"];
777
- case "llm-native-development":
778
- return ["context_isolation", "artifact_truth", "fail_loud_behavior"];
776
+ return [
777
+ "runtime_contract",
778
+ "test_evidence",
779
+ "error_path_clarity",
780
+ "context_isolation",
781
+ "artifact_truth",
782
+ "fail_loud_behavior",
783
+ ];
779
784
  default:
780
785
  return [];
781
786
  }
@@ -0,0 +1,250 @@
1
+ import path from "node:path";
2
+ import { PIPELINE_EXECUTION_LEDGER_SCHEMA_VERSION, buildLedgerTrust, buildOutputHashes, fileSha256IfPresent, isTrustedLedgerUnit, normalizeLedgerRefs, } from "../pipeline-execution-ledger.js";
3
+ const PRE_DELIBERATION_ISSUE_ARTIFACT_ORDER = [
4
+ "finding-ledger",
5
+ "finding-relation-graph",
6
+ "issue-ledger",
7
+ "issue-stance-matrix",
8
+ "deliberation-plan",
9
+ ];
10
+ function issueArtifactOutputPath(executionPlan, artifactId) {
11
+ switch (artifactId) {
12
+ case "finding-ledger":
13
+ return executionPlan.finding_ledger_path;
14
+ case "finding-relation-graph":
15
+ return executionPlan.finding_relation_graph_path;
16
+ case "issue-ledger":
17
+ return executionPlan.issue_ledger_path;
18
+ case "issue-stance-matrix":
19
+ return executionPlan.issue_stance_matrix_path;
20
+ case "deliberation-plan":
21
+ return executionPlan.deliberation_plan_path;
22
+ case "problem-framing":
23
+ return executionPlan.problem_framing_path;
24
+ }
25
+ }
26
+ function issueArtifactPacketPath(executionPlan, artifactId) {
27
+ return (executionPlan.issue_artifact_prompt_packet_seats.find((seat) => seat.artifact_id === artifactId)?.packet_path ?? null);
28
+ }
29
+ function allExecutionResults(executionResult) {
30
+ if (!executionResult)
31
+ return [];
32
+ return [
33
+ ...executionResult.lens_execution_results,
34
+ ...(executionResult.issue_artifact_execution_results ?? []),
35
+ ...(executionResult.deliberation_execution_results ?? []),
36
+ ...(executionResult.synthesize_execution_result
37
+ ? [executionResult.synthesize_execution_result]
38
+ : []),
39
+ ];
40
+ }
41
+ function statusFromWorkerUnit(workerUnit) {
42
+ if (workerUnit?.status === "completed")
43
+ return "completed";
44
+ if (workerUnit?.status === "failed")
45
+ return "failed";
46
+ if (workerUnit?.status === "skipped")
47
+ return "skipped";
48
+ return null;
49
+ }
50
+ function plannedReviewUnits(executionPlan) {
51
+ const lensUnitIds = executionPlan.lens_execution_seats.map((seat) => seat.lens_id);
52
+ const units = executionPlan.lens_execution_seats.map((seat) => ({
53
+ unitId: seat.lens_id,
54
+ unitKind: "lens",
55
+ owner: "host_llm",
56
+ packetRef: executionPlan.lens_prompt_packet_seats.find((packetSeat) => packetSeat.lens_id === seat.lens_id)?.packet_path ?? null,
57
+ outputRefs: [seat.output_path],
58
+ upstreamUnitIds: [],
59
+ }));
60
+ for (const [index, artifactId] of PRE_DELIBERATION_ISSUE_ARTIFACT_ORDER.entries()) {
61
+ const previousArtifactId = PRE_DELIBERATION_ISSUE_ARTIFACT_ORDER[index - 1];
62
+ const upstreamUnitIds = index === 0
63
+ ? lensUnitIds
64
+ : previousArtifactId
65
+ ? [previousArtifactId]
66
+ : lensUnitIds;
67
+ units.push({
68
+ unitId: artifactId,
69
+ unitKind: "issue_artifact",
70
+ owner: "host_llm",
71
+ packetRef: issueArtifactPacketPath(executionPlan, artifactId),
72
+ outputRefs: [issueArtifactOutputPath(executionPlan, artifactId)],
73
+ upstreamUnitIds,
74
+ });
75
+ }
76
+ const deliberationPlanUnitId = "deliberation-plan";
77
+ const deliberationUnitIds = executionPlan.lens_deliberation_prompt_packet_seats.map((seat) => `deliberation-${seat.lens_id}`);
78
+ const deliberationInputUnitIds = [deliberationPlanUnitId, ...lensUnitIds];
79
+ for (const seat of executionPlan.lens_deliberation_prompt_packet_seats) {
80
+ units.push({
81
+ unitId: `deliberation-${seat.lens_id}`,
82
+ unitKind: "deliberation",
83
+ owner: "host_llm",
84
+ packetRef: seat.packet_path,
85
+ outputRefs: [seat.output_path],
86
+ upstreamUnitIds: deliberationInputUnitIds,
87
+ });
88
+ }
89
+ units.push({
90
+ unitId: "controlled-deliberation",
91
+ unitKind: "deliberation",
92
+ owner: "host_llm",
93
+ packetRef: executionPlan.teamlead_deliberation_prompt_packet_path,
94
+ outputRefs: [executionPlan.deliberation_output_path],
95
+ upstreamUnitIds: deliberationUnitIds,
96
+ });
97
+ units.push({
98
+ unitId: "problem-framing",
99
+ unitKind: "issue_artifact",
100
+ owner: "host_llm",
101
+ packetRef: issueArtifactPacketPath(executionPlan, "problem-framing"),
102
+ outputRefs: [executionPlan.problem_framing_path],
103
+ upstreamUnitIds: ["controlled-deliberation"],
104
+ });
105
+ units.push({
106
+ unitId: "synthesize",
107
+ unitKind: "synthesize",
108
+ owner: "host_llm",
109
+ packetRef: executionPlan.synthesize_prompt_packet_path,
110
+ outputRefs: [executionPlan.synthesis_output_path],
111
+ upstreamUnitIds: ["controlled-deliberation", "problem-framing"],
112
+ });
113
+ return units;
114
+ }
115
+ function downstreamMap(units) {
116
+ const map = new Map();
117
+ for (const unit of units)
118
+ map.set(unit.unitId, []);
119
+ for (const unit of units) {
120
+ for (const upstreamUnitId of unit.upstreamUnitIds) {
121
+ map.set(upstreamUnitId, [...(map.get(upstreamUnitId) ?? []), unit.unitId]);
122
+ }
123
+ }
124
+ return map;
125
+ }
126
+ function statusFromBarrier(args) {
127
+ const barrier = args.lensCompletionBarrier;
128
+ if (!barrier)
129
+ return null;
130
+ if (barrier.completed_lens_ids.includes(args.unitId))
131
+ return "completed";
132
+ if (barrier.failed_lens_ids.includes(args.unitId))
133
+ return "failed";
134
+ if (barrier.missing_lens_ids.includes(args.unitId))
135
+ return "missing";
136
+ return null;
137
+ }
138
+ function deriveMissingStatus(args) {
139
+ if (!args.hasExecutionResult && !args.hasReviewRunManifest) {
140
+ return args.unit.upstreamUnitIds.length === 0 ? "planned" : "not_reached";
141
+ }
142
+ if (!args.upstreamTrusted)
143
+ return "not_reached";
144
+ return "missing";
145
+ }
146
+ async function buildUnitEntry(args) {
147
+ const packetRef = args.executionResult?.packet_path ??
148
+ args.workerUnit?.packet_path ??
149
+ args.plannedUnit.packetRef;
150
+ const outputRefs = [
151
+ args.executionResult?.output_path ??
152
+ args.workerUnit?.output_path ??
153
+ args.plannedUnit.outputRefs[0],
154
+ ].filter((ref) => typeof ref === "string" && ref.length > 0);
155
+ const outputHashes = await buildOutputHashes(outputRefs);
156
+ const upstreamTrusted = args.plannedUnit.upstreamUnitIds.every((unitId) => args.trustedUnitIds.has(unitId));
157
+ const status = args.executionResult?.status ??
158
+ statusFromWorkerUnit(args.workerUnit) ??
159
+ (args.plannedUnit.unitKind === "lens"
160
+ ? statusFromBarrier({
161
+ unitId: args.plannedUnit.unitId,
162
+ lensCompletionBarrier: args.lensCompletionBarrier,
163
+ })
164
+ : null) ??
165
+ deriveMissingStatus({
166
+ unit: args.plannedUnit,
167
+ hasExecutionResult: args.hasExecutionResult,
168
+ hasReviewRunManifest: args.hasReviewRunManifest,
169
+ upstreamTrusted,
170
+ });
171
+ const lastFailureMessage = args.executionResult?.failure_message ??
172
+ args.workerUnit?.failure_message ??
173
+ null;
174
+ const trust = buildLedgerTrust({
175
+ status,
176
+ outputRefs,
177
+ outputHashes,
178
+ upstreamTrusted,
179
+ lastFailureMessage,
180
+ });
181
+ const packetSha256 = args.workerUnit?.packet_sha256 ?? await fileSha256IfPresent(packetRef);
182
+ const upstreamOutputRefs = args.plannedUnit.upstreamUnitIds.flatMap((unitId) => args.outputRefsByUnitId.get(unitId) ?? []);
183
+ return {
184
+ unitId: args.plannedUnit.unitId,
185
+ unitKind: args.plannedUnit.unitKind,
186
+ owner: args.plannedUnit.owner,
187
+ producedArtifactRefs: outputRefs,
188
+ consumedArtifactRefs: normalizeLedgerRefs([
189
+ packetRef,
190
+ ...upstreamOutputRefs,
191
+ ]),
192
+ ...(packetRef !== null ? { packetRef } : {}),
193
+ ...(packetSha256 !== null ? { packetSha256 } : {}),
194
+ outputRefs,
195
+ outputHashes,
196
+ status,
197
+ trustStatus: trust.trustStatus,
198
+ trustReason: trust.trustReason,
199
+ attemptCount: args.executionResult || args.workerUnit ? 1 : 0,
200
+ lastFailureMessage,
201
+ upstreamUnitIds: args.plannedUnit.upstreamUnitIds,
202
+ downstreamUnitIds: args.downstreamUnitIds,
203
+ };
204
+ }
205
+ export async function buildReviewPipelineExecutionLedger(params) {
206
+ const units = plannedReviewUnits(params.executionPlan);
207
+ const downstreamUnitIds = downstreamMap(units);
208
+ const outputRefsByUnitId = new Map(units.map((unit) => [unit.unitId, unit.outputRefs]));
209
+ const executionResultsByUnitId = new Map(allExecutionResults(params.executionResult).map((result) => [
210
+ result.unit_id,
211
+ result,
212
+ ]));
213
+ const workerUnitsByUnitId = new Map((params.reviewRunManifest?.worker_units ?? [])
214
+ .filter((unit) => typeof unit.unit_id === "string")
215
+ .map((unit) => [unit.unit_id, unit]));
216
+ const trustedUnitIds = new Set();
217
+ const ledgerUnits = [];
218
+ for (const plannedUnit of units) {
219
+ const entry = await buildUnitEntry({
220
+ plannedUnit,
221
+ downstreamUnitIds: downstreamUnitIds.get(plannedUnit.unitId) ?? [],
222
+ outputRefsByUnitId,
223
+ executionResult: executionResultsByUnitId.get(plannedUnit.unitId),
224
+ workerUnit: workerUnitsByUnitId.get(plannedUnit.unitId),
225
+ lensCompletionBarrier: params.lensCompletionBarrier,
226
+ hasExecutionResult: params.executionResult !== null && params.executionResult !== undefined,
227
+ hasReviewRunManifest: params.reviewRunManifest !== null && params.reviewRunManifest !== undefined,
228
+ trustedUnitIds,
229
+ });
230
+ ledgerUnits.push(entry);
231
+ if (isTrustedLedgerUnit(entry))
232
+ trustedUnitIds.add(entry.unitId);
233
+ }
234
+ return {
235
+ schemaVersion: PIPELINE_EXECUTION_LEDGER_SCHEMA_VERSION,
236
+ pipeline: "review",
237
+ sessionId: params.executionPlan.session_id || path.basename(params.sessionRoot),
238
+ sourceRefs: normalizeLedgerRefs([
239
+ params.artifactRefs?.execution_plan,
240
+ params.artifactRefs?.review_run_manifest,
241
+ params.artifactRefs?.execution_result,
242
+ params.artifactRefs?.lens_completion_barrier,
243
+ params.artifactRefs?.review_context_manifest,
244
+ params.artifactRefs?.finding_ledger,
245
+ params.artifactRefs?.issue_ledger,
246
+ ...Object.values(params.reviewRunManifest?.artifact_refs ?? {}),
247
+ ]),
248
+ units: ledgerUnits,
249
+ };
250
+ }
@@ -117,11 +117,24 @@ export function toRelativePath(targetPath, projectRoot) {
117
117
  const normalized = relativePath === "" ? "." : relativePath;
118
118
  return normalized.split(path.sep).join(path.posix.sep);
119
119
  }
120
+ const DOMAIN_ALIAS_TO_CANONICAL = {
121
+ "llm-native-development": "software-engineering",
122
+ "software-development": "software-engineering",
123
+ };
124
+ function stripDomainSigil(domainValue) {
125
+ const trimmed = domainValue.trim();
126
+ return trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
127
+ }
120
128
  export function normalizeDomainValue(domainValue) {
121
- if (["", "-", "@-", "none"].includes(domainValue)) {
129
+ const stripped = stripDomainSigil(domainValue);
130
+ if (["", "-", "none"].includes(stripped)) {
122
131
  return "none";
123
132
  }
124
- return domainValue.startsWith("@") ? domainValue.slice(1) : domainValue;
133
+ return DOMAIN_ALIAS_TO_CANONICAL[stripped] ?? stripped;
134
+ }
135
+ export function isDeprecatedDomainAlias(domainValue) {
136
+ const stripped = stripDomainSigil(domainValue);
137
+ return Object.prototype.hasOwnProperty.call(DOMAIN_ALIAS_TO_CANONICAL, stripped);
125
138
  }
126
139
  export function parseBooleanFlag(optionValue, optionName) {
127
140
  if (typeof optionValue === "boolean") {