diff --git a/.trellis/spec/hyb-oa/project-governance.md b/.trellis/spec/hyb-oa/project-governance.md index cf9a62d7..149f8fcf 100644 --- a/.trellis/spec/hyb-oa/project-governance.md +++ b/.trellis/spec/hyb-oa/project-governance.md @@ -101,6 +101,8 @@ rollback and future self-maintenance. one deliberately. - Post-upgrade dry-run changes manifest again -> investigate template hash drift before commit. +- No active task directory after the last task is archived -> valid idle state; + governance still checks core files, docs registration and sensitive content. - Only documented project overlays remain modified -> acceptable after task and governance gates pass. @@ -118,6 +120,8 @@ rollback and future self-maintenance. - Assert CLI and project versions match the intended target. - Compile every Python file under `.trellis/scripts` and `.codex/hooks`. - Exercise task validate/current/list and run Trellis governance. +- Archive the final active task and assert Trellis governance still passes with + zero active task directories. - Confirm no `.new`, backup, bytecode or out-of-scope platform assets are tracked; finish with `git diff --check`. diff --git a/.trellis/tasks/archive/2026-07/07-26-trellis-upgrade-project-audit/research/current-state-audit.md b/.trellis/tasks/archive/2026-07/07-26-trellis-upgrade-project-audit/research/current-state-audit.md index f1b12eba..dd435bfe 100644 --- a/.trellis/tasks/archive/2026-07/07-26-trellis-upgrade-project-audit/research/current-state-audit.md +++ b/.trellis/tasks/archive/2026-07/07-26-trellis-upgrade-project-audit/research/current-state-audit.md @@ -16,6 +16,7 @@ - 四个冲突文件按设计完成合并,保留 Trellis-first overlay、Codex inline、禁止自动提交和 `workspace/` 忽略规则;未保留 `.new` 冲突副本。 - 0.6.9 runtime 的 `task_context.py` 包含 Python 3.9.2 不接受的嵌套多行 f-string;已改为先构造 warning 再着色,并通过全量 compileall 与 task runtime 验证。 - 升级后 dry-run 不再改变 manifest,仅报告 `task_context.py`、`config.yaml`、`.gitignore`、`workflow.md`、`AGENTS.md` 五个有意保留的项目定制。 +- 归档最后一个 active task 后,治理检查器曾将正常 idle 状态误报为 `tasks.none`;已调整为允许零个 active task,并增加单元回归测试。 ### 升级前版本与差异 diff --git a/scripts/qa/check-trellis-governance.mjs b/scripts/qa/check-trellis-governance.mjs index f1bebaa5..aa1fa286 100644 --- a/scripts/qa/check-trellis-governance.mjs +++ b/scripts/qa/check-trellis-governance.mjs @@ -97,6 +97,19 @@ export function contextManifestPolicy(dispatchMode) { }; } +export function activeTaskDirectoryPolicy(taskCount) { + if (taskCount === 0) { + return { + valid: true, + detail: "0 active task directories; idle state after archive is valid", + }; + } + return { + valid: true, + detail: `${taskCount} task directories have Trellis contracts`, + }; +} + function checkContextManifest(result, taskDir, action, dispatchMode) { const relativePath = `${taskDir}/${action}.jsonl`; const policy = contextManifestPolicy(dispatchMode); @@ -209,7 +222,8 @@ function checkTaskContracts(result) { const config = exists(".trellis/config.yaml") ? readText(".trellis/config.yaml") : ""; const dispatchMode = /dispatch_mode:\s*sub-agent\b/.test(config) ? "sub-agent" : "inline"; if (taskDirs.length === 0) { - fail(result, "tasks.none", "no .trellis/tasks/* directories found"); + const policy = activeTaskDirectoryPolicy(taskDirs.length); + pass(result, "task_contracts", policy.detail); return; } @@ -251,7 +265,10 @@ function checkTaskContracts(result) { checkContextManifest(result, dir, "implement", dispatchMode); checkContextManifest(result, dir, "check", dispatchMode); } - if (result.status === "PASS") pass(result, "task_contracts", `${taskDirs.length} task directories have Trellis contracts`); + if (result.status === "PASS") { + const policy = activeTaskDirectoryPolicy(taskDirs.length); + pass(result, "task_contracts", policy.detail); + } } function checkDocsRegistration(result) { diff --git a/server/tests/unit/scripts/check-trellis-governance.test.js b/server/tests/unit/scripts/check-trellis-governance.test.js index f672b2bf..1f1ac741 100644 --- a/server/tests/unit/scripts/check-trellis-governance.test.js +++ b/server/tests/unit/scripts/check-trellis-governance.test.js @@ -24,4 +24,11 @@ describe("Trellis context manifest governance", () => { rejectSeedRows: true, }); }); + + it("accepts the idle state after the last active task is archived", () => { + expect(governance.activeTaskDirectoryPolicy(0)).toEqual({ + valid: true, + detail: "0 active task directories; idle state after archive is valid", + }); + }); });