@xulthekl/team-flow 0.64.0 → 0.67.0
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/.claude/always/phase-guard.md +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/marketplace.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.github/plugin/marketplace.json +2 -2
- package/CHANGELOG.md +60 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +1 -1
- package/agents/architecture-design.md +1 -1
- package/agents/architecture-reviewer.md +6 -2
- package/agents/prd-completeness-reviewer.md +10 -0
- package/agents/prd-writer.md +1 -0
- package/agents/release-archivist.md +2 -0
- package/docs/README_en.md +1 -1
- package/docs/team-flow /344/275/277/347/224/250/350/257/264/346/230/216/357/274/210/347/240/224/345/217/221/345/233/242/351/230/237/347/211/210/357/274/211.md" +8 -6
- package/gemini-extension.json +1 -1
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/prd/v1/prd.md +1 -1
- package/scripts/guard/checks/arch-gate-exemptions.mjs +5 -3
- package/scripts/guard/checks/arch-readiness.mjs +1 -1
- package/scripts/guard/checks/arch-snapshot.mjs +5 -3
- package/scripts/guard/checks/history-risk.mjs +132 -0
- package/scripts/guard/checks/prd-clarity-state.mjs +41 -0
- package/scripts/guard/checks/prd-clarity.mjs +176 -0
- package/scripts/guard/guard.mjs +16 -8
- package/scripts/infer-workflow.mjs +20 -0
- package/scripts/lib/arch-merge.mjs +384 -50
- package/scripts/lib/arch-parse.mjs +5 -2
- package/scripts/lib/arch-registry.mjs +523 -0
- package/scripts/lib/arch-scan-code.mjs +518 -0
- package/scripts/lib/cmd-arch.mjs +9 -1
- package/scripts/lib/cmd-doctor.mjs +3 -3
- package/scripts/lib/cmd-prd.mjs +84 -1
- package/scripts/lib/cmd-solutions.mjs +3 -0
- package/scripts/lib/cmd-state.mjs +31 -1
- package/scripts/lib/config-loader.mjs +20 -0
- package/scripts/lib/solutions-capture.mjs +5 -0
- package/scripts/lib/solutions-index-gen.mjs +33 -3
- package/scripts/lib/solutions-inject.mjs +34 -9
- package/scripts/lib/state-loader.mjs +13 -0
- package/scripts/team-flow.mjs +3 -0
- package/skills/architecture-design/SKILL.md +29 -11
- package/skills/architecture-design/chapters/ch04-entity-to-aggregate.md +18 -7
- package/skills/architecture-design/chapters/ch06-integration.md +12 -3
- package/skills/architecture-design/glossary.md +5 -1
- package/skills/architecture-design/references/adr-templates.md +56 -0
- package/skills/architecture-design/references/context-map-8.md +47 -0
- package/skills/architecture-design/references/ddd-evented-playbook.md +41 -0
- package/skills/architecture-design/references/s3.5-architecture-template.md +36 -4
- package/skills/architecture-design/references/s3.5-loading-protocol.md +5 -4
- package/skills/architecture-design/references/s3.5-product-architecture.md +6 -6
- package/skills/architecture-design/templates/architecture.md +20 -0
- package/skills/ce-brainstorm/SKILL.md +3 -3
- package/skills/ce-brainstorm/references/grounding.md +1 -1
- package/skills/ce-brainstorm/references/prd-84-authoring-spec.md +26 -3
- package/skills/ce-brainstorm/references/prototype-loop.md +8 -0
- package/skills/ce-compound/references/concepts-vocabulary.md +1 -1
- package/skills/ce-compound/references/full-mode-workflow.md +2 -2
- package/skills/ce-compound/references/lightweight-mode.md +1 -1
- package/skills/ce-compound/references/promotion-rules.md +1 -1
- package/skills/ce-compound/references/three-tier-index.md +1 -1
- package/skills/ce-plan/references/research-workflow.md +1 -1
- package/skills/jarvis/references/protocols.md +1 -0
- package/skills/release-archivist/SKILL.md +21 -0
- package/skills/release-archivist/references/closing-procedures.md +1 -1
- package/skills/workflow-orchestrator/SKILL.md +8 -4
- package/skills/workflow-orchestrator/references/s1-path-router.md +7 -0
- package/skills/workflow-orchestrator/references/s2-prd-prototype-loop.md +16 -2
- package/skills/workflow-orchestrator/references/s3-plan-pipeline.md +1 -1
- package/skills/workflow-start/SKILL.md +1 -1
- package/templates/prd.md +9 -1
package/scripts/lib/cmd-prd.mjs
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
// 供主会话 Phase 0.0 的阻塞提问(G1)取判据——**判据不在 skill 散文里另写一套**。
|
|
15
15
|
|
|
16
16
|
import fs from 'node:fs';
|
|
17
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
17
18
|
import path from 'node:path';
|
|
19
|
+
import { createHash } from 'node:crypto';
|
|
18
20
|
import { parseArgs } from 'node:util';
|
|
19
21
|
import { loadConfig, resolveConfigWritePath } from './config-loader.mjs';
|
|
20
22
|
import {
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
compareAgainstAck,
|
|
24
26
|
shortHash,
|
|
25
27
|
} from './template-hash.mjs';
|
|
28
|
+
import { checkPrdClarity } from '../guard/checks/prd-clarity.mjs';
|
|
26
29
|
|
|
27
30
|
const VALID_MODES = ['adopt_latest', 'keep_legacy'];
|
|
28
31
|
|
|
@@ -48,6 +51,7 @@ export async function run(args) {
|
|
|
48
51
|
const sub = positionals[0];
|
|
49
52
|
if (sub === 'ack') return ack(positionals.slice(1), values);
|
|
50
53
|
if (sub === 'check') return check(values);
|
|
54
|
+
if (sub === 'check-clarity') return checkClarity(positionals.slice(1));
|
|
51
55
|
usage();
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -58,11 +62,90 @@ function usage() {
|
|
|
58
62
|
' tf prd ack set --mode adopt_latest --in-use-hash … [--plugin-hash …] [--spec-hash …]\n' +
|
|
59
63
|
' tf prd ack show # 查看当前 ack\n' +
|
|
60
64
|
' tf prd ack clear # 清除 ack(下次将重新提问)\n' +
|
|
61
|
-
' tf prd check [--template-path <p>] [--plugin-root <p>] # 比对 hash 与 ack,输出 STATUS'
|
|
65
|
+
' tf prd check [--template-path <p>] [--plugin-root <p>] # 比对 hash 与 ack,输出 STATUS\n' +
|
|
66
|
+
' tf prd check-clarity <dir|prd.md> # 清晰度机械门(弱词/段/§8.4 漂移),末行 STATUS: PASS | FAIL,FAIL exit 1'
|
|
62
67
|
);
|
|
63
68
|
process.exit(2);
|
|
64
69
|
}
|
|
65
70
|
|
|
71
|
+
/**
|
|
72
|
+
* `tf prd check-clarity`:产品级 PRD 清晰度机械门(agent-governance P0-1,DEC-8a)。
|
|
73
|
+
*
|
|
74
|
+
* 入参 = 目录(自动定位 requirement/vN/prd.md,多个 vN 取最大)或 prd.md 文件路径。
|
|
75
|
+
* 输出末行固定 `STATUS: PASS | FAIL`;**FAIL 时 exit 1**(fail-closed——本命令是门,
|
|
76
|
+
* 不同于 `tf prd check` 的判据工具语义;SKILL 冻结步骤 MUST 读 STATUS 且不得忽略非零退出码)。
|
|
77
|
+
* 判定细节见 scripts/guard/checks/prd-clarity.mjs 头注(规则源 / 豁免边界 / 校准纪律)。
|
|
78
|
+
*/
|
|
79
|
+
function checkClarity(positionalArgs) {
|
|
80
|
+
const target = positionalArgs[0];
|
|
81
|
+
if (!target) usage();
|
|
82
|
+
|
|
83
|
+
let prdPath = target;
|
|
84
|
+
if (fs.existsSync(target) && fs.statSync(target).isDirectory()) {
|
|
85
|
+
prdPath = resolvePrdInDir(target);
|
|
86
|
+
if (!prdPath) {
|
|
87
|
+
console.error(`no requirement/vN/prd.md found under: ${target}`);
|
|
88
|
+
console.log('STATUS: FAIL');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!fs.existsSync(prdPath)) {
|
|
93
|
+
console.error(`PRD file not found: ${prdPath}`);
|
|
94
|
+
console.log('STATUS: FAIL');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const { pass, failures, stats } = checkPrdClarity(prdPath);
|
|
99
|
+
console.log('prd :', prdPath);
|
|
100
|
+
console.log('weak_hits :', stats.weakHits, '| drift_cells:', stats.driftCells,
|
|
101
|
+
'| missing_sections:', stats.sectionsMissing.length ? stats.sectionsMissing.join(',') : '(none)');
|
|
102
|
+
for (const f of failures) console.log(f);
|
|
103
|
+
console.log(`STATUS: ${pass ? 'PASS' : 'FAIL'}`);
|
|
104
|
+
recordClarityResult(pass, prdPath); // P1-1 跨层管道:落产品级记录供 tf state init 拷贝
|
|
105
|
+
if (!pass) process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* P1-1 clarity 跨层管道的写侧:落 `<cwd>/.team-flow/prd-clarity.json`。
|
|
110
|
+
* 消费链 = `tf state init` 拷入 change state(prd_clarity_result/prd_clarity_hash)
|
|
111
|
+
* → guard 维度 `prd-clarity`(checks/prd-clarity-state.mjs)在接活前转换消费。
|
|
112
|
+
* PASS/FAIL 都落盘(fail 记录让绕过 S2 的 direct change 也在变更级被拦——双保险)。
|
|
113
|
+
*/
|
|
114
|
+
function recordClarityResult(pass, prdPath) {
|
|
115
|
+
try {
|
|
116
|
+
const dir = path.join(process.cwd(), '.team-flow');
|
|
117
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
118
|
+
const content = fs.readFileSync(prdPath, 'utf-8');
|
|
119
|
+
const sha = createHash('sha256').update(content).digest('hex');
|
|
120
|
+
fs.writeFileSync(path.join(dir, 'prd-clarity.json'), `${JSON.stringify({
|
|
121
|
+
status: pass ? 'pass' : 'fail',
|
|
122
|
+
prd: prdPath,
|
|
123
|
+
prd_hash: `sha256:${sha}`,
|
|
124
|
+
checked_at: new Date().toISOString(),
|
|
125
|
+
}, null, 2)}\n`);
|
|
126
|
+
} catch {
|
|
127
|
+
// 落盘失败不吞主判定——STATUS 已输出;管道缺失 = 变更级维度走中性,fail-closed 不受影响
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 目录内定位 prd.md:<dir>/prd.md、requirement/ 下最大 vN、或老布局 prd/ 下最大 vN
|
|
133
|
+
* (存量项目用 `prd/vN/prd.md`——2026-09-25 存量校准时实测补上,防新门卡死老布局)。
|
|
134
|
+
*/
|
|
135
|
+
function resolvePrdInDir(dir) {
|
|
136
|
+
const direct = path.join(dir, 'prd.md');
|
|
137
|
+
if (fs.existsSync(direct)) return direct;
|
|
138
|
+
for (const base of ['requirement', 'prd']) {
|
|
139
|
+
const reqDir = path.join(dir, base);
|
|
140
|
+
if (!fs.existsSync(reqDir)) continue;
|
|
141
|
+
const versions = fs.readdirSync(reqDir)
|
|
142
|
+
.filter((n) => fs.existsSync(path.join(reqDir, n, 'prd.md')))
|
|
143
|
+
.sort((a, b) => parseInt(a.replace(/\D/g, ''), 10) - parseInt(b.replace(/\D/g, ''), 10)); // 数值序:v10 > v9(字典序会取错)
|
|
144
|
+
if (versions.length > 0) return path.join(reqDir, versions[versions.length - 1], 'prd.md');
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
66
149
|
/** 读原始配置文件(未与 DEFAULTS 合并),用于区分「用户显式配置」与「默认值」。 */
|
|
67
150
|
function readRawConfig() {
|
|
68
151
|
const p = resolveConfigWritePath(process.cwd());
|
|
@@ -21,6 +21,8 @@ export async function run(args) {
|
|
|
21
21
|
severity: { type: 'string' },
|
|
22
22
|
summary: { type: 'string' },
|
|
23
23
|
source: { type: 'string' },
|
|
24
|
+
// agent-governance P2-1:纠错条目的来源事件锚(HOLD 的 msg_id / 决策日志行)
|
|
25
|
+
'source-event': { type: 'string' },
|
|
24
26
|
// v0.57.0 §4.1:inject 的展示条数控制与 backfill 的预演
|
|
25
27
|
limit: { type: 'string' },
|
|
26
28
|
all: { type: 'boolean' },
|
|
@@ -52,6 +54,7 @@ export async function run(args) {
|
|
|
52
54
|
severity: values.severity,
|
|
53
55
|
summary: values.summary,
|
|
54
56
|
source: values.source,
|
|
57
|
+
source_event: values['source-event'],
|
|
55
58
|
dir: values.dir,
|
|
56
59
|
});
|
|
57
60
|
return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// scripts/lib/cmd-state.mjs — tf state subcommand handler
|
|
2
2
|
import { parseArgs } from 'node:util';
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
|
-
import { existsSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
5
5
|
import path, { dirname, join } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
// VALID_STATES 统一从 state-loader.mjs 引入(状态机合法值唯一真相源),不再本地硬编码。
|
|
@@ -11,6 +11,26 @@ import { computeArtifactsHash, computeContractHash, computeTestMatrixHash } from
|
|
|
11
11
|
|
|
12
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* P1-1:自 changeDir 向上(限 6 层)找 `<root>/.team-flow/prd-clarity.json` 并解析。
|
|
16
|
+
* 找不到 / 解析失败 → null(= 中性,init 不打字段)。
|
|
17
|
+
*/
|
|
18
|
+
function findProductClarityRecord(changeDir) {
|
|
19
|
+
let dir = path.resolve(changeDir);
|
|
20
|
+
for (let i = 0; i < 6; i += 1) {
|
|
21
|
+
const rec = path.join(dir, '.team-flow', 'prd-clarity.json');
|
|
22
|
+
if (existsSync(rec)) {
|
|
23
|
+
const parsed = JSON.parse(readFileSync(rec, 'utf-8'));
|
|
24
|
+
if (parsed && (parsed.status === 'pass' || parsed.status === 'fail')) return parsed;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const parent = path.dirname(dir);
|
|
28
|
+
if (parent === dir) break;
|
|
29
|
+
dir = parent;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
14
34
|
// v0.13 §50(BUG-A 政策修正):test_result 移出可手工设置字段——测试证据必须经
|
|
15
35
|
// tf test record 程序化记录,手工自述值不再被 tests-passing 门禁接受。
|
|
16
36
|
// v0.13 §48.2:test_matrix_skip_reason 可设置(显式 skip 的理由留痕)。
|
|
@@ -121,6 +141,16 @@ export async function run(args) {
|
|
|
121
141
|
const state = readState(changeDir);
|
|
122
142
|
if (!stateFileExisted) {
|
|
123
143
|
state.schema_version = 1;
|
|
144
|
+
// P1-1 clarity 跨层管道:拷贝产品级记录(唯一写入路径——state 字段不在
|
|
145
|
+
// SETTABLE_FIELDS,防自助放行)。find 向上找 <root>/.team-flow/prd-clarity.json。
|
|
146
|
+
// 记录 fail 也拷:绕过 S2 冻结的 direct change 在变更级被 guard 拦下(双保险)。
|
|
147
|
+
try {
|
|
148
|
+
const rec = findProductClarityRecord(changeDir);
|
|
149
|
+
if (rec) {
|
|
150
|
+
state.prd_clarity_result = rec.status === 'fail' ? 'fail' : 'pass';
|
|
151
|
+
state.prd_clarity_hash = rec.prd_hash ?? null;
|
|
152
|
+
}
|
|
153
|
+
} catch { /* 无记录 = 中性,不阻断 init */ }
|
|
124
154
|
// v0.64.0 P0(§4 扫描基线):init 打戳 base_sha(架构 surface 扫描的 git 基线)。
|
|
125
155
|
// 非 git 环境 / 尚无提交 → 保持 null,扫描时按 §4 退化参照(origin → FAIL)。
|
|
126
156
|
try {
|
|
@@ -47,6 +47,26 @@ const DEFAULTS = {
|
|
|
47
47
|
// 各 skill 上下文加载时按 phase 过滤注入
|
|
48
48
|
// 示例: { database: ".team-flow/conventions/db-design.md", ... }
|
|
49
49
|
},
|
|
50
|
+
arch: {
|
|
51
|
+
// C4 代码注解扫描配置(ddd-purity-and-arch-merge-design v1.4 §5.4-4b)。
|
|
52
|
+
// C4 是本机制**唯一**「A 级 · 真独立」锚:锚点 = 代码本体,不经 arch-merge 写路径。
|
|
53
|
+
scan: {
|
|
54
|
+
// 持久化注解名(默认 MyBatis-Plus)。非该框架的项目改此值。
|
|
55
|
+
annotation: 'TableName',
|
|
56
|
+
// 自定义正则源(优先于 annotation)。约定 capture group(1) 为表名。
|
|
57
|
+
pattern: null,
|
|
58
|
+
// 扫描的目标文件扩展名。
|
|
59
|
+
extensions: ['.java'],
|
|
60
|
+
// 多仓场景:扫描根(相对项目根);为空则扫项目根。
|
|
61
|
+
// emp-auth 恰把两仓放在同一工作树,故单根可跑;两仓分属不同 git 仓库时须配置。
|
|
62
|
+
repos: [],
|
|
63
|
+
// 排除目录(按 basename 匹配,任意层级生效)。
|
|
64
|
+
// ★ 必配:emp-auth 根下有 4 个 .worktrees/ 副本,不排除会把同一批注解重复计入。
|
|
65
|
+
// ★ 真相源说明(P3 MIN-4):**强制底线以 `arch-scan-code.mjs` 的 `DEFAULT_EXCLUDE_DIRS`
|
|
66
|
+
// 为准**(并集语义恒生效,配置只能追加)——此处仅是文档性默认值,漂移不影响强制性。
|
|
67
|
+
exclude: ['.worktrees', '.git', 'node_modules', 'target', 'build', 'dist'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
50
70
|
glaf4_dev: {
|
|
51
71
|
// glaf4-dev 运行时探测结果(v2.1 §4 接口①)
|
|
52
72
|
// contract-builder 产出 execution-contract 时实时探测写入;delegation_mode 由用户/编排开关
|
|
@@ -42,6 +42,10 @@ export function run(args = {}) {
|
|
|
42
42
|
const severity = args.severity || 'medium';
|
|
43
43
|
const summary = args.summary || '(no summary)';
|
|
44
44
|
const source = args.source || '';
|
|
45
|
+
// agent-governance P2-1:来源事件锚——correction 条目的毕业条件消费它
|
|
46
|
+
//(P2-2「锚未标撤销」判定;无锚条目按未毕业处理)。HOLD 场景 = escalation msg_id
|
|
47
|
+
// 或决策日志行;非空才写入 frontmatter。
|
|
48
|
+
const sourceEvent = args.source_event || '';
|
|
45
49
|
const dir = args.dir || 'docs/solutions';
|
|
46
50
|
|
|
47
51
|
// 注:process.exit 后补 return——真实 CLI 下 exit 即终止;测试环境 mock exit 时
|
|
@@ -79,6 +83,7 @@ type: ${type}
|
|
|
79
83
|
severity: ${severity}
|
|
80
84
|
date: ${date}
|
|
81
85
|
source: ${source}
|
|
86
|
+
${sourceEvent ? `source_event: ${sourceEvent}` : ''}
|
|
82
87
|
title: ${title}
|
|
83
88
|
---
|
|
84
89
|
|
|
@@ -41,6 +41,34 @@ import { parseFrontmatter, listSolutionEntries } from './solutions-entry.mjs';
|
|
|
41
41
|
/** INDEX 保留的最大**条目数**(非行数——文件还含 4 行头部) */
|
|
42
42
|
export const MAX_INDEX_ENTRIES = 150;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* agent-governance P2-2(earned automation 见习):毕业阈值。
|
|
46
|
+
* `flags` 列派生规则(**纯派生、随重建重算**——INDEX 是投影):
|
|
47
|
+
* - 条目有 `source_event` 锚(P2-1 起的 correction 条目):confirmations ≥ 本阈值 → `auto-ok`,
|
|
48
|
+
* 否则 → `probation`(见习:不进自动注入上下文)。
|
|
49
|
+
* 「锚被标撤销」的毕业否决暂无实现(撤销动作未建,如实声明——source_event 锚已就位,
|
|
50
|
+
* 撤销标记是其消费侧的未来项)。
|
|
51
|
+
* - 无锚存量条目 → `auto-ok`(**grandfather**:它们已在注入通道,见习化 = 行为回退,不采纳;
|
|
52
|
+
* 与 schema_version 存量豁免同构)。
|
|
53
|
+
* - 红区硬排除不在此处:红区判定是**消费侧**职责(inject 按 summary/domain 关键词排除),
|
|
54
|
+
* flags 表示毕业状态、不表示区域。
|
|
55
|
+
*/
|
|
56
|
+
export const GRADUATED_MIN_CONFIRMATIONS = 3;
|
|
57
|
+
|
|
58
|
+
/** 解析 frontmatter confirmations 计数(宽松:仅计数,promote 的严格解析不在此复用)。 */
|
|
59
|
+
function countConfirmations(fm) {
|
|
60
|
+
const raw = fm?.confirmations;
|
|
61
|
+
if (raw == null || raw === '') return 0;
|
|
62
|
+
return String(raw).replace(/[[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).length;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** 派生 flags(见上注释的规则表)。 */
|
|
66
|
+
export function deriveFlags(fm) {
|
|
67
|
+
const hasAnchor = Boolean(fm?.source_event && String(fm.source_event).trim());
|
|
68
|
+
if (!hasAnchor) return 'auto-ok';
|
|
69
|
+
return countConfirmations(fm) >= GRADUATED_MIN_CONFIRMATIONS ? 'auto-ok' : 'probation';
|
|
70
|
+
}
|
|
71
|
+
|
|
44
72
|
/**
|
|
45
73
|
* 解析条目文件的 frontmatter(扁平键值)——**收敛到共享层**(v0.57.0 P4 二轮)。
|
|
46
74
|
*
|
|
@@ -111,6 +139,8 @@ export function refreshIndex(dir, { phases = SOLUTION_PHASES, maxEntries = MAX_I
|
|
|
111
139
|
file: `${phase}/${file}`,
|
|
112
140
|
// v0.57.0 P4:source 进 INDEX 供 inject 做同源聚类(此前只存在于条目文件,消费方读不到)
|
|
113
141
|
source: fm.source || '',
|
|
142
|
+
// P2-2:见习/毕业派生状态(规则见 GRADUATED_MIN_CONFIRMATIONS 注释)
|
|
143
|
+
flags: deriveFlags(fm),
|
|
114
144
|
});
|
|
115
145
|
}
|
|
116
146
|
}
|
|
@@ -133,10 +163,10 @@ export function refreshIndex(dir, { phases = SOLUTION_PHASES, maxEntries = MAX_I
|
|
|
133
163
|
// "只读 INDEX、不读条目文件",故聚类键必须进索引。消费方对 7/8 列都容错(见 solutions-inject)。
|
|
134
164
|
let index = '# Solutions Index\n';
|
|
135
165
|
index += `<!-- 每条一行,排序 severity 降序 → date 降序 → file 兜底,≤${maxEntries} 条上限;summary/source 内的 | 转义为 \\| -->\n`;
|
|
136
|
-
index += '| date | phase | domain | type | severity | summary | file | source |\n';
|
|
137
|
-
index += '
|
|
166
|
+
index += '| date | phase | domain | type | severity | summary | file | source | flags |\n';
|
|
167
|
+
index += '|------|-------|--------|------|----------|---------|------|--------|-------|\n';
|
|
138
168
|
for (const e of kept) {
|
|
139
|
-
index += `| ${escapeCell(e.date)} | ${escapeCell(e.phase)} | ${escapeCell(e.domain)} | ${escapeCell(e.type)} | ${escapeCell(e.severity)} | ${escapeCell(e.summary)} | ${escapeCell(e.file)} | ${escapeCell(e.source)} |\n`;
|
|
169
|
+
index += `| ${escapeCell(e.date)} | ${escapeCell(e.phase)} | ${escapeCell(e.domain)} | ${escapeCell(e.type)} | ${escapeCell(e.severity)} | ${escapeCell(e.summary)} | ${escapeCell(e.file)} | ${escapeCell(e.source)} | ${escapeCell(e.flags)} |\n`;
|
|
140
170
|
}
|
|
141
171
|
|
|
142
172
|
writeFileSync(join(dir, 'INDEX.md'), index, 'utf-8');
|
|
@@ -37,16 +37,31 @@ import { severityRank } from './severity.mjs';
|
|
|
37
37
|
import { parseTableRow } from './md-normalize.mjs';
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* INDEX 表列数范围(date | phase | domain | type | severity | summary | file
|
|
41
|
-
* v0.57.0 P4:`source`
|
|
40
|
+
* INDEX 表列数范围(date | phase | domain | type | severity | summary | file | source | flags)。
|
|
41
|
+
* v0.57.0 P4:`source` 列新增 ⇒ 7/8 都要接受;
|
|
42
|
+
* agent-governance P2-2:`flags` 列(见习/毕业)新增 ⇒ 8(上版重建)与 9(本版)都要接受,
|
|
43
|
+
* **7 列最旧存量同样接受**(flags 缺失 = 无锚存量 = grandfather auto-ok,见 index-gen deriveFlags)。
|
|
42
44
|
*/
|
|
43
45
|
const INDEX_COLUMNS_MIN = 7;
|
|
44
|
-
const INDEX_COLUMNS_MAX =
|
|
46
|
+
const INDEX_COLUMNS_MAX = 9;
|
|
45
47
|
/** `file` 列的形状(`<phase>/<name>.md`)——语义校验,见下方列解析注释 */
|
|
46
48
|
const ENTRY_FILE_RE = /^[a-z][a-z-]*\/.+\.md$/;
|
|
47
49
|
/** 默认展示条数 */
|
|
48
50
|
const DEFAULT_LIMIT = 5;
|
|
49
51
|
|
|
52
|
+
/**
|
|
53
|
+
* P2-2 红区硬排除:DP-A / Code Landing / publish 相关的复利建议**永不自动注入**
|
|
54
|
+
* (memo §2.4 红区护栏——红区永久人工,连"建议"也不自动进上下文,防复利通道
|
|
55
|
+
* 变相给红区动作背书)。宁可少注入(安全方向)不误放。
|
|
56
|
+
*/
|
|
57
|
+
const RED_ZONE_RE = /\bDP-A\b|Code Landing|\bpublish\b|发布闸|代码落地/i;
|
|
58
|
+
|
|
59
|
+
/** P2-2 见习判定:flags 列非 auto-ok(probation 或未知新值)即不自动注入。 */
|
|
60
|
+
function isProbation(flags) {
|
|
61
|
+
const f = String(flags || '').toLowerCase();
|
|
62
|
+
return f !== '' && f !== 'auto-ok';
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
export function run(args = {}) {
|
|
51
66
|
const phase = args.phase || 'cross-phase';
|
|
52
67
|
const domain = args.domain || '';
|
|
@@ -63,6 +78,8 @@ export function run(args = {}) {
|
|
|
63
78
|
|
|
64
79
|
const content = readFileSync(indexPath, 'utf-8');
|
|
65
80
|
const entries = [];
|
|
81
|
+
// P2-2 门控计数(可观察性:跳过多少 = 门在工作的证据)
|
|
82
|
+
const excluded = { probation: 0, redZone: 0 };
|
|
66
83
|
|
|
67
84
|
for (const line of content.split('\n')) {
|
|
68
85
|
if (!line.startsWith('|') || line.startsWith('| date') || line.startsWith('|--')) continue;
|
|
@@ -70,7 +87,7 @@ export function run(args = {}) {
|
|
|
70
87
|
const cells = parseTableRow(line);
|
|
71
88
|
// 上下界同时校验:只查下界无法发现"summary 含 `|` 导致列数变多、file 列错位"(v0.38.0 test-merge 同型缺陷)
|
|
72
89
|
if (cells.length < INDEX_COLUMNS_MIN || cells.length > INDEX_COLUMNS_MAX) continue;
|
|
73
|
-
const [date, ePhase, eDomain, type, severity, summary, file, source = ''] = cells;
|
|
90
|
+
const [date, ePhase, eDomain, type, severity, summary, file, source = '', flags = ''] = cells;
|
|
74
91
|
// file 列语义校验(v0.57.0 P4):列数在界内仍可能错位——例如 summary 含**未转义**的 `|`
|
|
75
92
|
// 时列数恰好落进 7/8 区间,摘要后半段会顶到 file 位。形状不符即丢弃,避免注入错位的路径。
|
|
76
93
|
if (!ENTRY_FILE_RE.test(file)) continue;
|
|
@@ -79,7 +96,10 @@ export function run(args = {}) {
|
|
|
79
96
|
const domainMatch = !domain || !eDomain || eDomain === 'general' || eDomain === domain;
|
|
80
97
|
|
|
81
98
|
if (phaseMatch && domainMatch) {
|
|
82
|
-
|
|
99
|
+
// P2-2 两道消费侧门控(跳过 = 不注入,落 excluded 计数可观察)
|
|
100
|
+
if (isProbation(flags)) { excluded.probation += 1; continue; }
|
|
101
|
+
if (RED_ZONE_RE.test(`${summary} ${eDomain}`)) { excluded.redZone += 1; continue; }
|
|
102
|
+
entries.push({ date, phase: ePhase, domain: eDomain, type, severity, summary, file, source, flags, isNative: ePhase === phase });
|
|
83
103
|
}
|
|
84
104
|
}
|
|
85
105
|
|
|
@@ -119,12 +139,17 @@ export function run(args = {}) {
|
|
|
119
139
|
const shown = all ? clustered : clustered.slice(0, limit);
|
|
120
140
|
|
|
121
141
|
if (shown.length === 0) {
|
|
122
|
-
|
|
123
|
-
|
|
142
|
+
// P2-2:「被门控排除成空」与「本来无匹配」语义不同——前者必须可见,否则门 = 隐形
|
|
143
|
+
const excl = (excluded.probation + excluded.redZone) > 0
|
|
144
|
+
? `(P2-2 门控排除 ${excluded.probation} 条见习 + ${excluded.redZone} 条红区)` : '';
|
|
145
|
+
console.log(`<!-- No matching solutions found (phase=${phase}, domain=${domain || 'any'})${excl} -->`);
|
|
146
|
+
return { entries: [], excluded };
|
|
124
147
|
}
|
|
125
148
|
|
|
126
149
|
const foldedNote = foldedCount > 0 ? `, ${foldedCount} 条同源已折叠` : '';
|
|
127
|
-
|
|
150
|
+
const excludedNote = (excluded.probation + excluded.redZone) > 0
|
|
151
|
+
? `, P2-2 门控排除 ${excluded.probation} 条见习 + ${excluded.redZone} 条红区` : '';
|
|
152
|
+
console.log(`## Solutions Context (phase=${phase}, domain=${domain || 'any'}, showing ${shown.length}/${clustered.length}${foldedNote}${excludedNote})`);
|
|
128
153
|
console.log('');
|
|
129
154
|
for (const e of shown) {
|
|
130
155
|
console.log(`- [${e.severity}] ${e.summary} (${e.phase}/${e.domain}, ${e.date}) → ${e.file}`);
|
|
@@ -140,7 +165,7 @@ export function run(args = {}) {
|
|
|
140
165
|
console.log('');
|
|
141
166
|
}
|
|
142
167
|
|
|
143
|
-
return { entries: shown, total: clustered.length, folded: foldedCount, hidden };
|
|
168
|
+
return { entries: shown, total: clustered.length, folded: foldedCount, hidden, excluded };
|
|
144
169
|
}
|
|
145
170
|
|
|
146
171
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
@@ -89,6 +89,11 @@ const BUILTIN_DEFAULTS = {
|
|
|
89
89
|
test_matrix_skip_reason: null,
|
|
90
90
|
// Test evidence (v0.13 §50:tf test record 落盘的 runner 输出证据路径)
|
|
91
91
|
test_evidence_path: null,
|
|
92
|
+
// Product-level PRD clarity record(agent-governance P1-1 跨层管道):
|
|
93
|
+
// 唯一写入路径 = tf state init 从 <root>/.team-flow/prd-clarity.json 拷贝;
|
|
94
|
+
// **有意不在 cmd-state SETTABLE_FIELDS**——可 set 就是自助放行通道(gate-hint-is-a-bypass)。
|
|
95
|
+
prd_clarity_result: null,
|
|
96
|
+
prd_clarity_hash: null,
|
|
92
97
|
// Tasks gate (v0.22 §85:hotfix/tweak 跳过 spec-writer 时显式跳过 tasks.md)
|
|
93
98
|
tasks_skipped: null,
|
|
94
99
|
tasks_skip_reason: null,
|
|
@@ -184,6 +189,14 @@ export function writeState(changeDir, state) {
|
|
|
184
189
|
lines.push('# === Hashes (fast staleness detection) ===');
|
|
185
190
|
lines.push(`artifacts_hash: ${state.artifacts_hash ?? 'null'}`);
|
|
186
191
|
lines.push(`contract_hash: ${state.contract_hash ?? 'null'}`);
|
|
192
|
+
// P1-1 clarity 管道:条件序列化(同 schema_version 模式)——存量 change 无记录不追加,
|
|
193
|
+
// readState 缺失回退 BUILTIN_DEFAULTS 的 null(= 变更级维度中性)。
|
|
194
|
+
if (state.prd_clarity_result != null) {
|
|
195
|
+
lines.push(`prd_clarity_result: ${state.prd_clarity_result}`);
|
|
196
|
+
}
|
|
197
|
+
if (state.prd_clarity_hash != null) {
|
|
198
|
+
lines.push(`prd_clarity_hash: ${state.prd_clarity_hash}`);
|
|
199
|
+
}
|
|
187
200
|
lines.push('');
|
|
188
201
|
lines.push('# === Execution progress ===');
|
|
189
202
|
lines.push(`execution_mode: ${state.execution_mode ?? 'null'}`);
|
package/scripts/team-flow.mjs
CHANGED
|
@@ -71,6 +71,9 @@ Commands:
|
|
|
71
71
|
arch scaffold Scaffold global docs/architecture/ ledger in generator format (v0.53.0 §102)
|
|
72
72
|
arch precheck <change-dir> [--json]
|
|
73
73
|
Emit deterministic architecture-gate evidence (v0.22 §88; evidence only, exit 0)
|
|
74
|
+
arch scan-code [--root <path>|--project-root <path>] [--repos <a,b>] [--annotation <name>] [--exclude <a,b>] [--json]
|
|
75
|
+
Scan code for persistence annotations (C4 anchor; v1.4 §5.4-4b;
|
|
76
|
+
read-only, zero-dep, evidence only, exit 0; status=na N/A, status=partial partial coverage — neither is PASS)
|
|
74
77
|
arch-merge <change-dir> [--project-root <path>] [--dry-run] [--light]
|
|
75
78
|
Merge architecture delta into global docs/architecture/
|
|
76
79
|
test-merge <change-dir> [--project-root <path>] [--dry-run] [--light]
|
|
@@ -22,7 +22,7 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
|
|
|
22
22
|
实体(唯一标识)+值对象(无标识)+聚合根(唯一入口)+事务边界(聚合内一事务)。聚合仅存于业务服务;数据服务/技术服务无聚合。
|
|
23
23
|
|
|
24
24
|
### F5 · 限界上下文(Context Map)
|
|
25
|
-
语义边界=L3
|
|
25
|
+
语义边界=L3 应用服务;同术语异义须显式映射——**经典 8 模式**(Shared Kernel / Customer-Supplier / Conformist / Anti-Corruption Layer / Open Host Service / Separate Ways / Partnership / Published Language),选型走决策流(`references/context-map-8.md`,含 Mermaid;CML NO-GO)。
|
|
26
26
|
|
|
27
27
|
### F6 · CQRS 写读模型
|
|
28
28
|
事务型对象→写模型(聚合,Command/Read 操作);分析型对象→读模型(查询模型,Query 派生,无事务)。Command/Read→写模型;Query 经阻断测试分流。
|
|
@@ -37,7 +37,7 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
|
|
|
37
37
|
- ch01-4a-domains — 4A 四域定义与分叉依赖
|
|
38
38
|
- ch02-change-cascade — 变更级联与跨域一致性门禁
|
|
39
39
|
- ch03-architecture-outputs — 架构产出三层 + 治理三支柱
|
|
40
|
-
- ch04-entity-to-aggregate —
|
|
40
|
+
- ch04-entity-to-aggregate — 业务实体→聚合→子域→限界上下文
|
|
41
41
|
- ch05-cqrs — 写/读模型、指令分流、三维判定
|
|
42
42
|
- ch06-integration — 与 team-flow / compound-engineering 的集成
|
|
43
43
|
|
|
@@ -54,6 +54,11 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
|
|
|
54
54
|
- Command / Read / Query → ch05
|
|
55
55
|
- 阻断测试 / 三维判定 → ch05
|
|
56
56
|
- 增量设计 / As-Is 冻结 / 复利回写 / 全局锚点 → ch06
|
|
57
|
+
- 子域 / 问题空间·解空间 / 统一语言索引 → ch04, 产品级模板 §0/§1.1(O2/O3)
|
|
58
|
+
- Context Map 8 模式 / 决策流 / Mermaid → references/context-map-8.md(O7)
|
|
59
|
+
- 事件 schema 版本策略 / 领域事件表 → 产品级模板 §3.2 门禁段 + 变更级模板 §2.5(O4)
|
|
60
|
+
- Saga 补偿矩阵 / Projection 重建 / ADR 模板 → references/ddd-evented-playbook.md, references/adr-templates.md(O5/O6)
|
|
61
|
+
- DDD 深度 advisory / ddd_depth(lightweight≠skipped)→ 「DDD 深度 advisory」段 + 结构化输出契约(O1)
|
|
57
62
|
|
|
58
63
|
## Workflow Integration: 判断+执行一体化(v0.9 §26)
|
|
59
64
|
|
|
@@ -67,10 +72,19 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
|
|
|
67
72
|
|
|
68
73
|
- `change-brief.md`(scope / AC / 技术方向)
|
|
69
74
|
- `requirement/vN/plan.md` 高阶技术设计段(模块边界/技术选型/数据流/关键聚合划分)
|
|
70
|
-
- `docs/architecture/iterations/vN/architecture.md
|
|
75
|
+
- `docs/architecture/iterations/vN/architecture.md`(产品级架构快照,**设计期主输入**,v0.35.0)——BC 边界/聚合所有权/全局契约的设计输入(★ O8:**落地态权威 = 全局 ARCHITECTURE.md**(registry 渲染),快照 = grounding + seed 源 + 体检基准,不称唯一事实源);**Fast Path 下不读**(见 `### Fast Path`)
|
|
71
76
|
- 全局 `docs/architecture/`(As-Is 实际态基线,已落地部分)
|
|
72
77
|
- 现有 `specs/`(若有)
|
|
73
78
|
|
|
79
|
+
### DDD 深度 advisory(O1 · 在五项检查**之前**执行)
|
|
80
|
+
|
|
81
|
+
按**领域复杂度**输出 DDD 深度旗标(advisory,**绝不替代 `decision`**):
|
|
82
|
+
|
|
83
|
+
- **三判据**(禁「4 选 2」硬阈值,防 LLM 套用偏差放大):① 是否有丰富行为/不变量 ② 是否存在模型冲突(同词异义/多义) ③ 是否存在值得深建模的 Core Domain。
|
|
84
|
+
- 输出 `ddd_depth: full | lightweight`。吸收「3 Questions + 反模式红牌」(微服务过早 / CQRS / 事件溯源 / DDD / Repository 可能过度工程)。
|
|
85
|
+
- **★ 头号红牌:`lightweight ≠ skipped`**——lightweight 分支**仍须走完五项检查,且第 4/5 项(API / DB schema)不得短路**;只是战术建模从简(可省略部分 DDD 战术制品),判定与 API/DB 设计照做。
|
|
86
|
+
- **诚实边界**:LLM 是否把 lightweight 误当"可跳过"**无法机械观测**——由契约正交 lint 与步骤表静态检查收敛路径,行为层保留人审(§10 风险如实登记)。
|
|
87
|
+
|
|
74
88
|
### 五项检查(架构变更判定)
|
|
75
89
|
|
|
76
90
|
依次检查以下五项,**全部为否** → `decision: skipped`;**任一为是** → `decision: required`:
|
|
@@ -111,25 +125,23 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
|
|
|
111
125
|
**流程**(不硬阻断,显式确认 + 登记 deviation):
|
|
112
126
|
1. **呈现变更摘要**:涉及的产品级决策 + 影响范围(引用快照章节)
|
|
113
127
|
2. **用户确认**(阻塞问题工具):接受 → 执行变更;拒绝 → 保持产品级定义,change 内走增量
|
|
114
|
-
3. **登记 deviation**:确认后写入 `orchestrator.yaml` 的 `replan_log`(`seq/trigger: arch-deviation/before/after/approved_by
|
|
128
|
+
3. **登记 deviation**:确认后写入 `orchestrator.yaml` 的 `replan_log`(`seq/trigger: arch-deviation/before/after/approved_by`——**可机读唯一落点**);**Rationale/Consequences 按 `references/adr-templates.md` 选型**(五模板;仅「难逆转 ∧ 无上下文会困惑 ∧ 真实权衡」三条件全满足才写完整 ADR,否则 replan_log 一行即可,防泛滥;**不另起 `docs/adr/`**,防双轨漂移)+ 在 `iterations/vN/architecture.md` 演进日志追加修订记录(迭代收尾 S3.5 确认晋升)
|
|
115
129
|
4. **`new` 聚合 flag**:在 `iterations/vN/architecture.md` 聚合注册表标注 `[pending-promotion]`,待下一迭代产品级晋升
|
|
116
130
|
|
|
117
131
|
### 执行流程
|
|
118
132
|
|
|
119
133
|
```
|
|
120
134
|
1. 读取输入(brief + plan + specs + 全局 ARCHITECTURE.md)——**Fast Path 裁剪为「brief + precheck 输出」**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
→ reason: 简述不涉及架构变更的理由
|
|
125
|
-
→ 返回结构化输出
|
|
135
|
+
1.5 DDD 深度 advisory(领域复杂度三判据 → ddd_depth: full | lightweight;advisory,不影响 decision)
|
|
136
|
+
2. 执行五项检查(ddd_depth: lightweight 分支**同样执行全部五项**,第 4/5 项不得短路)
|
|
137
|
+
3. 全部为否 → decision: skipped + reason(不涉及架构变更)→ 返回结构化输出(含 ddd_depth)
|
|
126
138
|
4. 任一为是:
|
|
127
139
|
→ decision: required
|
|
128
140
|
→ reason: 简述涉及的架构变更项
|
|
129
|
-
→
|
|
141
|
+
→ 执行 4A+DDD 增量设计(F1-F8;ddd_depth: lightweight 时战术制品从简,API/DB 产出不减)
|
|
130
142
|
→ 产出 architecture/architecture.md + database.md + api.md
|
|
131
143
|
→ artifacts: 产出路径列表
|
|
132
|
-
→
|
|
144
|
+
→ 返回结构化输出(含 ddd_depth)
|
|
133
145
|
```
|
|
134
146
|
|
|
135
147
|
### 结构化输出契约
|
|
@@ -137,6 +149,8 @@ description: 基于 4A 企业架构 + DDD 领域驱动设计的架构/API/DB 设
|
|
|
137
149
|
返回给 workflow-start 的结果**必须**包含以下字段:
|
|
138
150
|
|
|
139
151
|
```yaml
|
|
152
|
+
ddd_depth: full | lightweight # O1 advisory:与 decision **正交**——任意组合合法;
|
|
153
|
+
# 禁止从 lightweight 推导/默认出 skipped(契约正交 lint 锁定)
|
|
140
154
|
decision: required | skipped
|
|
141
155
|
reason: "..." # skipped 时:不涉及架构变更的理由
|
|
142
156
|
# required 时:涉及的变更项摘要
|
|
@@ -146,6 +160,10 @@ artifacts: # required 时必填,skipped 时为空
|
|
|
146
160
|
- architecture/api.md
|
|
147
161
|
```
|
|
148
162
|
|
|
163
|
+
> **schema 正交(O1 判据①,规则文本 lint)**:`ddd_depth ∈ {full, lightweight}` 与 `decision ∈ {required, skipped}`
|
|
164
|
+
> 同时存在、取值域独立、**任意组合合法**(lightweight+required / lightweight+skipped / full+required / full+skipped 全允许)——
|
|
165
|
+
> schema 层**不得**出现 `lightweight → skipped` 的推导或默认值。该 lint 校验的是**我们写下的规则文本自洽**,不校验 LLM 实际判定(诚实边界见 advisory 段)。
|
|
166
|
+
|
|
149
167
|
**职责边界**:architecture-design 负责**判断+产出**(五项检查判断是否涉及架构变更,涉及则产出架构设计文档),workflow-start 负责**reasonableness check + 状态写入**(确认判断合理性后写入 yaml)。
|
|
150
168
|
|
|
151
169
|
### 产出目录
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ch04 ·
|
|
1
|
+
# ch04 · 业务实体→聚合→子域→限界上下文
|
|
2
2
|
|
|
3
3
|
## 业务实体(识别起点)
|
|
4
4
|
- 定义:BA 流程中的**表证单书**(订单/合同/工单/客户档案/库存记录),是业务概念而非数据库表。
|
|
@@ -15,12 +15,23 @@
|
|
|
15
15
|
- 事务边界:聚合内所有操作须在一个事务完成(如创建订单同时建头/行项目/算总价)。
|
|
16
16
|
- **硬规则**:聚合仅存在于业务服务;数据服务(跨聚合查询分析)、技术服务(消息队列)**无聚合**。
|
|
17
17
|
|
|
18
|
-
##
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
## 子域(问题空间 · 投资分级)
|
|
19
|
+
- **子域(Subdomain)**:业务问题空间的分区(Vernon《IDDD》),先于解空间存在;子域 → 限界上下文是**多对多映射**(一个 BC 常服务多个子域),不是 1:1。
|
|
20
|
+
- **三分类**:**Core**(核心竞争力,深建模)/ **Supporting**(保障性,最小定制)/ **Generic**(通用能力,买或复用)——**分类驱动 BC 投资**。
|
|
21
|
+
- **纪律**:子域描述只写**业务问题**,不列 service / 包名 / 类名(问题空间 ≠ 解空间;按实现载体划子域/BC 是已知失效模式,须人审)。
|
|
22
|
+
|
|
23
|
+
## 限界上下文 / Context Map(核心框架 F5 · 经典 8 模式,O7)
|
|
24
|
+
- 限界上下文=语义边界,对应 L3 应用服务;相关聚合组成上下文(**解空间,≠ 子域**)。
|
|
25
|
+
- 同术语异义须显式映射——**8 模式全集**(与产品级模板 §1.2 同步,教 = 用):
|
|
26
|
+
- **Separate Ways**:不集成(先问要不要集成再选型)。
|
|
27
|
+
- **Partnership**:对等团队共同演进、双向承诺。
|
|
28
|
+
- **Customer-Supplier**:供需协商契约。
|
|
29
|
+
- **Conformist**:下游全盘接受上游模型。
|
|
30
|
+
- **Open Host Service**:上游开放标准协议供多下游消费。
|
|
31
|
+
- **Anti-Corruption Layer**:下游翻译上游模型,防止概念泄漏。
|
|
32
|
+
- **Shared Kernel**:两上下文共享部分模型,变更须协商。
|
|
33
|
+
- **Published Language**:标准化语义词汇(与 OHS 天然配对)。
|
|
34
|
+
- **决策流与 Mermaid 生成**:见 `references/context-map-8.md`(选型顺序 Separate Ways → Partnership → Customer-Supplier → Conformist → OHS+PL → ACL → Shared Kernel;CML DSL 导出 = NO-GO)。
|
|
24
35
|
|
|
25
36
|
## 应用提示
|
|
26
37
|
- 每变更设计先画"涉及实体的活动对象矩阵";再定聚合根与事务边界;最后落到全局 Context Map。
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
```
|
|
7
7
|
项目根/
|
|
8
8
|
├── STRATEGY.md # 产品/BA 锚点(compound,不动)
|
|
9
|
-
├── CONCEPTS.md # 领域词汇(追加 DDD 术语,复利累积)
|
|
10
9
|
├── docs/architecture/ # 【技术锚点层,独立于 STRATEGY.md】
|
|
10
|
+
│ ├── CONCEPTS.md # ★ 业务统一语言唯一内容写入点(per-BC 业务术语定义)+ DDD 方法术语,复利累积
|
|
11
|
+
│ │ # 快照 §0 只是其 per-BC 索引(术语→锚点,不含定义)——零双写,见 O2
|
|
11
12
|
│ ├── ARCHITECTURE.md # 全局架构(瘦锚点:Context Map+聚合清单+关键决策)
|
|
12
13
|
│ └── DATABASE.md # 全局 DB(实体+读写模型+OLTP/OLAP)
|
|
13
14
|
|
|
@@ -28,13 +29,21 @@ changes/<name>/ # change 容器
|
|
|
28
29
|
|
|
29
30
|
> **语义分离**:架构产出独立 `architecture/` 目录,不混入 `specs/`(行为规格)。目录存在 = 有架构产出,目录不存在 = 判定为不需要。下游消费方(spec-writer / release-archivist)显式读取此目录。
|
|
30
31
|
|
|
32
|
+
## CONCEPTS.md 维护(O2 · 业务统一语言)
|
|
33
|
+
|
|
34
|
+
- **两段拆分**:`docs/architecture/CONCEPTS.md` 内容组织分「**技术层角色词汇**」与「**per-BC 业务统一语言**」两段——技术分层角色(infra / agg / adapter / bff 等)**不是领域词**,不得混入业务段(消 emp-auth 审计 B6/B7 技术 jargon 污染)。
|
|
35
|
+
- **主动纪律(活的语言,非静态表)**:① **挑战术语**——业务术语首现即问"业务方听得懂吗";② **锐化模糊语**——歧义词当场拆义项,不带病累积;③ **场景压测**——拿真实业务场景验证术语覆盖度;④ **对照代码**——术语与代码标识符互查漂移(LLM 生成的 UL **必须人审**,防幻觉领域概念)。
|
|
36
|
+
- 快照 §0 只维护索引(per-BC 术语 → 锚点);本文件的更新触发时机靠流程纪律(**无机械门禁**,方案 CQ-12 已登记),由迭代收尾人审把关。
|
|
37
|
+
|
|
31
38
|
## 每变更增量设计(SOP 步骤,v0.35.0 更新:产品级快照为输入)
|
|
32
|
-
1. (LLM) 读全局 ARCHITECTURE.md **+ 产品级快照 `iterations/vN/architecture.md`**(v0.35.0
|
|
39
|
+
1. (LLM) 读全局 ARCHITECTURE.md **+ 产品级快照 `iterations/vN/architecture.md`**(v0.35.0 作 grounding;★ O8 修正:**落地态权威 = 全局 ARCHITECTURE.md marker 区**(registry 渲染、source 列归因),快照承担 grounding + 首次 seed + 差异体检基准三角色——**不再称"唯一事实源"**,forward-designed 快照是预测态);识别本 change 触及的 BC → 按 `references/s3.5-loading-protocol.md` 三段式装载对应域;用活动对象矩阵识别限界上下文/聚合(变更级只引用产品级注册表,不重定义)。
|
|
33
40
|
2. (LLM) 出 To-Be:**本 change 增量**(extend/new/refactor 三类动作)——新增/调整聚合、Context Map 关系、CQRS 读写模型、4A 跨域对齐;触及产品级决策走架构修订决策门。
|
|
34
41
|
3. **As-Is 冻结**(核心修正):复制产品级快照/全局相关章节**当前原文** + 记版本锚点(`iterations/vN/architecture.md@<change_id>#<章节>`),变更内不可变——杜绝活引用漂移。
|
|
35
42
|
4. (脚本) 填 frontmatter 并校验:`cap_id/date/change_type/bounded_contexts/aggregates_affected/cqrs`。
|
|
36
43
|
5. (LLM) 写 ADR 理由;API 标 Command/Read/Query + 阻断测试归属。
|
|
37
|
-
6. (
|
|
44
|
+
6. (LLM→脚本) **O8 两段式回写**:先(LLM 语义段)从本 change 制品产 `architecture/.arch-delta.json`
|
|
45
|
+
(new/extend/refactor/retire + evidence,见 release-archivist ①-pre);再(CLI 确定段)`tf arch-merge`
|
|
46
|
+
消费该制品合并进 `docs/architecture/.registry/registry.json` 并生成全局产物(确定段零 LLM,可重放)。
|
|
38
47
|
|
|
39
48
|
## 复利回写(借鉴 ce-compound,已正名)
|
|
40
49
|
- **one change per run**:一次回写一个变更 delta,可追溯、不混杂。
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Glossary · 架构设计术语表
|
|
2
2
|
|
|
3
|
+
> **本表是方法论术语表**(4A / DDD 概念),**不是业务域统一语言**——per-BC 业务术语的唯一内容写入点是 **`docs/architecture/CONCEPTS.md`**(根位置自 v0.23.0 已弃用),快照 §0 只是其索引(O2)。
|
|
4
|
+
|
|
3
5
|
- **BA / IA / AA / TA**:业务/信息(数据)/应用(功能)/技术 架构四域。仅 TA 是技术架构。
|
|
6
|
+
- **子域(Subdomain)**:业务**问题空间**的分区,先于解空间存在;Core/Supporting/Generic 三分类驱动投资。
|
|
7
|
+
- **问题空间 / 解空间**:问题空间 = 业务问题与子域(做什么);解空间 = 限界上下文与聚合(怎么做)。子域 → BC 多对多映射,**不是 1:1**;按实现载体(service/包)划子域是已知失效模式。
|
|
4
8
|
- **分叉依赖**:`BA→(IA∥AA)→TA`,BA 先行、IA/AA 并行双向对齐、TA 最后。
|
|
5
9
|
- **跨域一致性(双对齐)**:AA 功能≥1 IA 实体支撑,IA 实体≥1 AA 功能消费;结构+语义双对齐。
|
|
6
10
|
- **架构产出三层**:元素(积木)/制品(图纸)/交付件(成品)。
|
|
@@ -9,7 +13,7 @@
|
|
|
9
13
|
- **聚合(Aggregate)**:实体+值对象+聚合根+事务边界;仅存业务服务。
|
|
10
14
|
- **聚合根(Aggregate Root)**:聚合外部唯一入口。
|
|
11
15
|
- **值对象(Value Object)**:无独立标识,属性变即另一对象。
|
|
12
|
-
- **限界上下文(Bounded Context)**:语义边界,对应 L3
|
|
16
|
+
- **限界上下文(Bounded Context)**:语义边界,对应 L3 应用服务;属**解空间**,不等于子域。
|
|
13
17
|
- **Context Map**:限界上下文间关系图;映射类型 Shared Kernel / Anti-Corruption Layer / Open Host Service。
|
|
14
18
|
- **CQRS**:写模型(事务型,聚合)与读模型(分析型,查询模型)分离建模。
|
|
15
19
|
- **写模型(Write Model)**:事务型对象在 AA 的表达,有聚合根/事务边界,Command/Read 操作。
|