Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ CC-001/CC-002 were consumed by PR #24 fix bundle inline, with no standalone entr
| CC-525 | 🔵 active | copy-mode verifier fallback 的 generated provenance 必須指向實際 generator,並由 parity ratchet 防止再次漂移 | ops/test | 2026-07-28 | feedback:2026-07-28 | P3 | hygiene |
| CC-526 | 🔵 active | reviewer override file 的 symlink trust-boundary hardening 與相容性契約 | security/gate | 2026-07-28 | feedback:2026-07-28 | P2 | hygiene |
| CC-527 | 🔵 active | targeted gate CLI 拆分 pass、reviewer coverage 與 tier,避免 full targeted 語意重疊 | ux/gate | 2026-07-28 | feedback:2026-07-28 | P2 | design |
| CC-528 | 🔵 active | publish policy compatibility:generic 為可接受 baseline、maintainer 為 preferred,並允許 ship 驗證既有 current-tree Gate artifact | release/gate | 2026-07-30 | feedback:2026-07-30 | P1 | design |
| CC-529 | 🔵 active | publish assurance observability:在 ship 成功輸出、PR body 與 finish marker 保留 embedded policy 與 baseline/preferred satisfaction | release/gate | 2026-07-30 | feedback:2026-07-30 | P2 | hygiene |
| CC-465 | 🔵 active | memory/context 關鍵詞管線 CJK 支援:抽出共用零依賴斷詞 lib,取代三處各自 ASCII-only 抽詞;工作序列起點(465→467→468→466)(2026-07-07 記憶系統深入分析) | memory | 2026-07-07 | feedback:2026-07-07 | P2 | retrieval |
| CC-466 | ⏸ deferred | 記憶卡片生命週期閉環:expires_at 執行 + 關窗式 supersede + usage sidecar 休眠偵測 + doctor→distill 接線;僅在 CC-467 證明 stale/dormant card 已形成實際問題時啟動 | memory | 2026-07-07 | feedback:2026-07-07 | P2 | retrieval |
| CC-467 | 🔵 active | `pmctl memory stats`:注入效益可視化(唯讀聚合器)——注入 bytes/卡片命中分佈/從未命中卡/episode 填寫率,回答「記憶有跟沒有差在哪」;排在 CC-466 之前(2026-07-07;業界僅離線 recall 評測,無 per-injection 遙測) | DX/memory | 2026-07-07 | — | P2 | retrieval |
Expand Down Expand Up @@ -2531,6 +2533,119 @@ inheritance 依賴 [[CC-515]];maintainer consumer 接線由 [[CC-517]] 使用

---

## CC-528 — publish policy compatibility:generic baseline + maintainer preferred 🔵 active

**Problem**: `generic` 與 `maintainer` 是 Gate consumer policy,不是權限或身分;
但 shared verifier 目前以 policy 名稱完全相等判斷 applicability,並把 `publish`
直接映射成 `maintainer`。結果是 valid/current 的 generic GO 被標成
`consumer_policy_mismatch`,即使它已通過完整 diff classification、risk signals、
minimum tier、required reviewer coverage 與 dispatch evidence。`pmctl ship finish`
又只能重新執行 maintainer Gate,無法驗證呼叫者已有的 current-tree generic GO,
把「maintainer 是較佳發布保證」誤作「maintainer 是唯一可接受身分」。

**Requirement**:

