scene-capability-engine 3.6.46 → 3.6.47
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 +11 -0
- package/README.md +1 -0
- package/README.zh.md +1 -0
- package/docs/agent-runtime/symbol-evidence.schema.json +1 -1
- package/docs/command-reference.md +8 -0
- package/docs/interactive-customization/dialogue-governance-policy-baseline.json +4 -1
- package/docs/interactive-customization/embedded-assistant-authorization-dialogue-rules.md +5 -0
- package/docs/releases/README.md +1 -0
- package/docs/releases/v3.6.47.md +23 -0
- package/docs/sce-business-mode-map.md +2 -1
- package/docs/sce-capability-matrix-e2e-example.md +2 -1
- package/docs/security-governance-default-baseline.md +2 -0
- package/docs/starter-kit/README.md +3 -0
- package/docs/zh/releases/README.md +1 -0
- package/docs/zh/releases/v3.6.47.md +23 -0
- package/lib/workspace/takeover-baseline.js +293 -1
- package/package.json +4 -2
- package/scripts/clarification-first-audit.js +322 -0
- package/scripts/interactive-dialogue-governance.js +37 -6
- package/scripts/symbol-evidence-locate.js +7 -3
- package/template/.sce/README.md +1 -0
- package/template/.sce/steering/CORE_PRINCIPLES.md +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.47] - 2026-03-14
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Promoted "clarification before disable" to a global SCE baseline rule: missing business scene/module/page/entity context now defaults to clarification in builtin interactive governance, is written into steering/template core principles, and is documented as mandatory for all SCE-integrated projects with no exceptions.
|
|
14
|
+
- Added `clarification-first-audit` as a release/audit guard so core scripts, policy/docs, starter/template baselines, and legacy fallback phrases are continuously checked for regression.
|
|
15
|
+
- Wired `clarification-first-audit` into `test.yml`, `release.yml`, and `steering-hygiene.yml` so CI, tag releases, and scheduled hygiene runs all enforce the clarification-first baseline.
|
|
16
|
+
- Extended takeover baseline auto-alignment so older adopted projects also repair missing clarification-first `CORE_PRINCIPLES` content during best-effort startup/default alignment.
|
|
17
|
+
- Added CLI integration coverage for `sce adopt`, `sce upgrade`, and startup takeover auto-alignment so clarification-first baseline propagation is verified end-to-end on real project fixtures.
|
|
18
|
+
- Extended takeover baseline to auto-create `.sce/config/errorbook-registry.json` and to inventory project-defined mistake-book/postmortem style artifacts so SCE takeover converges them into the canonical `errorbook` flow instead of letting parallel mechanisms coexist.
|
|
19
|
+
- Added three more global core principles to the steering baseline: forbid blind fixes without problem evidence, require evaluation before any steering entry is added/removed/rewritten, and default frontend/backend mismatch fixes to align the frontend to the existing backend API contract unless an interface change is explicitly requested.
|
|
20
|
+
|
|
10
21
|
## [3.6.46] - 2026-03-13
|
|
11
22
|
|
|
12
23
|
### Added
|
package/README.md
CHANGED
|
@@ -139,6 +139,7 @@ sce auth status --json
|
|
|
139
139
|
SCE is opinionated by default.
|
|
140
140
|
|
|
141
141
|
- `studio plan` runs intake and scene/spec governance unless policy explicitly allows bypass.
|
|
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.
|
|
142
143
|
- `verify` and `release` enforce problem-closure and related gates when a spec is bound.
|
|
143
144
|
- Autonomous program execution applies gate evaluation, fallback-chain logic, governance replay, and auto-remediation.
|
|
144
145
|
- State persistence prefers SQLite, not ad hoc local caches.
|
package/README.zh.md
CHANGED
|
@@ -144,6 +144,7 @@ sce auth status --json
|
|
|
144
144
|
SCE 默认是强治理的。
|
|
145
145
|
|
|
146
146
|
- `studio plan` 默认执行 intake 与 scene/spec 治理,除非策略显式允许绕过
|
|
147
|
+
- 缺少业务场景/模块/页面/实体上下文时,SCE 必须先进入澄清,而不是把未知业务范围直接变成一刀切禁用
|
|
147
148
|
- 当 spec 绑定时,`verify` 和 `release` 默认执行 problem-closure 等相关门禁
|
|
148
149
|
- `close-loop-program` 默认带 gate 评估、fallback-chain、governance replay、auto-remediation
|
|
149
150
|
- 状态持久化默认优先走 SQLite,而不是零散本地缓存
|
|
@@ -366,6 +366,8 @@ sce workspace takeover-apply --json
|
|
|
366
366
|
# until manual migration is completed.
|
|
367
367
|
# For adopted projects, startup auto-runs takeover baseline alignment
|
|
368
368
|
# before command execution (best effort, non-blocking).
|
|
369
|
+
# Takeover alignment now also repairs missing clarification-first
|
|
370
|
+
# CORE_PRINCIPLES baseline when older adopted projects drift.
|
|
369
371
|
|
|
370
372
|
# Legacy commands (still supported)
|
|
371
373
|
sce workspace sync
|
|
@@ -1806,8 +1808,14 @@ Interactive dialogue governance helper (script-level communication-rule gate):
|
|
|
1806
1808
|
- Default policy: `docs/interactive-customization/dialogue-governance-policy-baseline.json` (fallback builtin policy when missing)
|
|
1807
1809
|
- Default authorization dialogue policy: `docs/interactive-customization/authorization-dialogue-policy-baseline.json`
|
|
1808
1810
|
- Default profile: `business-user` (use `system-maintainer` for maintenance/operator conversations)
|
|
1811
|
+
- Missing business scene/module/page/entity context defaults to `clarify`; unknown scope must not be converted into blanket disable fallback.
|
|
1809
1812
|
- `--fail-on-deny` exits with code `2` to block unsafe requests in CI/automation.
|
|
1810
1813
|
|
|
1814
|
+
Clarification-first baseline audit helper:
|
|
1815
|
+
- `node scripts/clarification-first-audit.js [--project-path <path>] [--out <path>] [--fail-on-violation] [--json]`: verify that SCE global clarification-first baselines are present across core scripts, policy/docs, starter/template assets, and that legacy blanket-disable phrases do not reappear in tracked source/docs.
|
|
1816
|
+
- Default behavior: audit current project root.
|
|
1817
|
+
- `--fail-on-violation` exits with code `2` when required clarification-first baselines drift or prohibited legacy phrases are detected.
|
|
1818
|
+
|
|
1811
1819
|
Interactive change-plan generator helper (script-level stage-B planning bridge):
|
|
1812
1820
|
- `node scripts/interactive-plan-build.js --intent <path> [--context <path>] [--execution-mode <suggestion|apply>] [--out-plan <path>] [--out-markdown <path>] [--json]`: generate structured `Change_Plan` from `Change_Intent`, including action candidates, risk level, verification checks, rollback plan, approval status, and gate hint command.
|
|
1813
1821
|
- Default outputs:
|
|
@@ -41,11 +41,13 @@
|
|
|
41
41
|
"Always restate objective, scope, and expected impact before recommendations.",
|
|
42
42
|
"When risk or permission is involved, explicitly list required approvals and authorization.",
|
|
43
43
|
"If requirement is ambiguous, ask at most two focused clarification questions.",
|
|
44
|
+
"If business scene, module, page, entity, or constraints are missing, clarify and narrow scope before using any fallback restriction; do not replace understanding with blanket disable.",
|
|
44
45
|
"Never propose credential export, approval bypass, or secret leakage."
|
|
45
46
|
],
|
|
46
47
|
"clarification_templates": [
|
|
47
48
|
"What business metric should improve first (speed, accuracy, cost, compliance)?",
|
|
48
|
-
"Which module/page should be changed first, and what must remain unchanged?"
|
|
49
|
+
"Which module/page should be changed first, and what must remain unchanged?",
|
|
50
|
+
"Which entity or business rule is affected, and what constraint must stay intact?"
|
|
49
51
|
],
|
|
50
52
|
"profiles": {
|
|
51
53
|
"business-user": {
|
|
@@ -75,6 +77,7 @@
|
|
|
75
77
|
],
|
|
76
78
|
"response_rules": [
|
|
77
79
|
"For maintenance requests, require change ticket, rollback plan, and approval role before execution.",
|
|
80
|
+
"When business context is incomplete, ask for the affected module/page/entity before considering deny or write restrictions.",
|
|
78
81
|
"If request targets production, require staged validation evidence first."
|
|
79
82
|
],
|
|
80
83
|
"clarification_templates": [
|
|
@@ -31,6 +31,7 @@ This guide defines mandatory conversation and authorization behavior for an embe
|
|
|
31
31
|
3. Confirmation before mutation:
|
|
32
32
|
- For `apply`, assistant must ask a final explicit confirmation.
|
|
33
33
|
- Confirmation text must include impact summary and rollback availability.
|
|
34
|
+
- Missing business scene/context must trigger clarification first; it must not be treated as a reason to blanket-disable the request.
|
|
34
35
|
|
|
35
36
|
## 4. Step-Up Authorization Rules
|
|
36
37
|
|
|
@@ -49,6 +50,10 @@ This guide defines mandatory conversation and authorization behavior for an embe
|
|
|
49
50
|
- reject execution,
|
|
50
51
|
- explain the blocked policy reason in plain language,
|
|
51
52
|
- provide at least one safe alternative (`suggestion`, ticket, or scope reduction).
|
|
53
|
+
- If business context or symbol evidence is incomplete, assistant must:
|
|
54
|
+
- ask for missing `module/page/entity/business constraint` details,
|
|
55
|
+
- reduce scope to a verifiable change candidate,
|
|
56
|
+
- avoid using fallback as a blanket disable substitute before context is understood.
|
|
52
57
|
- If environment is rate-limited or unstable (`429`/timeouts), assistant must:
|
|
53
58
|
- avoid aggressive retries,
|
|
54
59
|
- switch to phased queue execution guidance,
|
package/docs/releases/README.md
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.47 release notes](./v3.6.47.md)
|
|
12
13
|
- [v3.6.46 release notes](./v3.6.46.md)
|
|
13
14
|
- [v3.6.45 release notes](./v3.6.45.md)
|
|
14
15
|
- [v3.6.44 release notes](./v3.6.44.md)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# v3.6.47 Release Notes
|
|
2
|
+
|
|
3
|
+
Release date: 2026-03-14
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Promoted clarification-first into an SCE-wide baseline: when business scene, module, page, entity, or constraints are unclear, the assistant must narrow scope first instead of converting uncertainty into blanket disable.
|
|
8
|
+
- Extended takeover baseline alignment so adopted and upgraded projects automatically repair missing core principles, auto-seed `.sce/config/errorbook-registry.json`, and inventory project-defined postmortem or mistake-book style mechanisms for convergence into `.sce/errorbook`.
|
|
9
|
+
- Added three more global steering baselines: no blind fixes without problem evidence, no arbitrary steering entry add/remove without evaluation, and frontend/backend mismatch fixes must default to the existing backend API contract unless an interface change is explicitly requested.
|
|
10
|
+
|
|
11
|
+
## Validation
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/workspace/takeover-baseline.test.js --runInBand`
|
|
14
|
+
- `npx jest tests/integration/adopt-upgrade-clarification-first.integration.test.js --runInBand`
|
|
15
|
+
- `npx jest tests/integration/takeover-baseline-cli.integration.test.js --runInBand`
|
|
16
|
+
- `npm run audit:steering`
|
|
17
|
+
- `npm run gate:errorbook-registry-health`
|
|
18
|
+
- `npm run prepublishOnly`
|
|
19
|
+
|
|
20
|
+
## Release Notes
|
|
21
|
+
|
|
22
|
+
- This patch release formalizes the steering and takeover rules discussed during recent SCE hardening work, so they are no longer implicit operator expectations but enforced project baselines.
|
|
23
|
+
- Existing SCE-integrated projects now inherit these rules automatically through startup takeover alignment, `sce adopt`, and `sce upgrade`, which prevents drift between newly adopted projects and older onboarded repositories.
|
|
@@ -34,6 +34,8 @@ After SCE integration is enabled:
|
|
|
34
34
|
5. `gated execution`: runtime policy + authorization tier + approval gate.
|
|
35
35
|
6. `execution + audit`: execute or block, then emit summary and evidence.
|
|
36
36
|
|
|
37
|
+
If business scene or symbol evidence is incomplete, route to scope clarification first instead of using a blanket fallback disable.
|
|
38
|
+
|
|
37
39
|
## 5. Mode Playbooks
|
|
38
40
|
|
|
39
41
|
### 5.1 user-mode (business usage UI)
|
|
@@ -100,4 +102,3 @@ See also: `docs/security-governance-default-baseline.md`
|
|
|
100
102
|
3. Enable required gate artifacts and audit logs.
|
|
101
103
|
4. Run weekly governance and release gates.
|
|
102
104
|
5. Keep capability matrix and ontology mapping updated per release.
|
|
103
|
-
|
|
@@ -27,7 +27,8 @@ node scripts/symbol-evidence-locate.js \
|
|
|
27
27
|
|
|
28
28
|
Expected:
|
|
29
29
|
- reliable evidence => `fallback_action=allow_write`
|
|
30
|
-
- no reliable evidence => `fallback_action=
|
|
30
|
+
- no reliable evidence => `fallback_action=clarify_business_scope` and exit code `2`
|
|
31
|
+
- assistant must narrow module/page/entity and business constraints before deciding whether writes should proceed
|
|
31
32
|
|
|
32
33
|
## 3) Failure Attribution and Bounded Repair
|
|
33
34
|
|
|
@@ -5,6 +5,8 @@ This baseline is the default operating policy for SCE-driven delivery, including
|
|
|
5
5
|
## 1. Context and Data Safety
|
|
6
6
|
|
|
7
7
|
- Enforce strict context contract validation (`--context-contract`, strict mode on).
|
|
8
|
+
- Missing business scene/module/page/entity context must route to clarification first; unknown scope is never a valid reason for blanket disable.
|
|
9
|
+
- This clarification-first rule applies to every SCE-integrated project and surface with no project-specific exception.
|
|
8
10
|
- Block forbidden keys (for example secrets/private keys) from UI/provider payloads.
|
|
9
11
|
- Keep payload masking enabled for business data and identity fields.
|
|
10
12
|
- Reject context payloads that exceed size budget or schema bounds.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This starter kit is the default baseline for onboarding an external project (including Moqui-based solutions) into SCE without project-specific flags.
|
|
4
4
|
|
|
5
|
+
It also inherits SCE's clarification-first rule: if business scene/module/page/entity context is missing, the assistant must narrow scope before any deny/disable fallback. This baseline applies to every onboarded project with no project-specific exception.
|
|
6
|
+
|
|
5
7
|
## Included Assets
|
|
6
8
|
|
|
7
9
|
- `handoff-manifest.starter.json`: minimal manifest contract that works with `sce auto handoff` and `sce scene package-publish-batch`.
|
|
@@ -33,6 +35,7 @@ node scripts/release-ops-weekly-summary.js --json
|
|
|
33
35
|
|
|
34
36
|
- `scene package publish-batch` gate passes.
|
|
35
37
|
- capability lexicon unknown count is zero.
|
|
38
|
+
- missing business scope is handled through clarification, not blanket disable fallback.
|
|
36
39
|
- release preflight is not blocked for hard-gate profiles.
|
|
37
40
|
- weekly ops summary risk is not `high` unless explicitly approved.
|
|
38
41
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# v3.6.47 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-14
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 将 clarification-first 提升为 SCE 全局基线:业务场景、模块、页面、实体或约束不清楚时,必须先澄清范围,禁止把“不理解业务”直接落成一刀切禁用。
|
|
8
|
+
- 扩展 takeover baseline 对齐能力:已接管和升级项目现在会自动补齐缺失的核心原则、自动落 `.sce/config/errorbook-registry.json`,并把项目内自定义复盘册/问题账本类机制盘点后统一收敛到 `.sce/errorbook`。
|
|
9
|
+
- 新增三条全局 steering 基线:禁止盲改问题、禁止未经评估随意增删 steering 条目、以及问题修复时前后端接口不一致默认以后端现有契约为准。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/workspace/takeover-baseline.test.js --runInBand`
|
|
14
|
+
- `npx jest tests/integration/adopt-upgrade-clarification-first.integration.test.js --runInBand`
|
|
15
|
+
- `npx jest tests/integration/takeover-baseline-cli.integration.test.js --runInBand`
|
|
16
|
+
- `npm run audit:steering`
|
|
17
|
+
- `npm run gate:errorbook-registry-health`
|
|
18
|
+
- `npm run prepublishOnly`
|
|
19
|
+
|
|
20
|
+
## 发布说明
|
|
21
|
+
|
|
22
|
+
- 这个补丁版把最近一轮 SCE 治理收敛中的关键规则正式固化为了可执行基线,不再依赖操作者“记得遵守”。
|
|
23
|
+
- 之后无论是 startup auto-takeover、`sce adopt` 还是 `sce upgrade`,都会自动把这些规则补齐到项目里,避免新老接入项目在治理要求上继续分叉。
|
|
@@ -12,6 +12,122 @@ const {
|
|
|
12
12
|
} = require('../state/state-storage-policy');
|
|
13
13
|
|
|
14
14
|
const TAKEOVER_BASELINE_SCHEMA_VERSION = '1.0';
|
|
15
|
+
const CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING = '## 11. 业务场景未知时必须先澄清,禁止直接彻底禁用';
|
|
16
|
+
const CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION = [
|
|
17
|
+
CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
18
|
+
'',
|
|
19
|
+
'- 不了解业务场景、模块、页面、实体或业务约束时,默认动作是先补上下文、缩小范围、生成澄清问题。',
|
|
20
|
+
'- 禁止把“未知业务场景”直接等同于 `deny`、`disable`、answer-only 或其他一刀切兜底禁用。',
|
|
21
|
+
'- 只有在明确命中安全/权限/合规/破坏性规则后,才允许进入阻断;否则必须先完成业务范围澄清。',
|
|
22
|
+
'- 这条规则适用于所有接入 SCE 的项目、模式和交互面,不允许按项目例外绕过。'
|
|
23
|
+
].join('\n');
|
|
24
|
+
const NO_BLIND_FIX_CORE_PRINCIPLE_HEADING = '## 12. 禁止盲改问题,必须先建立问题契约和证据';
|
|
25
|
+
const NO_BLIND_FIX_CORE_PRINCIPLE_SECTION = [
|
|
26
|
+
NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
|
|
27
|
+
'',
|
|
28
|
+
'- 修改问题前,必须先明确现象、复现条件、影响范围、预期行为和验证方式。',
|
|
29
|
+
'- 缺少日志、数据、接口样本、最小复现或问题契约时,应先补证据,不得靠猜测连续改代码碰运气。',
|
|
30
|
+
'- 若两轮修改仍未收敛,必须回到调试、定位和根因分析,禁止在未理解问题前盲目扩大改动面。'
|
|
31
|
+
].join('\n');
|
|
32
|
+
const STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING = '## 13. Steering 条目变更必须先评估,禁止随意增删';
|
|
33
|
+
const STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION = [
|
|
34
|
+
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
|
|
35
|
+
'',
|
|
36
|
+
'- 新增、删除或重写 steering 条目前,必须先评估它是否真属于长期原则,是否与现有条目重复,是否应迁移到 `CURRENT_CONTEXT.md`、Spec 或项目文档。',
|
|
37
|
+
'- steering 变更必须说明触发原因、适用范围以及与现有规则的关系;未经评估,不得把临时偏好、短期任务或偶发结论直接固化进去。',
|
|
38
|
+
'- 接管、升级和治理脚本只能补齐基线、修复漂移,不能把未经评估的项目习惯直接塞进 steering。'
|
|
39
|
+
].join('\n');
|
|
40
|
+
const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING = '## 14. 问题修复时前后端接口不一致默认以后端契约为准';
|
|
41
|
+
const BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION = [
|
|
42
|
+
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
43
|
+
'',
|
|
44
|
+
'- 在修改问题的场景下,若前端调用后端 API 出现路径、方法、字段、状态码或响应结构不匹配,默认以后端现有接口契约为准。',
|
|
45
|
+
'- 除非明确要求新建接口或修改后端接口,否则禁止为了迁就前端错误调用去随意改后端实现或契约。',
|
|
46
|
+
'- 默认优先修正前端请求、映射、类型和兼容处理,使其与后端接口保持一致;若怀疑后端契约错误,应先确认再改。'
|
|
47
|
+
].join('\n');
|
|
48
|
+
const REQUIRED_CORE_PRINCIPLE_SECTIONS = Object.freeze([
|
|
49
|
+
{
|
|
50
|
+
heading: CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
51
|
+
section: CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
heading: NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
|
|
55
|
+
section: NO_BLIND_FIX_CORE_PRINCIPLE_SECTION
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
heading: STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
|
|
59
|
+
section: STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
heading: BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
63
|
+
section: BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const ERRORBOOK_REGISTRY_DEFAULTS = Object.freeze({
|
|
68
|
+
enabled: true,
|
|
69
|
+
search_mode: 'remote',
|
|
70
|
+
cache_file: '.sce/errorbook/registry-cache.json',
|
|
71
|
+
sources: [
|
|
72
|
+
{
|
|
73
|
+
name: 'central',
|
|
74
|
+
enabled: true,
|
|
75
|
+
url: 'https://raw.githubusercontent.com/heguangyong/sce-errorbook-registry/main/registry/errorbook-registry.json',
|
|
76
|
+
index_url: 'https://raw.githubusercontent.com/heguangyong/sce-errorbook-registry/main/registry/errorbook-registry.index.json'
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const ERRORBOOK_CONVERGENCE_DEFAULTS = Object.freeze({
|
|
82
|
+
enabled: true,
|
|
83
|
+
canonical_mechanism: 'errorbook',
|
|
84
|
+
absorb_project_defined_mechanisms: true,
|
|
85
|
+
disallow_parallel_mechanisms: true,
|
|
86
|
+
intake_inventory_path: '.sce/errorbook/project-intake/custom-mechanism-inventory.json',
|
|
87
|
+
strategy: 'absorb_into_sce_errorbook'
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const ERRORBOOK_PARALLEL_MECHANISM_KEYWORDS = Object.freeze([
|
|
91
|
+
'错题本',
|
|
92
|
+
'错题',
|
|
93
|
+
'故障复盘',
|
|
94
|
+
'事故复盘',
|
|
95
|
+
'问题复盘',
|
|
96
|
+
'复盘册',
|
|
97
|
+
'mistake-book',
|
|
98
|
+
'mistake_book',
|
|
99
|
+
'mistakebook',
|
|
100
|
+
'fault-book',
|
|
101
|
+
'fault_book',
|
|
102
|
+
'postmortem',
|
|
103
|
+
'post-mortem',
|
|
104
|
+
'lessons-learned',
|
|
105
|
+
'lessons_learned',
|
|
106
|
+
'defect-ledger',
|
|
107
|
+
'defect_ledger',
|
|
108
|
+
'issue-ledger',
|
|
109
|
+
'issue_ledger',
|
|
110
|
+
'incident-review',
|
|
111
|
+
'incident_review'
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
const ERRORBOOK_SCAN_IGNORED_DIRS = new Set([
|
|
115
|
+
'.git',
|
|
116
|
+
'.hg',
|
|
117
|
+
'.svn',
|
|
118
|
+
'.sce',
|
|
119
|
+
'node_modules',
|
|
120
|
+
'dist',
|
|
121
|
+
'build',
|
|
122
|
+
'coverage',
|
|
123
|
+
'.next',
|
|
124
|
+
'.turbo',
|
|
125
|
+
'.idea',
|
|
126
|
+
'.vscode',
|
|
127
|
+
'tmp',
|
|
128
|
+
'temp',
|
|
129
|
+
'.tmp'
|
|
130
|
+
]);
|
|
15
131
|
|
|
16
132
|
const SESSION_GOVERNANCE_DEFAULTS = Object.freeze({
|
|
17
133
|
schema_version: '1.0',
|
|
@@ -217,6 +333,7 @@ const TAKEOVER_DEFAULTS = Object.freeze({
|
|
|
217
333
|
max_direct_fix_rounds_before_debug: 2,
|
|
218
334
|
forbid_bypass_workarounds: true
|
|
219
335
|
},
|
|
336
|
+
errorbook_convergence: _clone(ERRORBOOK_CONVERGENCE_DEFAULTS),
|
|
220
337
|
migration_policy: {
|
|
221
338
|
legacy_kiro_supported: false,
|
|
222
339
|
require_manual_legacy_migration_confirmation: true
|
|
@@ -335,6 +452,113 @@ function _buildTakeoverBaselineConfig(existing, sceVersion) {
|
|
|
335
452
|
};
|
|
336
453
|
}
|
|
337
454
|
|
|
455
|
+
function _buildErrorbookRegistryConfig(existing) {
|
|
456
|
+
const base = _isObject(existing) ? _clone(existing) : {};
|
|
457
|
+
return {
|
|
458
|
+
..._clone(ERRORBOOK_REGISTRY_DEFAULTS),
|
|
459
|
+
...base,
|
|
460
|
+
sources: Array.isArray(base.sources) && base.sources.length > 0
|
|
461
|
+
? _clone(base.sources)
|
|
462
|
+
: _clone(ERRORBOOK_REGISTRY_DEFAULTS.sources)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function _normalizeRelativePath(value) {
|
|
467
|
+
return `${value || ''}`.replace(/\\/g, '/');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function _findParallelErrorbookKeyword(relativePath) {
|
|
471
|
+
const normalized = _normalizeRelativePath(relativePath).toLowerCase();
|
|
472
|
+
return ERRORBOOK_PARALLEL_MECHANISM_KEYWORDS.find((keyword) => normalized.includes(keyword.toLowerCase())) || null;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function _shouldSkipErrorbookScanDir(dirName) {
|
|
476
|
+
return ERRORBOOK_SCAN_IGNORED_DIRS.has(`${dirName || ''}`.trim());
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async function _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem, currentDir = projectPath, depth = 0, findings = []) {
|
|
480
|
+
let entries = [];
|
|
481
|
+
try {
|
|
482
|
+
entries = await fileSystem.readdir(currentDir, { withFileTypes: true });
|
|
483
|
+
} catch (_error) {
|
|
484
|
+
return findings;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
for (const entry of entries) {
|
|
488
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
489
|
+
const relativePath = _toRelativePosix(projectPath, absolutePath);
|
|
490
|
+
|
|
491
|
+
if (entry.isDirectory()) {
|
|
492
|
+
if (_shouldSkipErrorbookScanDir(entry.name)) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const keyword = _findParallelErrorbookKeyword(relativePath);
|
|
497
|
+
if (keyword) {
|
|
498
|
+
findings.push({
|
|
499
|
+
path: relativePath,
|
|
500
|
+
kind: 'directory',
|
|
501
|
+
keyword,
|
|
502
|
+
action: 'absorb_into_sce_errorbook'
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (depth < 5) {
|
|
507
|
+
await _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem, absolutePath, depth + 1, findings);
|
|
508
|
+
}
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (!entry.isFile()) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const keyword = _findParallelErrorbookKeyword(relativePath);
|
|
517
|
+
if (!keyword) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
findings.push({
|
|
522
|
+
path: relativePath,
|
|
523
|
+
kind: 'file',
|
|
524
|
+
keyword,
|
|
525
|
+
action: 'absorb_into_sce_errorbook'
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return findings;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function _dedupeFindings(findings = []) {
|
|
533
|
+
const seen = new Set();
|
|
534
|
+
return findings.filter((item) => {
|
|
535
|
+
const key = `${item.kind}:${item.path}`;
|
|
536
|
+
if (seen.has(key)) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
seen.add(key);
|
|
540
|
+
return true;
|
|
541
|
+
}).sort((left, right) => `${left.path}`.localeCompare(`${right.path}`));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function _buildErrorbookConvergenceInventory(sceVersion, findings = []) {
|
|
545
|
+
const dedupedFindings = _dedupeFindings(findings);
|
|
546
|
+
return {
|
|
547
|
+
schema_version: TAKEOVER_BASELINE_SCHEMA_VERSION,
|
|
548
|
+
canonical_mechanism: 'errorbook',
|
|
549
|
+
strategy: 'absorb_into_sce_errorbook',
|
|
550
|
+
last_aligned_sce_version: sceVersion,
|
|
551
|
+
summary: {
|
|
552
|
+
detected_custom_mechanisms: dedupedFindings.length
|
|
553
|
+
},
|
|
554
|
+
guidance: [
|
|
555
|
+
'Absorb reusable failure-remediation knowledge into .sce/errorbook instead of keeping project-defined parallel mistake-book flows.',
|
|
556
|
+
'Use `sce errorbook record` for curated entries and `sce errorbook incident *` for short trial-and-error loops before curation.'
|
|
557
|
+
],
|
|
558
|
+
findings: dedupedFindings
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
338
562
|
async function _reconcileJsonFile(filePath, desired, options = {}) {
|
|
339
563
|
const {
|
|
340
564
|
projectPath,
|
|
@@ -403,6 +627,37 @@ async function _reconcileSteeringContract(projectPath, options = {}) {
|
|
|
403
627
|
};
|
|
404
628
|
}
|
|
405
629
|
|
|
630
|
+
async function _reconcileCorePrinciplesBaseline(projectPath, options = {}) {
|
|
631
|
+
const { apply, fileSystem } = options;
|
|
632
|
+
const corePrinciplesPath = path.join(projectPath, SCE_STEERING_DIR, DEFAULT_LAYER_FILES.core_principles);
|
|
633
|
+
const exists = await fileSystem.pathExists(corePrinciplesPath);
|
|
634
|
+
const existingContent = exists ? await fileSystem.readFile(corePrinciplesPath, 'utf8') : '';
|
|
635
|
+
const missingSections = REQUIRED_CORE_PRINCIPLE_SECTIONS.filter(({ heading }) => !existingContent.includes(heading));
|
|
636
|
+
const changed = missingSections.length > 0;
|
|
637
|
+
|
|
638
|
+
if (apply && changed) {
|
|
639
|
+
const normalized = `${existingContent || ''}`.trimEnd();
|
|
640
|
+
const appendedSections = missingSections.map((item) => item.section).join('\n\n');
|
|
641
|
+
const nextContent = normalized
|
|
642
|
+
? `${normalized}\n\n${appendedSections}\n`
|
|
643
|
+
: `${appendedSections}\n`;
|
|
644
|
+
await fileSystem.ensureDir(path.dirname(corePrinciplesPath));
|
|
645
|
+
await fileSystem.writeFile(corePrinciplesPath, nextContent, 'utf8');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return {
|
|
649
|
+
path: _toRelativePosix(projectPath, corePrinciplesPath),
|
|
650
|
+
existed: exists,
|
|
651
|
+
changed,
|
|
652
|
+
status: !exists ? (changed ? 'created' : 'unchanged') : (changed ? 'updated' : 'unchanged'),
|
|
653
|
+
managed_by: 'takeover-baseline',
|
|
654
|
+
details: {
|
|
655
|
+
missing_required_headings_before: missingSections.map((item) => item.heading),
|
|
656
|
+
required_headings: REQUIRED_CORE_PRINCIPLE_SECTIONS.map((item) => item.heading)
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
406
661
|
function _summarize(items) {
|
|
407
662
|
const summary = {
|
|
408
663
|
created: 0,
|
|
@@ -477,33 +732,38 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
477
732
|
const adoptionPath = path.join(sceRoot, 'adoption-config.json');
|
|
478
733
|
const autoConfigPath = path.join(sceRoot, 'auto', 'config.json');
|
|
479
734
|
const takeoverConfigPath = path.join(sceRoot, 'config', 'takeover-baseline.json');
|
|
735
|
+
const errorbookRegistryPath = path.join(sceRoot, 'config', 'errorbook-registry.json');
|
|
480
736
|
const sessionGovernancePath = path.join(sceRoot, 'config', 'session-governance.json');
|
|
481
737
|
const specDomainPolicyPath = path.join(sceRoot, 'config', 'spec-domain-policy.json');
|
|
482
738
|
const problemEvalPolicyPath = path.join(sceRoot, 'config', 'problem-eval-policy.json');
|
|
483
739
|
const problemClosurePolicyPath = path.join(sceRoot, 'config', 'problem-closure-policy.json');
|
|
484
740
|
const studioIntakePolicyPath = path.join(sceRoot, 'config', 'studio-intake-policy.json');
|
|
485
741
|
const stateStoragePolicyPath = path.join(sceRoot, 'config', 'state-storage-policy.json');
|
|
742
|
+
const errorbookInventoryPath = path.join(sceRoot, 'errorbook', 'project-intake', 'custom-mechanism-inventory.json');
|
|
486
743
|
const reportPath = path.join(sceRoot, 'reports', 'takeover-baseline-latest.json');
|
|
487
744
|
|
|
488
745
|
const existingAdoption = await _readJsonSafe(adoptionPath, fileSystem);
|
|
489
746
|
const existingAuto = await _readJsonSafe(autoConfigPath, fileSystem);
|
|
490
747
|
const existingTakeover = await _readJsonSafe(takeoverConfigPath, fileSystem);
|
|
748
|
+
const existingErrorbookRegistry = await _readJsonSafe(errorbookRegistryPath, fileSystem);
|
|
491
749
|
const existingSessionGovernance = await _readJsonSafe(sessionGovernancePath, fileSystem);
|
|
492
750
|
const existingSpecDomainPolicy = await _readJsonSafe(specDomainPolicyPath, fileSystem);
|
|
493
751
|
const existingProblemEvalPolicy = await _readJsonSafe(problemEvalPolicyPath, fileSystem);
|
|
494
752
|
const existingProblemClosurePolicy = await _readJsonSafe(problemClosurePolicyPath, fileSystem);
|
|
495
753
|
const existingStudioIntakePolicy = await _readJsonSafe(studioIntakePolicyPath, fileSystem);
|
|
496
754
|
const existingStateStoragePolicy = await _readJsonSafe(stateStoragePolicyPath, fileSystem);
|
|
497
|
-
|
|
498
755
|
const desiredAdoption = _buildAdoptionConfig(existingAdoption, nowIso, sceVersion);
|
|
499
756
|
const desiredAutoConfig = _buildAutoConfig(existingAuto);
|
|
500
757
|
const desiredTakeover = _buildTakeoverBaselineConfig(existingTakeover, sceVersion);
|
|
758
|
+
const desiredErrorbookRegistry = _buildErrorbookRegistryConfig(existingErrorbookRegistry);
|
|
501
759
|
const desiredSessionGovernance = _deepMerge(existingSessionGovernance || {}, SESSION_GOVERNANCE_DEFAULTS);
|
|
502
760
|
const desiredSpecDomainPolicy = _deepMerge(existingSpecDomainPolicy || {}, SPEC_DOMAIN_POLICY_DEFAULTS);
|
|
503
761
|
const desiredProblemEvalPolicy = _deepMerge(existingProblemEvalPolicy || {}, PROBLEM_EVAL_POLICY_DEFAULTS);
|
|
504
762
|
const desiredProblemClosurePolicy = _deepMerge(existingProblemClosurePolicy || {}, PROBLEM_CLOSURE_POLICY_DEFAULTS);
|
|
505
763
|
const desiredStudioIntakePolicy = _deepMerge(existingStudioIntakePolicy || {}, STUDIO_INTAKE_POLICY_DEFAULTS);
|
|
506
764
|
const desiredStateStoragePolicy = _deepMerge(existingStateStoragePolicy || {}, cloneStateStoragePolicyDefaults());
|
|
765
|
+
const customErrorbookFindings = await _scanProjectDefinedErrorbookMechanisms(projectPath, fileSystem);
|
|
766
|
+
const desiredErrorbookInventory = _buildErrorbookConvergenceInventory(sceVersion, customErrorbookFindings);
|
|
507
767
|
|
|
508
768
|
const fileResults = [];
|
|
509
769
|
fileResults.push(await _reconcileJsonFile(adoptionPath, desiredAdoption, {
|
|
@@ -521,6 +781,11 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
521
781
|
apply,
|
|
522
782
|
fileSystem
|
|
523
783
|
}));
|
|
784
|
+
fileResults.push(await _reconcileJsonFile(errorbookRegistryPath, desiredErrorbookRegistry, {
|
|
785
|
+
projectPath,
|
|
786
|
+
apply,
|
|
787
|
+
fileSystem
|
|
788
|
+
}));
|
|
524
789
|
fileResults.push(await _reconcileJsonFile(sessionGovernancePath, desiredSessionGovernance, {
|
|
525
790
|
projectPath,
|
|
526
791
|
apply,
|
|
@@ -551,10 +816,20 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
551
816
|
apply,
|
|
552
817
|
fileSystem
|
|
553
818
|
}));
|
|
819
|
+
fileResults.push(await _reconcileJsonFile(errorbookInventoryPath, desiredErrorbookInventory, {
|
|
820
|
+
projectPath,
|
|
821
|
+
apply,
|
|
822
|
+
fileSystem,
|
|
823
|
+
managedBy: 'errorbook-convergence'
|
|
824
|
+
}));
|
|
554
825
|
fileResults.push(await _reconcileSteeringContract(projectPath, {
|
|
555
826
|
apply,
|
|
556
827
|
fileSystem
|
|
557
828
|
}));
|
|
829
|
+
fileResults.push(await _reconcileCorePrinciplesBaseline(projectPath, {
|
|
830
|
+
apply,
|
|
831
|
+
fileSystem
|
|
832
|
+
}));
|
|
558
833
|
|
|
559
834
|
const auditFiles = _toAuditStatus(fileResults, apply);
|
|
560
835
|
const summary = _summarize(auditFiles);
|
|
@@ -571,6 +846,12 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
571
846
|
sce_version: sceVersion,
|
|
572
847
|
drift_count: driftCount,
|
|
573
848
|
enforced_defaults: _clone(TAKEOVER_DEFAULTS),
|
|
849
|
+
errorbook_convergence: {
|
|
850
|
+
canonical_mechanism: 'errorbook',
|
|
851
|
+
strategy: 'absorb_into_sce_errorbook',
|
|
852
|
+
detected_custom_mechanism_count: desiredErrorbookInventory.summary.detected_custom_mechanisms,
|
|
853
|
+
inventory_file: _toRelativePosix(projectPath, errorbookInventoryPath)
|
|
854
|
+
},
|
|
574
855
|
files: auditFiles,
|
|
575
856
|
summary
|
|
576
857
|
};
|
|
@@ -595,6 +876,17 @@ async function applyTakeoverBaseline(projectPath = process.cwd(), options = {})
|
|
|
595
876
|
}
|
|
596
877
|
|
|
597
878
|
module.exports = {
|
|
879
|
+
CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING,
|
|
880
|
+
CLARIFICATION_FIRST_CORE_PRINCIPLE_SECTION,
|
|
881
|
+
NO_BLIND_FIX_CORE_PRINCIPLE_HEADING,
|
|
882
|
+
NO_BLIND_FIX_CORE_PRINCIPLE_SECTION,
|
|
883
|
+
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_HEADING,
|
|
884
|
+
STEERING_CHANGE_EVALUATION_CORE_PRINCIPLE_SECTION,
|
|
885
|
+
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_HEADING,
|
|
886
|
+
BACKEND_API_PRECEDENCE_CORE_PRINCIPLE_SECTION,
|
|
887
|
+
REQUIRED_CORE_PRINCIPLE_SECTIONS,
|
|
888
|
+
ERRORBOOK_REGISTRY_DEFAULTS,
|
|
889
|
+
ERRORBOOK_CONVERGENCE_DEFAULTS,
|
|
598
890
|
TAKEOVER_BASELINE_SCHEMA_VERSION,
|
|
599
891
|
TAKEOVER_DEFAULTS,
|
|
600
892
|
SESSION_GOVERNANCE_DEFAULTS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scene-capability-engine",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.47",
|
|
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": {
|
|
@@ -41,8 +41,10 @@
|
|
|
41
41
|
"gate:npm-runtime-assets": "node scripts/npm-package-runtime-asset-check.js --fail-on-violation",
|
|
42
42
|
"test:brand-consistency": "node scripts/check-branding-consistency.js",
|
|
43
43
|
"audit:steering": "node scripts/steering-content-audit.js --fail-on-error",
|
|
44
|
+
"audit:clarification-first": "node scripts/clarification-first-audit.js --fail-on-violation",
|
|
44
45
|
"audit:state-storage": "node scripts/state-storage-tiering-audit.js",
|
|
45
46
|
"report:steering-audit": "node scripts/steering-content-audit.js --json",
|
|
47
|
+
"report:clarification-first-audit": "node scripts/clarification-first-audit.js --json",
|
|
46
48
|
"report:state-storage": "node scripts/state-storage-tiering-audit.js --json",
|
|
47
49
|
"report:interactive-approval-projection": "node scripts/interactive-approval-event-projection.js --action doctor --json",
|
|
48
50
|
"audit:interactive-approval-projection": "node scripts/interactive-approval-event-projection.js --action doctor --fail-on-drift --fail-on-parse-error",
|
|
@@ -84,7 +86,7 @@
|
|
|
84
86
|
"gate:release-asset-integrity": "node scripts/release-asset-integrity-check.js",
|
|
85
87
|
"report:release-risk-remediation": "node scripts/release-risk-remediation-bundle.js --json",
|
|
86
88
|
"report:moqui-core-regression": "node scripts/moqui-core-regression-suite.js --json",
|
|
87
|
-
"prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run gate:npm-runtime-assets && npm run test:brand-consistency && npm run audit:steering && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
|
|
89
|
+
"prepublishOnly": "npm run test:release && npm run test:skip-audit && npm run test:sce-tracking && npm run gate:npm-runtime-assets && npm run test:brand-consistency && npm run audit:steering && npm run audit:clarification-first && npm run gate:git-managed && npm run gate:errorbook-registry-health && npm run gate:errorbook-release && npm run report:interactive-governance -- --fail-on-alert",
|
|
88
90
|
"publish:manual": "npm publish --access public",
|
|
89
91
|
"install-global": "npm install -g .",
|
|
90
92
|
"uninstall-global": "npm uninstall -g scene-capability-engine"
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const REQUIRED_CHECKS = [
|
|
8
|
+
{
|
|
9
|
+
path: 'scripts/interactive-dialogue-governance.js',
|
|
10
|
+
requiredSnippets: [
|
|
11
|
+
'contextHasBusinessScope',
|
|
12
|
+
'goalMentionsBusinessScope',
|
|
13
|
+
'business scene/module/page/entity context is missing; clarify scope before fallback or execution',
|
|
14
|
+
'Which module/page/entity is affected first?'
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
path: 'scripts/symbol-evidence-locate.js',
|
|
19
|
+
requiredSnippets: [
|
|
20
|
+
'clarify_business_scope',
|
|
21
|
+
'Clarify target module/page/entity and business constraints before deciding whether scoped writes are safe.'
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: 'lib/workspace/takeover-baseline.js',
|
|
26
|
+
requiredSnippets: [
|
|
27
|
+
'CLARIFICATION_FIRST_CORE_PRINCIPLE_HEADING',
|
|
28
|
+
'_reconcileCorePrinciplesBaseline',
|
|
29
|
+
'这条规则适用于所有接入 SCE 的项目、模式和交互面,不允许按项目例外绕过。'
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
path: 'docs/interactive-customization/dialogue-governance-policy-baseline.json',
|
|
34
|
+
requiredSnippets: [
|
|
35
|
+
'clarify and narrow scope before using any fallback restriction; do not replace understanding with blanket disable',
|
|
36
|
+
'Which entity or business rule is affected, and what constraint must stay intact?'
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: '.sce/steering/CORE_PRINCIPLES.md',
|
|
41
|
+
requiredSnippets: [
|
|
42
|
+
'业务场景未知时必须先澄清,禁止直接彻底禁用',
|
|
43
|
+
'这条规则适用于所有接入 SCE 的项目、模式和交互面,不允许按项目例外绕过。'
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
path: 'template/.sce/steering/CORE_PRINCIPLES.md',
|
|
48
|
+
requiredSnippets: [
|
|
49
|
+
'业务场景未知时先澄清,不得直接彻底禁用',
|
|
50
|
+
'这条规则适用于所有使用 SCE 的项目,不设项目级例外。'
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: 'README.md',
|
|
55
|
+
requiredSnippets: [
|
|
56
|
+
'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.'
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
path: 'README.zh.md',
|
|
61
|
+
requiredSnippets: [
|
|
62
|
+
'缺少业务场景/模块/页面/实体上下文时,SCE 必须先进入澄清,而不是把未知业务范围直接变成一刀切禁用'
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
path: 'docs/security-governance-default-baseline.md',
|
|
67
|
+
requiredSnippets: [
|
|
68
|
+
'Missing business scene/module/page/entity context must route to clarification first; unknown scope is never a valid reason for blanket disable.',
|
|
69
|
+
'This clarification-first rule applies to every SCE-integrated project and surface with no project-specific exception.'
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
path: 'docs/starter-kit/README.md',
|
|
74
|
+
requiredSnippets: [
|
|
75
|
+
'This baseline applies to every onboarded project with no project-specific exception.',
|
|
76
|
+
'missing business scope is handled through clarification, not blanket disable fallback.'
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
path: 'docs/command-reference.md',
|
|
81
|
+
requiredSnippets: [
|
|
82
|
+
'Missing business scene/module/page/entity context defaults to `clarify`; unknown scope must not be converted into blanket disable fallback.'
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const PROHIBITED_SNIPPETS = [
|
|
88
|
+
{
|
|
89
|
+
value: 'block_high_risk_write',
|
|
90
|
+
allowedPaths: [
|
|
91
|
+
'scripts/clarification-first-audit.js',
|
|
92
|
+
'tests/unit/scripts/clarification-first-audit.test.js'
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
value: 'Fallback to answer-only mode and block high-risk writes.',
|
|
97
|
+
allowedPaths: [
|
|
98
|
+
'scripts/clarification-first-audit.js',
|
|
99
|
+
'tests/unit/scripts/clarification-first-audit.test.js'
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const SEARCH_DIRECTORIES = ['lib', 'scripts', 'docs', '.sce', 'template', 'tests'];
|
|
105
|
+
const SEARCH_EXTENSIONS = new Set(['.js', '.md', '.json', '.txt', '.yaml', '.yml']);
|
|
106
|
+
|
|
107
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
108
|
+
const options = {
|
|
109
|
+
projectPath: process.cwd(),
|
|
110
|
+
json: false,
|
|
111
|
+
failOnViolation: false,
|
|
112
|
+
out: null
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
116
|
+
const token = argv[index];
|
|
117
|
+
const next = argv[index + 1];
|
|
118
|
+
if (token === '--project-path' && next) {
|
|
119
|
+
options.projectPath = path.resolve(next);
|
|
120
|
+
index += 1;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (token === '--json') {
|
|
124
|
+
options.json = true;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (token === '--fail-on-violation') {
|
|
128
|
+
options.failOnViolation = true;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (token === '--out' && next) {
|
|
132
|
+
options.out = path.resolve(next);
|
|
133
|
+
index += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (token === '--help' || token === '-h') {
|
|
137
|
+
printHelpAndExit(0);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return options;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function printHelpAndExit(code) {
|
|
145
|
+
const lines = [
|
|
146
|
+
'Usage: node scripts/clarification-first-audit.js [options]',
|
|
147
|
+
'',
|
|
148
|
+
'Options:',
|
|
149
|
+
' --project-path <path> Project root to audit (default: current directory)',
|
|
150
|
+
' --json Print JSON payload',
|
|
151
|
+
' --fail-on-violation Exit code 2 when any violation is found',
|
|
152
|
+
' --out <path> Write JSON payload to file',
|
|
153
|
+
' -h, --help Show this help'
|
|
154
|
+
];
|
|
155
|
+
console.log(lines.join('\n'));
|
|
156
|
+
process.exit(code);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function normalizeSlashes(value) {
|
|
160
|
+
return `${value || ''}`.replace(/\\/g, '/');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function pushViolation(violations, severity, rule, file, message) {
|
|
164
|
+
violations.push({
|
|
165
|
+
severity,
|
|
166
|
+
rule,
|
|
167
|
+
file,
|
|
168
|
+
message
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function readText(filePath) {
|
|
173
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function collectFilesRecursive(rootDir, relativeRoot = '') {
|
|
177
|
+
if (!fs.existsSync(rootDir)) {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
const results = [];
|
|
181
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
const absolutePath = path.join(rootDir, entry.name);
|
|
184
|
+
const relativePath = normalizeSlashes(path.join(relativeRoot, entry.name));
|
|
185
|
+
if (entry.isDirectory()) {
|
|
186
|
+
if (entry.name === 'node_modules' || entry.name === '.git') {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
results.push(...collectFilesRecursive(absolutePath, relativePath));
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (!entry.isFile()) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (!SEARCH_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
results.push({
|
|
199
|
+
absolutePath,
|
|
200
|
+
relativePath
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function auditClarificationFirst(options = {}) {
|
|
207
|
+
const projectPath = path.resolve(options.projectPath || process.cwd());
|
|
208
|
+
const violations = [];
|
|
209
|
+
const checkedFiles = [];
|
|
210
|
+
|
|
211
|
+
for (const check of REQUIRED_CHECKS) {
|
|
212
|
+
const relativePath = normalizeSlashes(check.path);
|
|
213
|
+
const absolutePath = path.join(projectPath, relativePath);
|
|
214
|
+
checkedFiles.push(relativePath);
|
|
215
|
+
if (!fs.existsSync(absolutePath)) {
|
|
216
|
+
pushViolation(
|
|
217
|
+
violations,
|
|
218
|
+
'error',
|
|
219
|
+
'missing_required_file',
|
|
220
|
+
relativePath,
|
|
221
|
+
`Required clarification-first baseline file is missing: ${relativePath}`
|
|
222
|
+
);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const content = readText(absolutePath);
|
|
227
|
+
for (const snippet of check.requiredSnippets) {
|
|
228
|
+
if (!content.includes(snippet)) {
|
|
229
|
+
pushViolation(
|
|
230
|
+
violations,
|
|
231
|
+
'error',
|
|
232
|
+
'missing_required_snippet',
|
|
233
|
+
relativePath,
|
|
234
|
+
`Missing required clarification-first snippet: ${snippet}`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const searchableFiles = SEARCH_DIRECTORIES.flatMap((dirName) => {
|
|
241
|
+
const absoluteDir = path.join(projectPath, dirName);
|
|
242
|
+
return collectFilesRecursive(absoluteDir, dirName);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
for (const file of searchableFiles) {
|
|
246
|
+
const content = readText(file.absolutePath);
|
|
247
|
+
for (const rule of PROHIBITED_SNIPPETS) {
|
|
248
|
+
if (!content.includes(rule.value)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const allowedPaths = Array.isArray(rule.allowedPaths) ? rule.allowedPaths.map(normalizeSlashes) : [];
|
|
252
|
+
if (allowedPaths.includes(file.relativePath)) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
pushViolation(
|
|
256
|
+
violations,
|
|
257
|
+
'error',
|
|
258
|
+
'prohibited_legacy_disable_phrase',
|
|
259
|
+
file.relativePath,
|
|
260
|
+
`Prohibited legacy fallback phrase found: ${rule.value}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const errorCount = violations.filter((item) => item.severity === 'error').length;
|
|
266
|
+
return {
|
|
267
|
+
mode: 'clarification-first-audit',
|
|
268
|
+
project_path: projectPath,
|
|
269
|
+
checked_files: checkedFiles,
|
|
270
|
+
searched_file_count: searchableFiles.length,
|
|
271
|
+
violation_count: violations.length,
|
|
272
|
+
error_count: errorCount,
|
|
273
|
+
passed: violations.length === 0,
|
|
274
|
+
violations
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function writeReportIfNeeded(report, outPath) {
|
|
279
|
+
if (!outPath) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const resolved = path.resolve(outPath);
|
|
283
|
+
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
284
|
+
fs.writeFileSync(resolved, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function main() {
|
|
288
|
+
const options = parseArgs(process.argv.slice(2));
|
|
289
|
+
const report = auditClarificationFirst(options);
|
|
290
|
+
writeReportIfNeeded(report, options.out);
|
|
291
|
+
|
|
292
|
+
if (options.json) {
|
|
293
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
294
|
+
} else if (report.passed) {
|
|
295
|
+
console.log('[clarification-first-audit] passed');
|
|
296
|
+
} else {
|
|
297
|
+
console.error(`[clarification-first-audit] failed with ${report.violation_count} violation(s)`);
|
|
298
|
+
for (const violation of report.violations) {
|
|
299
|
+
console.error(`[clarification-first-audit] ${violation.rule} ${violation.file}: ${violation.message}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (options.failOnViolation && !report.passed) {
|
|
304
|
+
process.exitCode = 2;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (require.main === module) {
|
|
309
|
+
try {
|
|
310
|
+
main();
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error(`[clarification-first-audit] ${error.message}`);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
module.exports = {
|
|
318
|
+
REQUIRED_CHECKS,
|
|
319
|
+
PROHIBITED_SNIPPETS,
|
|
320
|
+
parseArgs,
|
|
321
|
+
auditClarificationFirst
|
|
322
|
+
};
|
|
@@ -46,11 +46,13 @@ const BUILTIN_POLICY = {
|
|
|
46
46
|
'Always restate objective, scope, and expected impact before any action recommendation.',
|
|
47
47
|
'When risk or permission is involved, explicitly tell user what approval is required.',
|
|
48
48
|
'If requirement is ambiguous, ask at most two focused clarification questions.',
|
|
49
|
+
'If business scene, module, page, entity, or constraints are missing, clarify scope first; never replace missing understanding with blanket disable.',
|
|
49
50
|
'Never propose credential export, approval bypass, or secret leakage.'
|
|
50
51
|
],
|
|
51
52
|
clarification_templates: [
|
|
52
53
|
'What business outcome should improve first (speed, accuracy, cost, compliance)?',
|
|
53
|
-
'Which page or module should be changed first, and what should stay unchanged?'
|
|
54
|
+
'Which page or module should be changed first, and what should stay unchanged?',
|
|
55
|
+
'Which entity or business rule is affected, and what constraint must remain unchanged?'
|
|
54
56
|
],
|
|
55
57
|
profiles: {
|
|
56
58
|
'business-user': {
|
|
@@ -80,6 +82,7 @@ const BUILTIN_POLICY = {
|
|
|
80
82
|
],
|
|
81
83
|
response_rules: [
|
|
82
84
|
'For maintenance requests, require change ticket, rollback plan, and approval role before execution.',
|
|
85
|
+
'When business context is incomplete, ask for the affected module/page/entity before deny or write restriction decisions.',
|
|
83
86
|
'If request targets production, require staged validation evidence first.'
|
|
84
87
|
],
|
|
85
88
|
clarification_templates: [
|
|
@@ -686,11 +689,18 @@ function evaluatePatternRules(goal, rules) {
|
|
|
686
689
|
function pickClarificationQuestions(policy, context = {}) {
|
|
687
690
|
const questions = [];
|
|
688
691
|
const templates = Array.isArray(policy.clarification_templates) ? policy.clarification_templates : [];
|
|
689
|
-
if (!context.module) {
|
|
690
|
-
questions.push('Which module
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
|
|
692
|
+
if (!context.module && !context.page && !context.entity) {
|
|
693
|
+
questions.push('Which module/page/entity is affected first?');
|
|
694
|
+
} else {
|
|
695
|
+
if (!context.module) {
|
|
696
|
+
questions.push('Which module should be changed first?');
|
|
697
|
+
}
|
|
698
|
+
if (!context.page) {
|
|
699
|
+
questions.push('Which page or screen is currently problematic?');
|
|
700
|
+
}
|
|
701
|
+
if (!context.entity) {
|
|
702
|
+
questions.push('Which entity or business rule is affected?');
|
|
703
|
+
}
|
|
694
704
|
}
|
|
695
705
|
for (const template of templates) {
|
|
696
706
|
if (questions.length >= 2) {
|
|
@@ -703,11 +713,26 @@ function pickClarificationQuestions(policy, context = {}) {
|
|
|
703
713
|
return questions.slice(0, 2);
|
|
704
714
|
}
|
|
705
715
|
|
|
716
|
+
function contextHasBusinessScope(context = {}) {
|
|
717
|
+
const payload = context && typeof context === 'object' ? context : {};
|
|
718
|
+
return ['module', 'page', 'entity', 'scene_id', 'workflow_node']
|
|
719
|
+
.some((key) => normalizeText(payload[key]));
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function goalMentionsBusinessScope(goal = '') {
|
|
723
|
+
const normalizedGoal = normalizeText(goal).toLowerCase();
|
|
724
|
+
if (!normalizedGoal) {
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
return /\b(page|screen|module|entity|workflow|scene)\b/.test(normalizedGoal);
|
|
728
|
+
}
|
|
729
|
+
|
|
706
730
|
function evaluateDialogue(goal, context = {}, policy) {
|
|
707
731
|
const normalizedGoal = normalizeText(goal);
|
|
708
732
|
const tokens = normalizedGoal.split(/\s+/).filter(Boolean);
|
|
709
733
|
const denyHits = evaluatePatternRules(normalizedGoal, policy.deny_patterns);
|
|
710
734
|
const clarifyHits = evaluatePatternRules(normalizedGoal, policy.clarify_patterns);
|
|
735
|
+
const missingBusinessScope = !contextHasBusinessScope(context) && !goalMentionsBusinessScope(normalizedGoal);
|
|
711
736
|
|
|
712
737
|
const reasons = [];
|
|
713
738
|
if (normalizedGoal.length < policy.length_policy.min_chars) {
|
|
@@ -719,6 +744,9 @@ function evaluateDialogue(goal, context = {}, policy) {
|
|
|
719
744
|
if (tokens.length < policy.length_policy.min_significant_tokens) {
|
|
720
745
|
reasons.push(`goal has too few significant tokens (< ${policy.length_policy.min_significant_tokens})`);
|
|
721
746
|
}
|
|
747
|
+
if (missingBusinessScope) {
|
|
748
|
+
reasons.push('business scene/module/page/entity context is missing; clarify scope before fallback or execution');
|
|
749
|
+
}
|
|
722
750
|
reasons.push(...denyHits.map(item => item.reason));
|
|
723
751
|
reasons.push(...clarifyHits.map(item => item.reason));
|
|
724
752
|
|
|
@@ -726,6 +754,7 @@ function evaluateDialogue(goal, context = {}, policy) {
|
|
|
726
754
|
if (denyHits.length > 0) {
|
|
727
755
|
decision = 'deny';
|
|
728
756
|
} else if (
|
|
757
|
+
missingBusinessScope ||
|
|
729
758
|
clarifyHits.length > 0 ||
|
|
730
759
|
normalizedGoal.length < policy.length_policy.min_chars ||
|
|
731
760
|
tokens.length < policy.length_policy.min_significant_tokens
|
|
@@ -736,6 +765,7 @@ function evaluateDialogue(goal, context = {}, policy) {
|
|
|
736
765
|
return {
|
|
737
766
|
decision,
|
|
738
767
|
reasons: Array.from(new Set(reasons)),
|
|
768
|
+
business_scope_clarification_required: missingBusinessScope,
|
|
739
769
|
deny_hits: denyHits,
|
|
740
770
|
clarify_hits: clarifyHits,
|
|
741
771
|
response_rules: Array.isArray(policy.response_rules) ? policy.response_rules : [],
|
|
@@ -749,6 +779,7 @@ function toContextRef(context) {
|
|
|
749
779
|
product: normalizeText(payload.product || payload.app || ''),
|
|
750
780
|
module: normalizeText(payload.module || ''),
|
|
751
781
|
page: normalizeText(payload.page || ''),
|
|
782
|
+
entity: normalizeText(payload.entity || ''),
|
|
752
783
|
scene_id: normalizeText(payload.scene_id || '')
|
|
753
784
|
};
|
|
754
785
|
}
|
|
@@ -7,6 +7,8 @@ const path = require('path');
|
|
|
7
7
|
const DEFAULT_MAX_HITS = 10;
|
|
8
8
|
const DEFAULT_MIN_SCORE = 0.35;
|
|
9
9
|
const DEFAULT_MIN_RELIABLE_SCORE = 0.6;
|
|
10
|
+
const FALLBACK_ACTION_ALLOW_WRITE = 'allow_write';
|
|
11
|
+
const FALLBACK_ACTION_CLARIFY_BUSINESS_SCOPE = 'clarify_business_scope';
|
|
10
12
|
const DEFAULT_EXTENSIONS = [
|
|
11
13
|
'.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx',
|
|
12
14
|
'.py', '.java', '.go', '.rb', '.php', '.cs',
|
|
@@ -121,7 +123,7 @@ function printHelpAndExit(code) {
|
|
|
121
123
|
` --min-score <0-1> Minimum hit score (default: ${DEFAULT_MIN_SCORE})`,
|
|
122
124
|
` --min-reliable-score <0-1> Reliability threshold (default: ${DEFAULT_MIN_RELIABLE_SCORE})`,
|
|
123
125
|
` --extensions <csv> File extensions (default: ${DEFAULT_EXTENSIONS.join(',')})`,
|
|
124
|
-
' --strict Exit code 2 when no reliable evidence is found',
|
|
126
|
+
' --strict Exit code 2 when no reliable evidence is found and scope clarification is required',
|
|
125
127
|
' --json Print JSON payload',
|
|
126
128
|
' -h, --help Show this help'
|
|
127
129
|
];
|
|
@@ -306,10 +308,12 @@ function locateSymbolEvidence({
|
|
|
306
308
|
evidence: {
|
|
307
309
|
confidence,
|
|
308
310
|
reliable,
|
|
309
|
-
fallback_action: reliable
|
|
311
|
+
fallback_action: reliable
|
|
312
|
+
? FALLBACK_ACTION_ALLOW_WRITE
|
|
313
|
+
: FALLBACK_ACTION_CLARIFY_BUSINESS_SCOPE,
|
|
310
314
|
advisory: reliable
|
|
311
315
|
? 'Symbol evidence is reliable; scoped code change can proceed.'
|
|
312
|
-
: 'No reliable symbol evidence found.
|
|
316
|
+
: 'No reliable symbol evidence found yet. Clarify target module/page/entity and business constraints before deciding whether scoped writes are safe.'
|
|
313
317
|
},
|
|
314
318
|
summary: {
|
|
315
319
|
searched_files: candidateFiles.length,
|
package/template/.sce/README.md
CHANGED
|
@@ -15,6 +15,7 @@ This project uses **Spec-driven development** - a structured approach where:
|
|
|
15
15
|
- When user requests a feature → Check if Spec exists, if not, help create one
|
|
16
16
|
- When implementing → Follow the Spec's requirements and design
|
|
17
17
|
- When stuck → Read the Spec documents for context
|
|
18
|
+
- When business scene/module/page/entity is unclear → Clarify scope first; do not replace missing understanding with blanket disable
|
|
18
19
|
- Track progress by updating task status
|
|
19
20
|
|
|
20
21
|
---
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
## 4. 复用已有机制,不要平行造轮子
|
|
23
23
|
|
|
24
24
|
- 已有能力优先复用,例如缺陷经验与发布阻断统一走 `errorbook`。
|
|
25
|
+
- 若接管项目中已存在自定义缺陷复盘册、故障账本或问题经验库,必须统一盘点并吸收到 `.sce/errorbook`,不要长期并存混用。
|
|
25
26
|
- 不要在 steering 中额外定义另一套错题、发布、会话或治理模式。
|
|
26
27
|
|
|
27
28
|
## 5. 质量问题必须追根
|
|
@@ -33,3 +34,27 @@
|
|
|
33
34
|
|
|
34
35
|
- 每周、发布前、重大 Spec 收尾后运行 `npm run audit:steering`。
|
|
35
36
|
- 发现问题时优先合并重复、迁移错层、归档历史、删除失效条目。
|
|
37
|
+
|
|
38
|
+
## 7. 业务场景未知时先澄清,不得直接彻底禁用
|
|
39
|
+
|
|
40
|
+
- 不了解业务场景、模块、页面、实体或业务约束时,先补上下文并缩小范围。
|
|
41
|
+
- 禁止把“暂时没理解场景”直接变成 blanket disable、answer-only 或一刀切阻断。
|
|
42
|
+
- 只有明确命中安全、权限、合规或破坏性规则时,才允许阻断;否则先澄清业务范围。
|
|
43
|
+
- 这条规则适用于所有使用 SCE 的项目,不设项目级例外。
|
|
44
|
+
|
|
45
|
+
## 8. 禁止盲改问题
|
|
46
|
+
|
|
47
|
+
- 修问题前先明确现象、复现条件、影响范围和验证方式。
|
|
48
|
+
- 缺少证据时先补日志、数据、接口样本或最小复现,不要靠猜测连续改代码。
|
|
49
|
+
- 两轮修改仍未收敛时,先回到调试和根因分析,不要盲目扩大改动面。
|
|
50
|
+
|
|
51
|
+
## 9. Steering 变更先评估,不得随意增删
|
|
52
|
+
|
|
53
|
+
- 新增、删除或重写 steering 条目前,先判断它是否真属于长期原则,是否应迁到 `CURRENT_CONTEXT.md`、Spec 或项目文档。
|
|
54
|
+
- 未经评估,不要把临时偏好、短期任务或偶发结论直接固化进 steering。
|
|
55
|
+
|
|
56
|
+
## 10. 问题修复时前后端接口不一致默认以后端契约为准
|
|
57
|
+
|
|
58
|
+
- 前端调用后端 API 不匹配时,默认以后端现有接口契约为准。
|
|
59
|
+
- 除非明确要求新建或修改后端接口,否则不要为了迁就前端错误调用去改后端。
|
|
60
|
+
- 优先调整前端请求、映射、类型和兼容处理,使其与后端接口一致。
|