scene-capability-engine 3.6.56 → 3.6.57

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/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.6.57] - 2026-03-17
11
+
12
+ ### Added
13
+ - Added a read-only `strategy_assessment` advisory to `sce spec gate run --spec <id>` and `sce spec pipeline run --spec <id>` single-Spec output so workflow consumers can see when the current Spec should escalate to `multi-spec-program` or `research-program`.
14
+
15
+ ### Changed
16
+ - Human-readable `spec gate` and `spec pipeline` output now print an explicit strategy advisory for broad or clarification-heavy Specs, without auto-rerouting execution or changing the underlying execution decision itself.
17
+ - Shared project problem projection sync is now idempotent when content does not change, so collaboration governance checks no longer dirty the worktree just by refreshing `generated_at`.
18
+
10
19
  ## [3.6.56] - 2026-03-17
11
20
 
12
21
  ### Added
package/README.md CHANGED
@@ -140,6 +140,7 @@ SCE is opinionated by default.
140
140
 
141
141
  - `studio plan` runs intake and scene/spec governance unless policy explicitly allows bypass.
142
142
  - When business scene/module/page/entity context is missing, SCE must route to clarification first; unknown business scope must not be turned into blanket disable.
143
+ - `spec pipeline` and `spec gate` now carry a read-only strategy advisory for single-Spec runs, so broad or clarification-heavy work is surfaced as `multi-spec-program` / `research-program` instead of being blindly forced deeper into one Spec.
143
144
  - `verify` and `release` enforce problem-closure and related gates when a spec is bound.
144
145
  - Autonomous program execution applies gate evaluation, fallback-chain logic, governance replay, and auto-remediation.
145
146
  - Co-work baseline is enabled by default: initialized/adopted SCE projects provision `.sce/config/multi-agent.json` with `enabled=true`, while the central coordinator stays opt-in.
@@ -227,5 +228,5 @@ MIT. See [LICENSE](LICENSE).
227
228
 
228
229
  ---
229
230
 
230
- **Version**: 3.6.56
231
+ **Version**: 3.6.57
231
232
  **Last Updated**: 2026-03-17
package/README.zh.md CHANGED
@@ -145,6 +145,7 @@ SCE 默认是强治理的。
145
145
 
146
146
  - `studio plan` 默认执行 intake 与 scene/spec 治理,除非策略显式允许绕过
147
147
  - 缺少业务场景/模块/页面/实体上下文时,SCE 必须先进入澄清,而不是把未知业务范围直接变成一刀切禁用
148
+ - 单 spec 的 `spec pipeline` 和 `spec gate` 现在都会附带只读策略建议;当问题已经更适合 `multi-spec-program` / `research-program` 时,SCE 会显式提示,而不是继续把复杂问题盲目压进同一个 spec
148
149
  - 当 spec 绑定时,`verify` 和 `release` 默认执行 problem-closure 等相关门禁
149
150
  - `close-loop-program` 默认带 gate 评估、fallback-chain、governance replay、auto-remediation
150
151
  - co-work 基线默认开启:初始化或接管后的 SCE 项目会落地 `.sce/config/multi-agent.json` 且 `enabled=true`,但中央 coordinator 仍保持按需开启
@@ -232,5 +233,5 @@ MIT,见 [LICENSE](LICENSE)。
232
233
 
233
234
  ---
234
235
 
235
- **版本**:3.6.56
236
+ **版本**:3.6.57
236
237
  **最后更新**:2026-03-17
@@ -97,6 +97,8 @@ Suggested preflight:
97
97
  sce spec strategy assess --goal "broad complex goal" --json
