diff --git a/docs/development/ticket-regression-test-design.md b/docs/development/ticket-regression-test-design.md index 3bfc68327..c0479bce3 100644 --- a/docs/development/ticket-regression-test-design.md +++ b/docs/development/ticket-regression-test-design.md @@ -14,32 +14,32 @@ T-744の設計判断。公開入口で観測した値を次の操作へ渡せる ## 採否の要約 -| 優先 | 利用結果/具体的故障 | 判定と後続単位 | -| --- | --- | --- | -| P1 A | Repositoryなしで担当を読み、その観測IDで同じ委任へAnswer。readのID欠落・route差・投影差で次操作が拒否される | **新規が必要**。既存Server targetに通常Tools/WIPと実Backendの薄い適合結合。局所CAS/入力表は再作成しない | -| P1 B | 実装assignment/MRなしで結果返却。Hostのretry keyが実Backendで別操作になる/結果と通知sourceが分離する | **HTTP→保存→実sessionは既存で充足**。**Tools/WIP→同HTTPの適合だけ新規が必要**。Aとtransportを共有し、実Worker二重起動を避ける | -| P2 C | doneの結果、置換・case履歴を読み直してWebに表示。currentとpastの取り違え、parser拒否、旧結果の表示欠落 | **既存を強化+薄いadapter結合が必要**。Server公開readの観測追加、Web履歴component assertion、実Backend bytes→production parserを分ける | -| P2 D | 旧schema移行・再open後もunknownを依頼にせず検索・読取りできる | **既存を強化**。migration→配送対象は既存充足、同DB→authority公開read/queryへの接続だけ補う | -| 維持 E | 保存→配送→永続session、ACK喪失・復旧・並行scanで重複しない | **既存で充足**。既存実Workerケースを維持し、recording backendを実session証拠へ格上げしない | -| 対象外 | 実LLMの判断品質、任意OS crash、Drive共有、close後のMR処理を両branchで統一 | **仕様確認/別scopeが先**。機構テストで自然言語判断・電源断耐性を主張しない。MR差分はT-761/Orchestratorへsource差として返す | +| 優先 | 利用結果/具体的故障 | 判定と後続単位 | +| ------ | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| P1 A | Repositoryなしで担当を読み、その観測IDで同じ委任へAnswer。readのID欠落・route差・投影差で次操作が拒否される | **新規が必要**。既存Server targetに通常Tools/WIPと実Backendの薄い適合結合。局所CAS/入力表は再作成しない | +| P1 B | 実装assignment/MRなしで結果返却。Hostのretry keyが実Backendで別操作になる/結果と通知sourceが分離する | **HTTP→保存→実sessionは既存で充足**。**Tools/WIP→同HTTPの適合だけ新規が必要**。Aとtransportを共有し、実Worker二重起動を避ける | +| P2 C | doneの結果、置換・case履歴を読み直してWebに表示。currentとpastの取り違え、parser拒否、旧結果の表示欠落 | **既存を強化+薄いadapter結合が必要**。Server公開readの観測追加、Web履歴component assertion、実Backend bytes→production parserを分ける | +| P2 D | 旧schema移行・再open後もunknownを依頼にせず検索・読取りできる | **既存を強化**。migration→配送対象は既存充足、同DB→authority公開read/queryへの接続だけ補う | +| 維持 E | 保存→配送→永続session、ACK喪失・復旧・並行scanで重複しない | **既存で充足**。既存実Workerケースを維持し、recording backendを実session証拠へ格上げしない | +| 対象外 | 実LLMの判断品質、任意OS crash、Drive共有、close後のMR処理を両branchで統一 | **仕様確認/別scopeが先**。機構テストで自然言語判断・電源断耐性を主張しない。MR差分はT-761/Orchestratorへsource差として返す | ## 既存証拠と限界 -| 証拠(file / test名) | 実際のassertion・本番区間と代替境界 | -| --- | --- | -| `WT/assignment_public/tests.rs` / `continuing_answer_forwards_same_assignment_event_cas_and_saved_receipt`、`public_assignment_rejections_and_unknown_outcomes_never_auto_retry_or_replace_identity`、`assignment_wip_binds_ticket_and_preserves_normal_permission_and_cas_inputs` | 同assignment/event/key/bodyの転送、保存receipt、403/409/unknownで自動retryなし、WIP route束縛と入力偽装拒否。**固定応答Transport**であり実router・storeのJSONとの適合ではない。`assignment_tracking.rs`のreadも同じ限界 | -| `WS/server_assignment_tracking_tests.rs` / `public_assignment_answer_authenticates_source_replays_saved_result_and_rejects_read_reassign_race` | 公開HTTPの認証、Answerイベント1件・認証actor・本文、tracking不変、exact replay、異なるpayload/stale/actor偽装の拒否。SQLite/routerは本番。readの観測値はhelperから取得し、通常Tool/WIPの出力を次操作に渡してはいない | -| 同file / `same_principal_reassignment_retains_old_result_and_projects_replacement_identity` | signed HTTPの旧assignment readで `current=false`、done/result保持、`release.action=replaced`・後継ID、次assignmentはwaiting・resultなし。fresh DB起点。履歴ページは `tracking_history_is_assignment_scoped_and_paged_and_rejects_unknown_cursors` が担当 | -| `WS/server_assignment_delivery_tests.rs` / `assignment_done_historical_inputs_do_not_restart_work_but_reissue_is_new_delegation` | typed close/reopen→scanで入力なし、done不変、明示reissueは新IDで入力1件、旧結果保持、旧Assign replayで再実行なし。**recording backend**の入力観測。公開detail/historyの再照合やDOMまでの証拠ではない | -| 同file / `assignment_real_worker_response_loss_restore_and_concurrent_scans_commit_once` | 実Worker受付後に応答だけを落とす。DB再open・同Worker復元・title/self-report変更後も同request ID/本文、同一通知commit1回、8並行scanの新Answerは1配送、tracking不変。`delivery_receipts` は永続sessionのactivation receipt、`delivery_commits` はcanonical notification。LLM・応答喪失だけ代替。Answer準備はstore直呼びなのでAを代替しない | -| `WS/server_implementation_result_tests.rs` / `implementation_result_signed_http_reaches_persistent_orchestrator_without_assignment_or_mr` | 実装assignment/MRなしのsigned HTTP→結果照会receipt一致→実Orchestrator session commit、exact replay、異payload/別actor衝突、偽MR拒否、公開診断runtime_accepted・処理確認false、再scanでreceipt増加なし、case/handling不変。Orchestrator委任はあり、LLMは固定。`mr_result_recovery_and_handoff_are_distinct_persistent_inputs` はMRイベントとhandoffを別入力として確認。通知未接続を改めて追加する必要なし | -| `WS/implementation_result_tests.rs` / `implementation_result_notification_failure_rolls_back_and_concurrent_retries_share_receipt`、`implementation_result_v97_to_v98_preserves_legacy_bytes_receipts_and_notification_evidence` | 実DBのsource insert失敗で結果0・業務状態不変、並行retry receipt共有。旧JSON bytes・ACK・failure・制約・rollbackを保持、再open照会/replayで通知再captureなし。Workerを使わない保存保証。移行fixtureは旧schemaを再構成したものなので、真の古いDB全体からの更新とは区別 | -| `WS/assignment_tracking_tests.rs` / `tracking_store_real_schema91_to92_retains_queue_cases_principals_audit_receipts_and_claims` | 実旧schema91 fixture→migration、pending/progressだけwaiting/inprogress、invalid-fence/closed-reopen/replaced/historical-doneはtrackingなし。原assignment・監査・receipt・claim保持、DB再open後の履歴一致 | -| `WS/assignment_delivery_tests.rs` / `assignment_delivery_schema92_upgrade_uses_reconciled_migration_evidence_not_legacy_history` | 同旧fixtureから最新storeへopen。配送対象はpending/progressのみ、input IDはmigration tracking由来、保存行同値・FK違反0。**migration→配送対象の不足という旧想定は採用しない** | -| `WS/store.rs` / `schema_v89_runs_auth_then_cases_preserving_legacy_states_evidence_and_responsibility`・`schema_v90_cases_preserve_auth_archive_legacy_states_evidence_and_responsibility`、`crates/ticket/tests/migration.rs` / `standalone_schema7_migration_preserves_six_state_snapshot_and_evidence_without_success_inference` | 旧done/closedをClosed+Unknownへ保存、旧snapshot/evidence・case履歴を保持、reopenで成功やactive assignment復活を推論しない。Workspace helperは再openも確認。公開query/Webとの接続とは別 | -| `WS/server/tests/ticket_evidence_tests.rs` / `case_route_preserves_corrected_history_replay_and_reopen_aba_guard_without_mr` | 公開detailのcurrent_closure/history/keyが保存値と一致、訂正で旧判断不変、reopen・replay・古いclosure keyのABA拒否。`WS/ticket_browse_tests.rs` / `ticket_browse_all_filters_are_applied_before_limit_and_batch_fields_match` はbrowse/detailのtracking・closure一致、`ticket_browse_assignment_current_missing_unknown_and_cleared_semantics` は過去doneを現在検索へ混ぜない。移行DB起点ではない | -| `WEB/api/ticket-operations.test.ts` / `waiting answers carry the same assignment and observed event without status or Assign mutation`、`retained assignment page preserves result and release rather than rewriting handling to done` | Answer inputの同一ID/event、done/null観測を拒否、releaseとhandlingの分離。`api/ticket-browser.test.ts` の `Ticket Browser keeps self-reported delegation independent of case and Worker state` と `tags named ready and closed coexist with case judgment and retained reopen history without inferring state` はparserの値保持。手書きAPI fixtureでありBackend適合ではない | -| `WEB/tickets/ticket-operations.browser.spec.ts` / `an answer response loss keeps exact assignment/event/key/body for retry even when observed responsibility changes`、`a done reissue persists before a failed refresh and does not pretend delivery or execution succeeded` | happy-dom上でfetchをfake、再render後もexact bytes維持、保存済み+refresh失敗を配送成功と表示しない。`TicketHandling.browser.spec.ts` の `answer save keeps handling unchanged and refreshes history without diagnostics reads` はwaiting維持。**実HTTP/認証/Backend適合・実browserの証拠ではない** | +| 証拠(file / test名) | 実際のassertion・本番区間と代替境界 | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `WT/assignment_public/tests.rs` / `continuing_answer_forwards_same_assignment_event_cas_and_saved_receipt`、`public_assignment_rejections_and_unknown_outcomes_never_auto_retry_or_replace_identity`、`assignment_wip_binds_ticket_and_preserves_normal_permission_and_cas_inputs` | 同assignment/event/key/bodyの転送、保存receipt、403/409/unknownで自動retryなし、WIP route束縛と入力偽装拒否。**固定応答Transport**であり実router・storeのJSONとの適合ではない。`assignment_tracking.rs`のreadも同じ限界 | +| `WS/server_assignment_tracking_tests.rs` / `public_assignment_answer_authenticates_source_replays_saved_result_and_rejects_read_reassign_race` | 公開HTTPの認証、Answerイベント1件・認証actor・本文、tracking不変、exact replay、異なるpayload/stale/actor偽装の拒否。SQLite/routerは本番。readの観測値はhelperから取得し、通常Tool/WIPの出力を次操作に渡してはいない | +| 同file / `same_principal_reassignment_retains_old_result_and_projects_replacement_identity` | signed HTTPの旧assignment readで `current=false`、done/result保持、`release.action=replaced`・後継ID、次assignmentはwaiting・resultなし。fresh DB起点。履歴ページは `tracking_history_is_assignment_scoped_and_paged_and_rejects_unknown_cursors` が担当 | +| `WS/server_assignment_delivery_tests.rs` / `assignment_done_historical_inputs_do_not_restart_work_but_reissue_is_new_delegation` | typed close/reopen→scanで入力なし、done不変、明示reissueは新IDで入力1件、旧結果保持、旧Assign replayで再実行なし。**recording backend**の入力観測。公開detail/historyの再照合やDOMまでの証拠ではない | +| 同file / `assignment_real_worker_response_loss_restore_and_concurrent_scans_commit_once` | 実Worker受付後に応答だけを落とす。DB再open・同Worker復元・title/self-report変更後も同request ID/本文、同一通知commit1回、8並行scanの新Answerは1配送、tracking不変。`delivery_receipts` は永続sessionのactivation receipt、`delivery_commits` はcanonical notification。LLM・応答喪失に加えて起動・復元factoryもfixture(`DeliveryWorkerFactory`)。WorkerBootstrap/session/receiptは本番だが、`ProfileRuntimeWorkerFactory`や復元後Workspace client認証接続の証拠ではない。Answer準備はstore直呼びなのでAを代替しない | +| `WS/server_implementation_result_tests.rs` / `implementation_result_signed_http_reaches_persistent_orchestrator_without_assignment_or_mr` | 実装assignment/MRなしのsigned HTTP→結果照会receipt一致→実Orchestrator session commit、exact replay、異payload/別actor衝突、偽MR拒否、公開診断runtime_accepted・処理確認false、再scanでreceipt増加なし、case/handling不変。Orchestrator委任はあり、LLMは固定。`mr_result_recovery_and_handoff_are_distinct_persistent_inputs` はMRイベントとhandoffを別入力として確認。通知未接続を改めて追加する必要なし | +| `WS/implementation_result_tests.rs` / `implementation_result_notification_failure_rolls_back_and_concurrent_retries_share_receipt`、`implementation_result_v97_to_v98_preserves_legacy_bytes_receipts_and_notification_evidence` | 実DBのsource insert失敗で結果0・業務状態不変、並行retry receipt共有。旧JSON bytes・ACK・failure・制約・rollbackを保持、再open照会/replayで通知再captureなし。Workerを使わない保存保証。移行fixtureは旧schemaを再構成したものなので、真の古いDB全体からの更新とは区別 | +| `WS/assignment_tracking_tests.rs` / `tracking_store_real_schema91_to92_retains_queue_cases_principals_audit_receipts_and_claims` | 実旧schema91 fixture→migration、pending/progressだけwaiting/inprogress、invalid-fence/closed-reopen/replaced/historical-doneはtrackingなし。原assignment・監査・receipt・claim保持、DB再open後の履歴一致 | +| `WS/assignment_delivery_tests.rs` / `assignment_delivery_schema92_upgrade_uses_reconciled_migration_evidence_not_legacy_history` | 同旧fixtureから最新storeへopen。配送対象はpending/progressのみ、input IDはmigration tracking由来、保存行同値・FK違反0。**migration→配送対象の不足という旧想定は採用しない** | +| `WS/store.rs` / `schema_v89_runs_auth_then_cases_preserving_legacy_states_evidence_and_responsibility`・`schema_v90_cases_preserve_auth_archive_legacy_states_evidence_and_responsibility`、`crates/ticket/tests/migration.rs` / `standalone_schema7_migration_preserves_six_state_snapshot_and_evidence_without_success_inference` | 旧done/closedをClosed+Unknownへ保存、旧snapshot/evidence・case履歴を保持、reopenで成功やactive assignment復活を推論しない。Workspace helperは再openも確認。公開query/Webとの接続とは別 | +| `WS/server/tests/ticket_evidence_tests.rs` / `case_route_preserves_corrected_history_replay_and_reopen_aba_guard_without_mr` | 公開detailのcurrent_closure/history/keyが保存値と一致、訂正で旧判断不変、reopen・replay・古いclosure keyのABA拒否。`WS/ticket_browse_tests.rs` / `ticket_browse_all_filters_are_applied_before_limit_and_batch_fields_match` はbrowse/detailのtracking・closure一致、`ticket_browse_assignment_current_missing_unknown_and_cleared_semantics` は過去doneを現在検索へ混ぜない。移行DB起点ではない | +| `WEB/api/ticket-operations.test.ts` / `waiting answers carry the same assignment and observed event without status or Assign mutation`、`retained assignment page preserves result and release rather than rewriting handling to done` | Answer inputの同一ID/event、done/null観測を拒否、releaseとhandlingの分離。`api/ticket-browser.test.ts` の `Ticket Browser keeps self-reported delegation independent of case and Worker state` と `tags named ready and closed coexist with case judgment and retained reopen history without inferring state` はparserの値保持。手書きAPI fixtureでありBackend適合ではない | +| `WEB/tickets/ticket-operations.browser.spec.ts` / `an answer response loss keeps exact assignment/event/key/body for retry even when observed responsibility changes`、`a done reissue persists before a failed refresh and does not pretend delivery or execution succeeded` | happy-dom上でfetchをfake、再render後もexact bytes維持、保存済み+refresh失敗を配送成功と表示しない。`TicketHandling.browser.spec.ts` の `answer save keeps handling unchanged and refreshes history without diagnostics reads` はwaiting維持。**実HTTP/認証/Backend適合・実browserの証拠ではない** | ## 必要な変更の具体形 @@ -79,17 +79,17 @@ T-744の設計判断。公開入口で観測した値を次の操作へ渡せる 2026-10-17、このcheckoutで `-j 2`、稼働Server/Runtime・外部モデルを使わず実行した。以下は単発のホスト測定で、CI・中央値・T-761のhare/develop測定ではない。 -| 試行 | 結果/本体時間(外側buildは別) | -| --- | --- | -| 既存 `implementation_result_signed_http_reaches_persistent_orchestrator_without_assignment_or_mr` | 1 passed、9.61秒。初回外側build4分55秒、全コマンド5分05秒 | -| 既存 `assignment_real_worker_response_loss_restore_and_concurrent_scans_commit_once` | 実験復元後1 passed、14.58秒。再build1分27秒は実行時間に含めない | -| 既存 `assignment_done_historical_inputs_do_not_restart_work_but_reissue_is_new_delegation` | 1 passed、2.41秒 | -| 既存 `assignment_delivery_schema92_upgrade_uses_reconciled_migration_evidence_not_legacy_history` / `tracking_store_real_schema91_to92_retains_queue_cases_principals_audit_receipts_and_claims` | 各1 passed、1.91 / 2.04秒 | -| 既存 `same_principal_reassignment_retains_old_result_and_projects_replacement_identity` / `case_route_preserves_corrected_history_replay_and_reopen_aba_guard_without_mr` / `public_assignment_answer_authenticates_source_replays_saved_result_and_rejects_read_reassign_race` | 各1 passed、0.54 / 0.66 / 0.72秒 | -| `api/ticket-{browser,case,operations}.test.ts` | 32 passed、test合計147ms、Deno外側0.867秒 | -| Aの一時WIP probe | 本番mount→invoke→毎要求署名router→実SQLite。実readからID/eventをAnswerへ渡し、同receipt replay・保存イベント1件・waiting不変・自己入力0を確認。単独1 passed、2.37秒(外側build48.94秒) | -| Aのfault probe | 上記と同じ実router応答からlast_event_idだけをtransport境界で削除。正常1 passed+fault側1 failed、3.49秒。`read[0].last_event_id == store.last_event_id` がNull対Stringで意図どおり失敗(コマンドexit101)。Backend自体のprojectionを書き換えたmutationではなく、公開応答脱落の境界faultである | -| Cの一時parser probe | 上記DBの実HTTP detail/pageとWIP Answer receiptをファイル経由でproduction Web parserへ渡し、case=open/waiting・ID一致、次Answerの観測CAS、event欠落時の操作拒否を確認。成功、Deno全体0.137秒。DOM/HTTP fetch adapter全体は未試行 | +| 試行 | 結果/本体時間(外側buildは別) | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 既存 `implementation_result_signed_http_reaches_persistent_orchestrator_without_assignment_or_mr` | 1 passed、9.61秒。初回外側build4分55秒、全コマンド5分05秒 | +| 既存 `assignment_real_worker_response_loss_restore_and_concurrent_scans_commit_once` | 実験復元後1 passed、14.58秒。再build1分27秒は実行時間に含めない | +| 既存 `assignment_done_historical_inputs_do_not_restart_work_but_reissue_is_new_delegation` | 1 passed、2.41秒 | +| 既存 `assignment_delivery_schema92_upgrade_uses_reconciled_migration_evidence_not_legacy_history` / `tracking_store_real_schema91_to92_retains_queue_cases_principals_audit_receipts_and_claims` | 各1 passed、1.91 / 2.04秒 | +| 既存 `same_principal_reassignment_retains_old_result_and_projects_replacement_identity` / `case_route_preserves_corrected_history_replay_and_reopen_aba_guard_without_mr` / `public_assignment_answer_authenticates_source_replays_saved_result_and_rejects_read_reassign_race` | 各1 passed、0.54 / 0.66 / 0.72秒 | +| `api/ticket-{browser,case,operations}.test.ts` | 32 passed、test合計147ms、Deno外側0.867秒 | +| Aの一時WIP probe | 本番mount→invoke→毎要求署名router→実SQLite。実readからID/eventをAnswerへ渡し、同receipt replay・保存イベント1件・waiting不変・自己入力0を確認。単独1 passed、2.37秒(外側build48.94秒) | +| Aのfault probe | 上記と同じ実router応答からlast_event_idだけをtransport境界で削除。正常1 passed+fault側1 failed、3.49秒。`read[0].last_event_id == store.last_event_id` がNull対Stringで意図どおり失敗(コマンドexit101)。Backend自体のprojectionを書き換えたmutationではなく、公開応答脱落の境界faultである | +| Cの一時parser probe | 上記DBの実HTTP detail/pageとWIP Answer receiptをファイル経由でproduction Web parserへ渡し、case=open/waiting・ID一致、次Answerの観測CAS、event欠落時の操作拒否を確認。成功、Deno全体0.137秒。DOM/HTTP fetch adapter全体は未試行 | 一時probeは小fixtureで接続とassertionを試すためだけに作成した。初版の非公開install API呼出し・入れ子runtimeはfixture構築失敗、IDがTicket文字列を含むという誤期待と自己Answerの配送1件という誤期待はprobeの誤りとして修正した。いずれも製品不具合/回帰検出成功とは数えない。通常Tools側は公開Worker install/Tool取得を使う上記設計までで、未試行である。