Files
yoi/docs/report/t725-drive-connections.md

20 KiB
Raw Permalink Blame History

Drive共有の接続不足と検証(T-725、2026-10-19)

判断の基準

基準 adfa42297352c5a64fe8100969aad6fda4df8a81 と着手HEAD cea0225a6e2d9e23c59a7d4a453f99bc2e1eba97 を比較した。差分81 filesはSession保存、Journal、Ticket公開操作、復元親の子操作等であり、以下のDrive保存/API/Worker/Webテストに差分はない。Cargo.lockの wip-{client,http,protocol,text-view} はすべてcrates.ioの0.2.0で、ローカル差替えはしていない。

検証したテスト実装は専用branch work/T-725-drive-connections の ec6c5bed。以下の結果はこの実装に対する証拠であり、対象developへの統合判断とは分ける。

T-721〜724の保存・公開操作を再実装せず、別入口の返却値が次の操作へ渡る接続と、cleanupの所有境界だけを追加した。製品修正は不要だった。Ticket一巡は実装・採用済みT-744の ticket-regression-test-design.md、通常suiteの判断はT-761の regression-test-design.md と分担する。関連Ticketの変更・再開はしていない。

優先順位と追加した契約

配置は crates/workspace-server/src/server/tests/worker_drive_tests.rs。以下はすべて通常のServer lib targetであり、ignoreやテスト専用featureは追加しない。

優先 利用結果/具体故障・コード根拠 既存証拠の限界/採否
P1 ユーザーuploadの返却node/mutationをWorkdirなしTools/WIPが読み更新し、owner/別Workerが同一資料を取得する。server_drive::upload/read_text/public_node、Worker drive/backend.rs::read/mutate とWIPの投影がずれると、個別成功でも本文や観測が別物になる。 workdirless_workers_share_markdown_through_current_read_and_write_grants はWorker作成から別Worker読取り。image_attachment_retains_original_bytes_after_drive_update_and_revocation はuser uploadから画像添付。native_create_and_write_use_client_managed_committed_requests_and_reject_stale_worker はWIP作成から更新。この間のuser Markdown binary upload→Tools/WIP更新を新規接続。
P2 Workerを止め、保持規則に従い削除・交換してもDrive文書の参照と内容が残る。server/worker_operations.rs::stop/delete_from_plan、WorkerRemovalService と store::commit_worker_catalog_removal はWorker権限を終え、Drive資料を削除してはならない。 cleanup_service_deletes_stopped_singleton_worker は実Runtime停止・削除・交換、storeの drive_grants_migrate_and_preserve_audit_through_revoke_worker_delete_and_restart はgrant取消監査を確認するが、Drive資料の再取得はない。元参照→交換Workerの明示grant後読取りを新規接続。停止だけでgrantが失効するという別契約は追加しない。
P2 source Workdirを本当に削除した後も保存した資料を使える。drive.rs のSaveWorkdirはbytesをAPIへ渡し、execute_workdir_removal→Runtime→working_directory/cleanup.rs はmaterializationだけを削除する。誤ったroot削除やsource依存を検出する。 scoped_workdir_import_publishes_document_and_image_bytes_with_bounded_reads は独立metadata、完全download bytes、画像添付を確認するがsourceが残る。実provider削除の後に同node/mutation/bytes/receiptを読む接続を追加。保存crateのbackup/GC行列は増やさない。

入力・fixture・観測点

  • user_uploaded_markdown_roundtrips_through_workdirless_tools_and_native_wip_at_one_identity:既存Fixtureの実SQLite/FeatureStorage/LocalFileSystem、2 Workerの空Workdir links、明示read_write/read_only grantを使用。owner binary PUTはsize/SHA256と日本語Markdown bytesを渡す。Toolsとnative WIPの2経路で読取り・writeを行う。返却Workspace/node、uploadのlast_mutation_id、更新request ID=last_mutation_id、別Worker readのentry/本文、owner metadata、committed receiptのentry、mutation固定downloadの完全bytesを照合する。WIPは本番install/Inspect/Invoke、外部LLMは呼ぶとpanicする。Runtime起動とHTTP transportはfixtureだが、毎要求の署名・router・現grant・storeは本番。
  • worker_removal_preserves_drive_reference_for_explicitly_granted_replacement:real embedded Runtime+既存deterministic controller backendでRepository/WorkdirなしWorkerが文書を作る。本番WorkspaceWorker stop→Runtime stopped→cleanup plan→delete_from_planを通し、Runtime/catalog除去、旧Workerの拒否を確認。別IDの交換Workerはgrant前拒否、read_only付与後に元参照で完全entry(latest_url、last_mutation_idを含む)と本文が一致し、元receiptもcommitted。保持対象Sessionは既存fixtureで準備する。lifecycle admissionは内部Backend test contextであり、browser/Worker-control認証の新証拠ではない。実controllerのshutdown/モデル挙動は代替されている。
  • source_workdir_removal_keeps_published_drive_bytes_and_receipt:ticket_worker_launch_tests::LaunchFixture の既存認証付きloopback Runtimeを共有する。通常のServer Workdir createでlocal Git sourceからcleanなREADME.mdをmaterializeする。source sessionはLocalWorkdirSessionでread scopeと実materializer leaseを渡す(Runtime session transportは代替)。DriveSaveWorkdirはalias source+論理path README.md、元bytes clean\n。session close/drop後、Server removal→認証付きRuntime HTTP→実materializer unlinkを通し、Removed/nonretryable・物理root不存在・registry不存在をassert。その後、新しいWorkdirなしDriveFeatureから元entry/bytes/receiptを照合する。on_apiのcloneは同じstore/drive_host/Runtimeを共有し、別DBを作らない。