98
98
  ```
99
99
 
100
+ If you are already inside a single Spec flow, `sce spec gate run --spec <spec-id>` and `sce spec pipeline run --spec <spec-id>` now echo the same strategy concern as a non-blocking advisory when one Spec is no longer the right execution container.
101
+
100
102
  # Controller command: drain queue goals with autonomous close-loop-program runtime
101
103
  sce auto close-loop-controller .sce/auto/program-queue.lines \
102
104
  --dequeue-limit 2 \
@@ -101,6 +101,10 @@ Spec session governance:
101
101
  - When multiple active scenes exist, you must pass `--scene` explicitly.
102
102
  - Multi-Spec orchestrate fallback (`--specs ...`) follows the same scene binding and writes per-spec child-session archive records.
103
103
  - `sce spec strategy assess` is read-only and should be used when you are not sure whether the current problem still fits one Spec.
104
+ - `sce spec pipeline run --spec <id> --json` now includes the same read-only `strategy_assessment` block for single-Spec runs.
105
+ - `sce spec gate run --spec <id> --json` now includes a read-only `strategy_assessment` block for single-Spec runs.
106
+ - Human-readable `spec gate` output now prints a strategy advisory when the assessed decision is `multi-spec-program` or `research-program`, but it does not auto-reroute execution.
107
+ - Human-readable `spec pipeline` output now prints the same advisory after stage results for single-Spec runs.
104
108
  - `spec bootstrap` always generates problem-domain, scene-spec, and `problem-contract` artifacts to force domain-first exploration.
105
109
  - `spec gate` now hard-fails when either of the following is missing or structurally incomplete:
106
110
  - `.sce/specs/<spec>/custom/problem-domain-map.md`
@@ -9,6 +9,7 @@ This directory stores release-facing documents:
9
9
  ## Archived Versions
10
10
 
11
11
  - [Release checklist](../release-checklist.md)
12
+ - [v3.6.57 release notes](./v3.6.57.md)
12
13
  - [v3.6.56 release notes](./v3.6.56.md)
13
14
  - [v3.6.55 release notes](./v3.6.55.md)
14
15
  - [v3.6.54 release notes](./v3.6.54.md)
@@ -0,0 +1,19 @@
1
+ # v3.6.57 Release Notes
2
+
3
+ Release date: 2026-03-17
4
+
5
+ ## Highlights
6
+
7
+ - Added a read-only `strategy_assessment` block to single-Spec `sce spec gate run` and `sce spec pipeline run` output.
8
+ - Human-readable gate and pipeline flows now explicitly warn when a problem no longer fits one Spec and should escalate to `multi-spec-program` or `research-program`.
9
+ - Kept the integration conservative: SCE now surfaces the strategy mismatch early, but it does not auto-reroute execution or silently create more Specs.
10
+ - Fixed shared project problem projection sync to be idempotent when payload content is unchanged, preventing release/push governance from dirtying the worktree with timestamp-only rewrites.
11
+
12
+ ## Validation
13
+
14
+ - `npx jest tests/unit/commands/spec-gate.test.js tests/unit/commands/spec-pipeline.test.js --runInBand`
15
+ - `node scripts/release-doc-version-audit.js --fail-on-error`
16
+
17
+ ## Release Notes
18
+
19
+ - This patch closes the last obvious gap in the complex-problem strategy line added in `v3.6.56`. SCE could already assess whether a goal or Spec was too broad for one Spec; now the same judgment is visible inside the normal single-Spec execution path, so teams get an explicit warning before continuing blind decomposition in the wrong container. It also fixes a co-work publication edge case where project-shared problem projection refresh could dirty the repository even when nothing meaningful changed.
@@ -146,6 +146,8 @@ sce spec bootstrap --specs "spec-a,spec-b" --max-parallel 3
146
146
  sce auto close-loop-program "broad complex goal" --program-goals 4 --json
147
147
  ```
148
148
 
149
+ `sce spec gate run --spec <spec-id>` and `sce spec pipeline run --spec <spec-id>` now both carry a read-only strategy advisory for single-Spec runs. If the current Spec is assessed as `multi-spec-program` or `research-program`, SCE surfaces that explicitly instead of silently pushing more decomposition into the same Spec.
150
+
149
151
  The strategic gap currently being formalized is:
150
152
 
151
153
  - how SCE should assess this threshold explicitly
@@ -9,6 +9,7 @@
9
9
  ## 历史版本归档
10
10
 
11
11
  - [发布检查清单](../release-checklist.md)
12
+ - [v3.6.57 发布说明](./v3.6.57.md)
12
13
  - [v3.6.56 发布说明](./v3.6.56.md)
13
14
  - [v3.6.55 发布说明](./v3.6.55.md)
14
15
  - [v3.6.54 发布说明](./v3.6.54.md)
