Skip to content

Commit ea34406

Browse files
committed
feat: unify profile generation lifecycle
1 parent 31b70d4 commit ea34406

24 files changed

Lines changed: 1001 additions & 112 deletions

‎README.md‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ DevCodex 通过 `.github/`(Copilot)、`CLAUDE.md + .claude/ + .mcp.json`(C
6262
- **授权本地安全审查呈现**: `AuthorizedLocalSecurityAuditPresentationGate` 由 `security-threat-modeling` 承接,分离用户可见最小证据和隔离本地探针;内容不可见或额外安全检查发生时保存 `SafetyInterruptionCard` 并从文件真相/审查状态恢复,不把表达调整描述成绕过平台控制。V89 验证授权、证据预算与恢复链。
6363
- **发布凭据拓扑**: `PublisherCredentialTopologyGate` 由 `release-verification` 承接;首次发布或 publisher/repository/package/registry/auth topology 变化时核对发布身份、secret scope/access/inheritance、workflow permission、package ownership 和最近成功 run。只验证拓扑,不读取或输出 secret value;普通 patch 可记录 unchanged evidence。V90 与 R0~R7 共同守门。
6464
- **scoped registry 目标解析**: `ScopedRegistryResolutionGate` 由 `release-verification` 承接;scoped package 双仓发布必须同时冻结 global registry、`@scope:registry`、userconfig 与命令级 override,用隔离配置或显式 scope override 证明两通道独立解析。V92 与 targeted fixture 防止相同 scope 路由制造双仓假阳性。
65-
- **Profile 三档闭环校验**: Profile 按 `profile-lite` / `profile-standard` / `profile-closed-loop` 三档维护,执行 `ProfileTierStandardGate` 与 `ProfileLifecycleClassificationGate` 区分稳定基线、活文档和条件 / 本地文档;规范维护、SDK/CLI、文档站、public API 或用户要求全工作区校验时执行 `AllDevCodexProfileValidationGate`,通过 `node scripts/validate-all-profiles.js --workspace <workspace-root>` 扫描 `.devcodex/workspace/profile` 与 `.devcodex/<project>/profile`
65+
- **Profile 生成与三档闭环校验**: `ProfileGenerationContractGate` 统一 `profile-lite` / `profile-standard` / `profile-closed-loop` 的生成、加载、状态和校验契约;`FeatureInventorySchemaGate` 要求规范功能清单使用 `FeatureInventorySchemaV1`,`ProfileTierMigrationSafetyGate` 保证 plan/dry-run 零写入、升级保留正文、降档显式授权;`ProfileTierStandardGate`、`ProfileLifecycleClassificationGate` 与 `AllDevCodexProfileValidationGate` 继续负责档位、生命周期和全工作区校验
6666
- **项目工程泄漏审查**: 项目工程 / 代码质量审查执行 `PE-12 资源生命周期与泄漏风险`,必须检查内存泄露、资源泄漏、监听器/定时器/连接/流未释放、缓存无界增长和组件卸载清理缺失
6767
- **泄漏风险稳定性压测**: 写测试用例或回归验证时先执行 `LeakRiskStabilityPressureTest` 条件判定;命中长运行、高并发、缓存/连接/监听器/定时器/流/socket/worker/订阅/组件生命周期或 `PE-12` 风险时,TestRoute 纳入场景/负载/稳定性压测并记录基线、冷却后回落和资源指标前后对比;低风险任务写 `N/A + skipReason`
6868
- **coverage 与外部 runtime 生命周期验证**: 项目存在 coverage 阈值、CI coverage 或发布覆盖率要求时执行 `CoverageGateDecision`,区分断言通过与覆盖率门禁通过;外部 runtime/plugin/registry/adapter/provider、injected runtime、owner mutation 或 function source fingerprint 风险执行 `ExternalRuntimePluginLifecycleGate`、`ExternalRegistryLifecycleMatrixGate`、`FunctionSourceFingerprintMatrixGate`、`ClusterEscalationGate` 与 `RiskBasedValidationLadder`
@@ -304,6 +304,26 @@ devcodex migrate-layout rollback --manifest <manifest-path>
304304

305305
> 真相源说明:只有在 `layout.json` 已创建后,runtime / MCP / profile init 才会按 `.devcodex/workspace` 和 `.devcodex/<project>` 解析;未启用时继续兼容旧的 `<project>/.devcodex/`。启用后不得再向 `<project>/.devcodex/.tmp` 等旧项目内运行态目录写入产物。
306306
307+
## Profile 计划、生成与升级
308+
309+
> 发布状态:以下 `profile plan`、统一分档生成和安全迁移行为属于当前仓库的 **unreleased** 变更;正式包发布前,已安装的 v1.13.0 仍以其内置 CLI 为准。
310+
311+
先预览,再写入:
312+
313+
```bash
314+
devcodex profile plan
315+
devcodex profile plan --tier profile-standard
316+
devcodex profile init --tier profile-standard
317+
devcodex status
318+
```
319+
320+
- 首次创建默认目标是 `profile-lite`,命令会另外显示基于 package、脚本和目录证据得出的推荐档位;只有显式 `--tier` 才升级。
321+
- 已有 Profile 默认继承当前档位;升级只补缺失文件并保留原正文。显式降档必须追加 `--allow-downgrade`,高档文件仍会保留。
322+
- `profile plan` 等价于安全预览,和 `profile init --dry-run` 一样不会创建目录、文件或备份;`--force` 会在覆盖前备份。
323+
- 三档默认生成矩阵为 **5 / 8 / 9**:lite 生成 README、01~03、config;standard 再生成 04/05/06;closed-loop 再生成 07。规范清单采用 `FeatureInventorySchemaV1` 十字段表,扫描无法证明的事实保持 `unverified`,不会伪装成已发布能力。
324+
325+
完整命令、三档文件矩阵、迁移和排错见 [Profile 使用指南](./website/docs/guide/profile.md)。
326+
307327
## 本地开发
308328

309329
```bash

‎changelogs/unreleased.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@
88

99
## 当前未发布变更
1010

11-
> 暂无。上一批变更已归档到 `changelogs/releases/v1.13.0.md`;后续未发布实现继续按日期倒序追加。
11+
### 2026-07-14 — Profile 生成契约与功能清单闭环
12+
13+
- 新增 `ProfileGenerationContractGate`:`mcp/profile-contract.js` 成为三档文件集合、语义检查和功能清单 schema 的共享契约;CLI、加载器、状态和 validator 统一消费,默认生成矩阵固定为 5 / 8 / 9。
14+
- 新增 `devcodex profile plan` 与真实 `--dry-run` 零写入预览,展示目标根、已检测/请求/推荐/目标档位和逐文件动作;未知参数与非法档位友好失败。
15+
- 新增 `ProfileTierMigrationSafetyGate`:默认继承已有档位,升级只补缺失文件并保留正文,未授权降档拒绝,`--allow-downgrade` 仅调整声明并保留高档文件,`--force` 先备份。
16+
- 新增 `FeatureInventorySchemaGate` / `FeatureInventorySchemaV1` 十字段规范表;校验器拒绝空表、纯项目符号、占位行、伪来源、01/06 重复规范真相源及裸版本号发布状态冲突。
17+
- 强化 V83:除消费者术语同步外,执行 Profile validator 与 CLI 行为负向探针,覆盖 dry-run 写入、隐式降档、冲突档位、非结构化/空清单和重复 canonical source 假阳性。
18+
- 同步 `profile-bootstrap`、`load-profile`、`dev-init`、Profile Prompt、TestRoute、report、README、website Profile 使用指南、active Profile 与部署副本;全工作区校验由 `AllDevCodexProfileValidationGate` 收口。
1219

1320
## 记录提示
1421

‎index.js‎

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ const {
2424
writeManifestAtomic
2525
} = require('./scripts/lib/deployment-manifest-utils.js')
2626
const { runCli: runMigrateLayout } = require('./scripts/migrate-layout.js')
27-
const { detectProfileTier, filesForProfileTier, inspectProfileContract, normalizeProfileTier } = require('./mcp/profile-contract.js')
27+
const {
28+
detectProfileTier, filesForProfileTier, inspectProfileContract, normalizeProfileTier,
29+
compareProfileTiers, updateProfileTierDeclaration, FEATURE_INVENTORY_SCHEMA_VERSION,
30+
FEATURE_INVENTORY_COLUMN_LABELS
31+
} = require('./mcp/profile-contract.js')
2832
const {
2933
findLayoutInfo: sharedFindLayoutInfo,
3034
inferProjectFromCwd: sharedInferProjectFromCwd,
@@ -344,6 +348,7 @@ const {
344348
genTestSpec,
345349
genReleaseSpec,
346350
genFeatureInventory,
351+
recommendProfileTier,
347352
genUserContractSpec,
348353
genConfigJson,
349354
detectAgent
@@ -352,7 +357,9 @@ const {
352357
path,
353358
detectHostPlatform,
354359
detectInstalledHostAssets,
355-
processEnv: process.env
360+
processEnv: process.env,
361+
featureInventorySchemaVersion: FEATURE_INVENTORY_SCHEMA_VERSION,
362+
featureInventoryColumnLabels: FEATURE_INVENTORY_COLUMN_LABELS
356363
})
357364

358365
const { cmdInit, cmdInitClaude, cmdInitCodex } = buildCliInstallCommands({
@@ -373,14 +380,14 @@ const { cmdInit, cmdInitClaude, cmdInitCodex } = buildCliInstallCommands({
373380
function inspectProfileState(profileDir) {
374381
let availableFiles = []
375382
try { availableFiles = fs.readdirSync(profileDir).filter(file => fs.statSync(path.join(profileDir, file)).isFile()) } catch { }
376-
const corpus = availableFiles.filter(file => file.endsWith('.md'))
377-
.map(file => {
378-
try { return fs.readFileSync(path.join(profileDir, file), 'utf8') } catch { return '' }
379-
}).join('\n')
383+
const documents = Object.fromEntries(availableFiles.filter(file => file.endsWith('.md')).map(file => {
384+
try { return [file, fs.readFileSync(path.join(profileDir, file), 'utf8')] } catch { return [file, ''] }
385+
}))
386+
const corpus = Object.values(documents).join('\n')
380387
let tier = 'profile-lite'
381388
let error = null
382389
try { tier = detectProfileTier(corpus) } catch (err) { error = err.message }
383-
const state = inspectProfileContract(tier, availableFiles, corpus)
390+
const state = inspectProfileContract(tier, availableFiles, corpus, documents)
384391
const configExists = fs.existsSync(path.join(profileDir, 'config.json'))
385392
return { ...state, complete: !error && state.complete, configExists, error }
386393
}
@@ -390,9 +397,11 @@ const { cmdStatus, cmdProfileInit, cmdDoctor, cmdHelp } = buildCliMaintenanceCom
390397
walkDir, isSourceRepo, resolveActiveRuntimeRoot, resolveProfileDir, getLegacyCounts,
391398
getCodexConfigState, inspectProfileState, detectProfileTier,
392399
inspectProfileContract, normalizeProfileTier, filesForProfileTier,
400+
compareProfileTiers, updateProfileTierDeclaration,
393401
readJsonSafe, safeFirstLine, detectArch, listTopDirs, detectStyle,
394402
genProfileReadme, genProjectInfo, genArchitecture, genStyle, genTestSpec,
395403
genReleaseSpec, genFeatureInventory, genUserContractSpec, genConfigJson,
404+
recommendProfileTier,
396405
detectAgent, detectHostPlatform, detectInstalledHostAssets
397406
})
398407

‎instructions/01a-profile-loading.instructions.md‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ version: 1.13.0
3030
- `README.md`、`01-项目信息.md`、`02-架构约束.md`、`03-代码风格.md` 采用 `project file first + workspace fallback`
3131
- Profile 缺失时仍按 `prod` 保守降级;若用户要求补建 Profile、恢复 dev 模式、初始化 `.devcodex/profile/` 或修复 Profile 缺失,应读取 `profile-bootstrap` 并优先建议/执行 `devcodex profile init`,不得用 AI 推测内容静默替代 Profile 文件真相源。
3232

33+
### ProfileGenerationContractGate
34+
35+
- Profile 生成、加载、状态和校验统一使用 `profile-lite` / `profile-standard` / `profile-closed-loop` 契约;首次创建默认 lite,但先由 `devcodex profile plan` 展示推荐档位、目标根和逐文件动作。
36+
- `profile plan` / `--dry-run` 必须零写入;已有 Profile 默认继承档位。升级仅补缺失文件并保留正文,降档必须显式 `--allow-downgrade` 且保留高档文件,执行 `ProfileTierMigrationSafetyGate`。
37+
- `FeatureInventorySchemaGate`:standard/closed-loop 的功能清单来源必须是可定位 Markdown 文件;closed-loop 的 `06-功能清单.md` 必须使用 `FeatureInventorySchemaV1` 十字段表。`01-项目信息.md` 仅保留摘要和链接,不复制规范表。
38+
3339
### 运行态目录写入
3440

3541
- 单项目任务:写入 `<工作区根>/.devcodex/<project>/...`
@@ -76,8 +82,10 @@ version: 1.13.0
7682
| `01-项目信息.md` | 技术栈/仓库地址 | 是 |
7783
| `02-架构约束.md` | 目录结构/模块边界 | 是 |
7884
| `03-代码风格.md` | 编码规范 | 是 |
79-
| `04-测试规范.md` | 测试框架/覆盖率 | 按需 |
80-
| `05-发布规范.md` | 版本号/发布流程 | 按需 |
85+
| `04-测试规范.md` | 测试框架/覆盖率 | `profile-standard` 起必需 |
86+
| `05-交付发布规范.md` / `05-发布规范.md` | 版本号/发布流程 | `profile-standard` 起必需 |
87+
| `06-功能清单.md` | `FeatureInventorySchemaV1` 规范功能清单 | standard 默认生成;closed-loop 必需 |
88+
| `07-用户文档与契约规范.md` | 用户文档与公开契约维护规则 | `profile-closed-loop` 必需 |
8189
| `config.json` | 运行模式配置(ENV_MODE)+ agent 兜底标识;Auto 别名全局默认 `@rocky`,可配置 `extensions.devcodex.autoAliases` 替换默认别名;也可配置 `extensions.devcodex.concurrency` 并发策略 | 按需 |
8290
| `config.local.json` | 用户 / 项目指定时使用的本地 overlay:长期连接、本地明文连接信息、env / secretRef 引用、`extensions.<namespace>` 扩展位 | 可选 |
8391

0 commit comments

Comments
 (0)