Workdir用に新しい起動基盤は作らず、既存Launch backendにcleanupの実materializerへの委譲を足し、materializer配置をfixtureのTempDir配下へ閉じた。listenerは既存Dropでabort、通信は既存有界timeoutを利用する。embedded Server adapterは仕様上Workdir create/status/cleanup非対応(hosts.rs)。最初のembedded試行はAttentionRequiredとなったため不採用とし、成功fakeへ変えず既存HTTP harnessへ切り替えた。

追加しなかった保証と既存assertion

パスは、断りがなければServer src/server/tests/ 配下。

保証/採否 主な実在テストと観測、代替境界
stale先勝ち:維持 simultaneous_worker_edits_publish_exactly_one_last_mutation_id_and_preserve_the_loser_conflict は成功1件・敗者StructuredConflict・勝者本文/metadata、stale_worker_observations_cannot_write_edit_relocate_or_delete_newer_last_mutation_id はwrite/edit/move/delete拒否と本文/名前保持。nativeは前掲create/write testでvalidator conflictと勝者bytes。Tools/WIP→実署名router、Runtimeのみfixture。
現grant取消:維持 revocation_invalidates_cached_metadata_reads_writes_and_receipt_queries はread/write/list/search/status等のdeniedと別Worker本文保持。native_tree_does_not_index_entries_but_direct_inspect_and_invoke_use_current_grants はcached invoke/refreshed inspect拒否。drive_api_tests::drive_verified_upload_revoked_during_reception_cannot_commit_or_replay はbody frameで取消、403/denied、uncommitted、list空。最後の注入はverified-source Extensionを使用し、署名ingress自体の証拠とは分ける。
commit後応答喪失:維持 lost_mutation_response_is_resolved_by_receipt_without_resending_effect と lost_binary_upload_reply_reconciles_same_request_without_duplicate_publication は本番router成功後の返答だけをtransportで落とす。committed/元node、POSTまたはPUT数1、元requestのGET照会、別Worker一覧1件とmutation一致をassert。単なる失敗応答fakeではない。
Web接続:維持/明示実行 drive_web_roundtrip_tests::repositoryless_drive_shares_worker_bytes_and_enforces_current_read_only_grants_over_http はRepositoryなしbootstrap、実HTTP、Worker grant/revokeの403、一覧entryと実blob bytesを確認。repositoryless_drive_real_web_adapter_preserves_bytes_cas_and_latest_reference_lifecycle は実HTTPと本番Deno adapter(parser/operation/grant)を接続する既存ignored test。Worker起動はfixture、browser DOM/Passkey loginは対象外。画面draft/取消等は別のsynthetic API browser suiteを重複しない。
保存/reopen/backup/GC:所有crateを維持 workspace-drive/tests/storage.rs::markdown_image_empty_and_folders_survive_restart_with_stable_identity はDrive再open後のmetadata/本文/画像。receipts_survive_response_loss_and_restart_without_double_mutation はreceipt/replay一致・別actor拒否・list1件。stopped_writer_backup_restores_ids_last_mutation_ids_receipts_and_sequence_with_blobs は一致するDB+blobsの復元、元metadata/bytes/receiptと新ID採番。src/tests.rs::saved_blob_before_metadata_failure_is_not_published_and_restart_collects_it は未公開・uncommitted・再open回収、commit_failure_rolls_back_metadata_and_receipt_together はmetadata/receipt同時rollback。collection_cannot_remove_in_flight_upload_or_selected_read はin-flight保護。これらをServer全体再起動や実電源断保証に拡張せず、新たな保存障害行列は不採用。

故障検出試行と復元

以下は意図的なmutantであり、製品不具合の発見ではない。patchとログは target/t725/ に保持し、製品sourceは復元した。

