github-task-protocol 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. github-task-protocol-1.0.1/DECISIONS.md +1532 -0
  2. github-task-protocol-1.0.1/GTP.md +353 -0
  3. github-task-protocol-1.0.1/LICENSE +21 -0
  4. github-task-protocol-1.0.1/PKG-INFO +88 -0
  5. github-task-protocol-1.0.1/README.md +78 -0
  6. github-task-protocol-1.0.1/acceptance/legacy/issue-1/README.md +47 -0
  7. github-task-protocol-1.0.1/acceptance/legacy/issue-1/run.json +60 -0
  8. github-task-protocol-1.0.1/acceptance/legacy/v1.0.0/STATUS.md +31 -0
  9. github-task-protocol-1.0.1/acceptance/legacy/v1.0.0/v1.0.0.json +39 -0
  10. github-task-protocol-1.0.1/acceptance/level0/README.md +46 -0
  11. github-task-protocol-1.0.1/acceptance/level0/run.json +51 -0
  12. github-task-protocol-1.0.1/acceptance/level1/README.md +58 -0
  13. github-task-protocol-1.0.1/acceptance/level1/human-probe.md +54 -0
  14. github-task-protocol-1.0.1/acceptance/level1/run.json +135 -0
  15. github-task-protocol-1.0.1/acceptance/level1/stdout/done.txt +29 -0
  16. github-task-protocol-1.0.1/acceptance/level1/stdout/halt.txt +37 -0
  17. github-task-protocol-1.0.1/acceptance/level1/stdout/stopped.txt +27 -0
  18. github-task-protocol-1.0.1/acceptance/release-notes-v1.0.1.md +37 -0
  19. github-task-protocol-1.0.1/acceptance/release.json +64 -0
  20. github-task-protocol-1.0.1/build_backend.py +155 -0
  21. github-task-protocol-1.0.1/pyproject.toml +20 -0
  22. github-task-protocol-1.0.1/src/.DS_Store +0 -0
  23. github-task-protocol-1.0.1/src/gtp/__init__.py +3 -0
  24. github-task-protocol-1.0.1/src/gtp/__main__.py +4 -0
  25. github-task-protocol-1.0.1/src/gtp/__pycache__/__init__.cpython-312.pyc +0 -0
  26. github-task-protocol-1.0.1/src/gtp/__pycache__/__main__.cpython-312.pyc +0 -0
  27. github-task-protocol-1.0.1/src/gtp/__pycache__/carrier.cpython-312.pyc +0 -0
  28. github-task-protocol-1.0.1/src/gtp/__pycache__/cli.cpython-312.pyc +0 -0
  29. github-task-protocol-1.0.1/src/gtp/__pycache__/github.cpython-312.pyc +0 -0
  30. github-task-protocol-1.0.1/src/gtp/__pycache__/model.cpython-312.pyc +0 -0
  31. github-task-protocol-1.0.1/src/gtp/__pycache__/presentation.cpython-312.pyc +0 -0
  32. github-task-protocol-1.0.1/src/gtp/__pycache__/reducer.cpython-312.pyc +0 -0
  33. github-task-protocol-1.0.1/src/gtp/__pycache__/schema.cpython-312.pyc +0 -0
  34. github-task-protocol-1.0.1/src/gtp/__pycache__/status.cpython-312.pyc +0 -0
  35. github-task-protocol-1.0.1/src/gtp/__pycache__/urls.cpython-312.pyc +0 -0
  36. github-task-protocol-1.0.1/src/gtp/carrier.py +107 -0
  37. github-task-protocol-1.0.1/src/gtp/cli.py +52 -0
  38. github-task-protocol-1.0.1/src/gtp/github.py +214 -0
  39. github-task-protocol-1.0.1/src/gtp/model.py +93 -0
  40. github-task-protocol-1.0.1/src/gtp/presentation.py +419 -0
  41. github-task-protocol-1.0.1/src/gtp/reducer.py +184 -0
  42. github-task-protocol-1.0.1/src/gtp/schema.py +211 -0
  43. github-task-protocol-1.0.1/src/gtp/status.py +552 -0
  44. github-task-protocol-1.0.1/src/gtp/urls.py +100 -0
  45. github-task-protocol-1.0.1/tests/__pycache__/test_carrier.cpython-312.pyc +0 -0
  46. github-task-protocol-1.0.1/tests/__pycache__/test_schema.cpython-312.pyc +0 -0
  47. github-task-protocol-1.0.1/tests/fixtures/adr-conformance.json +28 -0
  48. github-task-protocol-1.0.1/tests/fixtures/carriers/contract-valid.md +22 -0
  49. github-task-protocol-1.0.1/tests/fixtures/carriers/done-valid.md +19 -0
  50. github-task-protocol-1.0.1/tests/fixtures/carriers/start-valid.md +16 -0
  51. github-task-protocol-1.0.1/tests/fixtures/carriers/stop-valid.md +16 -0
  52. github-task-protocol-1.0.1/tests/fixtures/cli/prune-report.txt +38 -0
  53. github-task-protocol-1.0.1/tests/fixtures/cli/status-matrix.json +141 -0
  54. github-task-protocol-1.0.1/tests/fixtures/http/done-success.json +71 -0
  55. github-task-protocol-1.0.1/tests/fixtures/http/live-binding-matrix.json +29 -0
  56. github-task-protocol-1.0.1/tests/fixtures/http/prune-report.txt +33 -0
  57. github-task-protocol-1.0.1/tests/fixtures/http/walking-skeleton.json +33 -0
  58. github-task-protocol-1.0.1/tests/fixtures/prune-report.txt +20 -0
  59. github-task-protocol-1.0.1/tests/fixtures/reducer-truth-table.json +10 -0
  60. github-task-protocol-1.0.1/tests/fixtures/release/prune-report.txt +36 -0
  61. github-task-protocol-1.0.1/tests/fixtures/release/surface.json +42 -0
  62. github-task-protocol-1.0.1/tests/fixtures/schema-conformance.json +6 -0
  63. github-task-protocol-1.0.1/tests/test_adr_coverage.py +26 -0
  64. github-task-protocol-1.0.1/tests/test_build_backend.py +119 -0
  65. github-task-protocol-1.0.1/tests/test_carrier.py +150 -0
  66. github-task-protocol-1.0.1/tests/test_cli.py +527 -0
  67. github-task-protocol-1.0.1/tests/test_github.py +147 -0
  68. github-task-protocol-1.0.1/tests/test_reducer.py +155 -0
  69. github-task-protocol-1.0.1/tests/test_release_surface.py +86 -0
  70. github-task-protocol-1.0.1/tests/test_schema.py +177 -0
  71. github-task-protocol-1.0.1/tests/test_status.py +442 -0
  72. github-task-protocol-1.0.1/tests/test_v1_conformance.py +72 -0
