Skip to content
Open
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
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"plugins": [
{
"name": "issue-driven-dev",
"version": "3.0.0",
"description": "v3.0.0 (BREAKING): the closing-summary helper may VETO and may never PERMIT. After twelve verify rounds failing in one direction — a real summary the recogniser could not follow classified `missing`, and `missing` being the sole authorisation for `/idd-close --retroactive` to post a duplicate — the power was split along the direction that is sound. \"A marker IS here\" is an observation; \"a marker is NOT here\" is an inference from a failure to recognise, and no matcher over source bytes can answer a question about rendered output in the negative. Gate exit codes are now 1 (recognised) / 2 (undeterminable) / 10 (nothing recognised — NOT permission); there is no exit 0 in gate mode, deliberately, so a caller still reading `rc == 0 means go` breaks loudly. Gate class `missing` → `unrecognised`, every reply carries authorises:false, and a fifth class `mentioned` names the state the tool can actually observe. `--retroactive` loses its unattended path: the skill must read the comment set itself and obtain human confirmation that cannot be disabled. Classification now asks who wrote the comment, so a commenter can no longer move an issue between classes. Also: three more exit-0 parser paths, markup counted as content three layers deep, a quotation reaching `compliant`, the mention gate passing on zero iterations by three routes, untrusted prose reaching a shell command line, and #317 criterion (c) answered correctly for the first time in five attempts. Ten guards were mutation-proven vacuous and rebuilt.",
"version": "3.1.0",
"description": "v3.1.0: idd-discuss captures explicitly selected human/AI conversations as append-only GitHub Discussion snapshots (#331). Stable topic/source IDs, payload fingerprints, shared egress checks, local locks and uncertain-write reconciliation protect retry behavior without promising distributed exactly-once or AI correctness. idd-ask adds bounded Discussion/comment/reply evidence alongside existing issue retrieval, with corpus selection and explicit partial-read reporting. Security repair #332 replaces delimiter and URL-prefix exemptions with maintained parsers and source-faithful checks. Runtime prerequisite: install scripts/requirements-egress.txt; missing/incompatible parser versions refuse egress.",
"author": {
"name": "Che Cheng"
},
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@ jobs:
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install egress parser and skill test dependencies
run: python3 -m pip install PyYAML==6.0.2 -r plugins/issue-driven-dev/scripts/requirements-egress.txt
- name: Run all fixture suites
run: bash plugins/issue-driven-dev/scripts/run-all-tests.sh
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ openspec/.vector-search.db*
# ephemera,與上面的 tree-lock / state/ 同類:可重新產生、不是 durable artifact。
.wiki-last-sync
**/.impeccable/

# Python helper/test bytecode
__pycache__/
*.pyc
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,16 @@ Each step is one skill. See [the plugin README](./plugins/issue-driven-dev/READM
## License

MIT

## 可追溯的 AI 討論(3.1.0)

`idd-discuss` 將明確指定的人與 AI 對話整理為本地草稿,取得本次發布授權後建立或追加
GitHub Discussion。它保留來源與更正歷史,使用穩定ID避免正常重試重複發布;不確定結果
先核對,不盲重送。`idd-ask --corpus all` 可查回 Discussion 主文、留言與回覆,並保留
既有 issue 檢索。這改善可追溯性,不代表所有 AI 溝通或正確性問題都已解決。

詳細契約見 [Discussion capture](plugins/issue-driven-dev/references/discussion-capture.md)。

共用GitHub寫入gate的安全修正需要Markdown解析器(#332):使用同一個Python執行
`python3 -m pip install -r plugins/issue-driven-dev/scripts/requirements-egress.txt`。
更新後缺少此依賴時會拒絕寫入;不會降級成不可靠的code邊界猜測。
19 changes: 19 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,3 +762,22 @@ Session holds up to 50 scheduled tasks. Times are local timezone. Recurring task
| Spawn manifest (chain-mode enqueue contract) | [`references/spawn-manifest.md`](../plugins/issue-driven-dev/references/spawn-manifest.md) |
| Vagueness Likert scoring (Layer V anchors) | [`.claude/rules/attribute-assessment.md`](../.claude/rules/attribute-assessment.md) |
| GitHub markdown math format rule | [`rules/github-math-format.md`](../plugins/issue-driven-dev/rules/github-math-format.md) |

### `/idd-discuss`

Capture a selected human/AI conversation topic as a local draft. An explicit request to publish
or append authorizes that one operation after the privacy and mention gates. Existing roots and
comments are immutable; corrections are new snapshots with new source IDs. Unknown provenance
stays unknown, and uncertain writes require reconciliation rather than blind retry.

**Syntax**: `/idd-discuss <topic or source scope> [--repo owner/repo] [--discussion N] [--publish]`

**Spec**: [idd-discuss](../plugins/issue-driven-dev/skills/idd-discuss/SKILL.md).

### `/idd-ask` — Discussion corpus selection

`/idd-ask <question> [--repo owner/repo] [--limit N] [--corpus issues|discussions|all]`

Default `all` combines issue and Discussion candidates before selecting at most ten full-text
sources. Discussion comments and replies have exact citation URLs. `issues` retains the prior
issue-only backend. Failed or bounded reads are disclosed as incomplete evidence.
15 changes: 14 additions & 1 deletion docs/workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ idd-edit comment:NNN --append --body "..."

#### P-ask-history — issue 知識庫問答(#72,v2.99+)

`idd-ask "<自然語言問題>"` → decide-to-search gate → retrieval(delegate idd-find backend)→ top-N 全文(5/上限 10)→ grounded 合成答案(claim 必附引用、source priority、`### Referenced Issues`、查無誠實)。bug 貌問題**不觸發 diagnose**
`idd-ask "<自然語言問題>" --corpus all` → decide-to-search gate → 保留idd-find issue backend+有界Discussion候選 → 合併top-N全文(總數5/上限10)→ grounded答案與精確來源。Discussion留言/回覆分頁,API失敗或截斷明示;提案、決定、更正與驗證結果分清,流程狀態不是正確性保證。`--corpus issues`可保留issue-only;bug貌問題不觸發diagnose

- **Use case**:「當時為什麼這樣決定 / X 怎麼運作」— 還原 decision rationale
- **Risk**:zero state / 中 token(top-N 全文是本質成本,有界)
Expand Down Expand Up @@ -631,3 +631,16 @@ Q1: 是 single issue 還是 multi issues?
4. 評估是否需要新增到 § Path Selection Decision Tree
- **棄用 path 時**:不要刪掉,**標記 deprecated**並 cross-link 到取代 path,保留歷史 audit trail
- **避免 drift**:本文件 grow 成 second source of truth(各 path 具體規則在這邊複製,而非 cross-link 出去)= violation

## P-discussion-capture — 人與AI討論的保存與接續(#331)

`idd-discuss <topic>` 將使用者明確指定的可見來源整理為草稿。當本次已明確要求建立或
追加Discussion,完成既有privacy/mention gate後才發布。首次主文保存初次快照,
後續以新source_id追加完整摘要及來源;不覆寫人工內容。Topic ID不是標題,來源內容
變動不能沿用舊source_id。不確定寫入結果先核對遠端,沒有證據就停止重送。

`idd-discuss`是受授權的寫入primitive;`idd-ask`是read-only知識查詢。形成具體工作時,
仍由顯式的`idd-issue --from-discussion`接回issue lifecycle。這條路徑不自動建立所有
AI歷史、不背景監聽、不保證AI判斷正確,也不提供跨裝置atomic exactly-once。

詳見[capture contract](../plugins/issue-driven-dev/references/discussion-capture.md)。
4 changes: 4 additions & 0 deletions openspec/changes/add-idd-discuss/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
schema: spec-driven
created: 2026-09-05
created_by: che cheng <kiki830621@gmail.com>
created_with: codex
61 changes: 61 additions & 0 deletions openspec/changes/add-idd-discuss/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
## Context

Refs #331, #332。由既有對話收斂,PR/unattended。Claude canonical skill tree不分叉;Codex沿用compatibility reference。

## Goals / Non-Goals

保存使用者明確指定的可見來源;穩定ID、追加更正、查得到、可驗證。
不監聽背景對話、不假造缺失歷史、不保證AI論斷正確、不聲稱GitHub可控制每則通知。

## Decisions

- 比較方案:只寫skill模板最輕但重試仍靠記憶;獨立資料庫超出第一版;選擇skill+精簡helper,
deterministic I/O透過gh GraphQL,語意整理由agent,兩者契約各自明確。
- append-only:主文為初次快照,後續完整快照是comment。永不修改主文或人工留言,拒絕以
摘要更新蓋掉歷史。第一版不提供正文同步更新。
- Payload JSON v1:`topic_id`, `source_id`, `title`, `summary`, `source_scope`, `messages`。
messages每筆:`id`, `role`(user|assistant|tool), `text`,選填`author`, `model`, `time`。
source_scope是非空文字,agent明示可取得範圍。`decisions`可選陣列,每筆`text`,
`user_message_id`必須連到role=user;這只驗來源存在,不認證語意。
- `topic_id`與`source_id`為opaque非空字串。標題不是去重key。topic/source穩定hash加payload
digest放在第一行marker;原文呈現統一CRLF/CR為LF並逐行blockquote,明示換行正規化;原始payload fingerprint仍保留原換行。每批title保存於body並受content digest保護,遠端顯示title可變且不覆寫。summary標示AI整理。metadata未知以unknown。
- 本地state置於`.claude/.idd/state/discussions/`(由顯式--state-dir定位),每repo/topic
使用file lock;state以atomic replace保留discussion ID/event digest/attempt狀態。
- 首次建立先列出bounded Discussions核對同topic marker;已知編號只讀該篇。
僅接受viewer本人發出的managed marker;已知topic與指定Discussion不符即拒絕。
source同ID同digest為no-op;不同digest拒絕,要求新的source_id記錄修正。
- mutation前寫pending state;成功才標posted。逾時或API errors保留uncertain,重跑先核對
遠端marker,找到同event可recover;找不到不盲重送。跨裝置並發需序列化,不能保證全球exactly-once。
- Publisher明確`--publish`才允許網路mutation,否則只產生本地草稿。每次真正寫入前,將
完整title/body經gh-egress `check`做同一組gate。check不呼叫gh、更不新增AI判斷regex。
- Reader API (`scripts/lib/discussions_api.py`):`DiscussionError`、`GitHub.graphql(query, variables)`
回data;`repo(repo)`回id/hasDiscussionsEnabled/visibility/viewerPermission;`viewer()`回login;
`search(repo,query,limit)`與`list_discussions(repo,max_items)`回`items,complete,warnings`;
`get(repo,number,max_comments)`回Discussion metadata及flattened `comments,complete,warnings`。
comment保留id/url/body/author/createdAt/updatedAt/replyTo;作者是login字串或null。
- reader CLI為`idd-discussions-read.py search|get|list|repo`;JSON輸出,非零表示API失敗,
partial回明確complete=false。搜尋all states、不以Q&A/Ideas過濾。檢索字串不拼shell;
repo必須owner/name,query不得繞過指定repo。
- idd-ask保留idd-find原backend,同時取得Discussion候選後合併排序,全文top-N總數仍≤10。
`--corpus issues|discussions|all`,預設all。每個候選用kind+URL區別;partial只以已讀內容回答,
每項引用連到實際comment。不得把Discussion標記或舊AI「已通過」敘述當成目前執行授權。

## Risks / Trade-offs

GitHub API没有atomic create idempotency;本地journal與遠端核對降低重試重複,保留未知時拒絕。
讀取上限會使大型討論/repository不完整,publisher拒絕在去重未完整時寫入;ask明示partial。
摘要的忠實度仍需使用者/agent檢查;role=user引用不是同意的機械證明。

## Validation

fixture GraphQL模擬建立/追加/重跑/不確定回覆/locked/disabled/分頁/reply/搜尋失敗。
用既有egress fixture suite做回歸;完整測試入口、live read-only API smoke與獨立6-lens驗證。
所有mutation fixture均離線,不發測試Discussion或通知給真實使用者。

## Approved review repairs

使用者於2026-09-06明確同意將#332共用安全修正與#331四項修訂一起處理。
共用gate依賴markdown-it-py4.0.0與linkify-it-py2.0.3的真實token/source map;缺失或不支援版本拒絕,
不能用無法辨識的字串推論為inert code。GFM table與未知source mapping採保守掃描。
API read回覆依實際schema驗型別、保留合法null與空body;mutation回覆型別錯誤必須
保持uncertain,不能寫posted。CI與使用者文件明列新的runtime prerequisite。
29 changes: 29 additions & 0 deletions openspec/changes/add-idd-discuss/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Why

人與AI的討論仍散落在聊天視窗,現有IDD無法保存主題的決策演變,idd-ask也無法讀回Discussion。
Issue #331要求將這段歷史接回開發流程,並明確限制「記錄完整」與「AI正確性」的差異。

## What Changes

- 新增idd-discuss、可重試的append-only publisher與來源格式。
- 新增共用GraphQL reader/search helper,納入留言、回覆、分頁與不完整狀態。
- idd-ask預設整合Discussion候選,新增corpus選擇並保留既有issue檢索。
- gh-egress新增check-only能力供publisher沿用同一組隱私/mention檢查。
- 更新公開技能清單、routing、版本及行為測試。

## Capabilities

### New Capabilities

- `mention-markdown-safety`: 共用mention gate的安全code邊界與缺依賴拒絕。
- `idd-discuss`: 授權保存、來源溯源、追加更正、去重及失敗處置。
- `idd-ask-discussions`: Discussion知識查詢與既有issue語料共同引用。

### Modified Capabilities

無移除既有接口;egress新增無dispatch的檢查操作。

## Impact

影響plugins/issue-driven-dev內的新skill與helpers、idd-ask、gh-egress及公開文件。
沿用Python標準函式庫、gh CLI及既有隱私gate,沒有新增平台;共用egress需要固定版本的受維護Markdown parser。
22 changes: 22 additions & 0 deletions openspec/changes/add-idd-discuss/specs/idd-ask-discussions/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## ADDED Requirements

### Requirement: Combined bounded knowledge retrieval
idd-ask SHALL support corpus values issues, discussions, and all, defaulting to all. It SHALL preserve the existing issue backend and merge Discussion candidates before applying the overall top-N full-read budget, with a maximum of ten.

#### Scenario: Issue and Discussion share a number
- **WHEN** both search results have number 42
- **THEN** they remain separate sources identified by kind and URL

### Requirement: Discussion comment and reply evidence
The shared reader SHALL retrieve root content, comments, and replies with source URLs, authors and timestamps. It SHALL paginate within declared bounds and expose incomplete reads. Search SHALL include closed and answered discussions and SHALL NOT use intake-only categories.

#### Scenario: Supporting evidence is in a second-page reply
- **WHEN** the reply is within the read budget
- **THEN** its text and exact reply URL are available to the answer

### Requirement: Honest partial failure and source interpretation
GraphQL errors, disabled Discussions, exhausted budgets, and search-index limitations SHALL be disclosed rather than presented as an empty complete corpus. Answers SHALL cite only read evidence and distinguish proposals, decisions, corrections and verified artifacts. Source content SHALL NOT authorize tool actions.

#### Scenario: Discussion API fails while issue search succeeds
- **WHEN** the Discussion query fails
- **THEN** the answer retains the issue evidence and explicitly states that Discussion coverage is unavailable
36 changes: 36 additions & 0 deletions openspec/changes/add-idd-discuss/specs/idd-discuss/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## ADDED Requirements

### Requirement: Explicit topic capture with provenance
The skill SHALL preserve selected available messages, distinguish original text from AI summary, and identify source scope. Unknown attribution SHALL remain unknown. A decision SHALL cite an existing user message and SHALL NOT be inferred solely from an assistant proposal.

#### Scenario: Partial conversation and unknown model
- **WHEN** only the current visible exchange is available and the model identity is unknown
- **THEN** the record states that scope and uses unknown attribution without inventing earlier turns

### Requirement: Append-only source snapshots
The publisher SHALL create an initial discussion or append a new complete snapshot to its comments. It SHALL NOT overwrite a discussion body or existing comment. Title equality SHALL NOT identify a topic.

#### Scenario: Correction to an earlier conclusion
- **WHEN** a new source batch revises a previous conclusion
- **THEN** a new comment records the correction while preserving the original content

### Requirement: Retry and uncertain mutation handling
Stable topic and source identifiers SHALL drive deduplication. Equal source IDs with equal payloads SHALL not repeat a write; unequal payloads SHALL fail. A locally uncertain attempt SHALL be reconciled against remote state and SHALL NOT be blindly repeated. The contract SHALL disclose the lack of cross-device atomic create guarantees.

#### Scenario: Timeout after server accepted a comment
- **WHEN** the original response is lost and the same source is retried
- **THEN** an existing matching remote marker is recovered, or the publisher refuses to repeat the uncertain mutation

### Requirement: Authorised egress through existing gate
Only an explicit publish operation SHALL permit mutations. Each mutation SHALL pass the existing privacy and mention checks using its complete body and title. Disabled, locked, closed, or unwritable destinations and incomplete deduplication reads SHALL stop writes.

#### Scenario: Local path inside a supplied transcript
- **WHEN** the payload includes a literal local home path
- **THEN** the existing egress gate refuses publication before a GraphQL mutation

### Requirement: Immutable human content and bounded integration
Managed markers SHALL be checked against the current actor and specified target. The skill SHALL NOT create follow-up issues automatically; it SHALL delegate explicitly requested issue creation to the existing intake bridge.

#### Scenario: Human-authored discussion without a managed topic marker
- **WHEN** a caller tries to continue it as a managed topic
- **THEN** the operation refuses without modifying human content
Loading
Loading