1. 定義 policy compatibility:`generic` 是最低可接受 baseline,`maintainer` 是其
stronger policy;explicit `maintainer` consumer 仍嚴格要求 maintainer,
`generic` consumer 可接受 generic 或 maintainer,`publish` consumer 接受兩者並
以 maintainer 為 preferred。`embedded` consumer 繼續驗 artifact 自己宣告的 policy。
2. `policy_applicable` 除 required/embedded policy 外,必須輸出
`preferred_policy` 與 `policy_satisfaction: baseline|preferred`。未達 preferred
只能降為 baseline 訊號,不得讓 applicability fail;低於 required minimum 才以
穩定 reason code fail。
3. `pmctl ship finish` 預設仍執行 maintainer policy;新增明確
`--gate-result <artifact>` 讓 caller 沿用既有 initial result。Supplied artifact
必須以 publish consumer 通過 artifact validity、current subject、policy
applicability、canonical dispatch authorization 與 scope evidence;targeted
artifact 在 [[CC-517]] closure path 交付前不得單獨授權 publish,且所有 result
仍受 gate 前後
HEAD/dirty guards 與 current-tree authoritative full-suite 約束。
4. `publish` 的 direct current-tree review path 不要求 remediation closure;這是
[[CC-511]] 已決定的第一種 review authorization。Primary review 經 remediation
後以 closure 授權 final tree 的第二條 path 仍由 [[CC-517]]/CC-511 Phase B
實作,本票不得假裝已交付。
5. CLI 必須拒絕 `--gate-result` 與只對新 Gate 有意義的 `--reviewers` 混用;relative
artifact path 以 `--cd` worktree 為基準。不得自動掃描或猜測 latest result。
6. 回歸覆蓋 generic→generic、maintainer→generic、generic→maintainer、
generic→publish baseline、maintainer→publish preferred,以及 supplied
valid/stale/invalid Gate result 對 ship publish boundary 的行為。

**Done-when**: valid/current generic GO 可作 publish baseline,maintainer GO 以
machine-readable preferred 狀態呈現;explicit maintainer verification 仍不接受
generic;`ship finish --gate-result` 可沿用指定 artifact 且不放寬其他發布軸。

**Non-goals**: 不降低 generic risk-based floor;不改 maintainer initial 五 reviewer
coverage或 mode recommendation;不實作 remediation ledger/targeted confirmation;
不自動選擇 result;不把 Gate GO、full-suite PASS、publish authorization 或 merge
authorization重新合併成單一座標。

**Dependencies**: 延伸 [[CC-513]] policy resolver、[[CC-515]] shared verifier與
[[CC-518]] scope manifest;是 [[CC-517]]/CC-511 Phase B 前的 policy compatibility
clarification。P1,排入 v0.11.0 delivery assurance correctness。

**Cross-link**: [[CC-511]]、[[CC-513]]、[[CC-515]]、[[CC-517]]、[[CC-518]]、
[[CC-529]]。

---

## CC-529 — publish assurance observability:baseline/preferred 可追溯 🔵 active

**Framing**: 本票只延伸 [[CC-528]] 已建立的 publish policy compatibility,
讓成功發布保留「哪一種 producer policy、以 baseline 或 preferred 滿足 publish」
的 machine-readable audit trail。Shared verifier 仍是 policy applicability 的唯一
owner,`pmctl ship finish` 只能呈現 verifier 已驗證的 axes;不得從 tier、reviewer
數量、mode 或 human `Final: GO` 反推 assurance strength,也不得藉本票改寫
generic/maintainer policy、publication floor 或 [[CC-517]] remediation closure。

**Problem**: [[CC-528]] 讓 generic current-tree initial GO 可作 publish baseline,
maintainer GO 則是 preferred;但 successful `pmctl ship finish` stdout、PR body 的
Gate section 與 `.pm-dispatch-ship-finish.json` marker 目前只保留 `Final: GO` 與
result path。兩種不同 assurance strength 最後留下相同的 publication record,
操作者與 incident review 無法事後判斷該次發布是 generic baseline 或 maintainer
preferred。CLI usage 雖已列出 `--gate-result`,也缺少回歸測試防止 help synopsis
與 parser mutual-exclusion 契約再次漂移。

**Requirement**:

1. `pmctl ship finish` 只能從已通過 shared verifier 的 structured
`policy_applicable` axis 取得 `embedded_policy`、`required_policy`、
`preferred_policy` 與 `policy_satisfaction`;缺欄位、未知值或 verifier
assessment 不完整時 fail closed,不以 result prose 或 Gate coverage 猜值。
2. Fresh maintainer Gate 與 supplied generic/maintainer result 的成功路徑,都要在
stdout summary、PR body Gate section 及 `.pm-dispatch-ship-finish.json` marker
明確保留 producer policy 與 `baseline|preferred` satisfaction。三個 surface
必須來自同一份已驗證 assessment,不得各自重算。
3. Marker 變更採 additive、versioned 或明確 backward-compatible contract;既有
不含新欄位的 marker 仍可由 status/list reader 安全讀取,但新 writer 不得在
assessment 可用時省略 assurance fields。不得把 baseline 顯示成 failure,
也不得把 generic 誤標為 maintainer。
4. PR body 與 human stdout 必須讓操作者一眼區分 baseline/preferred,同時保留
result artifact path 供完整 verifier 重播;不得只加入模糊的「policy checked」
文字。
5. Public help regression 必須斷言 `pmctl ship finish --help`/usage 包含
`--gate-result`、`--full-result`,並保留 `--gate-result` 與 `--reviewers`
mutual-exclusion 的表達;parser 行為測試仍是獨立 oracle。
6. Deterministic tests 覆蓋 supplied generic baseline、supplied/fresh maintainer
preferred、缺失/malformed assurance fields、舊 marker reader compatibility,
以及 stdout/PR body/marker 三個 surface 的值一致性。

