scene-capability-engine 3.6.47 → 3.6.48

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.48] - 2026-03-14
11
+
12
+ ### Changed
13
+ - Added `governance.duplicate_detection_scope` to studio spec governance policy with supported values `all`, `non_completed`, and `active_only`.
14
+ - Changed the default duplicate governance scope to `non_completed`, so duplicate detection compares active and stale specs but no longer treats completed historical specs as duplicate noise.
15
+ - Updated studio intake normalization and scene governance reporting to filter duplicate candidate sets by the configured scope before generating duplicate alerts.
16
+ - Synced the new duplicate governance scope into takeover baseline defaults so adopted and upgraded projects inherit the same non-completed duplicate detection behavior by default.
17
+ - Added regression coverage proving completed history specs do not trigger duplicate governance alerts under the new default scope.
18
+
10
19
  ## [3.6.47] - 2026-03-14
11
20
 
12
21
  ### Changed
@@ -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.48 release notes](./v3.6.48.md)
12
13
  - [v3.6.47 release notes](./v3.6.47.md)
13
14
  - [v3.6.46 release notes](./v3.6.46.md)
14
15
  - [v3.6.45 release notes](./v3.6.45.md)
@@ -0,0 +1,19 @@
1
+ # v3.6.48 Release Notes
2
+
3
+ Release date: 2026-03-14
4
+
5
+ ## Highlights
6
+
7
+ - Added `governance.duplicate_detection_scope` to studio spec governance with three supported values: `all`, `non_completed`, and `active_only`.
8
+ - Changed the default duplicate governance scope to `non_completed`, so duplicate checks now compare active and stale specs while excluding completed historical specs from duplicate pair detection.
9
+ - Synced the same default into takeover baseline, so adopted and upgraded projects inherit the lower-noise duplicate governance behavior automatically.
10
+
11
+ ## Validation
12
+
13
+ - `npx jest tests/unit/studio/spec-intake-governor.test.js --runInBand`
14
+ - `npm run prepublishOnly`
15
+
16
+ ## Release Notes
17
+
18
+ - This patch reduces governance noise in repositories with many completed template-style specs, where historical completed work previously flooded duplicate alerts and hid active governance problems.
19
+ - The default keeps duplicate sensitivity on unclosed work (`active` + `stale`) without requiring every upgraded project to hand-tune its own studio intake policy.
@@ -9,6 +9,7 @@
9
9
  ## 历史版本归档
10
10
 
11
11
  - [发布检查清单](../release-checklist.md)
12
+ - [v3.6.48 发布说明](./v3.6.48.md)
12
13
  - [v3.6.47 发布说明](./v3.6.47.md)
13
14
  - [v3.6.46 发布说明](./v3.6.46.md)
14
15
  - [v3.6.45 发布说明](./v3.6.45.md)
