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.
- package/.onto/authority/core-lexicon.yaml +12 -0
- package/.onto/domains/software-engineering/competency_qs.md +192 -63
- package/.onto/domains/software-engineering/concepts.md +67 -5
- package/.onto/domains/software-engineering/conciseness_rules.md +22 -2
- package/.onto/domains/software-engineering/dependency_rules.md +78 -8
- package/.onto/domains/software-engineering/domain_scope.md +181 -150
- package/.onto/domains/software-engineering/extension_cases.md +318 -542
- package/.onto/domains/software-engineering/logic_rules.md +75 -3
- package/.onto/domains/software-engineering/problem_framing_profile.md +29 -2
- package/.onto/domains/software-engineering/prompt_interface.md +122 -0
- package/.onto/domains/software-engineering/structure_spec.md +53 -4
- package/.onto/principles/llm-native-development-guideline.md +20 -0
- package/.onto/principles/productization-charter.md +6 -0
- package/.onto/processes/evolve/material-kind-adapter-contract.md +6 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +468 -81
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +177 -0
- package/.onto/processes/reconstruct/source-profile-contract.md +39 -6
- package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +387 -0
- package/.onto/processes/review/binding-contract.md +8 -0
- package/.onto/processes/review/lens-registry.md +16 -0
- package/.onto/processes/review/pre-dispatch-contracts.md +34 -13
- package/.onto/processes/review/productized-live-path.md +3 -1
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +185 -0
- package/.onto/processes/shared/target-material-kind-contract.md +24 -2
- package/.onto/roles/axiology.md +7 -2
- package/AGENTS.md +4 -2
- package/README.md +52 -29
- package/dist/core-api/reconstruct-api.js +92 -5
- package/dist/core-api/review-api.js +1744 -371
- package/dist/core-runtime/cli/mock-review-unit-executor.js +17 -0
- package/dist/core-runtime/cli/render-review-final-output.js +9 -0
- package/dist/core-runtime/cli/review-invoke.js +387 -55
- package/dist/core-runtime/cli/run-review-prompt-execution.js +361 -90
- package/dist/core-runtime/path-boundary.js +58 -0
- package/dist/core-runtime/pipeline-execution-ledger.js +100 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +33 -1
- package/dist/core-runtime/reconstruct/materialize-preparation.js +54 -4
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +342 -0
- package/dist/core-runtime/reconstruct/post-seed-validation.js +630 -0
- package/dist/core-runtime/reconstruct/record.js +105 -1
- package/dist/core-runtime/reconstruct/run.js +1594 -38
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +29 -0
- package/dist/core-runtime/review/continuation-plan.js +160 -0
- package/dist/core-runtime/review/execution-plan-boundary.js +123 -0
- package/dist/core-runtime/review/materializers.js +8 -3
- package/dist/core-runtime/review/pipeline-execution-ledger.js +250 -0
- package/dist/core-runtime/review/review-artifact-utils.js +15 -2
- package/dist/core-runtime/review/review-invocation-runner.js +604 -0
- package/dist/core-runtime/target-material-kind.js +43 -5
- package/dist/mcp/server.js +289 -59
- package/dist/mcp/tool-schemas.js +28 -2
- package/package.json +4 -2
- package/.onto/domains/llm-native-development/competency_qs.md +0 -430
- package/.onto/domains/llm-native-development/concepts.md +0 -242
- package/.onto/domains/llm-native-development/conciseness_rules.md +0 -163
- package/.onto/domains/llm-native-development/dependency_rules.md +0 -216
- package/.onto/domains/llm-native-development/domain_scope.md +0 -197
- package/.onto/domains/llm-native-development/extension_cases.md +0 -474
- package/.onto/domains/llm-native-development/logic_rules.md +0 -123
- package/.onto/domains/llm-native-development/prompt_interface.md +0 -49
- 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 [
|
|
777
|
-
|
|
778
|
-
|
|
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
|
-
|
|
129
|
+
const stripped = stripDomainSigil(domainValue);
|
|
130
|
+
if (["", "-", "none"].includes(stripped)) {
|
|
122
131
|
return "none";
|
|
123
132
|
}
|
|
124
|
-
return
|
|
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") {
|