@@ -0,0 +1,1532 @@
1
+ # GTP decisions
2
+
3
+ > 現在のprotocolの唯一の正本は[`GTP.md`](GTP.md)である。この文書は採否理由と設計履歴を所有し、Record作成やstate判断の追加仕様ではない。意味が衝突する場合は`GTP.md`を優先する。
4
+
5
+ ## 現在の判断を読む順序
6
+
7
+ 1. ADR-027: `GTP.md`を唯一の公開正本とし、4 Record・6 state・7 halt reasonへ限定した理由。
8
+ 2. ADR-028: Exact Carrier、closed schema、pure reducerを中間不整合なく切り替えた理由。
9
+ 3. ADR-029: GitHub live bindingをGET-onlyとし、Acquisition Errorをhaltから分離した理由。
10
+
11
+ ADR-001〜ADR-026は設計履歴として残す。現行`GTP.md`と矛盾する旧語彙や修復機構を、現在の公開仕様として使用しない。
12
+
13
+ ## ADR-001: GTPを権限の根拠にしない
14
+
15
+ - Status: Accepted
16
+ - Date: 2026-07-19
17
+
18
+ ### 背景
19
+
20
+ GTPはGitHub上のrecordと観測事実から、タスクの現在地を説明する。一方、v1.0はactorの本人性、credential、組織上の権限を検証しない。そのため、recordの投稿だけで変更やmergeの権限が生まれると定義しても、その権限の正当性をGTP自身では証明できない。
21
+
22
+ ### 決定
23
+
24
+ GTPのrecord、tool出力、GitHub上の観測事実は、変更、完了宣言、mergeの権限を一切与えない。
25
+
26
+ GTPは、外部から既に与えられた権限下の作業を制約し、現在地を説明するだけである。`contract`と`start`も許可証ではなく、タスク境界と開始事実の主張として扱う。
27
+
28
+ ### 結果
29
+
30
+ - GTPはactor識別やcredential管理を実装しない。
31
+ - toolの状態、exit code、next actionを操作権限として解釈しない。
32
+ - 実行主体は、変更前にGTPの外部で権限が与えられていることを確認する。
33
+ - GTPは外部権限の存在や妥当性を証明したとは主張しない。
34
+
35
+ ## ADR-002: exact markerでcarrierを識別する
36
+
37
+ - Status: Accepted
38
+ - Date: 2026-07-19
39
+
40
+ ### 背景
41
+
42
+ Issue commentには説明用のJSON、引用、通常の会話が混在する。JSON fenceだけを手掛かりにすると、GTP recordではないcommentを誤認する可能性がある。一方、曖昧一致を導入するとclassifierの判定規則が増え、引用や入力ミスをrecordとして拾う危険が残る。
43
+
44
+ ### 決定
45
+
46
+ GTP carrierは、次をすべて満たすIssue commentとする。
47
+
48
+ 1. 最初の非空行は、前後whitespaceのない、空でない1行の人向け要約である。
49
+ 2. 次の非空行は、列0から正確に `<!-- gtp-record:v1 -->` である。
50
+ 3. markerの後に、opening lineが列0から正確に ```` ```json ````、closing lineが列0から正確に ```` ``` ````であるJSON fenceが1個だけある。
51
+ 4. JSON fenceの内容は単一のGTP record objectである。
52
+ 5. 要約、marker、fenceの間とcomment末尾には空白行だけを許可し、それ以外のproseやwrapperを許可しない。
53
+
54
+ 大文字`JSON`、tilde fence、4個以上のbacktick、追加info string、fence lineの行末空白、`<details>` wrapperは拒否する。要約が日本語か、平易かはmachine検査しない。要約はLogical Record identityへ含めない。
55
+
56
+ markerがないcomment内のJSONは、通常のcommentとして無視する。exact markerがあるのにcarrierまたはJSONが壊れている場合は、`invalid_record`として当該comment URLを示して停止する。
57
+
58
+ `gtp status`と`gtp check`は、同じcarrier classifierを使用する。
59
+
60
+ ```text
61
+ gtp status <issue-url> # GitHub APIから取得したraw commentを検査
62
+ gtp check <comment.md> # 投稿予定のcomment全文を検査
63
+ ```
64
+
65
+ `gtp check`はJSON断片ではなく、実際に投稿するMarkdown comment全文を入力とする。
66
+
67
+ ### 最低限の受け入れケース
68
+
69
+ | 入力 | 結果 |
70
+ |---|---|
71
+ | exact marker + valid JSON | recordとして受理 |
72
+ | markerなしのJSON | 通常のcommentとして無視 |
73
+ | marker typo | 投稿前の`gtp check`で拒否 |
74
+ | exact marker + malformed JSON | `invalid_record`としてcomment URLを表示 |
75
+
76
+ ### 結果
77
+
78
+ - 普通のcommentとGTP recordを、raw Markdownから決定的に区別できる。
79
+ - 新しいstate、record type、commandは増えない。
80
+ - Level 0でtoolを使わずmarkerを打ち間違えたcommentは、live readerから認識されない。
81
+ - live readerはmarker typoを推測で補正しない。この見落としは、通常commentの誤認を防ぐための明示的なtrade-offである。
82
+
83
+ ### 参考
84
+
85
+ - [GitHub Flavored Markdown: HTML comment](https://github.github.com/gfm/#html-comment)
86
+ - [GitHub REST API: Issue comments](https://docs.github.com/en/rest/issues/comments)
87
+
88
+ ## ADR-003: `supersedes`を常時配列にする
89
+
90
+ - Status: Accepted
91
+ - Date: 2026-07-19
92
+
93
+ ### 背景
94
+
95
+ 同じ`type`の有効な葉が複数あると、状態は`conflicting_records`になる。`supersedes`が単一URLの場合、新しいrecordが一方を置換しても、置換されなかった葉と新しいrecordが残る。そのため、一般的な競合を1本の有効な葉へ戻せない。
96
+
97
+ exact marker付きで壊れ、`type`を判定できないcarrierも考慮する必要がある。このcarrierを後続recordから置換できない場合、`invalid_record`が永久に修復不能になる。
98
+
99
+ ### 決定
100
+
101
+ `supersedes`の正準形は、常にcomment URLの配列とする。新規recordは空配列を使用する。
102
+
103
+ ```json
104
+ "supersedes": []
105
+ ```
106
+
107
+ 有効な参照は、次をすべて満たす。
108
+
109
+ - 参照元と同じIssueにある。
110
+ - 参照元commentより前にGitHubへ投稿されている。
111
+ - 参照先が有効recordなら、参照元と同じ`type`である。
112
+ - 配列内のURLは重複しない。
113
+ - 1件のrecordから複数の過去commentを参照できる。
114
+
115
+ 自己参照、未来参照、別Issue参照、重複URL、有効recordへのcross-type参照は`invalid_record`とする。
116
+
117
+ 順序判定にはrecord内の`created_at`などの自己申告値を使わない。GitHub commentのserver orderを使用する。
118
+
119
+ exact marker付きだが壊れており、`type`を判定できないcarrierには回復用例外を設ける。後続の有効recordは、その壊れたcarrierのcomment URLを`supersedes`へ指定できる。置換された壊れたcarrierは、以後の`invalid_record`原因から外れる。
120
+
121
+ ### 競合のjoin
122
+
123
+ 有効な同型record AとBが競合している場合、後続のCは両方を列挙して競合を解消できる。
124
+
125
+ ```json
126
+ "supersedes": [
127
+ "https://github.com/.../issuecomment-A",
128
+ "https://github.com/.../issuecomment-B"
129
+ ]
130
+ ```
131
+
132
+ ### 結果
133
+
134
+ - `conflicting_records`と、type不明の壊れたcarrierから回復できる。
135
+ - 参照先を過去commentだけに限定するため、cycleは構造的に作れない。
136
+ - cycle専用のstate、reason code、検査機構は追加しない。
137
+ - record内の自己申告時刻は、順序やsupersessionの正当性を決めない。
138
+
139
+ ## ADR-004: read-side convergenceで安全なretryを扱う
140
+
141
+ - Status: Accepted
142
+ - Date: 2026-07-19
143
+
144
+ ### 背景
145
+
146
+ Issue comment投稿の応答が途切れると、producerは投稿が成功したか判断できず、同じrecordを再投稿する可能性がある。GitHub Issue Comment作成APIには、公開仕様上、commentの`body`とは別のidempotency keyがない。同じ意味のretryを別recordとして扱うと、安全な再送が`conflicting_records`を発生させる。
147
+
148
+ 一方、同じ`id`で異なる内容が投稿された場合はretryとみなせない。さらに、そのcollisionに異なる`type`が含まれると、通常のcross-type supersession禁止だけでは回復不能になる。
149
+
150
+ ### 決定
151
+
152
+ 同じ`id`かつ同じparsed JSONを持つcomment群は、1つの論理recordへ畳む。comment URL群は、その論理recordのaliasとしてcomment一覧から毎回導出する。alias台帳や保存フィールドは追加しない。
153
+
154
+ #### parsed JSON一致
155
+
156
+ 一致は、JSON文字列ではなく、検証済みJSON値の構造的一致で判定する。
157
+
158
+ - objectのキー順、空白、carrier外側の平易な要約は無視する。
159
+ - 配列順、文字列、大小文字、JSON型、値の差は保持する。
160
+ - duplicate keyを含むJSONは、比較前に`invalid_record`とする。
161
+
162
+ #### aliasとsupersession
163
+
164
+ - aliasの1つがsupersedeされたら、論理record全体をsupersedeされた扱いにする。
165
+ - 論理recordがsupersedeされた後に同一内容のretry commentが現れても、その論理recordは復活しない。
166
+ - aliasは観測したcomment集合から決定的に再導出する。
167
+
168
+ #### identity collision
169
+
170
+ 同じ`id`でparsed JSONが異なる場合は、identity collisionとして`invalid_record`にする。
171
+
172
+ 回復のため、次の狭い例外を設ける。
173
+
174
+ > 新しい`id`のrecordは、検出済みsame-id collisionを修復する場合に限り、そのcollisionに属する全comment URLを`type`にかかわらずsupersedeできる。
175
+
176
+ この例外は、collisionに属する全comment URLを列挙した場合だけ成立する。一部だけの置換、collisionではない通常recordへのcross-type参照、同じ`id`を再利用した修復は認めない。
177
+
178
+ ### 結果
179
+
180
+ - 同一内容のretryは競合を発生させない。
181
+ - 異内容のsame-id collisionはfail-closedで検出され、後続の新しい`id`から回復できる。
182
+ - 新しいstate、record type、永続的なalias台帳は追加しない。
183
+ - groupingとsupersessionは、毎回取得したGitHub comment集合から再計算できる。
184
+
185
+ ### 参考
186
+
187
+ - [GitHub REST API: Create an issue comment](https://docs.github.com/en/rest/issues/comments?apiVersion=2022-11-28#create-an-issue-comment)
188
+
189
+ ## ADR-005: core recordとGitHub observationを分離する
190
+
191
+ - Status: Accepted
192
+ - Date: 2026-07-19
193
+
194
+ ### 背景
195
+
196
+ Draftのcore envelopeには、自己申告の`author`と`created_at`が含まれていた。しかし、GTPはactorの本人性を証明せず、recordの順序にはGitHub commentのserver orderを使う。GitHub metadataと同じ情報をrecordへ重複して持つと、不一致規則が必要になり、retry時に時刻だけが変化してidentity collisionになる危険もある。
197
+
198
+ ### 決定
199
+
200
+ core envelopeを次へ限定する。
201
+
202
+ ```json
203
+ {
204
+ "gtp": "1.0",
205
+ "type": "contract | start | done | stop",
206
+ "id": "<UUID小文字>",
207
+ "supersedes": []
208
+ }
209
+ ```
210
+
211
+ `author`と`created_at`はcore recordから削除する。type固有payloadは、この共通envelopeへ追加する。
212
+
213
+ GitHubから取得したmetadataは、commentへ書き込むrecord fieldではなく、machine出力へ付加する導出情報として扱う。
214
+
215
+ ```json
216
+ {
217
+ "record": {
218
+ "gtp": "1.0",
219
+ "type": "contract",
220
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
221
+ "supersedes": []
222
+ },
223
+ "observation": {
224
+ "comment_url": "...",
225
+ "comment_id": 123,
226
+ "github_login": "...",
227
+ "created_at": "..."
228
+ }
229
+ }
230
+ ```
231
+
232
+ GitHub metadataを観測情報の唯一のownerとし、論理recordの同一性比較には含めない。`github_login`は投稿に使われたGitHub accountを表すだけで、人間の本人性、runtime、実行権限を証明しない。
233
+
234
+ ### `gtp check`の検査境界
235
+
236
+ GitHub metadataなしで検査できるのは、次に限定する。
237
+
238
+ - JSON構文とduplicate key
239
+ - core envelope schema
240
+ - UUIDの表記
241
+ - record typeごとの必須field
242
+ - `supersedes`がURL配列であること
243
+
244
+ 別Issue参照、未来参照、server order、参照先`type`、comment URLの存在などはIssue文脈が必要であり、offlineでは判定できない。offline結果を「完全にvalid」と表示せず、`schema_valid`とcontextual checks未実施を区別する。この区別はCLIの検査結果であり、GTPのstateではない。
245
+
246
+ ### 結果
247
+
248
+ - record本体は純粋なプロトコル情報だけを持つ。
249
+ - 自己申告値とGitHub metadataの不一致規則を作らない。
250
+ - retry時にmetadata差分でidentity collisionが発生しない。
251
+ - actor本人性と権限判定は、引き続きGTPの対象外である。
252
+
253
+ ## ADR-006: `gtp check`をoffline schema検査に限定する
254
+
255
+ - Status: Accepted
256
+ - Date: 2026-07-19
257
+
258
+ ### 背景
259
+
260
+ 単一commentの形式検査と、GitHub Issue全体の文脈検査では必要な入力と失敗理由が異なる。両方を`gtp check`へ入れると、network、認証、Issue指定が必要になり、offlineで決定的に実行できる利点が失われる。一方、offline結果を「完全にvalid」と表示すると、参照先やserver orderまで確認済みだと誤解される。
261
+
262
+ ### 決定
263
+
264
+ `gtp check <comment.md>`は、単一commentのoffline schema検査だけを行う。将来の`--issue` optionはv1.0へ追加しない。
265
+
266
+ 検査対象は次に限定する。
267
+
268
+ - GTP carrierの認識と構造
269
+ - JSONの厳密なparse
270
+ - duplicate keyの拒否
271
+ - core envelopeのschemaと必須field
272
+ - `gtp`、`type`、UUID、`supersedes`の形式
273
+ - type固有payloadの形式
274
+
275
+ 次は検査しない。
276
+
277
+ - 参照先commentの存在
278
+ - 参照元と参照先が同一Issueか
279
+ - 過去参照か
280
+ - type間のsupersession可否
281
+ - alias、競合、有効な葉
282
+ - GitHub author、comment URL、server order
283
+
284
+ 通常comment、認識した有効carrier、認識した壊れたcarrierを、protocol stateとは別のCLI結果で区別する。
285
+
286
+ 通常comment:
287
+
288
+ ```json
289
+ {
290
+ "recognized": false,
291
+ "schema_valid": null,
292
+ "contextual_checks": "not_run"
293
+ }
294
+ ```
295
+
296
+ 認識した有効carrier:
297
+
298
+ ```json
299
+ {
300
+ "recognized": true,
301
+ "schema_valid": true,
302
+ "contextual_checks": "not_run"
303
+ }
304
+ ```
305
+
306
+ 認識した壊れたcarrier:
307
+
308
+ ```json
309
+ {
310
+ "recognized": true,
311
+ "schema_valid": false,
312
+ "contextual_checks": "not_run",
313
+ "errors": ["..."]
314
+ }
315
+ ```
316
+
317
+ `gtp status`は別のschema validatorを実装しない。最初に`gtp check`と同じoffline validatorを使用し、その後だけGitHub Issue文脈の検査と状態導出を追加する。
318
+
319
+ ### 結果
320
+
321
+ - schema規則の実装ownerは1つになる。
322
+ - `gtp check`はnetworkと認証に依存せず、決定的に実行できる。
323
+ - 未検査項目を成功扱いしない。
324
+ - `recognized`、`schema_valid`、`contextual_checks`はCLI検査結果であり、新しいprotocol stateではない。
325
+ - contextual preflightはv1へ含めない。
326
+
327
+ ## ADR-007: GTP v1 core schemaを閉じる
328
+
329
+ - Status: Accepted
330
+ - Date: 2026-07-19
331
+
332
+ ### 背景
333
+
334
+ 未知fieldを保持して無視すると、field名のtypoを見逃す。さらに、未知fieldがlogical recordの構造比較へ入り込むと、安全なretryとidentity collisionの境界が不明確になる。GTP v1は外部JSON Schema libraryを使わず、依存ゼロで実装する制約もある。
335
+
336
+ ### 決定
337
+
338
+ GTP v1 core schemaを閉じる。
339
+
340
+ - `gtp: "1.0"`の各`type`について、許可fieldと必須fieldを完全列挙する。
341
+ - GTPが所有するすべてのobject階層で未知fieldを拒否する。
342
+ - 未知の`gtp` versionと未知の`type`もschema不適合とする。
343
+ - schema検証を通過したrecordだけを、grouping、supersession、reducerへ渡す。
344
+ - `gtp check`と`gtp status`は同じoffline validatorを使用する。
345
+ - GitHub observationとCLI出力はcore recordではないため、core schemaの閉鎖範囲に含めない。
346
+ - GTP v1は外部運用向けの拡張field、専用marker、adapterを定義しない。
347
+ - 新fieldが必要になっても`gtp: "1.0"`を黙って拡張せず、version変更と互換性を判断する。
348
+
349
+ 未知fieldは、例えば次のvalidator診断を返す。
350
+
351
+ ```json
352
+ {
353
+ "recognized": true,
354
+ "schema_valid": false,
355
+ "contextual_checks": "not_run",
356
+ "errors": [
357
+ {
358
+ "code": "unknown_field",
359
+ "path": "$.suprsedes"
360
+ }
361
+ ]
362
+ }
363
+ ```
364
+
365
+ `unknown_field`はoffline validatorの診断codeであり、Issue全体のprotocol stateやhalt reasonではない。
366
+
367
+ ### validator方針
368
+
369
+ 外部JSON Schema libraryは追加しない。共有validatorが、各`type`の許可field集合、必須field集合、値の型と形式を直接照合する。
370
+
371
+ 共有validatorは`gtp check`と`gtp status`の両方が使用する。schema-invalid recordをgrouping、supersession、reducerへ渡さない。schema拡張用の予約fieldや仮設物は定義しない。
372
+
373
+ ### scalarとURLの正準形
374
+
375
+ - `id`は次のcanonical lowercase UUID v4とする。
376
+
377
+ ```regex
378
+ ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
379
+ ```
380
+
381
+ - `head_sha`は省略なしのlowercase 40桁hexとする。
382
+ - `goal`とDone Conditionの`text`は空でない文字列とし、前後whitespaceとcontrol characterを禁止する。
383
+ - Unicode normalization、日本語判定、protocol独自の文字数上限は設けない。
384
+ - v1のGitHub resource URLは`https://github.com`だけを受理し、GitHub Enterprise Serverは対象外とする。
385
+ - query、userinfo、独自portを全resourceで禁止する。
386
+ - fragmentは原則禁止する。Issue Comment URLだけ、正確な`#issuecomment-<decimal-id>`を必須とする。
387
+ - Issue、PR、Issue Comment、Check Run、blobごとにpath profileを固定する。
388
+ - liveな同一repository判定はURL文字列ではなく、GitHubから取得したrepository identityで行う。
389
+
390
+ ownerとrepositoryのsegmentは、空でないliteral segmentとする。`%`、`/`、`\\`、NULを禁止し、`.`と`..`も拒否する。GitHub固有の完全な名前文法は再実装しない。
391
+
392
+ resourceごとのpath profileは次とする。decimal IDは`[1-9][0-9]*`である。
393
+
394
+ ```text
395
+ Issue:
396
+ https://github.com/{owner}/{repo}/issues/{issue-id}
397
+
398
+ PR:
399
+ https://github.com/{owner}/{repo}/pull/{pr-id}
400
+
401
+ Issue Comment:
402
+ https://github.com/{owner}/{repo}/issues/{issue-id}#issuecomment-{comment-id}
403
+
404
+ Check Run:
405
+ https://github.com/{owner}/{repo}/runs/{check-run-id}
406
+
407
+ Artifact:
408
+ https://github.com/{owner}/{repo}/blob/{lowercase-40-hex-sha}/{nonempty-path}
409
+ ```
410
+
411
+ Artifact pathだけはpercent encodingを許可する。ただし、malformedな`%XX`、UTF-8として不正なdecoded bytes、encodedまたはliteralの`/`によるsegment変形、`\\`、NUL、decode後の`.`または`..` segmentを拒否する。pathは空でなく、queryとfragmentを持たない。
412
+
413
+ ### 結果
414
+
415
+ - typoと未知versionをfail-closedで検出できる。
416
+ - idempotencyの構造比較へ、未定義fieldが入り込まない。
417
+ - 外部運用向けの拡張契約はv1 coreへ含めない。
418
+ - 各typeのpayloadを完全列挙するまで、schema実装は開始できない。
419
+
420
+ ### 参考
421
+
422
+ - [JSON Schema: Objects](https://json-schema.org/understanding-json-schema/reference/object)
423
+
424
+ ## ADR-008: unknownをprotocol modelへ入れない
425
+
426
+ - Status: Accepted
427
+ - Date: 2026-07-19
428
+
429
+ ### 背景
430
+
431
+ 自由文のunknownをrecordへ保存しても、reducerはその意味や重要性を決定的に判定できない。unknownがstateへ影響しないならfieldは冗長であり、影響させるなら`paused`などの新stateと解釈規則が必要になる。また、完了条件と無関係な将来的疑問は、GTPの完了判定対象ではない。
432
+
433
+ ### 決定
434
+
435
+ - `contract.unknowns`と`done.unknowns`を削除する。
436
+ - `none_observed`を導入しない。
437
+ - unknown専用のrecord、field、stateを作らない。
438
+ - 契約確定前の質問は通常commentへ書き、解決するまで`contract`を投稿しない。
439
+ - 契約を変えない実装上の質問は通常commentへ書き、stateは`in_progress`のままにする。
440
+ - 完了条件の充足を確認できない場合は`done`を投稿しない。
441
+ - `paused` stateを追加しない。
442
+ - reducerは自由文と外部運用情報を解釈しない。
443
+
444
+ 完了時の未確認事項とは、done conditionの成否に関係するものだけを指す。完了条件と無関係な将来的疑問はGTPの判定対象外である。
445
+
446
+ GTPは、外部運用向けのcompanion artifact、専用marker、adapterを定義しない。
447
+
448
+ ### 結果
449
+
450
+ - GTPにはunknownを表す構造や待機stateが存在しない。
451
+ - 質問と議論はGitHubの通常commentへ残る。
452
+ - done conditionを確認できない作業は、完了として扱われない。
453
+ - 外部の開発管理機構なしでも、GTP仕様とGitHub commentだけで利用できる。
454
+
455
+ ## ADR-009: scopeは狭い形式のtask境界とする
456
+
457
+ - Status: Accepted
458
+ - Date: 2026-07-19
459
+
460
+ ### 背景
461
+
462
+ `contract.scope`をPR差分へ機械的に強制するには、glob、rename、submodule、生成物などの判定規則が必要になる。v1で不完全なscope checkerを提供すると、検証していない差分へ「範囲内」という誤った保証を与える危険がある。一方、agentの引き継ぎと人間の理解には、対象pathを狭い形式で示す価値がある。
463
+
464
+ ### 決定
465
+
466
+ `scope`はrequiredの配列とし、1件以上のrepository-relative pathを含む。
467
+
468
+ ```json
469
+ "scope": [
470
+ "src/",
471
+ "README.md"
472
+ ]
473
+ ```
474
+
475
+ 形式規則は次とする。
476
+
477
+ - 配列は空にしない。
478
+ - 同じpathを重複させない。
479
+ - directoryは末尾`/`で表す。
480
+ - fileはrepository rootからの正確なpathで表す。
481
+ - `.`だけはrepository全体を表す。
482
+ - glob、絶対path、空文字、`..` path segmentを禁止する。
483
+ - `.`以外の`.` path segmentと、空のpath segmentを禁止する。
484
+
485
+ `scope`はtask境界の主張であり、変更権限を与えない。`gtp status`はPR diffがscope内であることを検査せず、遵守済みとも表示しない。
486
+
487
+ ### 結果
488
+
489
+ - agentと人間は、contractから対象領域を読み取れる。
490
+ - scope grammarは小さく決定的になる。
491
+ - PR差分のscope遵守証明はv1の非目標となる。
492
+ - scope遵守の機械検査はv1へ含めない。
493
+
494
+ ## ADR-010: done conditionsとevidenceをmapで対応付ける
495
+
496
+ - Status: Accepted
497
+ - Date: 2026-07-19
498
+
499
+ ### 背景
500
+
501
+ 配列形式ではcondition IDの一意性と`done.evidence`との対応付けを別規則で管理する必要がある。condition IDをobject keyにすれば、IDがcanonical ownerとなり、対応付け専用fieldと配列順への依存を除去できる。
502
+
503
+ ### 決定
504
+
505
+ `contract.done_conditions`を、condition IDからcondition定義へのmapとする。
506
+
507
+ ```json
508
+ "done_conditions": {
509
+ "tests_pass": {
510
+ "text": "すべてのテストが成功する",
511
+ "evidence_kind": "check"
512
+ }
513
+ }
514
+ ```
515
+
516
+ `done.evidence`は、同じcondition IDからevidence URLへのmapとする。
517
+
518
+ ```json
519
+ "evidence": {
520
+ "tests_pass": "https://github.com/..."
521
+ }
522
+ ```
523
+
524
+ condition IDは次の正規表現へ一致させる。
525
+
526
+ ```regex
527
+ ^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$
528
+ ```
529
+
530
+ 先頭・末尾の`_`、連続する`__`、大文字は認めない。
531
+
532
+ `done_conditions`の規則:
533
+
534
+ - requiredかつ空でないobjectである。
535
+ - 各conditionは`text`と`evidence_kind`だけを持つ。
536
+ - `text`は空でない文字列である。
537
+ - `evidence_kind`は許可されたkindの1つである。
538
+ - duplicate condition IDはduplicate JSON keyとして拒否する。
539
+
540
+ `done.evidence`の規則:
541
+
542
+ - requiredかつ空でないobjectである。
543
+ - keyはcondition IDと同じ形式に従う。
544
+ - 値はevidence参照の基本schemaに従う。
545
+ - `kind`を繰り返さない。kindのownerはcontract側だけである。
546
+
547
+ ### 検査境界
548
+
549
+ offline validatorは、両mapの存在、空でないこと、key形式、duplicate key、nested field、値の基本schemaを検査する。
550
+
551
+ `gtp status`のcontextual validatorは、active contractの`done_conditions`と`done.evidence`のkey集合が完全一致することと、各参照がcontract側の`evidence_kind`へ適合することを検査する。不足、余分、key不一致はcontextualな`invalid_record`とする。
552
+
553
+ objectの記述順に意味を持たせない。人向け表示とmachine出力を生成するときだけ、condition IDをlexicographic順に並べる。
554
+
555
+ ### 限界
556
+
557
+ key集合が一致し、URL形式とevidence kindが適合しても、done conditionの自然言語上の内容が本当に充足されたことまでは自動的に証明しない。GTPが主張できるのは、要求された種類のevidence参照が各conditionへ提示され、検証可能なGitHub factと整合している範囲までである。
558
+
559
+ ### 結果
560
+
561
+ - condition IDの一意性と対応関係が構造で表現される。
562
+ - `evidence_kind`のownerがcontract側へ一本化される。
563
+ - 配列順と対応付け専用fieldが不要になる。
564
+ - 条件内容の意味評価をGTPが行ったという過剰な主張を避ける。
565
+
566
+ ## ADR-011: evidence kindを`check`と`artifact`へ限定する
567
+
568
+ - Status: Accepted
569
+ - Date: 2026-07-19
570
+
571
+ ### 背景
572
+
573
+ `human` evidenceが参照するcommentは、GitHub accountによる投稿が存在することしか証明しない。本人性、権限、判断能力、記述内容の真実性は証明できない。`approval`や`attestation`へ改名しても、この境界は変わらない。また、複数種類のGitHub check resourceを同じkindへ含めると、URL profileとAPI validatorが増える。
574
+
575
+ ### 決定
576
+
577
+ GTP v1のevidence kindを、次の2種類だけに限定する。
578
+
579
+ ```text
580
+ check | artifact
581
+ ```
582
+
583
+ `human`、`approval`、`attestation`は定義しない。人間の権限判断と最終判断はGitHub nativeのreview・mergeへ残す。
584
+
585
+ #### `check`
586
+
587
+ `check`が参照できるresourceはGitHub Check Runだけとする。validatorは次を確認する。
588
+
589
+ - Check Runがbound PRと同じrepositoryに属する。
590
+ - `status == completed`である。
591
+ - `conclusion == success`である。
592
+ - `head_sha == done.head_sha`である。
593
+
594
+ GitHub Actions Workflow Runはv1の`check` profileへ含めない。
595
+
596
+ #### `artifact`
597
+
598
+ `artifact`は、bound PRと同じrepositoryにあるfileのimmutable blob permalinkとする。validatorは次を確認する。
599
+
600
+ - URLが`/blob/<full-sha>/<path>`形式である。
601
+ - URLのfull SHAが`done.head_sha`と一致する。
602
+ - fileがそのcommitに存在する。
603
+ - branch名、tag、`main`などを使った可変URLではない。
604
+
605
+ 手動probeの結果をevidenceにする場合は、結果をrepository内のfileへ記録し、full-SHA permalinkを`artifact`として参照できる。
606
+
607
+ ### evidenceが証明する範囲
608
+
609
+ `check`が証明するのは、指定SHAに対してGitHub Check Runが`success`を返したことまでである。check内容がdone conditionの自然言語上の意味を十分に検査したことまでは証明しない。
610
+
611
+ `artifact`が証明するのは、指定SHAに参照先fileが存在することまでである。fileの内容、記録されたprobeの実施方法、記述の真実性までは証明しない。
612
+
613
+ GTPが検証するのは、evidence参照の存在、固定性、repository、resource状態、SHA bindingである。
614
+
615
+ ### 取得失敗との分離
616
+
617
+ - resourceを取得でき、repository、SHA、status、conclusion、URL profileが一致しなければevidence不適合とする。
618
+ - network、認証、rate limitなどでresourceを取得できなければ検査不能とする。record不正とは断定しない。
619
+ - 検査不能時は`done`を確認済みと表示せず、CLIの取得エラーとして報告する。
620
+ - 取得失敗のための新しいprotocol stateは追加しない。
621
+
622
+ ### 結果
623
+
624
+ - evidence validatorは2種類の固定profileだけを持つ。
625
+ - commentを人間性や権限の証明として扱わない。
626
+ - evidenceの存在とdone conditionの真実性を混同しない。
627
+ - GitHubデータ取得不能とprotocol不適合を分離する。
628
+
629
+ ## ADR-012: repair supersessionをinvalid groupの完全置換へ統合する
630
+
631
+ - Status: Accepted
632
+ - Date: 2026-07-19
633
+
634
+ ### 背景
635
+
636
+ recognizedだがJSONまたはschemaが壊れたcarrierと、same-ID identity collisionは、どちらも通常のsame-type supersessionだけでは回復できない。個別の例外を増やす代わりに、readerが一時的なrepair groupを導出し、invalidな過去comment集合の完全置換として共通判定できる。
637
+
638
+ ### repair groupの導出
639
+
640
+ readerは次の優先順位でgroupを導出する。
641
+
642
+ 1. Edited Carrierはsingleton groupとする。
643
+ 2. Intrinsic-validなsame-ID identity collisionは、collisionに属するcomment全体で1 groupとする。
644
+ 3. Intrinsic-invalidなrecognized Carrierはsingleton groupとする。
645
+ 4. Historical Contextual-invalidのうち、規定されたclosed reason-code setに属するcommentはsingleton groupとする。
646
+
647
+ 1つのcommentを複数groupへ所属させない。Edited Carrierはidentity groupingへ入れず、collision memberはcontextual-invalid singletonへも入れない。repair group membershipをreaderの自由な「repairable」判断から導出してはならず、closed reason-code setだけをownerとする。
648
+
649
+ Historical Contextual-invalid singletonを作るclosed reason-code setは次の8個だけとする。
650
+
651
+ ```text
652
+ invalid_supersession
653
+ incomplete_repair_group
654
+ start_contract_binding_failed
655
+ done_before_start
656
+ done_condition_keys_mismatch
657
+ done_evidence_kind_mismatch
658
+ stop_without_contract
659
+ successor_order_invalid
660
+ ```
661
+
662
+ `successor_order_invalid`はself-reference、source Issue以前、Stopより後に作成された場合だけを含む。Successor Issueの後日の削除、移管、取得不能はLive ConformanceまたはAcquisition Errorであり、このcodeへ含めない。
663
+
664
+ post-start Contract、Started Once後のfresh-ID Start、Contract Freeze違反、terminal後の新Logical Record、terminal violationはrepair groupへ入れない。これらはhistoricalで単調なlifecycle factであり、後続supersessionによって消せない。
665
+
666
+ Live Conformance不適合もrepair groupへ入れない。terminal前のvalid DoneまたはStopがlive resourceと不適合になった場合は、通常のsame-type supersessionで新しいRecordへ置換できる。
667
+
668
+ repair groupはrecordへ保存するfieldやprotocol stateではなく、観測したcomment集合からreaderが一時的に導出する検査単位である。
669
+
670
+ ### supersession判定
671
+
672
+ `supersedes`の各URLを次の順で判定する。
673
+
674
+ ```text
675
+ URLがrepair groupに属する
676
+ → repair recordよりserver order上で過去のgroup memberを完全列挙しているか
677
+ → repair recordがfresh idを持つか
678
+ → group内に限りtype不一致を許容
679
+
680
+ URLがrepair groupに属さない
681
+ → 通常の過去・同一Issue・同一type規則
682
+ ```
683
+
684
+ URLがrepair groupに属する場合、通常規則へfallbackできない。必ずrepair規則を満たす。これにより、schema-validかつ同型に見えるidentity collision memberだけを部分的にsupersedeすることを防ぐ。
685
+
686
+ 完全列挙の対象は、repair recordよりserver order上で過去に存在するgroup memberとする。repair後に遅延retry commentが現れても、過去のrepairを遡ってinvalidにしない。同一内容の遅延retryは、既存のalias規則により、supersede済みの論理recordへ畳まれる。
687
+
688
+ 複数groupを1件のrecordで修復する場合は、各groupについて独立に完全列挙する。
689
+
690
+ ### 緩和する範囲
691
+
692
+ repair規則が緩和するのは、完全列挙したgroup内部の`type`一致条件だけである。repair record自体は、通常のschema、freshな`id`、過去参照、同一Issue、lifecycle、type固有payloadのすべてを満たす必要がある。repair supersessionを使って不正なstate transitionを正当化できない。
693
+
694
+ ### 結果
695
+
696
+ - 壊れたCarrier、Edited Carrier、identity collision、closed setに属するHistorical Contextual-invalidを同じ判定で修復できる。
697
+ - repair groupの部分置換を禁止できる。
698
+ - 遅延retryにより過去のrepairが遡及的に無効にならない。
699
+ - repair専用field、record type、state、reason codeは追加しない。
700
+
701
+ ## ADR-013: 最初のvalid startでcontractをfreezeする
702
+
703
+ - Status: Accepted
704
+ - Date: 2026-07-19
705
+
706
+ ### 背景
707
+
708
+ 作業開始後に同じIssue内でgoal、scope、done conditionsを変更できると、どのcontractに対して作業とevidenceを評価すべきかが曖昧になる。変更の大小をreducerが判断する規則も必要になる。Issueを分ける手間と引き換えに、開始時のcontractが途中で変わらない不変条件を採用する。
709
+
710
+ ### 歴史的なfreeze判定
711
+
712
+ server orderでcommentを先頭から評価し、各comment投稿時点までのprefixに対してvalidだった`start`が1件でも存在すれば、`started_once`をtrueとする。
713
+
714
+ ```text
715
+ started_once = 過去にprefix-validなstartが1件でも存在した
716
+ ```
717
+
718
+ `started_once`はcomment履歴から導出する単調な事実であり、record fieldや永続stateではない。後から該当`start`がsupersedeされても、same-ID collisionへ巻き込まれても、falseへ戻らない。
719
+
720
+ ### contract freeze
721
+
722
+ - `started_once == false`の間は、contractを通常のsupersessionで訂正できる。
723
+ - 最初のprefix-validな`start`以後、新しい`id`のcontractは、内容が同じでもfreeze違反になる。
724
+ - 同じ`id`かつ同じparsed JSONの再投稿だけは、API retry aliasとして扱う。
725
+ - 同じ`id`かつ異なるparsed JSONはidentity collisionである。
726
+ - scope縮小、condition追加、文言修正を含め、parsed JSONが変わるcontractは変更の大小を問わない。
727
+
728
+ post-start contractはactive contractにならず、pre-startに確定したcontractをsupersedeしない。active contractは最後のpre-start contractのまま保持し、Issueは`halt`になる。post-start contractを新しい仕様として解釈しない。後続supersessionでも歴史的なfreeze違反は消えない。
729
+
730
+ ### contract変更が必要な場合
731
+
732
+ 次の順序でsuccessor Issueへ移行する。
733
+
734
+ ```text
735
+ successor Issueを先に作成
736
+ → 旧Issueへ stop(reason="superseded", successor_ref="...")
737
+ → successor Issueへ新しいcontract
738
+ → successor Issueへ新しいstart
739
+ ```
740
+
741
+ successor Issueを作成できなければ、旧Issueは`in_progress`のまま維持し、`successor_ref`のない`superseded` stopを残さない。
742
+
743
+ ### freeze違反からのstop
744
+
745
+ contract freeze違反による`halt`中でも、schemaと通常のstop条件を満たす`stop`だけは受理できる。有効な`stop`後は`stopped`をterminal stateとして表示し、freeze違反commentは履歴上のdiagnosticとして残す。
746
+
747
+ この例外はfreeze違反を正当化せず、旧Issueを閉じてsuccessor chainを残すためだけに使う。
748
+
749
+ ### 結果
750
+
751
+ - 作業開始時のcontractが途中で変わらない。
752
+ - 歴史的なstartを後から消してfreezeを解除できない。
753
+ - API retryとcontract改訂を明確に区別できる。
754
+ - freeze違反があっても、successor Issueへの正式な移行経路を失わない。
755
+
756
+ ## ADR-014: startから`contract_ref`を削除する
757
+
758
+ - Status: Accepted
759
+ - Date: 2026-07-19
760
+
761
+ ### 背景
762
+
763
+ contract freezeと、start投稿時点でactiveな論理contractが1件だけという条件があれば、`contract_ref`はreaderが導出できるfactの重複保存になる。明示URLを保存すると、stale URL、typo、別Issue参照、retry aliasのどれを選ぶかという追加規則が必要になる。
764
+
765
+ ### start payload
766
+
767
+ `start`のtype固有payloadは`branch`だけとする。
768
+
769
+ ```json
770
+ {
771
+ "gtp": "1.0",
772
+ "type": "start",
773
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
774
+ "supersedes": [],
775
+ "branch": "feature/example"
776
+ }
777
+ ```
778
+
779
+ ### contract binding
780
+
781
+ bindingは各`start`について、次の順序で決定する。
782
+
783
+ 1. `start`より前のcommentだけをserver orderで評価する。
784
+ 2. repair、supersession、alias groupingを適用する。
785
+ 3. activeな論理`contract`を数える。
786
+ 4. 正確に1件なら、その論理contractへbindingする。
787
+ 5. 0件または複数なら、`start`をcontextual invalidとする。
788
+ 6. bindingに成功した`start`だけがcontract freezeを発生させる。
789
+
790
+ comment URL数ではなく論理record数を数える。同じcontractに複数のretry aliasがあっても、active contractは1件である。
791
+
792
+ bindingは常にstart投稿時点のcomment prefixから導出する。後のcommentを使って過去のstartを別contractへrebindしない。post-start contractによってIssueが`halt`しても、元のbindingは変わらない。
793
+
794
+ bindingに失敗したStartはfreezeを発生させない。修正版Startはfreshな`id`を持ち、`supersedes`へ置換対象のinvalid Start URLを含める。activeなinvalid Startが複数ある場合は全active leafを列挙する。GitHub取得不能はbinding failureと断定しない。
795
+
796
+ 一度prefix-valid Startが成立した後は、同じbranchと内容であってもfresh IDのStartによる改訂を認めない。同じID・同じparsed JSONの遅延retryだけをaliasとして扱う。branchを変更する場合はvalid StopとSuccessor Issueを使用する。
797
+
798
+ ### machine output
799
+
800
+ binding結果をrecordへ保存せず、machine outputへ次の導出情報を含める。
801
+
802
+ ```json
803
+ {
804
+ "bound_contract": {
805
+ "id": "contract-record-id",
806
+ "url": "https://github.com/.../issuecomment-...",
807
+ "aliases": [
808
+ "https://github.com/.../issuecomment-..."
809
+ ]
810
+ }
811
+ }
812
+ ```
813
+
814
+ `url`はserver order上で最初のaliasをcanonical表示にする。`aliases`は観測した全comment URLをserver orderで含める。
815
+
816
+ ### 結果
817
+
818
+ - contract bindingのownerはreaderのprefix評価へ一本化される。
819
+ - stale URL、別Issue参照、alias選択の規則が不要になる。
820
+ - `gtp check`はGitHub文脈なしでstart schemaを検査できる。
821
+ - contract commentが削除された場合は内容を復元できないため、`contract_ref`を保存しても回復性は増えない。
822
+
823
+ ## ADR-015: branchはshort nameの宣言とlive bindingに分ける
824
+
825
+ - Status: Accepted
826
+ - Date: 2026-07-19
827
+
828
+ ### 背景
829
+
830
+ Git ref文法全体をoffline validatorへ再実装すると独自規則が増える。一方、branchは削除可能なmutable GitHub resourceであり、comment履歴から導出する`start`やcontract freezeとは寿命が異なる。
831
+
832
+ ### offline schema
833
+
834
+ `start.branch`は次を満たす。
835
+
836
+ - requiredの空でない文字列である。
837
+ - 前後にwhitespaceがない。
838
+ - control characterを含まない。
839
+ - `refs/heads/`で始まらない。
840
+ - URL形式ではない。
841
+ - `/`を含むshort branch nameを許容する。
842
+
843
+ repository名らしい文字列かどうかや、Git ref文法全体はofflineで判定しない。
844
+
845
+ ### live binding
846
+
847
+ `gtp status`はIssueと同じrepositoryでbranch名をexact matchし、次の規則を適用する。
848
+
849
+ - `in_progress`ではbranchの存在が必要である。
850
+ - valid `done`があってもbound PRが未mergeならbranchの存在が必要である。
851
+ - bound PRがmerge済みならbranch不在を許容する。
852
+ - `stopped`ではbranch不在を許容する。
853
+ - merge後のbranch削除で、過去のvalid `done`、prefix-validな`start`、`started_once`を取り消さない。
854
+
855
+ exact branchの存在を確認できればbinding適合、GitHubから不在を確認できればbinding不適合とする。network、認証、rate limitなどで判定できなければ取得不能とし、record不正とは断定しない。
856
+
857
+ branch存在はmutableなlive observationであり、`start` recordのschema validityとcontract freezeから分離する。branchが一時的に消えても、過去のvalid startは消えない。
858
+
859
+ ### 結果
860
+
861
+ - offline validatorは独自のGit ref文法を持たない。
862
+ - native merge前のbranch消失を検出できる。
863
+ - merge後の自動branch削除を正常に扱える。
864
+ - immutableなcomment履歴とmutableなbranch factを混同しない。
865
+
866
+ ## ADR-016: Bound PRは`done.pr_ref`で明示する
867
+
868
+ - Status: Accepted
869
+ - Date: 2026-07-19
870
+
871
+ ### 背景
872
+
873
+ Contractは同じIssue内のimmutableなcomment prefixから一意に導出できる。一方、PRはbranch名で検索するmutableな外部resourceである。branch名は削除後に再利用できるため、`start.branch`だけからPR identityを永続的に導出すると、後年の同名branchと新しいPRによって過去Issueのbindingが変わり得る。
874
+
875
+ ### 決定
876
+
877
+ `done.pr_ref`を維持し、特定のPR identityを選ぶdurable bindingとする。
878
+
879
+ ```json
880
+ {
881
+ "gtp": "1.0",
882
+ "type": "done",
883
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
884
+ "supersedes": [],
885
+ "pr_ref": "https://github.com/owner/repo/pull/123",
886
+ "head_sha": "...",
887
+ "evidence": {}
888
+ }
889
+ ```
890
+
891
+ `gtp status`はvalid `done.pr_ref`について次を検査する。
892
+
893
+ - PRのbase repositoryがIssue repositoryと一致する。
894
+ - PRのhead repositoryがIssue repositoryと一致する。
895
+ - PRの`head.ref`が`start.branch`と一致する。
896
+ - `done.head_sha`がPRの対象head SHAと一致する。
897
+ - fork PRではない。
898
+
899
+ valid `done.pr_ref`でbindingした後は、そのPRをBound PRとする。後から同名branchが再利用され、新しいPRが作られても、過去IssueのBound PRを変更しない。
900
+
901
+ ### done前のPR候補
902
+
903
+ `done`前は、`start.branch`からPR候補をtentativeなObservationとして導出する。この候補はBound PRではない。
904
+
905
+ 候補は次をすべて満たすPRだけとする。
906
+
907
+ - base repositoryがIssue repositoryである。
908
+ - head repositoryもIssue repositoryである。
909
+ - `head.ref == start.branch`である。
910
+ - fork PRではない。
911
+
912
+ 検索対象はopen、closed-unmerged、mergedの全履歴とする。候補0件は正常であり、候補が正確に1件ならidentityは一意である。closed-unmergedが1件だけでも、それだけでは`halt`にしない。branchが存在しなければLive Branch Binding mismatchは別に評価する。PR Candidateのmachine表示shapeはprotocol coreに含めない。
913
+
914
+ ```text
915
+ done前:
916
+ branch → PR候補(導出・tentative)
917
+
918
+ done時:
919
+ pr_ref → Bound PR(明示・durable)
920
+ ```
921
+
922
+ active Doneがない状態で同じbranchをheadとするsame-repository PR Candidateが複数存在すれば`halt`とする。ただし、halt中にvalid `done.pr_ref`がrepository、branch、head SHAへ適合する1件を明示した場合、そのPRをBound PRとしてambiguityを解消できる。Doneは権限や品質を決めず、PR identityだけを選択する。valid Stopによる終了も許可する。
923
+
924
+ `merge_without_done`をLate Doneで解消する場合、`pr_ref`は実際にmergeされたPRを指さなければならない。無関係な未merge候補を選んでも、過去のmerge異常は解消しない。
925
+
926
+ Bound PR確定後は、将来のbranch再利用による候補増加を過去Issueの競合として扱わない。
927
+
928
+ ### 結果
929
+
930
+ - branch labelの再利用で過去のPR bindingが変わらない。
931
+ - PR作成時刻とdone投稿時刻の比較や、branch名の永久再利用禁止が不要になる。
932
+ - `pr_ref`は重複情報ではなく、mutableな候補からstableなPR identityを選ぶfieldとなる。
933
+ - fork PRはv1の対象外となる。
934
+
935
+ ## ADR-017: PR head変更時はstale doneとしてfail-closedにする
936
+
937
+ - Status: Accepted
938
+ - Date: 2026-07-19
939
+
940
+ ### 背景
941
+
942
+ `done`は`head_sha`で示した特定のsource commitに対する完了主張である。valid `done`の投稿後、merge前にBound PRへcommitが追加されると、既存evidenceは新しいheadを検証していない。一方、古い`done`はschema-validであり、投稿時点では主張が成立していた可能性があるため、record自体を`invalid_record`へ変更してはならない。
943
+
944
+ ### 決定
945
+
946
+ active `done`の`head_sha`とBound PRの現在のsource head SHAが異なる場合、record validityではなくLive Conformance mismatchとしてIssueを`halt`にする。正準tokenは`done_head_sha_mismatch`だけとし、`stale_done`、`stale_evidence`、`head_sha_mismatch`を別tokenとして使用しない。新しいprotocol stateは追加しない。
947
+
948
+ ```json
949
+ {
950
+ "state": "halt",
951
+ "active_done_head_sha": "old-sha",
952
+ "bound_pr_head_sha": "new-sha"
953
+ }
954
+ ```
955
+
956
+ この`halt`中は、修正版`done`またはvalid `stop`を受理できる。
957
+
958
+ 修正版`done`は次をすべて満たす。
959
+
960
+ - freshな`id`を持つ。
961
+ - 古いactive `done`を`supersedes`で置換する。
962
+ - conflictingなactive `done`が複数ある場合は、すべてのactive leafを列挙する。
963
+ - Bound PRの現在のsource head SHAを完全な`head_sha`として持つ。
964
+ - active Contractの全Done Conditionについて、新しいSHAへbindingされたevidenceを完全に再提示する。
965
+ - 古い`done`のevidenceを暗黙に継承しない。
966
+
967
+ bindingが再び一致した場合だけ、Issueは完了へ復帰できる。
968
+
969
+ ### merge時のSHA
970
+
971
+ `done.head_sha`と比較するのは、PRからmerge対象になったsource head SHAである。merge後にbase branchへ作られたmerge commit、squash commit、rebase後のcommitのSHAとは比較しない。
972
+
973
+ Bound PRがmergeされた後は、そのPRについて記録されたsource head SHAを評価する。将来の同名branch再利用や別PRは、確定済みBound PRと過去の`done`へ影響しない。
974
+
975
+ ### 結果
976
+
977
+ - evidence取得後に追加されたcodeを未検証のまま完了扱いしない。
978
+ - 過去に成立し得た`done`のrecord validityを遡及的に壊さない。
979
+ - 回復に新しいstate、record type、evidence継承規則を必要としない。
980
+
981
+ ## ADR-018: Stopのsuccessorは同一repositoryの未来のIssueへ限定する
982
+
983
+ - Status: Accepted
984
+ - Date: 2026-07-19
985
+
986
+ ### 背景
987
+
988
+ `stop`はtaskを中止するだけでなく、`superseded`の場合には後継Issueを明示する。参照先のrepositoryと作成順を制限しなければ、別repositoryへの不安定な移管や、Issue AからB、BからAというsuccessor cycleを作れる。
989
+
990
+ ### 決定
991
+
992
+ `stop`のtype固有payloadは`reason`と`successor_ref`だけを持ち、`successor_ref`は常にrequiredとする。
993
+
994
+ ```json
995
+ {
996
+ "gtp": "1.0",
997
+ "type": "stop",
998
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
999
+ "supersedes": [],
1000
+ "reason": "abandoned",
1001
+ "successor_ref": null
1002
+ }
1003
+ ```
1004
+
1005
+ fieldの組合せは次に限定する。
1006
+
1007
+ - `reason == "abandoned"`なら`successor_ref`は`null`。
1008
+ - `reason == "superseded"`なら`successor_ref`はcanonical GitHub Issue URL文字列。
1009
+ - PR URL、comment URL、fragment付きURL、query付きURLはsuccessorとして拒否する。
1010
+
1011
+ `gtp check`はこの型、enum、条件付き組合せ、URL入力形だけをofflineで検査する。
1012
+
1013
+ `successor_ref`のURL入力形はIntrinsic Validityで検査する。参照先を取得できた場合、そのstableな作成時刻を使って、source Issue自身ではないこと、source Issueより後かつ`stop` comment以前に作成されたことをHistorical Contextual Validityで検査する。
1014
+
1015
+ Successor Issueの現在の存在とrepository identityへの解決はLive Conformanceとする。後の移管や削除によってStop Record自体を遡及的にcontext-invalidへ変えない。open/closed状態、GTP Recordの有無、successor Issueの内容を条件にせず、successor chainも再帰評価しない。
1016
+
1017
+ 時間関係は次のとおりとする。
1018
+
1019
+ ```text
1020
+ source Issue creation
1021
+ < successor Issue creation
1022
+ <= stop comment creation
1023
+ ```
1024
+
1025
+ 作成順の不一致を確認できた場合はcontextual invalidとする。現在の存在またはrepository identityの不一致はlive reference mismatchとする。network、認証、rate limitなどで取得できない場合は取得不能として扱い、record不正とは断定しない。
1026
+
1027
+ successor Issueが後でclosedになっても、過去のvalid `stop`には影響しない。後からURLを解決できなくなった場合はlive reference mismatchとして表示し、`stop`のschema validityとは分離する。
1028
+
1029
+ ### 結果
1030
+
1031
+ - successor chainはIssue作成順で常に未来へ進む。
1032
+ - cycle専用のstate、reason、再帰検査を追加せずcycleを排除できる。
1033
+ - `successor_ref`のnullable条件が`reason`だけで決まる。
1034
+ - Operation連携、権限、successor Issueの内容評価をGTPへ持ち込まない。
1035
+
1036
+ ## ADR-019: valid Doneのmerge待ちはin_progressのまま扱う
1037
+
1038
+ - Status: Accepted
1039
+ - Date: 2026-07-19
1040
+
1041
+ ### 背景
1042
+
1043
+ `done` Recordは特定のsource commitについてDone Conditionsを満たしたという主張であり、Evidenceはその主張へ対応する参照である。GTPが機械的に確認できるのはEvidence resourceの存在、状態、repository、種類、SHA bindingまでであり、条件内容の真実性そのものではない。また、taskの最終事実はBound PRのnative mergeである。
1044
+
1045
+ validなactive `done`が存在しても、Bound PRが未mergeであることは矛盾でもblockerでもない。この待機を独立stateへすると、既存の`in_progress`で表せる状態を増やすことになる。
1046
+
1047
+ ### 決定
1048
+
1049
+ 次をすべて満たし、Bound PRが未mergeの場合、Issue stateは`in_progress`のままとする。
1050
+
1051
+ - activeなvalid `done`がある。
1052
+ - Doneの全Evidence参照がactive ContractのDone Conditionsと対応する。
1053
+ - 各Evidence resourceのrepository、種類、状態、`done.head_sha`へのbindingが適合する。
1054
+ - Bound PRのsource head SHAが`done.head_sha`と一致する。
1055
+ - Bound PRは未mergeである。
1056
+
1057
+ `awaiting_merge`などのprotocol stateは追加しない。Done Claim、Evidence Binding、merge待ちをどのfield名で表示するかはCLI projectionであり、protocol coreに含めない。Done Conditionの内容自体をGTPが証明したように表現してはならない。
1058
+
1059
+ Bound PRが`done.head_sha`に対応するsource headをnative mergeした時点だけ、Issue stateを`done`へ移す。
1060
+
1061
+ 人向けには、完了の主張と各条件に対応するEvidence参照があり、それらが対象commitへbindingされているが、PRは未mergeであることを表示する。
1062
+
1063
+ ### 結果
1064
+
1065
+ - Done Claim、Evidence Binding、native mergeを別のfactとして表示できる。
1066
+ - 通常のmerge待ちを`halt`へ昇格しない。
1067
+ - 新しいprotocol stateを追加せず、進行状況を正確に説明できる。
1068
+
1069
+ ## ADR-020: Haltは導出不能なtransitionだけを止める
1070
+
1071
+ - Status: Accepted
1072
+ - Date: 2026-07-19
1073
+
1074
+ ### 背景
1075
+
1076
+ `halt`をagentの全行動を禁止するstateとして解釈すると、矛盾の確認、修正版Recordの投稿、valid `stop`など、回復に必要な行動まで止めてしまう。また、GTPは操作権限を与えたり取り消したりするprotocolではない。
1077
+
1078
+ ### 決定
1079
+
1080
+ `halt`は、GitHub履歴とlive observationsから特定のprotocol transitionを一意かつ安全に導出できないため、そのtransitionを進めない状態とする。
1081
+
1082
+ - agent全体への停止命令ではない。
1083
+ - repository mutationの許可または禁止を表さない。
1084
+ - 通常の待機や取得不能を自動的にtask全体のblockerへ昇格しない。
1085
+ - 各halt reasonが明示的に許す修正版Recordやvalid `stop`などの回復操作は妨げない。
1086
+ - 人向け出力は、止めるtransition、理由、確認対象URL、許可を与える表示ではないことを説明する。
1087
+
1088
+ ### 結果
1089
+
1090
+ - fail-closedの対象を曖昧なtransitionへ限定できる。
1091
+ - recovery pathまで包括的に禁止する過剰停止を避けられる。
1092
+ - GTPのstateと外部の操作権限を混同しない。
1093
+
1094
+ ## ADR-021: Carrier編集を拒否し、削除検出の限界を明示する
1095
+
1096
+ - Status: Accepted
1097
+ - Date: 2026-07-19
1098
+
1099
+ ### 背景
1100
+
1101
+ GTPはappend-onlyなcomment履歴からstateを再構成するが、GitHub Issue Commentは編集・削除できる。v1 readerが過去bodyを完全な台帳として再構成しようとすると、GraphQLの編集差分、権限、欠落履歴を含む別の履歴機構が必要になる。
1102
+
1103
+ ### 決定
1104
+
1105
+ - 現在もExact Markerを持ち、GitHub metadataから編集済みと観測できるCarrierを`edited_carrier`とする。
1106
+ - unresolvedなEdited Carrierはsingleton Repair Groupとする。
1107
+ - fresh IDの後続Recordが当該URLを明示的に完全置換した後は、Edited Carrierをactiveなhalt原因に残さない。
1108
+ - 要約だけの編集も区別せず拒否する。
1109
+ - markerを除去する編集は、過去bodyやcarrier台帳を再構成しないv1 readerでは通常commentと区別できない場合がある。
1110
+ - 削除済みで、どの参照にも現れないCarrierも検出できない。
1111
+ - 参照先の欠落を確認できた場合はlive reference mismatchとして表示する。
1112
+ - network、認証、rate limitなどにより欠落と取得不能を区別できない場合はrecord不正と断定しない。
1113
+ - GTPはtamper-proof ledgerや、特権主体による改変への耐性を提供しない。
1114
+
1115
+ Terminal根拠となるCarrier自体が編集・削除された場合は、append-onlyな後続commentに対するTerminal Resultの単調性より、この編集・欠落規則を優先する。
1116
+
1117
+ ### 結果
1118
+
1119
+ - accidentによるCarrier編集を明示的に検出・修復できる。
1120
+ - 過去body再構成用の台帳や新しいprotocol stateを追加しない。
1121
+ - readerが検出できない改変を検出可能と主張しない。
1122
+
1123
+ ### 参考
1124
+
1125
+ - [GitHub REST API: Issue comments](https://docs.github.com/en/rest/issues/comments?apiVersion=2022-11-28)
1126
+ - [GitHub GraphQL: IssueComment](https://docs.github.com/en/graphql/reference/issues#issuecomment)
1127
+
1128
+ ## ADR-022: Terminal Resultはappend-onlyな後続commentに対して単調とする
1129
+
1130
+ - Status: Accepted
1131
+ - Date: 2026-07-19
1132
+
1133
+ ### 背景
1134
+
1135
+ terminal後の誤投稿を常に`halt`へ昇格すると、既に完了または中止したtaskが回復不能になる。一方、Terminal根拠Carrier自体の編集・削除まで無視すると、fresh readerが確認できない履歴を証明したことになる。
1136
+
1137
+ ### 決定
1138
+
1139
+ - valid Stopは、すべてのpre-terminal `halt`から利用できる非完了escapeとする。
1140
+ - Stop CarrierがIntrinsic-validであること、Stop以前にHistorical Contextual-valid Contractが1件以上存在すること、先行Terminal Resultがないこと、reasonとSuccessor規則が適合すること、Stop自身の`supersedes`が適合することだけを受理条件とする。
1141
+ - active Contractの一意性、Start、active Done、pre-terminal diagnosticの解消、PR state、branch存在はStopの受理条件にしない。
1142
+ - valid Contractが存在する`ready`、Start後、active DoneのPR merge前、すべてのpre-terminal `halt`からvalid Stopを受理できる。
1143
+ - prefix-valid Stop、またはactive valid Doneが対象とするsource headのnative mergeによってTerminal Resultが成立する。
1144
+ - Terminal Resultはappend-onlyな後続commentによって覆らない。
1145
+ - 既存Logical Recordと同じID・同じparsed JSONの遅延retryは新しいLogical Recordではないため、terminal violationにならない。
1146
+ - terminal後の新しいLogical RecordはTerminal Resultを変更せず、`terminal_violation` diagnosticを残す。stateは`done`または`stopped`を維持する。
1147
+ - Stop後にPRがmergeされても`stopped`を維持し、`merge_after_stop` diagnosticを表示する。
1148
+ - terminalになる前のinvalid StopまたはDoneは、通常のrepair規則に従って修復できる。
1149
+ - Terminal根拠Carrier自体の編集・削除にはADR-021を適用し、Terminal Resultの単調性で覆い隠さない。
1150
+
1151
+ valid Stop成立後、過去のpre-terminal blockerはdiagnosticとして残るが、stateは`stopped`とする。Stopは完了、権限付与、過去Recordの消去を意味しない。先行Terminal Resultがある場合だけ、fresh Stopを受理しない。
1152
+
1153
+ Terminal Result成立後に再検査するlive resourceは、その結果が実際に依存するものだけに限定する。
1154
+
1155
+ DoneによるTerminal Resultは次に依存する。
1156
+
1157
+ - intactなDone Carrierまたは未編集alias。
1158
+ - Bound PR。
1159
+ - merge対象source head SHA。
1160
+ - Doneが列挙したEvidence resource。
1161
+
1162
+ Superseded StopによるTerminal Resultは次に依存する。
1163
+
1164
+ - intactなStop Carrierまたは未編集alias。
1165
+ - Successor Issue identityと作成時間関係。
1166
+
1167
+ merge後に削除されたbranch、Bound PR確定後の同名branch、将来の同名branch PR、stopped後のbranch不在はTerminal Resultの依存resourceではない。
1168
+
1169
+ 依存resourceの適合を確認できれば`done`または`stopped`とする。不一致または欠落を十分なアクセス下で確認した場合は、live reference mismatchとして`halt`にする。network、認証、rate limit、権限不足と区別できない404などではstateを確認済みとして出力せず、acquisition errorとする。resourceが再び確認可能になれば、新Recordなしで再導出する。
1170
+
1171
+ Terminal Result成立後は、fresh DoneまたはStopによる依存resourceの差し替えを許可しない。terminal dependencyが永久に失われた場合は同じIssue内で回復不能になり得る。過去cache、永続alias台帳、terminal repair例外は追加しない。
1172
+
1173
+ ### 結果
1174
+
1175
+ - 後続の誤投稿でterminal taskが回復不能な`halt`へ変わらない。
1176
+ - append-only履歴に対する単調性と、観測できない履歴を証明しない境界を両立する。
1177
+ - 新しいterminal stateや修復record typeを追加しない。
1178
+
1179
+ ## ADR-023: DoneなしのmergeはHaltとし、後続Recordのprefixで回復する
1180
+
1181
+ - Status: Accepted
1182
+ - Date: 2026-07-19
1183
+
1184
+ ### 背景
1185
+
1186
+ native mergeはtaskの最終的なGitHub factだが、active valid Doneがなければ、Done Conditionsに対応するEvidence付き完了主張が存在しない。mergeだけを理由に`done`へ進めると、Evidence要件を迂回できる。
1187
+
1188
+ ### 決定
1189
+
1190
+ 一意なsame-repository PR Candidateがmerge済みで、active valid Doneがない場合は、`merge_without_done`を理由に`halt`とする。
1191
+
1192
+ late Doneはmerge時点へ遡及しない。次の順序で、そのcomment prefixにおいてTerminal Resultを成立させる。
1193
+
1194
+ ```text
1195
+ merge発生
1196
+ → halt: merge_without_done
1197
+ → late Done投稿
1198
+ → late DoneのprefixでTerminal Result成立
1199
+ ```
1200
+
1201
+ late Doneはfreshな`id`、merged PRの`pr_ref`、merge対象だったsource head SHA、全Done Conditionに対応するEvidenceを持つ。merged PRではbranch存在を要求しない。複数PR Candidateが存在する場合でも、実際にmergeされたPRを明示することでPR identityを決定できる。無関係なPRへのbindingでは`merge_without_done`を解消しない。
1202
+
1203
+ valid Stopによる回復も許可する。この場合は`stopped`となり、mergeを取り消したともTask Completionを主張したとも解釈しない。merge済みという外部事実は`merge_before_stop` diagnosticとして残す。
1204
+
1205
+ ### 結果
1206
+
1207
+ - mergeだけでEvidence要件を迂回できない。
1208
+ - late DoneがいつTerminal Resultを成立させたかをServer Orderで説明できる。
1209
+ - Evidenceを提示できない場合も、完了を主張せずStopできる。
1210
+
1211
+ ## ADR-024: ReaderはServer Orderのincremental prefix foldで履歴を評価する
1212
+
1213
+ - Status: Accepted
1214
+ - Date: 2026-07-19
1215
+
1216
+ ### 背景
1217
+
1218
+ same-ID grouping、collision、Repair Groupを最終履歴からglobalに先読みすると、将来のcommentが過去prefixのStart Bindingやhistorical factを書き換える。GitHub Issue Comment APIはIssue単位のcommentをascending IDで返すため、その順序をserver-ownedな評価順として利用できる。
1219
+
1220
+ ### 決定
1221
+
1222
+ readerの正準評価は次の3段階とする。
1223
+
1224
+ 1. Intrinsic prepass。
1225
+ 2. Server Orderによるincremental prefix fold。
1226
+ 3. state決定に必要なlive resourceとのconformance評価。
1227
+
1228
+ 次の不変条件を満たす限り、内部関数、cache、API client、pagination処理の構造は実装へ委ねる。
1229
+
1230
+ - comment snapshotは完全で、comment IDがstrict ascendingかつ重複なしでなければならない。
1231
+ - future commentを過去prefixの評価へ使用しない。
1232
+ - same-ID grouping、collision、Repair Groupもprefix-localに更新する。
1233
+ - `supersedes`は過去prefixだけで検査する。
1234
+ - prefix foldはContract Binding、Started Once、Start Binding、valid Done Claim、Stop Terminalを導出する。
1235
+ - PR mergeとEvidenceなどのlive resourceはcomment fold後に結合する。
1236
+ - state決定に必要なacquisitionが不完全ならstateを確定しない。
1237
+ - intactなTerminal Result成立後の新commentは結果を変更しない。
1238
+ - Terminal根拠Carrier自体の編集はADR-021を優先する。未編集aliasが残れば、そのLogical Recordから証明できる。
1239
+ - 証明可能なaliasがなければ現在のsnapshotだけから再導出し、過去cacheを正本にしない。
1240
+
1241
+ blocking原因、関連URL、terminal前後、unresolvedかrepair済みかはprotocol semanticsに必要である。diagnosticのexact sort、表示上の重複排除、JSON field配置はCLI projectionへ委ねる。
1242
+
1243
+ ### 結果
1244
+
1245
+ - future commentが過去prefixのbindingやhistorical factを書き換えない。
1246
+ - grouping、repair、lifecycleを同じServer Orderで説明できる。
1247
+ - 不完全取得をprotocol stateとして誤表示しない。
1248
+
1249
+ ### 参考
1250
+
1251
+ - [GitHub REST API: Issue comments](https://docs.github.com/en/rest/issues/comments?apiVersion=2022-11-28)
1252
+
1253
+ ## ADR-025: Stateをpriority orderと3つの検査境界から導出する
1254
+
1255
+ - Status: Accepted
1256
+ - Date: 2026-07-19
1257
+
1258
+ ### 背景
1259
+
1260
+ state条件を独立した表として並べると、取得不能、terminal後diagnostic、invalid Carrierが同時に存在する場合の優先順位に穴が生じる。また、単一Carrierの形式不適合、履歴prefixの不適合、mutableなGitHub resourceとの不一致を同じvalidityとして扱うと、過去Recordを不必要に遡及invalid化する。
1261
+
1262
+ ### 決定
1263
+
1264
+ stateは次のpriority orderで導出する。
1265
+
1266
+ 1. state決定に必要なdependencyの取得が不完全なら、stateを確定しない。CLIでは`state: null`として表現できるが、これはprotocol stateではない。
1267
+ 2. 完全なcomment snapshotにrecognized Carrierが0件なら`unmanaged`。
1268
+ 3. 証明可能なTerminal Resultがあれば`done`または`stopped`。terminal後のcomment異常はdiagnosticだけとし、Terminal根拠自体の編集・欠落は例外とする。
1269
+ 4. terminal前のblocking diagnosticがあれば`halt`。
1270
+ 5. active Contractが正確に1件、Started Onceがfalse、blocking diagnosticがなければ`ready`。
1271
+ 6. Started Onceがtrue、Terminal Resultがなく、blocking diagnosticがなければ`in_progress`。
1272
+
1273
+ 任意のAPI取得失敗ではなく、現在のstateを決定するために必要なdependencyだけをstep 1の対象にする。Issueのopen/closedはGTP stateへ影響しない。表示するかどうかはCLI projectionへ委ねる。
1274
+
1275
+ 検査境界は次の3つに分ける。これらは説明上の分類であり、Record fieldやprotocol stateを追加しない。
1276
+
1277
+ - **Intrinsic Validity**: 単一Carrierだけで判定する。Carrier正準形、strict JSON、duplicate key、closed schema、UUID、scalar、URL入力形を含む。
1278
+ - **Historical Contextual Validity**: 完全なcomment snapshotと各prefixで判定する。past・same-Issue supersession、Repair Group完全列挙、alias/collision、Contract Binding、Contract Freeze、Start Binding、Done ConditionとEvidenceのkey集合、lifecycle cardinalityを含む。
1279
+ - **Live Conformance**: 現在取得した外部resourceとの対応。branch、PR、Check Run、Artifact、Successor Issueの現在の解決、repository identityを含む。
1280
+
1281
+ IntrinsicまたはHistorical Contextual不適合のRecordはactive reducer inputへ渡さない。Live不適合はRecord自体をinvalidにせず、依存するtransitionを`halt`する。Acquisition Errorでは適合・不適合を断定せず、必要なstateを確定しない。Edited CarrierはRecord validity以前のCarrier-level問題とする。
1282
+
1283
+ typeごとのcardinalityは次とする。
1284
+
1285
+ - ContractはStart前にactive Logical Recordが最大1件。複数leafはconflict。valid Start後の新Contractはfreeze violationでactiveにならない。
1286
+ - 最初のprefix-valid Startだけがhistorical Start Bindingを作る。後続fresh-ID Startはlifecycle violation。invalid Startの修正版は対象URLを明示的にsupersedeする。
1287
+ - terminal前のactive valid Doneは最大1件。複数のunsuperseded leafはconflictであり、修正版Doneは全active leafをsupersedeする。
1288
+ - 最初のprefix-valid StopだけがStop Terminalを作る。後続Stopはactive setへ入らずterminal violation diagnosticとなる。invalid Stopはterminalを作らず、明示的なsupersessionで修復できる。
1289
+ - invalid Start、Done、Stopの対象が複数leafなら、修正版は全leafを列挙する。
1290
+ - StopはContract、Start、Doneをcross-type supersedeしない。terminal selectionはlifecycleが担当する。
1291
+
1292
+ ### core transition token
1293
+
1294
+ exact tokenを機械が読んでstateまたは許可されるrepair transitionを変える場合だけ、tokenをprotocol coreに含める。v1のclosed vocabularyは次で全部とする。
1295
+
1296
+ Repair Group membershipまたはrepair routeを変えるtoken:
1297
+
1298
+ ```text
1299
+ invalid_record
1300
+ edited_carrier
1301
+ identity_collision
1302
+ invalid_supersession
1303
+ incomplete_repair_group
1304
+ start_contract_binding_failed
1305
+ done_before_start
1306
+ done_condition_keys_mismatch
1307
+ done_evidence_kind_mismatch
1308
+ stop_without_contract
1309
+ successor_order_invalid
1310
+ ```
1311
+
1312
+ その他のstateまたは許可transitionを変えるtoken:
1313
+
1314
+ ```text
1315
+ conflicting_records
1316
+ multiple_pr_candidates
1317
+ merge_without_done
1318
+ contract_freeze_violation
1319
+ start_redefinition
1320
+ branch_binding_mismatch
1321
+ pr_binding_mismatch
1322
+ done_head_sha_mismatch
1323
+ evidence_live_mismatch
1324
+ terminal_violation
1325
+ terminal_dependency_mismatch
1326
+ ```
1327
+
1328
+ `evidence_live_mismatch`は取得できたEvidenceがrepository、SHA、kind、またはcompleted-success条件へ不適合な場合に用いる。Check Runがまだ完了していないだけならDone Terminal未成立の`in_progress`であり、このtokenを付けて`halt`へ進めない。
1329
+
1330
+ `terminal_dependency_mismatch`は、十分なアクセス下でTerminal Dependencyの欠落または不一致を確認した場合だけに用いる。一時的な取得不能には使用しない。
1331
+
1332
+ pre-terminalにおけるtokenと、通常進行へ戻るために許されるtransitionを次へ固定する。Stopの5条件を満たすvalid Stopは、すべてのpre-terminal行に共通する非完了escapeである。ただし`stop_without_contract`では、先にHistorical Contextual-valid Contractが必要となる。
1333
+
1334
+ | token | stateへの作用 | Stop以外の解消経路 |
1335
+ |---|---|---|
1336
+ | `invalid_record` | `halt` | singleton Repair Groupの完全置換 |
1337
+ | `edited_carrier` | `halt` | singleton Repair Groupの完全置換 |
1338
+ | `identity_collision` | `halt` | collision Repair Groupの完全置換 |
1339
+ | `invalid_supersession` | `halt` | singleton Repair Groupの完全置換 |
1340
+ | `incomplete_repair_group` | `halt` | 新しいfresh-ID Recordによる完全置換 |
1341
+ | `start_contract_binding_failed` | `halt` | Contract側を一意にした後、invalid Startを完全置換 |
1342
+ | `done_before_start` | `halt` | valid Start成立後、invalid Doneを完全置換 |
1343
+ | `done_condition_keys_mismatch` | `halt` | fresh-ID Doneで完全置換 |
1344
+ | `done_evidence_kind_mismatch` | `halt` | fresh-ID Doneで完全置換 |
1345
+ | `stop_without_contract` | `halt` | valid Contract成立後、invalid Stopを完全置換 |
1346
+ | `successor_order_invalid` | `halt` | fresh-ID Stopで完全置換 |
1347
+ | `conflicting_records` | `halt` | fresh-IDの同type Recordで全active leafを通常supersession |
1348
+ | `multiple_pr_candidates` | `halt` | valid `done.pr_ref`で1件をBound PRにする |
1349
+ | `merge_without_done` | `halt` | mergeされたPRを指すLate Done |
1350
+ | `contract_freeze_violation` | `halt` | Record修復なし。valid Stopのみ |
1351
+ | `start_redefinition` | `halt` | Record修復なし。valid Stopのみ |
1352
+ | `branch_binding_mismatch` | `halt` | 同じbranch identityのLive Conformance回復 |
1353
+ | `pr_binding_mismatch` | `halt` | terminal前のfresh-ID Doneによる通常supersession、または同じPRのLive Conformance回復 |
1354
+ | `done_head_sha_mismatch` | `halt` | 新headと全Evidenceを持つfresh-ID Doneによる通常supersession |
1355
+ | `evidence_live_mismatch` | `halt` | 全Evidenceを再提示するfresh-ID Doneによる通常supersession |
1356
+ | `terminal_violation` | terminal stateを変更しない | 新Logical Recordを結果へ反映しない。retry aliasだけ許容 |
1357
+ | `terminal_dependency_mismatch` | `halt` | Record修復なし。同じTerminal Dependencyの回復だけを再評価 |
1358
+
1359
+ intactなTerminal Result成立後に現れたtokenは、`terminal_dependency_mismatch`とTerminal根拠Carrierの編集・欠落を除き、terminal stateを変更しないdiagnosticとなる。
1360
+
1361
+ Acquisition Errorはprotocol stateではないが、reader動作を固定するclosed classificationとして`acquisition_incomplete`だけを使用する。state決定に必要なcomment snapshotまたはlive resourceを完全に取得できない場合を含み、stateを確定しない。詳細なnetwork、authentication、rate-limitなどの表示codeはCLI specificationへ委ねる。
1362
+
1363
+ 上記以外のexact diagnostic tokenをv1 readerがstateまたはrepair判断へ使用してはならない。同じ意味へ複数tokenを割り当てない。説明文、表示順、severity、JSON field配置はprotocol coreに含めない。
1364
+
1365
+ ### 結果
1366
+
1367
+ - 6 stateを増やさず、同時に成立する条件の優先順位を固定できる。
1368
+ - Record validityとmutableなexternal resourceの不一致を分離できる。
1369
+ - active setへ入るRecordとhistorical factのownerが明確になる。
1370
+
1371
+ ## ADR-026: Done Terminal成立時刻とStop時刻を比較する
1372
+
1373
+ - Status: Accepted
1374
+ - Date: 2026-07-19
1375
+
1376
+ ### 背景
1377
+
1378
+ PRの`merged_at`だけでDoneとStopの先後を決めると、merge後にStop、その後にLate Doneが投稿された場合に、Doneが先にterminalになったと誤判定する。また、Done投稿時にはpendingだったCheck Runが後からsuccessになる場合、Evidence Bindingが成立する前にDone Terminalを成立させてしまう。
1379
+
1380
+ ### 決定
1381
+
1382
+ 比較対象となるDoneは現在のLive Conformanceを満たさなければならない。Done Terminal Atを次で導出する。
1383
+
1384
+ ```text
1385
+ done_terminal_at = max(
1386
+ Done comment.created_at,
1387
+ Bound PR.merged_at,
1388
+ Doneが参照する全Check Runのcompleted_at
1389
+ )
1390
+ ```
1391
+
1392
+ Artifactは`done.head_sha`のcommitに既に存在するfileであるため、追加の成立時刻を持たない。
1393
+
1394
+ Done Terminal AtとStop commentのserver-owned `created_at`を比較する。
1395
+
1396
+ ```text
1397
+ done_terminal_at <= stop.created_at
1398
+ → done
1399
+
1400
+ stop.created_at < done_terminal_at
1401
+ → stopped
1402
+ ```
1403
+
1404
+ 同値ではDoneを優先する。異なるGitHub resource間で表示精度より細かい全順序を復元する新機構は追加しない。
1405
+
1406
+ Late Doneは自身のcomment時刻がmaxへ入るため、先に成立したStopを遡及的に覆さない。Check RunがStop後にsuccessとなった場合も、先に成立したStopを覆さない。
1407
+
1408
+ ### 結果
1409
+
1410
+ - Done Claim、merge、Check Run successがすべて成立した時点でDone Terminalを評価できる。
1411
+ - Late Doneが過去へ遡及しない。
1412
+ - 同秒timestampのための追加stateや外部台帳を必要としない。
1413
+
1414
+ ### 参考
1415
+
1416
+ - [GitHub REST API: Check runs](https://docs.github.com/en/rest/checks/runs)
1417
+
1418
+ ## 文書境界(GTP protocol外)
1419
+
1420
+ 今後、規則をprotocol coreへ含めるかは、その規則を削除したとき、適合する2つのreaderがCarrier認識、offline validity、state、repair結果のいずれかで異なるかによって判断する。異ならない表示shape、diagnostic sort、日本語文面、pagination実装、API client構造はCLIまたは開発文書へ置く。
1421
+
1422
+ protocol coreは次の4領域へ限定する。
1423
+
1424
+ 1. CarrierとRecord schema。
1425
+ 2. Offline validation。
1426
+ 3. Prefix reducerとstate。GitHub API取得、Live Conformance、Acquisition Errorは外部入力境界として扱う。
1427
+ 4. Supersession、retry、repair。
1428
+
1429
+ この節はGTP利用者のprotocol semanticsやadmission ruleではなく、仕様書を肥大化させないための開発・文書分類である。
1430
+
1431
+ ## ADR-027: `GTP.md`を唯一の公開正本にし、複雑な同一Issue内修復を外す
1432
+
1433
+ - Status: Accepted
1434
+ - Date: 2026-07-19
1435
+ - Supersedes: ADR-002〜ADR-026のうち`GTP.md`と矛盾する公開protocol semantics
1436
+
1437
+ ### 観測事実
1438
+
1439
+ - 現行仕様は26件のADR、`CONTEXT.md`、実装、acceptance記録へ分散し、利用者が1ファイルだけをコピーしてRecordを作れる形ではない。
1440
+ - 現行実装にはRepair Group、任意数leafのjoin、Done Terminal成立時刻、Late Done、24個相当の細分化されたtransition tokenがある。
1441
+ - Issue #1とPR #2では、GitHub Issue、branch、PR、Evidence、native mergeから状態を再構成するwalking skeletonを実GitHubで観測した。
1442
+ - 比較対象の`gtp-test` PR #1と`gtp-test2` PR #1では、1ファイルの仕様正本、人向け日本語を先に出すCLI、仕様・pure reducer・GitHub取得・表示の責務分離が提案された。これらを本repositoryの公開candidateで受け入れた事実は、後続のLevel 0/Level 1 acceptanceまで未確認である。
1443
+
1444
+ ### 推論
1445
+
1446
+ - 非エンジニアの個人開発者が導入し、異なるruntime間で引き継ぐ目的には、同一Issue内であらゆる壊れ方を修復する能力より、規則を1ファイルから一意に読めることの方が重要である。
1447
+ - 複雑な修復を残すと、producerとreaderの双方が理解・実装すべき分岐が増え、実際の事故URLがない機構まで公開契約になる。
1448
+ - pre-terminalな矛盾を最後のvalid Stopで閉じ、新Issueへ移る単一経路があれば、履歴を消さずに安全な再開先を作れる。
1449
+
1450
+ ### 決定
1451
+
1452
+ - repository rootの`GTP.md`をprotocolの唯一の公開正本とする。意味が衝突する場合、`GTP.md`を優先する。
1453
+ - `DECISIONS.md`は採否理由と設計履歴を所有し、公開Recordを作るための追加仕様にはしない。
1454
+ - 公開v1を`contract`、`start`、`done`、`stop`の4 Record、6 state、7 halt reasonへ限定する。
1455
+ - Repair Group、任意数leafのjoin、同一Issue内のRecord置換、Done active interval、Late Done専用機構、細分化されたtransition token、`human` Evidenceを外す。
1456
+ - 訂正の正準経路を、最後のvalid Stopと新Issueへの移行へ一本化する。
1457
+ - ADR-001の「GTPを権限の根拠にしない」は`GTP.md`と整合するため、そのまま維持する。
1458
+ - ADR-002〜ADR-026は削除せず設計履歴として保持するが、`GTP.md`と矛盾する意味を現行仕様として使用しない。
1459
+
1460
+ ### 結果
1461
+
1462
+ - 利用者は`GTP.md`と共通adapter文だけでprotocolへ参加できる。
1463
+ - 後続実装は`GTP.md`のclosed schemaと語彙へ適合させる必要があり、現行codeとtestsはこのADRだけでは適合済みにならない。
1464
+ - 旧acceptanceはwalking skeletonの回帰材料として残るが、新しい最小仕様のLevel 0/Level 1 acceptanceを証明しない。
1465
+ - 公開仕様から外した複雑な修復が必要になった場合は、実際のfailure URLを持つ新IssueとDecisionで再検討する。
1466
+
1467
+ ## ADR-028: Carrier、closed schema、pure reducerをatomicに切り替える
1468
+
1469
+ - Status: Accepted
1470
+ - Date: 2026-07-19
1471
+ - Supersedes: ADR-002〜ADR-026のうちRepair Group、Record supersession、DoneWindow、旧diagnostic tokenに依存する実装判断
1472
+
1473
+ ### 観測事実
1474
+
1475
+ - Issue #8の途中実装ではExact Carrierとclosed schemaのtargeted tests 24件が成功した。
1476
+ - 同じ候補でfull suite 76件を実行すると、旧reducerとstatusが`supersedes`、Repair Group、DoneWindowを要求するため36 failures、2 errorsになった。
1477
+ - `GTP.md`はこれらを公開v1へ含めず、4 Record、6 state、7 halt reasonだけを定義している。
1478
+ - Issue #18ではContract Recordの必須fieldを欠く投稿ミスがあり、そのRecordを編集せずStopしてIssue #20へ移行した。
1479
+
1480
+ ### 推論
1481
+
1482
+ - Carrier/schemaだけを先にmainへ入れると、同じrepository内に互いに矛盾するreaderが共存する。
1483
+ - legacy compatibility layerを足すと、`GTP.md`から削除した意味をproduction codeへ温存することになる。
1484
+ - pure reducerを既存CLIから検証するには、GitHub取得全体を再設計せず、status adapterの接続点だけを同じ変更で更新する必要がある。
1485
+
1486
+ ### 決定
1487
+
1488
+ - Issue #8と#9を一つのatomic変更として後継Issue #20とPRで実装する。
1489
+ - `src/gtp/model.py`と`src/gtp/reducer.py`からRepair Group、Record supersession、DoneWindowを削除する。
1490
+ - reducerのdiagnostic tokenを`GTP.md`の7 halt reasonだけに限定する。
1491
+ - `src/gtp/status.py`は新reducerへ接続する最小限のadapter変更を許可し、GitHub取得・live判定の全面整理はIssue #10へ残す。
1492
+ - safe retryは同一`id`かつ構造的に同じRecordのaliasだけとし、同じIssue内の修復はfinal Stopと新Issueで行う。
1493
+
1494
+ ### 結果
1495
+
1496
+ - Exact Carrier、closed schema、pure reducerを中間不整合なしに同時導入できる。
1497
+ - reducer truth tableとlegacy vocabulary prune reportをimmutable artifactとしてDone Evidenceに使用できる。
1498
+ - 旧ADRは設計履歴として残るが、現行動作の根拠は`GTP.md`、ADR-027、ADR-028になる。
1499
+
1500
+ ## ADR-029: GitHub live bindingをGET-only HTTP境界として固定する
1501
+
1502
+ - Status: Accepted
1503
+ - Date: 2026-07-19
1504
+
1505
+ ### 観測事実
1506
+
1507
+ - Issue #10開始時点の`GitHubClient`はGET、Link pagination、repository/Issue/comment/branch/PR/Check Run/artifact取得の骨格を持っていた。
1508
+ - 同時点のstatus adapterにはPR changed filesのscope検査、rename旧path検査、Issue snapshot再読、Bound PR head再読、successor時刻検査がなかった。
1509
+ - Check RunがpendingのときはDone Evidence不適合ではなく`in_progress`を返し、Doneなしmergeは`invalid_transition`へ分類していた。
1510
+ - 既存status testはin-memory clientを使い、HTTP responseからCLIまでの接続を証明していなかった。
1511
+
1512
+ ### 推論
1513
+
1514
+ - pure reducerへnetwork処理を戻さず、GitHub REST adapterとstatus application serviceの境界でlive Observationを結合すれば、Historical stateとAcquisition Errorを分離できる。
1515
+ - 内部moduleをmockするだけではrequest method、pagination、host、redirect headerを検証できないため、外部HTTP境界だけを置換するfixtureが必要である。
1516
+ - branch、PR、Evidenceの個別取得が成功しても、読取中にIssueまたはBound PR headが変われば同一snapshotとはいえない。
1517
+
1518
+ ### 決定
1519
+
1520
+ - production transportはPython standard libraryの`Request`と`HTTPRedirectHandler`を用いるGET-only adapterとする。
1521
+ - 初期requestと最終response URLを`https://api.github.com`へ限定し、cross-origin redirectでは`Authorization`を除去する。
1522
+ - Issue metadataをread前後で比較し、Bound PRはEvidenceとchanged files取得後にsource headを再読する。変化時はhaltではなくAcquisition Errorを返す。
1523
+ - PR changed filesを全page取得し、renameでは`filename`と`previous_filename`の両方をBound Contract scopeへ照合する。
1524
+ - fork、repository mismatch、branch mismatch、scope外pathを`invalid_binding`、SHA不一致を`stale_evidence`、Evidence resource不適合を`invalid_evidence`へ分類する。
1525
+ - pendingまたはfailureのCheck RunはDone条件を満たさないため`invalid_evidence`とする。Doneなしmerge、Doneより先のmerge、Stop後mergeは`terminal_violation`とする。
1526
+ - HTTP fixture suiteはCLI、URL admission、classifier、reducer、binding logicをproduction実装のまま通し、`_open`だけを外部境界として置換する。
1527
+
1528
+ ### 結果
1529
+
1530
+ - 取得不能時にstateを推測せず、`state: null`と`acquisition: incomplete`を返せる。
1531
+ - GitHubへのwrite path、GraphQL、webhook、cache、database、fork、GHESを追加せず、Issue #10のlive binding規則を検証できる。
1532
+ - live HTTP matrixとprune reportをimmutable Done Evidenceとして利用できる。