git:20260730.6ee304a to git:20260906.8d1c8e1

17 added, 2 removed. Audit A to A.

---
name: audit-session
description: 审计工作流的跨会话状态机 — 在 <audit-root>/.audit-state/<session-id>.json 持久化轮次/发现项/收敛状态,支持 Token 中断后精准恢复
---
# Audit Session Skill
## 适用范围
- 触发:意图为 `audit` 且预期轮次 ≥3(即所有非 chat 审计场景)
- 不适用:analyze(仅 ≥3 轮收敛但无 audit finding 交接状态机)、chat(无审计语义)
## 状态文件路径
```text
<audit-root>/.audit-state/<session-id>.json
```
`<audit-root>` 取值:
- 旧布局:`<项目根>/.devcodex`
- 集中布局单项目:`<工作区根>/.devcodex/<project>`
- 集中布局全工作区:`<工作区根>/.devcodex/workspace`
- `<session-id>` 取首次启动审计的时间戳:`YYYYMMDD-HHmmss`
- `<audit-root>/.audit-state/` 目录由本 Skill 首次写入时创建(不随 `init` 分发)
- `.gitignore` 须覆盖 `<audit-root>/.audit-state/` 对应路径(如 `.devcodex/.audit-state/`、`.devcodex/*/.audit-state/`,同记忆策略)
## 状态机
```text
active ──┬─> paused (Token 防护触发 / 用户中断)
├─> resumed (跨会话 resume 重新进入)
├─> converged (CRS + PCV 通过 + 连续3轮零发现)
└─> closed (用户确认审计闭环)
paused ──> resumed ──> active
converged ──> closed
```
| 状态 | 进入条件 | 退出条件 |
|------|---------|---------|
| `active` | 首次 audit 意图识别成功 | 任一退出条件触发 |
| `paused` | C08 Token 防护(>15 轮)或 用户中断 | resume 意图 + 当前 session 命中 |
| `resumed` | resume 意图 + 读取本文件 | 立即转 `active` 继续审计 |
| `converged` | `zeroFindingStreak ≥ 3` 且 `crsPassed` 且 `pcvPassed` | 用户确认 → `closed` |
| `closed` | 用户确认审计完成或放弃 | 终态(不再写入)|
## 状态文件 schema
```json
{
+ "schemaVersion": "AuditSessionStateV2",
"sessionId": "20260520-143055",
"startedAt": "2026-05-20T14:30:55+08:00",
"lastUpdatedAt": "2026-05-20T16:12:33+08:00",
"target": {
"type": "spec | tech-design | requirements | project | report | document",
"scope": "<被审查文件 glob 或目录>"
},
"dimensions": ["D1", "D2", "..."],
"round": 3,
"state": "active | paused | resumed | converged | closed",
"findings": [
{
"id": "F-001",
"round": 1,
"dim": "D5",
"file": "instructions/12-audit.instructions.md",
"severity": "🔴 | 🟡 | 💡",
"summary": "<一句话>",
"status": "open | pending | in-progress | fixed | wontfix | accepted | recorded | transferred | superseded",
"category": "spec-defect | release-pending | v{X.Y.Z}-candidate",
"fixPlan": "<修复方案概述>",
"fixCommit": "<git commit hash, 修复后写入>",
"linkedPF": "PF-NNN | null"
}
],
"regressionProbes": [
{
"findingId": "F-007",
"scanCmd": "grep -c 'PC5' CLAUDE.md",
"expectedMatches": 3,
"lastVerifiedRound": 4,
"lastVerifiedAt": "2026-05-21T03:30:00+08:00"
}
],
"r2Probes": [{"name": "<probe>", "status": "✅|⚠️|❌"}],
"r3Probes": [{"name": "<probe>", "status": "✅|⚠️|❌"}],
"r4Probes": [{"name": "<probe>", "status": "✅|⚠️|❌"}],
"zeroFindingStreak": 0,
"crsPassed": false,
"pcvPassed": false,
"remoteReleased": {
"gitPush": false,
"npmPublish": false,
"recordedAt": "ISO8601",
"source": "user-confirmed-manual | ci-automation"
},
"lastCheckpoint": {
"round": 3,
"writtenAt": "2026-05-20T16:12:33+08:00",
"reason": "round-end | token-protect | user-interrupt | switching-to-release-vX.Y.Z | release-pending-vX.Y.Z"
},
"linkedMemory": "tasks/20260520.md",
"linkedReport": "<active-root>/<task-kind>/<task>/reports/<agent>/20260520/01--<name>.md",
"linkedRelease": "<active-root>/requirements/<task>/reports/<agent>/YYYYMMDD/01--vX.Y.Z-release.md"
}
```
+ ### `.audit-state` 兼容读取边界
+
+ `.audit-state` 是多类运行态证据的共享目录名,不代表目录内每个 JSON 都属于当前审计会话。读取者必须先分类,再决定校验方式:
+
+ | 分类 | 识别 | 处理 |
+ |---|---|---|
+ | current session | exact `AuditSessionStateV1` / `AuditSessionStateV2` | 按本 Skill 的状态、finding 与 regression probe 合同严格校验 |
+ | legacy audit | `AuditStateV1` 或可识别的历史无 schema 审计形状 | 只读导航与取证,不要求满足当前枚举或新探针,不改写历史字节 |
+ | non-audit | SkillRoute、batch plan、validation 等其他 schema | 跳过审计会话校验,由各自 owner 负责 |
+ | unsupported current | 未支持的 `AuditSessionStateV*` | 明确报告不支持,禁止猜测或降成 legacy |
+ | invalid | JSON 损坏或顶层不是 object | 报告结构错误,不静默忽略 |
+
+ 兼容分类只解决 reader 误判,不授予旧状态新的写权限,也不得伪造 `superseded`、重算旧 finding 或迁移历史文件。
+
### v1.9.4+ schema 字段说明
| 字段 | 引入 | 用途 |
|------|:----:|------|
| `findings[].category` | v1.9.4 | 分类标识:`spec-defect`(规范缺陷)/ `release-pending`(仅发版动作未启动导致)/ `v{X.Y.Z}-candidate`(推迟到下版本同源合并)|
| `findings[].fixPlan` | v1.9.4 | 修复方案概述,留作 release/dev 工作流参考 |
| `findings[].fixCommit` | v1.9.4 | 独立 fix/self-fix 工作流产生的修复 commit hash;audit 只读取并验证,不自行提交 |
| `regressionProbes[]` | v1.9.5+ | 已修复 finding 的回归扫描定义;audit-common §收敛门禁第 7 步触发;任一回归 → status 切回 open,streak 归零 |
| `r{N}Probes[]` | v1.9.4 | 第 N 轮的探针清单与状态,便于跨会话 resume 时审计深度可追溯 |
| `remoteReleased` | v1.9.4 | 远端发版动作状态(git push + npm publish),消除 release-pending findings 的依据 |
| `lastCheckpoint.reason` | v1.9.4 | 扩充值:`switching-to-release-vX.Y.Z`(切 release 流程缓冲)/ `release-pending-vX.Y.Z`(等下版本合并)|
| `linkedRelease` | v1.9.4 | 关联 release 报告路径,建立 audit → release 双向链 |
### findings[].status 枚举
| 状态 | 含义 | 是否未解决 |
|------|------|:----------:|
| `open` | 当前审计仍需处理 | 是 |
| `pending` | 已确认但等待后续批次处理 | 是 |
| `in-progress` | 正在修复或验证中 | 是 |
| `fixed` | 已修复并通过回归验证 | 否 |
| `wontfix` | 已确认不修复,需保留理由 | 否 |
| `accepted` | 已接受为项目例外或可接受风险,需保留理由 | 否 |
| `recorded` | 已记录到外部台账、问题池或报告,当前审计不再直接处理 | 否 |
| `transferred` | 已转入其他报告、需求或问题池继续跟进 | 否 |
| `superseded` | 已被后续报告或新版结论取代 | 否 |
> 终态 `converged` / `closed` 不得保留 `open`、`pending`、`in-progress` findings;允许 `fixed`、`wontfix`、`accepted`、`recorded`、`transferred`、`superseded` 作为已处置状态。
## 写入时机
`AuditMutationBoundaryGate`:audit session 只记录 finding/交接/外部修复证据;`sourceMutationAuthorized` 在 audit 中恒为 `false`,用户修复授权由独立 fix/self-fix 的 CP/ExecutionContract 持有。
| 时机 | 动作 | 字段更新 |
|------|------|---------|
| 首轮启动 | 创建文件,state=active | sessionId / startedAt / target / dimensions |
| 每轮结束 | 追加 findings + 更新 round | round / findings / zeroFindingStreak |
| CRS 完成 | 标记通过状态 | crsPassed |
| PCV 完成 | 标记通过状态 | pcvPassed |
| Token 防护(C08 >15轮)| state=paused | state / lastCheckpoint.reason=token-protect |
| 收敛 | state=converged | state |
| 用户确认 | state=closed | state |
## 与其他 Skill / Instruction 的协同
| 关联点 | 说明 |
|--------|------|
| `instructions/12-audit.instructions.md` | 审计工作流入口须读取/创建本文件;收敛门禁须校验 `crsPassed && pcvPassed && zeroFindingStreak>=3` |
| `instructions/15-memory.instructions.md` | tasks/YYYYMMDD.md 段落须追加 `🔗 审计会话:<session-id>` 字段,建立双向链 |
| `intent/SKILL.md` | resume 意图识别后须在三层记忆读取之前优先扫描 `<audit-root>/.audit-state/*.json` 查找未 closed 的会话 |
| `skills/audit-execution-guide/SKILL.md` | finding 先记录/交接;用户显式授权的独立 fix/self-fix 完成后,audit 读取新证据并重启新轮,旧轮不得在 audit 内伪造 fixed |
## 跨会话 resume 流程
1. 用户说"继续审计" / "继续上次的审查"
- 2. 读取 `<audit-root>/.audit-state/` 下所有 `.json`,按 `lastUpdatedAt` 倒序
- 3. 找出 state ∈ {paused, active, resumed} 的最新一份
+ 2. 读取 `<audit-root>/.audit-state/` 下有界 `.json` 清单,先按上述兼容规则分类
+ 3. 只在 current session 与可导航的 legacy audit 中按 `lastUpdatedAt` 倒序,找出 state ∈ {paused, active, resumed} 的最新一份;其他 schema 不参与排序
4. 输出:"发现未完成审计会话 `<sessionId>`:目标 `<target.scope>`,已完成 `R{round}`,发现 `{open}` 项 open。是否继续?"
5. 用户确认 → state=resumed → 立即 → active,从 round+1 开始
6. 用户拒绝 → 询问是否 closed 该会话
## ⛔ 禁止
- ⛔ 状态文件不得提交到 git(同 `.devcodex/.memory/`)
- ⛔ 同一 sessionId 不得并行写入;这是 C07 `ConcurrencyPolicy` 中不可变 `audit-session` 单写者锁,不受项目 concurrency 配置放开
- ⛔ converged 状态不得自动转 closed —— 须用户明确确认(避免静默关闭)
- ⛔ audit 不得因 finding 严重度或对象是 plugin 文件而自动获得 fix/self-fix、`git add`、commit 或 source mutation 权限