soloforge 1.4.4 → 1.4.6
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/README.md +6 -5
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +50 -12
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/shared/workflow_template.js +1 -1
- package/dist/bin/soloforge.d.ts.map +1 -1
- package/dist/bin/soloforge.js +73 -16
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/backend_implementation_contract.js +1 -1
- package/dist/engine/code_maintainability_observability_contract.js +7 -7
- package/dist/engine/code_maintainability_observability_contract.js.map +1 -1
- package/dist/engine/consumption_trace_store.d.ts +9 -1
- package/dist/engine/consumption_trace_store.d.ts.map +1 -1
- package/dist/engine/consumption_trace_store.js +3 -0
- package/dist/engine/consumption_trace_store.js.map +1 -1
- package/dist/engine/design_artifact_pack.d.ts +2 -0
- package/dist/engine/design_artifact_pack.d.ts.map +1 -1
- package/dist/engine/design_artifact_pack.js +30 -17
- package/dist/engine/design_artifact_pack.js.map +1 -1
- package/dist/engine/design_lifecycle_contract.d.ts +60 -0
- package/dist/engine/design_lifecycle_contract.d.ts.map +1 -0
- package/dist/engine/design_lifecycle_contract.js +499 -0
- package/dist/engine/design_lifecycle_contract.js.map +1 -0
- package/dist/engine/diagnostic_registry.js +2 -2
- package/dist/engine/diagnostic_registry.js.map +1 -1
- package/dist/engine/foundation_scenario_registry.js +2 -2
- package/dist/engine/foundation_scenario_registry.js.map +1 -1
- package/dist/engine/foundation_scenario_runners.js +9 -9
- package/dist/engine/foundation_scenario_runners.js.map +1 -1
- package/dist/engine/historical_issue_mechanization_matrix.js +1 -1
- package/dist/engine/historical_issue_mechanization_matrix.js.map +1 -1
- package/dist/engine/implementation_roadmap_registry.js +2 -2
- package/dist/engine/implementation_roadmap_registry.js.map +1 -1
- package/dist/engine/input_material_extractor.js +1 -1
- package/dist/engine/input_material_extractor.js.map +1 -1
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +38 -15
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/knowledge_asset_consumer.d.ts.map +1 -1
- package/dist/engine/knowledge_asset_consumer.js +21 -13
- package/dist/engine/knowledge_asset_consumer.js.map +1 -1
- package/dist/engine/knowledge_injection_boundary.d.ts +2 -2
- package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -1
- package/dist/engine/knowledge_injection_boundary.js +19 -7
- package/dist/engine/knowledge_injection_boundary.js.map +1 -1
- package/dist/engine/lifecycle_knowledge_contract.d.ts +59 -0
- package/dist/engine/lifecycle_knowledge_contract.d.ts.map +1 -0
- package/dist/engine/lifecycle_knowledge_contract.js +203 -0
- package/dist/engine/lifecycle_knowledge_contract.js.map +1 -0
- package/dist/engine/next_action_planner.d.ts.map +1 -1
- package/dist/engine/next_action_planner.js +142 -37
- package/dist/engine/next_action_planner.js.map +1 -1
- package/dist/engine/observed_consumption.d.ts.map +1 -1
- package/dist/engine/observed_consumption.js +2 -1
- package/dist/engine/observed_consumption.js.map +1 -1
- package/dist/engine/project_knowledge_contract.d.ts +75 -1
- package/dist/engine/project_knowledge_contract.d.ts.map +1 -1
- package/dist/engine/project_knowledge_contract.js +289 -33
- package/dist/engine/project_knowledge_contract.js.map +1 -1
- package/dist/engine/regression_matrix.js +1 -1
- package/dist/engine/regression_matrix.js.map +1 -1
- package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -1
- package/dist/engine/release_issue_scenario_registry.js +15 -12
- package/dist/engine/release_issue_scenario_registry.js.map +1 -1
- package/dist/engine/release_readiness_gate.d.ts.map +1 -1
- package/dist/engine/release_readiness_gate.js +183 -54
- package/dist/engine/release_readiness_gate.js.map +1 -1
- package/dist/engine/stale_current_task_detector.d.ts +1 -1
- package/dist/engine/stale_current_task_detector.js +4 -4
- package/dist/engine/stale_current_task_detector.js.map +1 -1
- package/dist/engine/task_context.d.ts.map +1 -1
- package/dist/engine/task_context.js +2 -0
- package/dist/engine/task_context.js.map +1 -1
- package/dist/engine/traceability.d.ts +2 -2
- package/dist/engine/traceability.d.ts.map +1 -1
- package/dist/engine/traceability.js +86 -16
- package/dist/engine/traceability.js.map +1 -1
- package/dist/engine/workflow_navigation_contract.d.ts +11 -0
- package/dist/engine/workflow_navigation_contract.d.ts.map +1 -1
- package/dist/engine/workspace_resumer.d.ts.map +1 -1
- package/dist/engine/workspace_resumer.js +2 -1
- package/dist/engine/workspace_resumer.js.map +1 -1
- package/dist/knowledge/conflict_detector.d.ts +1 -1
- package/dist/knowledge/conflict_detector.d.ts.map +1 -1
- package/dist/knowledge/conflict_detector.js +88 -2
- package/dist/knowledge/conflict_detector.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/knowledge/acceptance_templates//344/273/243/347/240/201/346/263/250/351/207/212/344/270/216/346/227/245/345/277/227/351/252/214/346/224/266/346/250/241/346/235/277.md +1 -1
- package/templates/knowledge/acceptance_templates//345/216/237/345/236/213/350/257/264/346/230/216/346/250/241/347/211/210.md +6 -6
- package/templates/knowledge/acceptance_templates//351/234/200/346/261/202/345/216/237/345/236/213/350/256/276/350/256/241/345/256/236/347/216/260/350/277/275/350/270/252/347/237/251/351/230/265/346/250/241/347/211/210.md +25 -20
- package/templates/knowledge/procedures//346/272/220/347/240/201/345/216/237/345/236/213/344/272/244/344/273/230/346/265/201/347/250/213.md +8 -5
- package/templates/knowledge/procedures//350/257/246/347/273/206/350/256/276/350/256/241/346/265/201/347/250/213.md +19 -6
- package/templates/knowledge/rules//344/273/243/347/240/201/346/263/250/351/207/212/344/270/216/346/227/245/345/277/227/345/245/221/347/272/246/350/247/204/345/210/231.md +4 -4
- package/templates/knowledge/rules//350/256/276/350/256/241/344/272/247/347/211/251/345/214/205/350/247/204/345/210/231.md +16 -0
|
@@ -1625,7 +1625,7 @@ async function checkWorkflowNavigationBehavior(rootDir, hardFail, _info) {
|
|
|
1625
1625
|
fs.mkdirSync(sfDir, { recursive: true });
|
|
1626
1626
|
fs.writeFileSync(path.join(sfDir, "config.yaml"), [
|
|
1627
1627
|
"schema_version: 1",
|
|
1628
|
-
"name:
|
|
1628
|
+
"name: demo-saas",
|
|
1629
1629
|
"tech_stack:",
|
|
1630
1630
|
" backend:",
|
|
1631
1631
|
" lang: java",
|
|
@@ -1647,8 +1647,8 @@ async function checkWorkflowNavigationBehavior(rootDir, hardFail, _info) {
|
|
|
1647
1647
|
" test: npm test",
|
|
1648
1648
|
" full: npm run build && npm test",
|
|
1649
1649
|
"scope:",
|
|
1650
|
-
" backend:
|
|
1651
|
-
" frontend:
|
|
1650
|
+
" backend: demo-saas-backend",
|
|
1651
|
+
" frontend: demo-saas-frontend",
|
|
1652
1652
|
].join("\n"), "utf-8");
|
|
1653
1653
|
fs.writeFileSync(path.join(sfDir, "config.evidence.json"), JSON.stringify({
|
|
1654
1654
|
schema_version: 2,
|
|
@@ -1763,8 +1763,8 @@ async function checkImplementationContractBehavior(rootDir, hardFail, _info) {
|
|
|
1763
1763
|
hardFail("BACKEND_API_OPENAPI_DRIFT_FALSE_PASS", "problem-67: Markdown API 与 OpenAPI endpoint 漂移未阻断", ["src/engine/backend_implementation_contract.ts"], "problem-67", "契约对齐必须由行为检查证明", "修复 API/OpenAPI 漂移检测");
|
|
1764
1764
|
}
|
|
1765
1765
|
const lombokFindings = backend.reviewBackendImplementationFiles({
|
|
1766
|
-
"src/main/java/com/
|
|
1767
|
-
"src/main/java/com/
|
|
1766
|
+
"src/main/java/com/demoapp/account/entity/Account.java": "import jakarta.persistence.Entity; import lombok.Data; @Entity @Data public class Account { private Long id; }",
|
|
1767
|
+
"src/main/java/com/demoapp/account/dto/AccountCreateRequest.java": "import lombok.Getter; import lombok.Setter; @Getter @Setter public class AccountCreateRequest { private String name; }",
|
|
1768
1768
|
});
|
|
1769
1769
|
const modelContractFindings = lombokFindings.filter((item) => item.category === "model_lombok_contract" && item.severity === "hard_fail");
|
|
1770
1770
|
if (modelContractFindings.length < 2) {
|
|
@@ -2116,6 +2116,28 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
|
|
|
2116
2116
|
!designPackText.includes("auditDesignImplementationTraceability")) {
|
|
2117
2117
|
hardFail("RELEASE_ISSUE_TRACEABILITY_DESIGN_AUDIT_MISSING", "问题七十三未并入设计产物包审计", ["src/engine/design_artifact_pack.ts"], "problem-73", "追踪矩阵不进入 audit-design-artifacts 会导致用户设计阶段无法发现缺口", "把追踪矩阵作为设计产物包权威资产审计");
|
|
2118
2118
|
}
|
|
2119
|
+
const lifecycleContractText = safeRead(path.join(rootDir, "src", "engine", "design_lifecycle_contract.ts")) ?? "";
|
|
2120
|
+
const lifecycleKnowledgeText = safeRead(path.join(rootDir, "src", "engine", "lifecycle_knowledge_contract.ts")) ?? "";
|
|
2121
|
+
if (!lifecycleContractText.includes("detail_design") ||
|
|
2122
|
+
!lifecycleContractText.includes("docs/architecture/02-数据库设计文档.md") ||
|
|
2123
|
+
!lifecycleContractText.includes("docs/architecture/03-API接口规格文档.md") ||
|
|
2124
|
+
!lifecycleContractText.includes("optional_implementation_detail_document") ||
|
|
2125
|
+
!lifecycleContractText.includes("docs/architecture/04-开发切片计划.md") ||
|
|
2126
|
+
!lifecycleContractText.includes("DESIGN_LIFECYCLE_LEGACY_SLICE_PLAN_PATHS") ||
|
|
2127
|
+
!lifecycleContractText.includes("slice_planning") ||
|
|
2128
|
+
!designPackText.includes("getDesignLifecycleArtifactPaths")) {
|
|
2129
|
+
hardFail("RELEASE_ISSUE_DESIGN_LIFECYCLE_CONTRACT_MISSING", "设计、实现、测试、验收生命周期 I/O 合同缺失或未被设计产物包消费", ["src/engine/design_lifecycle_contract.ts", "src/engine/design_artifact_pack.ts"], "problem-62/problem-73", "没有中心合同会导致后续门禁凭空新增输入输出,详细设计又被误判成单文件", "建立中心生命周期合同,并让设计产物包、追踪审计和 hook 消费同一合同");
|
|
2130
|
+
}
|
|
2131
|
+
if (!lifecycleKnowledgeText.includes("evaluateLifecycleKnowledgeDecision") ||
|
|
2132
|
+
!lifecycleKnowledgeText.includes("selectProjectKnowledgeForTaskWithReasons") ||
|
|
2133
|
+
!lifecycleKnowledgeText.includes("auditDesignImplementationTraceability") ||
|
|
2134
|
+
!lifecycleKnowledgeText.includes("assessControlledGenerationChain")) {
|
|
2135
|
+
hardFail("RELEASE_ISSUE_UNIFIED_LIFECYCLE_KNOWLEDGE_CONTRACT_MISSING", "生命周期、项目知识选择和证据消费仍未收口到统一决策合同", ["src/engine/lifecycle_knowledge_contract.ts"], "problem-62/problem-73/project-knowledge-control-plane", "三个并行机制会导致 next/expand/verify/deliver 各自新增局部口径", "建立并强制消费 evaluateLifecycleKnowledgeDecision");
|
|
2136
|
+
}
|
|
2137
|
+
const injectionBoundaryText = safeRead(path.join(rootDir, "src", "engine", "knowledge_injection_boundary.ts")) ?? "";
|
|
2138
|
+
if (injectionBoundaryText.includes("buildTemplateAssetContracts(process.cwd())")) {
|
|
2139
|
+
hardFail("RELEASE_ISSUE_KNOWLEDGE_CONTRACT_CWD_DRIFT", "知识注入边界仍用 process.cwd() 读取模板合同", ["src/engine/knowledge_injection_boundary.ts"], "project-knowledge-consumption", "用户项目、全局安装和测试目录会取错合同根目录", "改为从模块根或显式合同根读取模板合同");
|
|
2140
|
+
}
|
|
2119
2141
|
if (!cliText.includes("cmdAuditDesignArtifacts") ||
|
|
2120
2142
|
!cliText.includes("cmdUpgradeDesignArtifacts") ||
|
|
2121
2143
|
!cliText.includes("currentTask?.design_artifact_pack")) {
|
|
@@ -2149,6 +2171,26 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
|
|
|
2149
2171
|
try {
|
|
2150
2172
|
const workshop = await import(path.join(rootDir, "dist", "engine", "architecture_decision_workshop.js"));
|
|
2151
2173
|
const designPack = await import(path.join(rootDir, "dist", "engine", "design_artifact_pack.js"));
|
|
2174
|
+
const lifecycle = await import(path.join(rootDir, "dist", "engine", "design_lifecycle_contract.js"));
|
|
2175
|
+
const lifecycleFindings = lifecycle.validateDesignLifecycleContract();
|
|
2176
|
+
if (lifecycleFindings.length > 0) {
|
|
2177
|
+
hardFail("RELEASE_ISSUE_DESIGN_LIFECYCLE_CONTRACT_INVALID", `设计生命周期合同不满足不变量: ${lifecycleFindings.map((finding) => finding.code).join(",")}`, ["src/engine/design_lifecycle_contract.ts"], "problem-62/problem-73", "生命周期合同必须明确设计、实现、测试、验收节点的输入输出和门禁", "修复 validateDesignLifecycleContract 报告的不变量缺口");
|
|
2178
|
+
}
|
|
2179
|
+
const detailStage = lifecycle.getDesignLifecycleStageContract("detail_design");
|
|
2180
|
+
const detailRequiredOutputs = detailStage.outputs.filter((artifact) => artifact.required).map((artifact) => artifact.path);
|
|
2181
|
+
if (!detailRequiredOutputs.includes("docs/architecture/02-数据库设计文档.md") ||
|
|
2182
|
+
!detailRequiredOutputs.includes("docs/architecture/03-API接口规格文档.md") ||
|
|
2183
|
+
detailRequiredOutputs.includes("docs/architecture/04-详细设计文档.md")) {
|
|
2184
|
+
hardFail("RELEASE_ISSUE_DETAIL_DESIGN_TOPOLOGY_INVALID", "详细设计阶段输出拓扑错误", ["src/engine/design_lifecycle_contract.ts"], "problem-62/problem-73", "详细设计必需载体是数据库设计和 API 规格,04-详细设计文档只能是可选兼容", "修复 detail_design 生命周期合同");
|
|
2185
|
+
}
|
|
2186
|
+
const lifecyclePaths = lifecycle.getDesignLifecycleArtifactPaths();
|
|
2187
|
+
if (lifecyclePaths.slice_plan !== "docs/architecture/04-开发切片计划.md") {
|
|
2188
|
+
hardFail("RELEASE_ISSUE_SLICE_PLAN_CANONICAL_PATH_INVALID", "开发切片计划仍绑定到固定阶段文件", ["src/engine/design_lifecycle_contract.ts"], "problem-62/problem-73", "切片计划是全项目调度权威资产,不能命名成第一阶段", "将 canonical slice_plan 改为 docs/architecture/04-开发切片计划.md,旧第一阶段文件仅作为 alias");
|
|
2189
|
+
}
|
|
2190
|
+
const packPaths = designPack.defaultDesignArtifactPaths();
|
|
2191
|
+
if (JSON.stringify(lifecyclePaths) !== JSON.stringify(packPaths)) {
|
|
2192
|
+
hardFail("RELEASE_ISSUE_DESIGN_PACK_PATH_DRIFT", "设计产物包路径与生命周期合同漂移", ["src/engine/design_lifecycle_contract.ts", "src/engine/design_artifact_pack.ts"], "problem-62/problem-73", "设计产物包不得独立硬编码另一套输入输出路径", "让 defaultDesignArtifactPaths 从 getDesignLifecycleArtifactPaths 派生");
|
|
2193
|
+
}
|
|
2152
2194
|
const draft = workshop.createArchitectureDecisionWorkshop("release-issue", "new_system");
|
|
2153
2195
|
if (workshop.evaluateArchitectureDecisionWorkshop(draft).allowed) {
|
|
2154
2196
|
hardFail("RELEASE_ISSUE_BEHAVIOR_FALSE_PASS", "问题六十一未确认六域的草稿错误放行", ["src/engine/architecture_decision_workshop.ts"], "problem-61", "必须有负向行为证据", "修复研讨生成门");
|
|
@@ -2173,29 +2215,30 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
|
|
|
2173
2215
|
"# 需求原型设计实现追踪矩阵",
|
|
2174
2216
|
"| 需求 | 原型 | 架构 | 详细设计 | 切片 | 验收 |",
|
|
2175
2217
|
"| --- | --- | --- | --- | --- | --- |",
|
|
2176
|
-
"| REQ-001 | PROTO-001 | ARCH-001 | DD-
|
|
2218
|
+
"| REQ-001 | PROTO-001 | ARCH-001 | DD-T001, DD-A001 | PHASE-001, SLICE-001 | AC-001 |",
|
|
2177
2219
|
].join("\n"));
|
|
2178
|
-
write("docs/architecture/
|
|
2179
|
-
write("docs/architecture/
|
|
2220
|
+
write("docs/architecture/02-数据库设计文档.md", "# 数据库设计\nARCH-001 -> DD-T001");
|
|
2221
|
+
write("docs/architecture/03-API接口规格文档.md", "# API 设计\nARCH-001 -> DD-A001");
|
|
2222
|
+
write("docs/architecture/04-开发切片计划.md", "# 开发切片计划\nPHASE-001\nSLICE-001\n来源 DD-T001, DD-A001\n验收 AC-001");
|
|
2180
2223
|
const bindingFail = traceability.verifyChangedFilesAgainstDesignTraceability(tmp, ["src/main/java/demo/BedService.java"], {
|
|
2181
2224
|
task_id: "trace-gate",
|
|
2182
2225
|
created_at: new Date().toISOString(),
|
|
2183
|
-
intent: "
|
|
2226
|
+
intent: "实现资源管理",
|
|
2184
2227
|
product_profile: "default",
|
|
2185
2228
|
status: "executing",
|
|
2186
2229
|
});
|
|
2187
2230
|
if (bindingFail.passed || !bindingFail.findings.some((f) => f.code === "TRACEABILITY_CODE_BINDING_MISSING")) {
|
|
2188
|
-
hardFail("RELEASE_ISSUE_TRACEABILITY_CODE_BINDING_FALSE_PASS", "问题七十三编码缺少 SLICE/DD/AC 绑定时错误放行", ["src/engine/traceability.ts", "src/adapters/claude_code/tools.ts"], "problem-73", "实现代码必须能追溯到详细设计、切片和验收", "修复 sf_expand/sf_verify 追踪绑定门");
|
|
2231
|
+
hardFail("RELEASE_ISSUE_TRACEABILITY_CODE_BINDING_FALSE_PASS", "问题七十三编码缺少 PHASE/SLICE/DD/AC 绑定时错误放行", ["src/engine/traceability.ts", "src/adapters/claude_code/tools.ts"], "problem-73", "实现代码必须能追溯到详细设计、切片和验收", "修复 sf_expand/sf_verify 追踪绑定门");
|
|
2189
2232
|
}
|
|
2190
2233
|
const bindingPass = traceability.verifyChangedFilesAgainstDesignTraceability(tmp, ["src/main/java/demo/BedService.java"], {
|
|
2191
2234
|
task_id: "trace-gate-ok",
|
|
2192
2235
|
created_at: new Date().toISOString(),
|
|
2193
|
-
intent: "
|
|
2236
|
+
intent: "实现资源管理 PHASE-001 SLICE-001 DD-T001 DD-A001 AC-001",
|
|
2194
2237
|
product_profile: "default",
|
|
2195
2238
|
status: "executing",
|
|
2196
2239
|
});
|
|
2197
2240
|
if (!bindingPass.passed) {
|
|
2198
|
-
hardFail("RELEASE_ISSUE_TRACEABILITY_CODE_BINDING_FALSE_BLOCK", "问题七十三合法 SLICE/DD/AC 绑定被错误阻断", ["src/engine/traceability.ts"], "problem-73", "合法追踪绑定应允许编码验证继续", "修复 traceability binding 校验");
|
|
2241
|
+
hardFail("RELEASE_ISSUE_TRACEABILITY_CODE_BINDING_FALSE_BLOCK", "问题七十三合法 PHASE/SLICE/DD/AC 绑定被错误阻断", ["src/engine/traceability.ts"], "problem-73", "合法追踪绑定应允许编码验证继续", "修复 traceability binding 校验");
|
|
2199
2242
|
}
|
|
2200
2243
|
}
|
|
2201
2244
|
catch (error) {
|
|
@@ -2539,26 +2582,26 @@ async function checkCodeObservabilityBehavior(rootDir, hardFail, _info) {
|
|
|
2539
2582
|
}
|
|
2540
2583
|
// 行为验证: 普通 Spring 后端 Slice 的 CRUD/事务双写无日志无注释也必须被检测。
|
|
2541
2584
|
const smartCareSliceFindings = obs.verifyChangedFilesObservability({
|
|
2542
|
-
changed_files: ["src/main/java/com/
|
|
2585
|
+
changed_files: ["src/main/java/com/demoapp/account/service/impl/AccountServiceImpl.java"],
|
|
2543
2586
|
file_contents: {
|
|
2544
|
-
"src/main/java/com/
|
|
2545
|
-
public class
|
|
2587
|
+
"src/main/java/com/demoapp/account/service/impl/AccountServiceImpl.java": `@Service
|
|
2588
|
+
public class AccountServiceImpl implements AccountService {
|
|
2546
2589
|
@Transactional
|
|
2547
|
-
public
|
|
2548
|
-
|
|
2549
|
-
|
|
2590
|
+
public AccountVO create(AccountCreateRequest request) {
|
|
2591
|
+
Account account = convert(request);
|
|
2592
|
+
accountMapper.insert(account);
|
|
2550
2593
|
SysUser user = buildUser(request);
|
|
2551
2594
|
sysUserMapper.insert(user);
|
|
2552
|
-
return toVO(
|
|
2595
|
+
return toVO(account);
|
|
2553
2596
|
}
|
|
2554
2597
|
@Transactional
|
|
2555
|
-
public void resign(Long
|
|
2556
|
-
|
|
2557
|
-
sysUserMapper.updateAccountStatus(
|
|
2598
|
+
public void resign(Long accountId) {
|
|
2599
|
+
accountMapper.updateStatus(accountId, AccountStatus.RESIGNED);
|
|
2600
|
+
sysUserMapper.updateAccountStatus(accountId, 0);
|
|
2558
2601
|
}
|
|
2559
2602
|
}`,
|
|
2560
2603
|
},
|
|
2561
|
-
intent: "完成 Slice 2
|
|
2604
|
+
intent: "完成 Slice 2 资源目录与账号管理后端实现",
|
|
2562
2605
|
});
|
|
2563
2606
|
const smartCareBlocked = smartCareSliceFindings.some((f) => f.category === "missing_log_business_write" && f.severity === "hard_fail")
|
|
2564
2607
|
&& smartCareSliceFindings.some((f) => f.category === "missing_comment_complex");
|
|
@@ -2566,46 +2609,46 @@ public class StaffServiceImpl implements StaffService {
|
|
|
2566
2609
|
hardFail("CODE_OBSERVABILITY_BACKEND_SLICE_FALSE_PASS", "problem-68: 普通后端 Slice 的 Controller/Service 事务双写和级联规则无日志无注释未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "旧门禁只覆盖支付/安全/迁移,真实 CRUD 后端实现仍可无日志无注释通过", "扩展后端实现文件检测,覆盖 Controller/Service/DTO/Entity");
|
|
2567
2610
|
}
|
|
2568
2611
|
const javaDocAndChineseFindings = obs.verifyChangedFilesObservability({
|
|
2569
|
-
changed_files: ["src/main/java/com/
|
|
2612
|
+
changed_files: ["src/main/java/com/demoapp/account/service/impl/AccountServiceImpl.java"],
|
|
2570
2613
|
file_contents: {
|
|
2571
|
-
"src/main/java/com/
|
|
2572
|
-
public class
|
|
2573
|
-
public
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
logger.info("
|
|
2577
|
-
return toVO(
|
|
2614
|
+
"src/main/java/com/demoapp/account/service/impl/AccountServiceImpl.java": `@Service
|
|
2615
|
+
public class AccountServiceImpl implements AccountService {
|
|
2616
|
+
public AccountVO create(AccountCreateRequest request) {
|
|
2617
|
+
Account account = convert(request);
|
|
2618
|
+
accountMapper.insert(account);
|
|
2619
|
+
logger.info("account created accountId=" + account.getId());
|
|
2620
|
+
return toVO(account);
|
|
2578
2621
|
}
|
|
2579
2622
|
}`,
|
|
2580
2623
|
},
|
|
2581
|
-
intent: "完成 Slice 2
|
|
2624
|
+
intent: "完成 Slice 2 账号管理后端实现",
|
|
2582
2625
|
});
|
|
2583
2626
|
const javaDocAndChineseBlocked = ["missing_class_doc", "missing_method_doc", "missing_important_line_comment", "non_chinese_log"].every((category) => javaDocAndChineseFindings.some((f) => f.category === category && f.severity === "hard_fail"));
|
|
2584
2627
|
if (!javaDocAndChineseBlocked) {
|
|
2585
2628
|
hardFail("CODE_OBSERVABILITY_CHINESE_DOC_CONTRACT_FALSE_PASS", "problem-68: 后端类/方法中文 Javadoc、关键行中文注释或中文日志缺失未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "只检查是否有日志/注释会放过英文日志、无类说明、无方法入参出参说明和关键行业务意图缺失", "扩展 reviewCommentQuality/reviewMissingLogs,强制中文日志、中文注释、类 Javadoc、方法 Javadoc 和关键行注释");
|
|
2586
2629
|
}
|
|
2587
2630
|
const crossStackFindings = obs.verifyChangedFilesObservability({
|
|
2588
|
-
changed_files: ["src/routes/
|
|
2631
|
+
changed_files: ["src/routes/account.route.ts", "app/api/account.py", "src/pages/AccountForm.tsx"],
|
|
2589
2632
|
file_contents: {
|
|
2590
|
-
"src/routes/
|
|
2591
|
-
const
|
|
2592
|
-
await userRepo.create({
|
|
2593
|
-
res.json(
|
|
2633
|
+
"src/routes/account.route.ts": `router.post('/account', async (req, res) => {
|
|
2634
|
+
const account = await accountRepo.create(req.body);
|
|
2635
|
+
await userRepo.create({ accountId: account.id });
|
|
2636
|
+
res.json(account);
|
|
2594
2637
|
});`,
|
|
2595
|
-
"app/api/
|
|
2596
|
-
async def
|
|
2597
|
-
|
|
2598
|
-
await user_repo.create(
|
|
2599
|
-
return
|
|
2600
|
-
"src/pages/
|
|
2638
|
+
"app/api/account.py": `@router.post("/account")
|
|
2639
|
+
async def create_account(payload: AccountCreate):
|
|
2640
|
+
account = await account_repo.create(payload)
|
|
2641
|
+
await user_repo.create(account_id=account.id)
|
|
2642
|
+
return account`,
|
|
2643
|
+
"src/pages/AccountForm.tsx": `export function AccountForm() {
|
|
2601
2644
|
async function handleSubmit(values) {
|
|
2602
|
-
await apiClient.post('/api/
|
|
2645
|
+
await apiClient.post('/api/tenant/users', values);
|
|
2603
2646
|
setStatus('created');
|
|
2604
2647
|
}
|
|
2605
2648
|
return <form onSubmit={handleSubmit}>...</form>;
|
|
2606
2649
|
}`,
|
|
2607
2650
|
},
|
|
2608
|
-
intent: "
|
|
2651
|
+
intent: "实现账号新增前后端接口与表单",
|
|
2609
2652
|
});
|
|
2610
2653
|
const crossStackBlocked = crossStackFindings.filter((f) => f.category === "missing_log_business_write" && f.severity === "hard_fail").length >= 3;
|
|
2611
2654
|
if (!crossStackBlocked) {
|
|
@@ -2763,7 +2806,7 @@ async function checkTemplateAndProjectKnowledgeHygiene(rootDir, hardFail, _info)
|
|
|
2763
2806
|
}
|
|
2764
2807
|
try {
|
|
2765
2808
|
const obs = await import(path.join(rootDir, "dist", "engine", "code_maintainability_observability_contract.js"));
|
|
2766
|
-
const ordinaryApiImplementationTriggers = obs.requiresCodeObservabilityContract?.("
|
|
2809
|
+
const ordinaryApiImplementationTriggers = obs.requiresCodeObservabilityContract?.("实现业务端业务办理列表接口", "code_change") === true;
|
|
2767
2810
|
if (!ordinaryApiImplementationTriggers) {
|
|
2768
2811
|
hardFail("CODE_OBSERVABILITY_BUSINESS_API_NOT_TRIGGERED", "problem-68: 普通业务接口实现未触发代码注释与日志契约,真实项目会绕过问题六十八", ["src/engine/code_maintainability_observability_contract.ts", "src/adapters/claude_code/tools.ts"], "problem-68", "旧行为只覆盖支付/安全等关键词,未覆盖普通 Controller/API/Service 编码", "扩展触发条件并在 sf_expand 聚合返回工作包");
|
|
2769
2812
|
}
|
|
@@ -2776,7 +2819,7 @@ async function checkTemplateAndProjectKnowledgeHygiene(rootDir, hardFail, _info)
|
|
|
2776
2819
|
const goodDir = path.join(tmp, ".soloforge", "knowledge", "rules");
|
|
2777
2820
|
fs.mkdirSync(goodDir, { recursive: true });
|
|
2778
2821
|
fs.writeFileSync(path.join(goodDir, "API响应规则.md"), `---
|
|
2779
|
-
id:
|
|
2822
|
+
id: demo-api-response-rule
|
|
2780
2823
|
asset_kind: hard_rule
|
|
2781
2824
|
routes:
|
|
2782
2825
|
- code_change
|
|
@@ -2795,21 +2838,56 @@ enforcement:
|
|
|
2795
2838
|
必须使用项目统一响应结构,错误码、字段表和 OpenAPI 保持一致。
|
|
2796
2839
|
`, "utf-8");
|
|
2797
2840
|
const projectKnowledge = await import(path.join(rootDir, "dist", "engine", "project_knowledge_contract.js"));
|
|
2841
|
+
const lifecycleKnowledge = await import(path.join(rootDir, "dist", "engine", "lifecycle_knowledge_contract.js"));
|
|
2798
2842
|
const report = projectKnowledge.auditProjectKnowledge(tmp);
|
|
2799
2843
|
if (report.hard_fail_count !== 0 || report.injectable < 1) {
|
|
2800
2844
|
hardFail("PROJECT_KNOWLEDGE_RULE_NOT_CONSUMABLE", "用户项目 .soloforge/knowledge hard rule 未被识别为可消费规则", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "旧链路只同步/索引内置模板,未证明用户项目自定义规则可被承载消费", "修复项目知识合同审计与选择逻辑");
|
|
2801
2845
|
}
|
|
2802
|
-
const selected = projectKnowledge.
|
|
2803
|
-
intent: "
|
|
2846
|
+
const selected = projectKnowledge.selectProjectKnowledgeForTaskWithReasons(report, {
|
|
2847
|
+
intent: "实现业务端 API 接口统一响应",
|
|
2804
2848
|
route: "code_change",
|
|
2805
2849
|
tech_stack: ["spring"],
|
|
2806
2850
|
});
|
|
2807
|
-
if (!selected.some((
|
|
2851
|
+
if (!selected.selected.some((decision) => decision.asset.id === "demo-api-response-rule")) {
|
|
2808
2852
|
hardFail("PROJECT_KNOWLEDGE_RULE_NOT_SELECTED", "用户项目自定义 hard rule 未按意图/路由/技术栈被选中", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "索引存在不等于任务会消费", "补齐 selectProjectKnowledgeForTask 行为和门禁");
|
|
2809
2853
|
}
|
|
2854
|
+
const selection = projectKnowledge.selectProjectKnowledgeForTaskWithReasons(report, {
|
|
2855
|
+
intent: "实现业务端 API 接口统一响应 PHASE-001 SLICE-001 DD-A001 AC-001",
|
|
2856
|
+
route: "code_change",
|
|
2857
|
+
tech_stack: ["spring"],
|
|
2858
|
+
lifecycle_stage: "implementation",
|
|
2859
|
+
changed_files: ["backend/web/src/main/java/com/example/web/tenant/TenantUserController.java"],
|
|
2860
|
+
traceability_ids: ["PHASE-001", "SLICE-001", "DD-A001", "AC-001"],
|
|
2861
|
+
});
|
|
2862
|
+
const selectedDecision = selection.selected.find((decision) => decision.asset.id === "demo-api-response-rule");
|
|
2863
|
+
if (!selectedDecision || !selectedDecision.reason_zh || !Array.isArray(selectedDecision.matched_signals)) {
|
|
2864
|
+
hardFail("PROJECT_KNOWLEDGE_SELECTION_REASON_MISSING", "用户项目规则选择缺少 why selected / matched_signals 结构化解释", ["src/engine/project_knowledge_contract.ts", "src/engine/intent_expander.ts"], "project-knowledge-consumption", "用户不知道为什么规则被选中就无法判断必须确认和修复路径", "让项目知识选择返回 SelectionDecision 而不是裸资产");
|
|
2865
|
+
}
|
|
2866
|
+
const unifiedDecision = lifecycleKnowledge.evaluateLifecycleKnowledgeDecision({
|
|
2867
|
+
projectPath: tmp,
|
|
2868
|
+
consumer: "sf_expand",
|
|
2869
|
+
intent: "实现业务端 API 接口统一响应 PHASE-001 SLICE-001 DD-A001 AC-001",
|
|
2870
|
+
route: "code_change",
|
|
2871
|
+
lifecycle_stage: "implementation",
|
|
2872
|
+
changed_files: ["backend/web/src/main/java/com/example/web/tenant/TenantUserController.java"],
|
|
2873
|
+
verified_files: ["backend/web/src/main/java/com/example/web/tenant/TenantUserController.java"],
|
|
2874
|
+
traceability_ids: ["PHASE-001", "SLICE-001", "DD-A001", "AC-001"],
|
|
2875
|
+
tech_stack: ["spring"],
|
|
2876
|
+
generation_traces: [
|
|
2877
|
+
{ tool_name: "sf_classify", status: "passed", evidence_kind: "result" },
|
|
2878
|
+
{ tool_name: "sf_expand", status: "passed", evidence_kind: "result" },
|
|
2879
|
+
],
|
|
2880
|
+
record_trace: true,
|
|
2881
|
+
});
|
|
2882
|
+
if (unifiedDecision.contract_id !== "lifecycle_knowledge_contract/v1" ||
|
|
2883
|
+
!unifiedDecision.knowledge_selection.selected.some((decision) => decision.asset.id === "demo-api-response-rule") ||
|
|
2884
|
+
!unifiedDecision.authoritative_paths.traceability_matrix ||
|
|
2885
|
+
!Array.isArray(unifiedDecision.recovery_commands)) {
|
|
2886
|
+
hardFail("LIFECYCLE_KNOWLEDGE_DECISION_BUNDLE_INVALID", "统一生命周期知识决策包未同时携带权威路径、SelectionDecision、恢复命令和消费 trace", ["src/engine/lifecycle_knowledge_contract.ts", "src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "next/expand/verify/deliver 如果不消费同一决策包,会再次产生局部口径", "修复 evaluateLifecycleKnowledgeDecision 返回结构和入口消费");
|
|
2887
|
+
}
|
|
2810
2888
|
const expander = await import(path.join(rootDir, "dist", "engine", "intent_expander.js"));
|
|
2811
2889
|
const expandResult = await expander.expand({
|
|
2812
|
-
intent: "
|
|
2890
|
+
intent: "实现业务端 API 接口统一响应",
|
|
2813
2891
|
classification: {
|
|
2814
2892
|
task_type: "feature",
|
|
2815
2893
|
risk: "low",
|
|
@@ -2852,8 +2930,10 @@ enforcement:
|
|
|
2852
2930
|
decision_version: 1,
|
|
2853
2931
|
},
|
|
2854
2932
|
});
|
|
2855
|
-
if (!expandResult.project_knowledge?.selected?.some((asset) => asset.id === "
|
|
2856
|
-
|| !String(expandResult.prompt).includes("## 用户项目规则")
|
|
2933
|
+
if (!expandResult.project_knowledge?.selected?.some((asset) => asset.id === "demo-api-response-rule")
|
|
2934
|
+
|| !String(expandResult.prompt).includes("## 用户项目规则")
|
|
2935
|
+
|| !String(expandResult.prompt).includes("选中原因")
|
|
2936
|
+
|| !expandResult.project_knowledge?.selection_decisions?.some((decision) => decision.id === "demo-api-response-rule" && decision.reason_zh)) {
|
|
2857
2937
|
hardFail("PROJECT_KNOWLEDGE_NOT_IN_EXPAND_MAINPATH", "用户项目规则未进入 sf_expand 真实 prompt 和结构化结果", ["src/engine/intent_expander.ts", "src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "审计/选择通过不等于 MCP 主链路会消费", "将项目规则接入 sf_expand 并补主链路测试");
|
|
2858
2938
|
}
|
|
2859
2939
|
const nextPlanner = await import(path.join(rootDir, "dist", "engine", "next_action_planner.js"));
|
|
@@ -2861,11 +2941,24 @@ enforcement:
|
|
|
2861
2941
|
if (!nextPlan.project_knowledge_context || nextPlan.project_knowledge_context.total < 1) {
|
|
2862
2942
|
hardFail("PROJECT_KNOWLEDGE_NOT_IN_NEXT", "soloforge next 未携带项目知识上下文,用户无法知道下一步会应用哪些项目规则", ["src/engine/next_action_planner.ts", "src/bin/soloforge.ts"], "project-knowledge-consumption", "旧导航只看阶段,不看项目规则", "将项目知识上下文接入 next JSON 和人类输出");
|
|
2863
2943
|
}
|
|
2944
|
+
if (nextPlan.project_knowledge_context?.selected?.length
|
|
2945
|
+
&& !nextPlan.project_knowledge_context.selected.some((item) => item.reason_zh && item.enforcement)) {
|
|
2946
|
+
hardFail("PROJECT_KNOWLEDGE_NEXT_REASON_MISSING", "soloforge next 项目规则上下文缺少选中原因或强制级别", ["src/engine/next_action_planner.ts", "src/bin/soloforge.ts"], "project-knowledge-consumption", "next 只列规则名不能支撑用户确认哪些必须满足", "在 next 中展示 SelectionDecision 的 reason/enforcement/verification");
|
|
2947
|
+
}
|
|
2864
2948
|
const badTmp = fs.mkdtempSync(path.join(os.tmpdir(), "soloforge-project-knowledge-bad-"));
|
|
2865
2949
|
try {
|
|
2866
2950
|
const badDir = path.join(badTmp, ".soloforge", "knowledge", "rules");
|
|
2867
2951
|
fs.mkdirSync(badDir, { recursive: true });
|
|
2868
|
-
fs.writeFileSync(path.join(badDir, "未路由强规则.md"),
|
|
2952
|
+
fs.writeFileSync(path.join(badDir, "未路由强规则.md"), `---
|
|
2953
|
+
id: unrouted-hard-rule
|
|
2954
|
+
asset_kind: hard_rule
|
|
2955
|
+
enforcement:
|
|
2956
|
+
level: hard_rule
|
|
2957
|
+
---
|
|
2958
|
+
# 未路由强规则
|
|
2959
|
+
|
|
2960
|
+
必须使用统一响应。
|
|
2961
|
+
`, "utf-8");
|
|
2869
2962
|
const badReport = projectKnowledge.auditProjectKnowledge(badTmp);
|
|
2870
2963
|
if (badReport.hard_fail_count === 0) {
|
|
2871
2964
|
hardFail("PROJECT_KNOWLEDGE_UNROUTED_RULE_FALSE_PASS", "用户项目 hard rule 缺少 routes/primary_triggers 时错误放行", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "规则文件存在不等于可稳定消费", "对未路由 hard rule fail-closed");
|
|
@@ -2914,6 +3007,42 @@ enforcement:
|
|
|
2914
3007
|
finally {
|
|
2915
3008
|
fs.rmSync(conflictTmp, { recursive: true, force: true });
|
|
2916
3009
|
}
|
|
3010
|
+
const semanticConflictTmp = fs.mkdtempSync(path.join(os.tmpdir(), "soloforge-project-knowledge-semantic-conflict-"));
|
|
3011
|
+
try {
|
|
3012
|
+
const semanticDir = path.join(semanticConflictTmp, ".soloforge", "knowledge", "rules");
|
|
3013
|
+
fs.mkdirSync(semanticDir, { recursive: true });
|
|
3014
|
+
fs.writeFileSync(path.join(semanticDir, "响应ApiResponse.md"), `---
|
|
3015
|
+
id: response-api-response
|
|
3016
|
+
asset_kind: hard_rule
|
|
3017
|
+
routes: [code_change]
|
|
3018
|
+
primary_triggers: [API响应]
|
|
3019
|
+
enforcement:
|
|
3020
|
+
level: hard_rule
|
|
3021
|
+
---
|
|
3022
|
+
# API 响应
|
|
3023
|
+
|
|
3024
|
+
必须使用 ApiResponse。
|
|
3025
|
+
`, "utf-8");
|
|
3026
|
+
fs.writeFileSync(path.join(semanticDir, "响应Result.md"), `---
|
|
3027
|
+
id: response-result
|
|
3028
|
+
asset_kind: hard_rule
|
|
3029
|
+
routes: [code_change]
|
|
3030
|
+
primary_triggers: [接口响应]
|
|
3031
|
+
enforcement:
|
|
3032
|
+
level: hard_rule
|
|
3033
|
+
---
|
|
3034
|
+
# 接口响应
|
|
3035
|
+
|
|
3036
|
+
必须使用 Result。
|
|
3037
|
+
`, "utf-8");
|
|
3038
|
+
const semanticConflictReport = projectKnowledge.auditProjectKnowledge(semanticConflictTmp);
|
|
3039
|
+
if (!semanticConflictReport.assets.some((asset) => asset.findings.some((finding) => finding.code === "PROJECT_KNOWLEDGE_RULE_CONFLICT"))) {
|
|
3040
|
+
hardFail("PROJECT_KNOWLEDGE_SEMANTIC_CONFLICT_FALSE_PASS", "API 响应格式语义冲突依赖手写 conflict_group,未自动进入用户确认", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "项目规则冲突不能要求用户预先正确标注才能发现", "补 API 响应/分页/日志/DB/权限语义冲突检测");
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
finally {
|
|
3044
|
+
fs.rmSync(semanticConflictTmp, { recursive: true, force: true });
|
|
3045
|
+
}
|
|
2917
3046
|
}
|
|
2918
3047
|
catch (e) {
|
|
2919
3048
|
hardFail("PROJECT_KNOWLEDGE_AUDIT_FAILED", `用户项目知识消费行为审计执行失败: ${e.message}`, ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "项目知识消费必须有可执行行为门禁", "修复项目知识合同模块和编译产物");
|