@@ -0,0 +1,19 @@
1
+ # v3.6.48 发布说明
2
+
3
+ 发布日期:2026-03-14
4
+
5
+ ## 重点变化
6
+
7
+ - 为 studio spec governance 增加 `governance.duplicate_detection_scope`,支持 `all`、`non_completed`、`active_only` 三种取值。
8
+ - 将默认 duplicate 检测策略调整为 `non_completed`:只比较 `active` 与 `stale` spec,不再把 `completed` 历史 spec 纳入 duplicate 对比。
9
+ - 将同样的默认值同步到 takeover baseline,确保 adopt / upgrade 后的项目自动继承这套降噪后的治理行为。
10
+
11
+ ## 验证
12
+
13
+ - `npx jest tests/unit/studio/spec-intake-governor.test.js --runInBand`
14
+ - `npm run prepublishOnly`
15
+
16
+ ## 发布说明
17
+
18
+ - 这个补丁版主要解决“历史 completed spec 太多时 duplicate 告警淹没真实 active 治理问题”的噪音问题。
19
+ - 新默认值仍保留对未收口 spec 的治理敏感度,但不再让历史归档 spec 持续制造无效 duplicate 告警。
@@ -82,7 +82,8 @@ const DEFAULT_STUDIO_INTAKE_POLICY = Object.freeze({
82
82
  require_auto_on_plan: true,
83
83
  max_active_specs_per_scene: 3,
84
84
  stale_days: 14,
85
- duplicate_similarity_threshold: 0.66
85
+ duplicate_similarity_threshold: 0.66,
86
+ duplicate_detection_scope: 'non_completed'
86
87
  },
87
88
  backfill: {
88
89
  enabled: true,
@@ -132,6 +133,14 @@ function normalizeBoolean(value, fallback = false) {
132
133
  return fallback;
133
134
  }
134
135
 
136
+ function normalizeDuplicateDetectionScope(value, fallback = 'non_completed') {
137
+ const normalized = normalizeText(value).toLowerCase();
138
+ if (['all', 'non_completed', 'active_only'].includes(normalized)) {
139
+ return normalized;
140
+ }
141
+ return fallback;
142
+ }
143
+
135
144
  function normalizeTextList(value = []) {
136
145
  if (!Array.isArray(value)) {
137
146
  return [];
@@ -330,6 +339,10 @@ function normalizeStudioIntakePolicy(raw = {}) {
330
339
  governance.duplicate_similarity_threshold,
331
340
  DEFAULT_STUDIO_INTAKE_POLICY.governance.duplicate_similarity_threshold
332
341
  ))
342
+ ),
343
+ duplicate_detection_scope: normalizeDuplicateDetectionScope(
344
+ governance.duplicate_detection_scope,
345
+ DEFAULT_STUDIO_INTAKE_POLICY.governance.duplicate_detection_scope
333
346
  )
334
347
  },
335
348
  backfill: {
@@ -898,6 +911,10 @@ function buildSceneGovernanceReport(records = [], policy = DEFAULT_STUDIO_INTAKE
898
911
  const governance = policy.governance || DEFAULT_STUDIO_INTAKE_POLICY.governance;
899
912
  const threshold = normalizeNumber(governance.duplicate_similarity_threshold, 0.66);
900
913
  const maxActive = normalizeInteger(governance.max_active_specs_per_scene, 3, 1, 200);
914
+ const duplicateScope = normalizeDuplicateDetectionScope(
915
+ governance.duplicate_detection_scope,
916
+ DEFAULT_STUDIO_INTAKE_POLICY.governance.duplicate_detection_scope
917
+ );
901
918
 
902
919
  const sceneMap = new Map();
903
920
  for (const record of records) {
@@ -918,12 +935,17 @@ function buildSceneGovernanceReport(records = [], policy = DEFAULT_STUDIO_INTAKE
918
935
  const activeSpecs = sortedSpecs.filter((item) => item.lifecycle_state === 'active');
919
936
  const staleSpecs = sortedSpecs.filter((item) => item.lifecycle_state === 'stale');
920
937
  const completedSpecs = sortedSpecs.filter((item) => item.lifecycle_state === 'completed');
938
+ const duplicateCandidateSpecs = duplicateScope === 'active_only'
939
+ ? activeSpecs
940
+ : (duplicateScope === 'non_completed'
941
+ ? sortedSpecs.filter((item) => item.lifecycle_state !== 'completed')
942
+ : sortedSpecs);
921
943
 
922
944
  const duplicates = [];
923
- for (let i = 0; i < sortedSpecs.length; i += 1) {
924
- for (let j = i + 1; j < sortedSpecs.length; j += 1) {
925
- const left = sortedSpecs[i];
926
- const right = sortedSpecs[j];
945
+ for (let i = 0; i < duplicateCandidateSpecs.length; i += 1) {
946
+ for (let j = i + 1; j < duplicateCandidateSpecs.length; j += 1) {
947
+ const left = duplicateCandidateSpecs[i];
948
+ const right = duplicateCandidateSpecs[j];
927
949
  const similarity = computeJaccard(left.tokens, right.tokens);
928
950
  if (similarity >= threshold) {
929
951
  duplicatePairs += 1;
@@ -235,7 +235,8 @@ const STUDIO_INTAKE_POLICY_DEFAULTS = Object.freeze({
235
235
  require_auto_on_plan: true,
236
236
  max_active_specs_per_scene: 3,
237
237
  stale_days: 14,
238
- duplicate_similarity_threshold: 0.66
238
+ duplicate_similarity_threshold: 0.66,
239
+ duplicate_detection_scope: 'non_completed'
239
240
  },
240
241
  backfill: {
241
242
  enabled: true,
@@ -319,7 +320,8 @@ const TAKEOVER_DEFAULTS = Object.freeze({
319
320
  require_auto_on_plan: true,
320
321
  max_active_specs_per_scene: 3,
321
322
  stale_days: 14,
322
- duplicate_similarity_threshold: 0.66
323
+ duplicate_similarity_threshold: 0.66,
324
+ duplicate_detection_scope: 'non_completed'
323
325
  },
324
326
  backfill: {
325
327
  enabled: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scene-capability-engine",
3
- "version": "3.6.47",
3
+ "version": "3.6.48",
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": {