試行 注入と検出 実行結果(外側wall/libtest)
mutant-read server_drive::read_text の返却本文を String::new() にする。P1 filterの元upload本文比較が空文字≠日本語Markdownで失敗。 exit101、64.156秒/0.41秒(build込み)
mutant-cleanup execute_workdir_removal に誤ったDrive blob rootのremove_dir_allを挿入。実source削除後のfresh DriveReadが公開error「Drive storage or transport unavailable」で失敗。 exit101、88.103秒/0.59秒(build込み)
復元 server.rs と server_drive.rs に差分がないことを検査後、Server全crateと3つの個別filterを実行。 下表の全成功。故障をテストから避ける製品修正はない。

開発中にはsource fixtureの未定義git helperによるcompile error、準備用Repository FK不足、embedded adapter非対応の試行失敗もあった。helperを増やさず既存clean READMEを使用し、最終fixtureは本番Server create+既存HTTP Runtimeを利用した。これらを製品regressionや故障検出成功には数えない。いずれも cargo test --locked -p yoi-workspace-server --lib source_workdir_removal_keeps の試行で、source-removal-first はcompile exit101/wall6.875秒、source-removal はFK失敗exit101/wall84.053秒/libtest1.64秒、source-removal-fixed は非対応判定exit101/wall56.519秒/libtest2.14秒、HTTP経路への修正後 source-removal-http は1 pass/wall83.709秒/libtest0.61秒。時間採取は /usr/bin/time がないためBash TIMEFORMAT を使用し、出力のなかった背景起動の試行はbuild成功に数えなかった。

実行区分・費用とT-761への接続

すべて専用checkoutで実行した単発実測であり、CIや全通常suiteの速度ではない。wall はCargo起動/build込み、libtest時間は実行のみ。既存dead_code warningsは継続。

command(root) 結果 wall/実行秒
cargo test --locked -p yoi-workspace-server --lib worker_drive_tests --no-run 初回build成功 234.981/実行なし
cargo test --locked -p yoi-workspace-server --lib worker_drive_tests -- --test-threads=4 P1+Worker寿命追加時20 pass 71.131/9.69
cargo test --locked -p yoi-workspace-server -- --test-threads=4 最終実装1210 lib+12 bin pass、既存3 ignored、doctest対象0 400.021/291.85(lib)
cargo test --locked -p yoi-workspace-server --lib user_uploaded_markdown_roundtrips 復元後1 pass(Tools/WIP両方) 0.994/0.72
cargo test --locked -p yoi-workspace-server --lib worker_removal_preserves_drive_reference 復元後1 pass 4.458/4.20
cargo test --locked -p yoi-workspace-server --lib source_workdir_removal_keeps 復元後1 pass 0.872/0.62
cargo test --locked -p workspace-drive 40 unit+13 storage pass、doctest対象0 4.934/0.21+0.09
cargo check --locked root通常compile closure成功 75.368
cargo test --locked -p yoi-workspace-server --lib drive_web_roundtrip_tests -- --ignored 明示Web adapter1 pass 1.051/0.75

最終module境界コメントの補正後にも同じ worker_drive_tests -- --test-threads=4 を実行し21 pass(wall71.296秒、libtest9.75秒)を確認した。cargo doc --locked -p yoi-workspace-server --no-deps は成功(wall70.312秒)。cargo fmt --all -- --check(3.824秒)、git diff --check HEAD(0.004秒)、env -u LD_LIBRARY_PATH deno run --allow-read --allow-run=git tools/check-state-contract-names.ts(0.189秒、0 unapproved/0 stale exceptions)、2文書の deno fmt --check も成功した。文書の相対参照先は実在する。

T-761の通常runnerはCargo通常lib targetを列挙するため、追加3件は同targetのままで選択される。3件の逐次libtest実測合計5.54秒(単独Cargo wall合計6.324秒)。既存runnerのshard/並列負荷やcold build増分は未測定であり、全体時間へ単純加算しない。最も重いWorker寿命4.20秒は実永続Runtime停止・保持・再作成を検出する費用で、既存DB単体や共有2Workerの成功では代替できない。通常suiteへの追加はこの3件だけとし、Web adapterの既存ignoreは変更しない。

全Workspace deno task test、browser、製品全体E2E、実モデル判断、物理電源断、Server/Runtime全体再起動、CI実行は未実施。新規CI jobは追加しておらず、CIへの自動配線・実行済みとは扱わない。実モデルの調査・待機・完了判断を固定LLM応答で証明せず、追加したのは機構の接続保証である。

証拠は target/t725/*.log・*.time と2つのmutant patch。報告書へ生ログ/秘密は転載しない。稼働環境・対象develop・Ticket caseは変更していない。