@@ -0,0 +1,19 @@
1
+ # v3.6.57 发布说明
2
+
3
+ 发布日期:2026-03-17
4
+
5
+ ## 重点变化
6
+
7
+ - 为单 spec 的 `sce spec gate run` 和 `sce spec pipeline run` 输出增加只读 `strategy_assessment` 字段。
8
+ - 当问题已经不适合继续塞进一个 spec,而应升级为 `multi-spec-program` 或 `research-program` 时,gate 和 pipeline 的人类可读输出会明确给出提示。
9
+ - 这次集成保持保守:SCE 会尽早暴露策略不匹配,但不会擅自改道执行,也不会静默创建更多 spec。
10
+ - 修复共享问题投影同步的幂等性;当内容未变化时,不再只因 `generated_at` 刷新就把仓库重新写脏,避免 push / 发版治理被时间戳漂移误伤。
11
+
12
+ ## 验证
13
+
14
+ - `npx jest tests/unit/commands/spec-gate.test.js tests/unit/commands/spec-pipeline.test.js --runInBand`
15
+ - `node scripts/release-doc-version-audit.js --fail-on-error`
16
+
17
+ ## 发布说明
18
+
19
+ - 这个补丁版把 `v3.6.56` 刚加上的复杂问题策略评估真正接入到了日常单 spec 主路径。现在 SCE 不只是“能评估”,而是会在正常的 gate / pipeline 过程中显式提醒:当前问题已经不该继续在一个 spec 里盲拆,而应升级为更合适的 program 路径。同时也修掉了 co-work 发布链路上的一个实际阻断点:共享问题投影在内容不变时不应因为时间戳刷新而制造脏工作区。
@@ -15,9 +15,11 @@ const { ResultEmitter } = require('../spec-gate/result-emitter');
15
15
  const { SessionStore } = require('../runtime/session-store');
16
16
  const { resolveSpecSceneBinding } = require('../runtime/scene-session-binding');
17
17
  const { bindMultiSpecSceneSession } = require('../runtime/multi-spec-scene-session');
18
+ const { assessComplexityStrategy } = require('../spec/complexity-strategy');
18
19
 
19
20
  async function runSpecGate(options = {}, dependencies = {}) {
20
21
  const projectPath = dependencies.projectPath || process.cwd();
22
+ const fileSystem = dependencies.fileSystem || fs;
21
23
  const sessionStore = dependencies.sessionStore || new SessionStore(projectPath);
22
24
  const specTargets = parseSpecTargets(options);
23
25
 
@@ -43,7 +45,7 @@ async function runSpecGate(options = {}, dependencies = {}) {
43
45
  })
44
46
  }, {
45
47
  projectPath,
46
- fileSystem: dependencies.fileSystem || fs,
48
+ fileSystem,
47
49
  sessionStore
48
50
  });
49
51
  }
