soloforge 1.2.16 → 1.2.17

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.
@@ -0,0 +1,154 @@
1
+ /**
2
+ * RouteDecision 合同验证器 — 验证 route_decision 与 workflow_trace 的一致性。
3
+ *
4
+ * 被 sf_verify、scenario runner、negative tests 共用。
5
+ */
6
+ export function verifyRouteDecisionContract(input) {
7
+ const findings = [];
8
+ const rd = input.route_decision;
9
+ const wt = input.workflow_trace;
10
+ // 1. route_decision must exist
11
+ if (!rd) {
12
+ findings.push({ severity: "hard_fail", rule: "rd-missing", message: "route_decision 不存在,验证无法继续" });
13
+ return findings;
14
+ }
15
+ // 2. workflow_trace must exist when route_decision exists
16
+ if (!wt) {
17
+ findings.push({ severity: "hard_fail", rule: "wt-missing", message: "workflow_trace 不存在,无法验证路由一致性" });
18
+ }
19
+ // 3. workflow_trace.route must match route_decision.route
20
+ if (wt && wt.route !== rd.route) {
21
+ findings.push({
22
+ severity: "hard_fail",
23
+ rule: "wt-route-mismatch",
24
+ message: `workflow_trace.route="${wt.route}" !== route_decision.route="${rd.route}"`,
25
+ });
26
+ }
27
+ // 4. workflow_trace.execution_shape must match route_decision.execution_shape
28
+ if (wt && wt.execution_shape !== rd.execution_shape) {
29
+ findings.push({
30
+ severity: "hard_fail",
31
+ rule: "wt-shape-mismatch",
32
+ message: `workflow_trace.execution_shape="${wt.execution_shape}" !== route_decision.execution_shape="${rd.execution_shape}"`,
33
+ });
34
+ }
35
+ // 5. missing_required_inputs non-empty must block normal verify
36
+ if (rd.missing_required_inputs && rd.missing_required_inputs.length > 0) {
37
+ findings.push({
38
+ severity: "blocked",
39
+ rule: "rd-missing-inputs",
40
+ message: `missing_required_inputs 非空: ${rd.missing_required_inputs.join(", ")}`,
41
+ });
42
+ }
43
+ // 6. input_materials preservation check
44
+ if (rd.input_materials && rd.input_materials.length > 0 && input.expansion_input_materials) {
45
+ const rdKinds = new Set(rd.input_materials.map(m => m.kind));
46
+ const expRefs = input.expansion_input_materials.map(m => m.path_or_ref ?? "").filter(r => r.length > 0);
47
+ // At least one expansion input_material should correspond to an rd input_material
48
+ const rdPaths = rd.input_materials.filter(m => m.path).map(m => m.path);
49
+ if (rdPaths.length > 0 && expRefs.length > 0) {
50
+ const anyPreserved = rdPaths.some(p => expRefs.some(e => e.includes(p)));
51
+ if (!anyPreserved) {
52
+ findings.push({
53
+ severity: "degraded",
54
+ rule: "rd-inputs-lost",
55
+ message: `route_decision input_materials paths [${rdPaths.join(",")}] not preserved in expansion input_materials`,
56
+ });
57
+ }
58
+ }
59
+ }
60
+ // 7. mutation_allowed / scope consistency
61
+ if (rd.scope && rd.scope.read_only !== undefined && rd.scope.read_only !== !rd.mutation_allowed) {
62
+ findings.push({
63
+ severity: "hard_fail",
64
+ rule: "rd-scope-mutation-mismatch",
65
+ message: `scope.read_only=${rd.scope.read_only} inconsistent with mutation_allowed=${rd.mutation_allowed}`,
66
+ });
67
+ }
68
+ // 8. mutation_allowed upgrade detection (source_extraction must be false)
69
+ if (rd.route === "source_extraction" && rd.mutation_allowed === true) {
70
+ findings.push({
71
+ severity: "hard_fail",
72
+ rule: "rd-mutation-upgraded",
73
+ message: "source_extraction route must have mutation_allowed=false, got true (upgrade detected)",
74
+ });
75
+ }
76
+ // 9. output_artifact consistency check
77
+ const rdArtifact = rd.output_artifact;
78
+ const expArtifact = input.expansion_output_artifact;
79
+ if (rdArtifact) {
80
+ if (!expArtifact) {
81
+ findings.push({
82
+ severity: "hard_fail",
83
+ rule: "rd-output-artifact-missing",
84
+ message: `route_decision.output_artifact exists (kind=${rdArtifact.kind ?? "?"}) but expansion output artifact is missing`,
85
+ });
86
+ }
87
+ else {
88
+ if (rdArtifact.kind && expArtifact.kind && rdArtifact.kind !== expArtifact.kind) {
89
+ findings.push({
90
+ severity: "hard_fail",
91
+ rule: "rd-output-artifact-kind-mismatch",
92
+ message: `route_decision.output_artifact.kind="${rdArtifact.kind}" !== expansion output kind="${expArtifact.kind}"`,
93
+ });
94
+ }
95
+ if (rdArtifact.path && expArtifact.path && rdArtifact.path !== expArtifact.path) {
96
+ findings.push({
97
+ severity: "hard_fail",
98
+ rule: "rd-output-artifact-path-mismatch",
99
+ message: `route_decision.output_artifact.path="${rdArtifact.path}" !== expansion output path="${expArtifact.path}"`,
100
+ });
101
+ }
102
+ }
103
+ }
104
+ // 10. constraints preservation check
105
+ // 10a. If expansion_constraints explicitly provided, compare against rd.constraints
106
+ if (rd.constraints && rd.constraints.length > 0 && Array.isArray(input.expansion_constraints)) {
107
+ const expConstraints = input.expansion_constraints;
108
+ if (expConstraints.length === 0) {
109
+ findings.push({
110
+ severity: "hard_fail",
111
+ rule: "rd-constraints-lost",
112
+ message: `route_decision.constraints [${rd.constraints.join(",")}] not preserved in expansion (empty)`,
113
+ });
114
+ }
115
+ else {
116
+ if (rd.route === "source_extraction" && rd.constraints.includes("no_mutation") && !expConstraints.includes("no_mutation")) {
117
+ findings.push({
118
+ severity: "hard_fail",
119
+ rule: "rd-constraint-no-mutation-lost",
120
+ message: "source_extraction no_mutation constraint lost in expansion",
121
+ });
122
+ }
123
+ }
124
+ }
125
+ // 10b. Self-consistency: source_extraction with mutation_allowed=false must have no_mutation constraint
126
+ if (rd.route === "source_extraction" && !rd.mutation_allowed && rd.constraints && !rd.constraints.includes("no_mutation")) {
127
+ findings.push({
128
+ severity: "hard_fail",
129
+ rule: "rd-constraint-no-mutation-missing",
130
+ message: "source_extraction with mutation_allowed=false must have no_mutation constraint",
131
+ });
132
+ }
133
+ // 10c. If rd had constraints but they were completely removed (constraints field is empty/missing when it shouldn't be)
134
+ if (rd.route === "source_extraction" && !rd.mutation_allowed && (!rd.constraints || rd.constraints.length === 0)) {
135
+ findings.push({
136
+ severity: "hard_fail",
137
+ rule: "rd-constraints-empty",
138
+ message: "source_extraction with mutation_allowed=false has empty constraints",
139
+ });
140
+ }
141
+ // 11. input_materials exist but expansion_input_materials missing/empty → blocked
142
+ if (rd.input_materials && rd.input_materials.length > 0) {
143
+ const expInputs = input.expansion_input_materials;
144
+ if (!expInputs || expInputs.length === 0) {
145
+ findings.push({
146
+ severity: "blocked",
147
+ rule: "rd-inputs-no-expansion",
148
+ message: `route_decision has ${rd.input_materials.length} input_materials but expansion_input_materials is empty or missing`,
149
+ });
150
+ }
151
+ }
152
+ return findings;
153
+ }
154
+ //# sourceMappingURL=route_decision_contract_verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route_decision_contract_verifier.js","sourceRoot":"","sources":["../../src/engine/route_decision_contract_verifier.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soloforge",
3
- "version": "1.2.16",
3
+ "version": "1.2.17",
4
4
  "description": "AI-driven development workflow system - one person does the work of a five-person team",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",