**Done-when**: 任一成功 ship publication 都能只靠 stdout、PR body 或 finish
marker 回答 embedded producer policy 與 publish satisfaction,三者與 shared
verifier 完全一致;舊 marker 保持可讀,help synopsis 與 parser contract 有回歸
鎖定。

**Non-goals**: 不改 generic/maintainer reviewer floor、tier、mode 或 compatibility
ordering;不新增 Gate、publish authorization 或 workflow engine;不實作 dashboard、
scheduled audit 或歷史 marker backfill;不把 [[CC-517]] remediation closure 併入。

**Dependencies**: 延伸 [[CC-528]] policy compatibility 與 [[CC-515]] shared
verifier,沿用 [[CC-511]] publish marker/PR boundary。P2,排入 v0.11.0 delivery
assurance observability。

**Cross-link**: [[CC-511]]、[[CC-513]]、[[CC-515]]、[[CC-517]]、[[CC-528]]。

---

## CC-508 — 所有間接 dispatch 的 parent-operation control plane ✅ 2026-07-25

**Problem**: `pmctl gate run`、`pmctl ship --parallel`/adapter 路徑、`pmctl task dispatch` 與任何未來 producer 都可能以一個 parent operation 間接啟動一或多個 detached dispatch;但產品控制面主要只暴露個別 `pmctl dispatch cancel <run_id>`。parent ID 與其子 run 沒有強制、可查的 ownership relation,也沒有一致的 producer-level cancel surface。當任一 producer 卡住、選錯 executor 或需中止時,操作者無法透過 pmctl 取消整個 operation;直接對 supervisor PID 操作會繞過 run state、sentinel 與 cancel-vs-complete 單一終態契約,並可能留下無法判定的 stale operation。
Expand Down
39 changes: 39 additions & 0 deletions DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,45 @@ H2 標題格式:## YYYY-MM-DD: <短描述>
與 BACKLOG closure 對應的 entry,內文首行寫:Closes: BACKLOG.md#<PREFIX>-NNN
-->

## 2026-07-30: publish-accepts-generic-baseline-and-prefers-maintainer

Relates: CC-511, CC-513, CC-515, CC-517, CC-528

**Context**: `generic` 與 `maintainer` 是 Gate consumer policy;前者依完整 diff
classification 與 risk signals 建立 reviewer floor,後者在 initial pass 固定增加五個
reviewer dimensions。Shared verifier 卻把 producer policy 名稱當成必須完全相等的
身分,並將 publish consumer 直接等同 maintainer。這讓 valid/current generic GO
即使已滿足其 risk-based floor,仍因名稱不等而無法作為發布 baseline;`ship finish`
也只能重跑 maintainer,無法驗證 caller 已明確指定的 current-tree result。Preference
因而被誤寫為唯一合法性,且較強的 maintainer artifact 也不能滿足 generic consumer。

**Decision**: Policy applicability 使用有方向的 compatibility:generic 是 baseline,
maintainer 是 stronger policy。Explicit maintainer consumer 仍嚴格要求 maintainer;
generic consumer 接受 generic 或 maintainer;publish consumer 的 minimum 是 generic、
preferred 是 maintainer。Verifier 同時輸出 required、preferred、embedded policy 與
`baseline|preferred` satisfaction;未達 preference 不使 applicability fail。Repo-owned
`ship finish` 預設仍產生 maintainer Gate,但接受明確 `--gate-result`,以 publish
consumer 驗證既有 current-tree initial result後再走同一 full-suite 與 publication
guards。Direct current-tree initial review 是 publish authorization 的第一條路,不
需要 remediation closure;targeted result 單獨不能取代 initial review。