@@ -51,7 +53,7 @@ async function runSpecGate(options = {}, dependencies = {}) {
51
53
  const specId = specTargets[0];
52
54
 
53
55
  const specPath = path.join(projectPath, '.sce', 'specs', specId);
54
- if (!await fs.pathExists(specPath)) {
56
+ if (!await fileSystem.pathExists(specPath)) {
55
57
  throw new Error(`Spec not found: ${specId}`);
56
58
  }
57
59
 
@@ -60,7 +62,7 @@ async function runSpecGate(options = {}, dependencies = {}) {
60
62
  allowNoScene: false
61
63
  }, {
62
64
  projectPath,
63
- fileSystem: dependencies.fileSystem || fs,
65
+ fileSystem,
64
66
  sessionStore
65
67
  });
66
68
  const linked = await sessionStore.startSpecSession({
@@ -83,13 +85,22 @@ async function runSpecGate(options = {}, dependencies = {}) {
83
85
  policy
84
86
  });
85
87
 
86
- const result = await engine.evaluate({ specId });
88
+ const gateResult = await engine.evaluate({ specId });
89
+ const result = {
90
+ ...gateResult,
91
+ strategy_assessment: await buildStrategyAssessment(specId, {
92
+ projectPath,
93
+ fileSystem,
94
+ strategyAssessor: dependencies.strategyAssessor
95
+ })
96
+ };
87
97
  const emitter = dependencies.emitter || new ResultEmitter(projectPath);
88
98
  const emitted = await emitter.emit(result, {
89
99
  json: options.json,
90
100
  out: options.out,
91
101
  silent: options.silent
92
102
  });
103
+ emitStrategyAdvisory(result.strategy_assessment, options);
93
104
 
94
105
  const decisionStatus = result.decision === 'no-go' ? 'failed' : 'completed';
95
106
  await sessionStore.completeSpecSession({
@@ -101,7 +112,8 @@ async function runSpecGate(options = {}, dependencies = {}) {
101
112
  spec: specId,
102
113
  decision: result.decision,
103
114
  score: result.score,
104
- report_path: emitted.outputPath || null
115
+ report_path: emitted.outputPath || null,
116
+ strategy_decision: result.strategy_assessment ? result.strategy_assessment.decision : null
105
117
  }
106
118
  });
107
119
 
@@ -132,6 +144,43 @@ async function runSpecGate(options = {}, dependencies = {}) {
132
144
  }
133
145
  }
134
146
 
147
+ async function buildStrategyAssessment(specId, dependencies = {}) {
148
+ const assess = dependencies.strategyAssessor || assessComplexityStrategy;
149
+ try {
150
+ return await assess({
151
+ spec: specId
152
+ }, {
153
+ projectPath: dependencies.projectPath,
154
+ fileSystem: dependencies.fileSystem
155
+ });
156
+ } catch (error) {
157
+ return {
158
+ decision: 'assessment-unavailable',
159
+ decision_reason: error.message,
160
+ advisory_only: true
161
+ };
162
+ }
163
+ }
164
+
165
+ function emitStrategyAdvisory(strategyAssessment, options = {}) {
166
+ if (!strategyAssessment || options.json || options.silent) {
167
+ return;
168
+ }
169
+
170
+ if (!['multi-spec-program', 'research-program'].includes(strategyAssessment.decision)) {
171
+ return;
172
+ }
173
+
174
+ console.log();
175
+ console.log(chalk.yellow('⚠ Strategy Advisory'));
176
+ console.log(` ${strategyAssessment.decision}: ${strategyAssessment.decision_reason}`);
177
+ if (Array.isArray(strategyAssessment.next_actions)) {
178
+ strategyAssessment.next_actions.forEach(action => {
179
+ console.log(` - ${action}`);
180
+ });
181
+ }
182
+ }
183
+
135
184
  async function generateSpecGatePolicyTemplate(options = {}, dependencies = {}) {
136
185
  const projectPath = dependencies.projectPath || process.cwd();
137
186
  const loader = dependencies.policyLoader || new PolicyLoader(projectPath);
@@ -220,5 +269,7 @@ module.exports = {
220
269
  registerSpecGateCommand,
221
270
  runSpecGate,
222
271
  generateSpecGatePolicyTemplate,
223
- _parseSpecTargets
272
+ _parseSpecTargets,
273
+ buildStrategyAssessment,
274
+ emitStrategyAdvisory
224
275
  };
@@ -13,9 +13,11 @@ const { createDefaultStageAdapters } = require('../spec/pipeline/stage-adapters'
13
13
  const { SessionStore } = require('../runtime/session-store');
14
14
  const { resolveSpecSceneBinding } = require('../runtime/scene-session-binding');
15
15
  const { bindMultiSpecSceneSession } = require('../runtime/multi-spec-scene-session');
16
+ const { buildStrategyAssessment, emitStrategyAdvisory } = require('./spec-gate');
16
17
 
17
18
  async function runSpecPipeline(options = {}, dependencies = {}) {
18
19
  const projectPath = dependencies.projectPath || process.cwd();
20
+ const fileSystem = dependencies.fileSystem || fs;
19
21
  const sessionStore = dependencies.sessionStore || new SessionStore(projectPath);
20
22
  const specTargets = parseSpecTargets(options);
21
23
  if (specTargets.length === 0) {
@@ -40,7 +42,7 @@ async function runSpecPipeline(options = {}, dependencies = {}) {
40
42
  })
41
43
  }, {
42
44
  projectPath,
43
- fileSystem: dependencies.fileSystem || fs,
45
+ fileSystem,
44
46
  sessionStore
45
47
  });
46
48
  }
@@ -48,7 +50,7 @@ async function runSpecPipeline(options = {}, dependencies = {}) {
48
50
  const specId = specTargets[0];
49
51
 
50
52
  const specPath = path.join(projectPath, '.sce', 'specs', specId);
51
- if (!await fs.pathExists(specPath)) {
53
+ if (!await fileSystem.pathExists(specPath)) {
52
54
  throw new Error(`Spec not found: ${specId}`);
53
55
  }
54
56
 
@@ -57,7 +59,7 @@ async function runSpecPipeline(options = {}, dependencies = {}) {
57
59
  allowNoScene: false
58
60
  }, {
59
61
  projectPath,
60
- fileSystem: dependencies.fileSystem || fs,
62
+ fileSystem,
61
63
  sessionStore
62
64
  });
63
65
 
@@ -130,6 +132,11 @@ async function runSpecPipeline(options = {}, dependencies = {}) {
130
132
  status: execution.status,
131
133
  stage_results: execution.stageResults,
132
134
  failure: execution.failure,
135
+ strategy_assessment: await buildStrategyAssessment(specId, {
136
+ projectPath,
137
+ fileSystem,
138
+ strategyAssessor: dependencies.strategyAssessor
139
+ }),
133
140
  next_actions: buildNextActions(execution),
134
141
  state_file: path.relative(projectPath, stateStore.getRunPath(specId, state.run_id)),
135
142
  scene_session: sceneBinding
@@ -156,7 +163,8 @@ async function runSpecPipeline(options = {}, dependencies = {}) {
156
163
  spec: specId,
157
164
  run_id: state.run_id,
158
165
  pipeline_status: execution.status,
159
- failure: execution.failure || null
166
+ failure: execution.failure || null,
167
+ strategy_decision: result.strategy_assessment ? result.strategy_assessment.decision : null
160
168
  }
161
169
  });
162
170
  }