**Alternatives considered**: (a) 維持 exact-name equality——否決,consumer policy
不是權限身分,也會反向拒絕 stronger evidence。(b) 讓 ship 永遠重跑 maintainer——
否決,會把 preferred 變成 mandatory 並重複已完成的 generic review。(c) 自動掃描
latest Gate result——否決,latest 不代表 caller intent 或 current subject,容易誤用
stale/不同 scope artifact。(d) 同時實作 primary-remediation closure publish——
否決,該 lifecycle、ledger 與 targeted confirmation 仍由 CC-517/CC-511 Phase B
擁有,不應混入 compatibility slice。

**Constraints introduced**: `--gate-result` 必須明確指定且 relative path 以 ship
worktree 為基準;不得與只影響新 Gate 的 reviewer selection 混用。Supplied result
不得繞過 artifact integrity、canonical dispatch authorization、scope manifest、
subject freshness、branch/HEAD/dirty guards 或 current-tree authoritative full
suite。Maintainer initial 五 reviewer coverage與 mode recommendation不變。Publish
接受 generic GO 不代表自動 merge,也不表示 targeted remediation closure 已交付。

---

## 2026-07-29: structured-reviewer-verdicts-replace-markdown-heading-parsing

Relates: CC-519
Expand Down
2 changes: 2 additions & 0 deletions MILESTONES.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@

| 票 | 摘要 | 狀態 |
|----|------|------|
| CC-528 | publish policy compatibility:generic current-tree initial GO 為 baseline、maintainer 為 preferred;ship 可驗證明確 supplied result | 🔵 |
| CC-529 | publish assurance observability:ship stdout、PR body、finish marker 保留 producer policy 與 baseline/preferred satisfaction | 🔵 |
| CC-517 | `/ship` primary review→local/targeted/split remediation closure→final affected/full tests;不虛稱 final-tree GO | 🔵 |
| CC-511 Phase B | final-tree review或 primary-review closure authorization + current-tree full PASS → publish | 🔵 |

Expand Down
2 changes: 1 addition & 1 deletion cli/commands.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ worktree remove Remove a managed worktree. pmctl worktree remove <name-or-branch
worktree gc Remove stale managed worktree records. pmctl worktree gc [options] experimental false true --cd, --dry-run, --merged, --force, --max-age-days pmctl worktree gc --dry-run
ship Run the ticket delivery workflow. pmctl ship <ticket-id> [options] experimental false true --worktree, --adapter, --from, --isolation, --model, --auto-pack, --cd pmctl ship CC-NNN --adapter codex
ship prepare Prepare a ticket delivery run. pmctl ship prepare <ticket-id> [--cd <dir>] experimental false true --cd pmctl ship prepare CC-NNN
ship finish Finish a prepared ticket delivery run. pmctl ship finish <ticket-id> [options] experimental false true --cd, --reviewers, --full-result pmctl ship finish CC-NNN
ship finish Finish a prepared ticket delivery run. pmctl ship finish <ticket-id> [options] experimental false true --cd, --reviewers, --gate-result, --full-result pmctl ship finish CC-NNN
ship --parallel Run multiple ticket delivery workflows. pmctl ship --parallel <ticket-id>... [options] experimental false true --from, --adapter, --isolation, --model, --auto-pack, --cd pmctl ship --parallel CC-NNN CC-MMM
ship status Show and refresh a parallel ship run. pmctl ship status [--cd <dir>] [--json] experimental true true --cd, --json pmctl ship status --json
ship list List and refresh completed parallel ship runs. pmctl ship list [--cd <dir>] [--json] experimental true true --cd, --json pmctl ship list --json
Expand Down
3 changes: 3 additions & 0 deletions cli/pmctl
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ case "$cmd/$sub" in
case "$1" in
--cd) _ship_cd="${2:-}"; shift 2 ;;
--reviewers) _ship_rest+=(--reviewers "${2:-}"); shift 2 ;;
--gate-result)
[[ $# -ge 2 && -n "$2" && "$2" != --* ]] || pmctl_die "ship finish: --gate-result requires an artifact path"
_ship_rest+=(--gate-result "$2"); shift 2 ;;
--full-result)
[[ $# -ge 2 && -n "$2" && "$2" != --* ]] || pmctl_die "ship finish: --full-result requires an artifact path"
_ship_rest+=(--full-result "$2"); shift 2 ;;
Expand Down
29 changes: 25 additions & 4 deletions commands/ship.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,18 @@ resolve to the selected gate model. Mode is user-owned: append the literal
the gate auto-selects the policy recommendation. Preserve the user's explicit
choice on targeted re-runs unless the user changes it.

Run `pmctl gate run --executor <gate_executor> --policy maintainer --cd "<work_dir>" --lifecycle foreground`
Prefer `pmctl gate run --executor <gate_executor> --policy maintainer --cd "<work_dir>" --lifecycle foreground`
(substitute `<work_dir>` with the literal absolute working directory, not
`"$PWD"` — a shell-variable expansion makes the command unanalyzable
statically and forces a manual approval every time even though a bare
`pmctl ...` invocation matches allowlisted `Bash(pmctl:*)`-style permission
rules). The `/pr-gate` command is the orchestration wrapper around this exact
invocation — either entry point is acceptable, but the underlying gate call
is always this one, never `bash runtime/bin/pr-gate.sh` directly.
is always this one, never `bash runtime/bin/pr-gate.sh` directly. Maintainer is
the preferred initial publication policy because it fixes coverage at all five
reviewer dimensions. A valid current-tree initial GO already produced by
`/pr-gate` with `--policy generic` is also an acceptable publication baseline;
do not rerun it only to change the policy label.
`--lifecycle foreground` is required here: the default `--lifecycle detached`
returns only a `gate_id` immediately and the gate keeps running in the
background — reading `Final:` right after that call would read a stale or
Expand All @@ -155,11 +159,12 @@ nothing else for the main thread to do while it waits, so there is no reason
to pay the detached/`pmctl gate wait` two-call complexity that `/pr-gate`
uses to keep the main thread free for other work; run `foreground`, parse its
literal `result: <path>`, then run
`pmctl gate verify <result_path> --cd "<work_dir>" --consumer maintainer --json`.
`pmctl gate verify <result_path> --cd "<work_dir>" --consumer publish --json`.
The result file's `Final: GO|NO-GO` remains the review verdict, but it is not
freshness or continuation authorization by itself. A GO may continue only
when the named-consumer verification exits 0 and reports `artifact_valid`,
`subject_current`, and `policy_applicable` all `pass`.
`subject_current`, and `policy_applicable` all `pass`. The policy axis reports
generic as `baseline` or maintainer as `preferred`; both are accepted here.

- **GO + all three axes pass** → go to Step 3.5.
- **GO + any axis not pass** → stop before full-suite or publication work.
Expand Down Expand Up @@ -213,6 +218,22 @@ than using that primitive, run `bash tests/bin/run-all-tests.sh` once and
verify its authoritative result artifact. This is the final repo-wide
regression check, not an iteration tool.

When the initial Gate result still covers the exact current tree, reuse it
explicitly:

```bash
pmctl ship finish <ticket-id> --cd "<work_dir>" \
--gate-result "<initial_gate_result_path>"
```

Relative Gate-result paths resolve against `<work_dir>`. Finish verifies the
artifact with the `publish` consumer and still enforces branch, HEAD, dirty
tree, canonical dispatch, scope, and authoritative full-suite boundaries. If
no `--gate-result` is supplied, finish produces a fresh preferred maintainer
Gate. Never pass a targeted result as standalone publication authorization:
until the structured remediation-closure path is available, a remediated tree
must either receive a fresh current-tree initial Gate or stop before publish.

If the full suite finds a diff-caused failure, fix it, rerun affected tests,
apply the same refactor/reuse recheck threshold, and return to the targeted
gate path for every reviewer territory the fix touched. After GO, run the full
Expand Down
6 changes: 6 additions & 0 deletions core/schema/gate-verification.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,14 @@
"required_policy": {
"enum": ["generic", "maintainer"]
},
"preferred_policy": {
"enum": ["generic", "maintainer"]
},
"embedded_policy": {
"enum": ["generic", "maintainer"]
},
"policy_satisfaction": {
"enum": ["baseline", "preferred"]
}
},
"additionalProperties": false
Expand Down
Loading