@@ -174,6 +182,7 @@ async function runSpecPipeline(options = {}, dependencies = {}) {
174
182
  console.log(JSON.stringify(result, null, 2));
175
183
  } else {
176
184
  printResult(result);
185
+ emitStrategyAdvisory(result.strategy_assessment, options);
177
186
  }
178
187
 
179
188
  return result;
@@ -82,6 +82,31 @@ function toRelativePosix(projectPath, absolutePath) {
82
82
  return path.relative(projectPath, absolutePath).replace(/\\/g, '/');
83
83
  }
84
84
 
85
+ function sortKeysDeep(value) {
86
+ if (Array.isArray(value)) {
87
+ return value.map((item) => sortKeysDeep(item));
88
+ }
89
+ if (!value || typeof value !== 'object') {
90
+ return value;
91
+ }
92
+ const sorted = {};
93
+ Object.keys(value).sort().forEach((key) => {
94
+ sorted[key] = sortKeysDeep(value[key]);
95
+ });
96
+ return sorted;
97
+ }
98
+
99
+ function toComparableProjection(payload) {
100
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
101
+ return null;
102
+ }
103
+ const clone = {
104
+ ...payload
105
+ };
106
+ delete clone.generated_at;
107
+ return sortKeysDeep(clone);
108
+ }
109
+
85
110
  async function buildProjectSharedProblemProjection(projectPath = process.cwd(), options = {}, dependencies = {}) {
86
111
  const fileSystem = dependencies.fileSystem || fs;
87
112
  const studioIntakePolicy = dependencies.studioIntakePolicy || await loadStudioIntakePolicy(projectPath, fileSystem);
@@ -212,6 +237,24 @@ async function syncProjectSharedProblemProjection(projectPath = process.cwd(), o
212
237
  ...dependencies,
213
238
  problemClosurePolicyBundle: closurePolicy
214
239
  });
240
+ const existing = await readJsonSafe(absolutePath, fileSystem);
241
+ const existingComparable = toComparableProjection(existing);
242
+ const nextComparable = toComparableProjection(payload);
243
+
244
+ if (
245
+ existingComparable
246
+ && nextComparable
247
+ && JSON.stringify(existingComparable) === JSON.stringify(nextComparable)
248
+ ) {
249
+ return {
250
+ mode: 'project-problem-projection-sync',
251
+ enabled: true,
252
+ file: absolutePath,
253
+ scope: projectionConfig.scope,
254
+ total_entries: Number(payload.summary.total_entries || payload.entries.length || 0),
255
+ refreshed: false
256
+ };
257
+ }
215
258
 
216
259
  await fileSystem.ensureDir(path.dirname(absolutePath));
217
260
  await fileSystem.writeJson(absolutePath, payload, { spaces: 2 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.6.56",
3
+ "version": "3.6.57",
4
4
  "description": "SCE (Scene Capability Engine) - A CLI tool and npm package for spec-driven development with AI coding assistants.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -243,6 +243,6 @@ A Spec is a complete feature definition with three parts:
243
243
  ---
244
244
 
245
245
  **Project Type**: Spec-driven development
246
- **sce Version**: 3.6.56
246
+ **sce Version**: 3.6.57
247
247
  **Last Updated**: 2026-03-17
248
248
  **Purpose**: Guide AI tools to work effectively with this project