Bind immutable Job kind/id/input digest to retained input provenance. Recheck current Host authority after hooks and at each compactor request; restored or rewritten input cannot become a local grant or switch Job identities. Add actual Controller, lifecycle, correction and signed Host/model regressions for Journal and consolidation.
88 lines
28 KiB
Markdown
88 lines
28 KiB
Markdown
# T-787 操作認可境界の棚卸し
|
||
|
||
## 観測範囲
|
||
|
||
2026-10-28、HEAD `618880d38ded5e501d7c926006d1869282f06892` に対する共有作業ツリーの未commit差分を読んだ記録。T-787の本文とAGENTSの文書管理・検証規則を基準にした。実装とテストは並行して変更中であり、この記録は受入条件の充足、テスト成功、全入口の保護完了を示さない。将来の仕様正本や維持対象のAPI一覧ではなく、一律gate撤去で到達可能になる境界の調査証拠として残す。
|
||
|
||
共通の判断基準は [正本・権限・実行の原則](../principle/authority-and-history.md#featureの構成と実操作) に置く。下表の操作名は完全一致の例であり、`ticket` が `ticket.create` を含むという意味ではない。`Workspace` 資源はcollection操作用で、別kindの個別資源を含まない。操作名を列挙した行も、列挙以外を許可するものではない。
|
||
|
||
## Feature・経路別の境界
|
||
|
||
資源名は `crates/server-api/src/authorization.rs::PermissionResource` のvariantを指す。共通境界欄は読取り時点で確認した呼出し位置であり、provider欄の既存検査とは別の制約である。通常の登録はローカル処理であり、表の外部処理が起動に必須かどうかとは分離する。
|
||
|
||
以下、`WB/` は `crates/worker/src/feature/builtin/`、`WS/` は `crates/workspace-server/src/server/`、`W/` は `crates/worker/src/`。
|
||
|
||
| Feature・経路 | 操作例と実資源 | 共通境界・別入口 | 合成するprovider側の検査 | 起動必須性・拒否時の扱い |
|
||
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| task | 保護された外部操作なし | `WB/task/mod.rs` のTaskStore・Tool登録・履歴replay | セッション内の入力検証・保存契約。Subject policyを要求しない | ローカル初期化。権限未設定でも起動・操作・restore可能であるべき |
|
||
| image・通常のファイル操作・Bash | `filesystem.read`、`filesystem.write`、`bash.execute` / `Workdir` のID・path・再帰範囲 | `W/authorized_workdir.rs` のsession wrapper。Toolごとの認可だけに頼らない | attachment選択、provider scope、解決済みpath・symlink、capability、明示command grant | Tool登録だけなら外部読取りなし。ViewImageの読取り・Workdir由来の起動入力は別途検査対象。画像bytesの再供給までの証明は未確認 |
|
||
| web | `web.search` / `Network` のprovider endpoint URL、`web.fetch` / 各取得・redirect先URL | `WB/web.rs::WorkspaceWebAuthorizer` → `crates/tools/src/web.rs`。検索のsecret取得・network前、fetchのDNS・network前にcallback | 公開HTTP(S)・private/local拒否、credential禁止、redirect・byte・timeout上限、secret provider | 任意Toolの登録でsecret読取り・通信をしない。要求時の拒否を通信や空の検索結果に置き換えない |
|
||
| sub_worker | `subworker.spawn`、`subworker.send_input`、`subworker.stop`、`subworker.observe` / Hostで束縛した親runtime/worker+子nameの `SubWorker` | `W/spawn/tool.rs`、`WB/manage_worker.rs`、`WB/worker_observation.rs` → bound-check | 親の委譲scope、明示command、子所有、name予約、Reviewer capability、現行委譲上限 | 登録はローカル。spawn・入力・観測・停止時は実操作。standaloneのローカル親所有child互換を他のWorker制御へ広げない |
|
||
| flow | ローカルなFlow状態遷移にFeature起動権限なし。verifierのWorkdir読取りは `filesystem.read` / `Workdir` | `WB/flow_transition.rs` のcoordinator・固定capture・read-only internal verifier | Flow graph・typed verdict、Session commit、read-only wrapper。verifierにはWorkspaceやBashを渡さない | 登録・復元はローカル。verifier実行やファイル読取りまで「ローカルだから無認可」と一般化しない。LLM/provider接続の独立検証はこの読取り調査では未確認 |
|
||
| worker・worker observation | `worker.list`、`worker.create`、`worker.observe.list` / `Workspace`。`worker.send_input`、`worker.notify`、`worker.cancel`、`worker.stop`、`worker.restore`、`worker.remove`、`worker.observe` / 正確な `Worker` | `WB/manage_worker.rs` のcontrol/lifecycle service、`WB/worker_observation.rs` | control/resource grant、Runtime/Worker所有・状態、観測範囲、削除・restore条件、Subject delegation専用経路 | 登録でWorker作成・復元を行わない。既存grantやWorker生存を操作認可の代わりにしない |
|
||
| workspace_worker_discovery | `worker.discover` / `Workspace` | `WB/workspace_worker_discovery.rs` のlist前 | bounded query、cursor、Workspace一覧のprovider契約。発見はcontrol/observeの付与ではない | 任意Tool。拒否時は下流一覧取得前に失敗 |
|
||
| manage_workdir・workdir_catalog | `repository.list`、`workdir.list`、`workdir.attachment.list` / `Workspace`。`repository.read`、`workdir.create` / `Repository`。`workdir.read`、`workdir.attach`、`workdir.delete` / `Workdir`。`workdir.attachment.read`、`workdir.detach` / `WorkdirAttachment` | `WB/manage_workdir.rs` と `manage_workdir/wip.rs`。detachはHostがaliasからconnection IDを束縛 | provider scope、attachment接続CAS・release fence、稼働占有・削除条件、repository materializer・既存資源grant | 登録はローカル。設定済attachmentの準備と任意の作成/解除Toolを区別。解除と削除を分離し、古いalias観測で別接続を解除しない |
|
||
| workspace_config | `workspace_config.attach`、`workspace_config.observe`、`workspace_config.read`、`workspace_config.commit` / `WorkspaceConfig` のpath・再帰範囲 | `WB/workspace_config/backend.rs::authorize_post` → 共通HTTP送信。commitはroot entrypoint変更と各path、renameの両側を検査 | config tree所有・path検証、observed content/CAS、commitのatomicity | WIP登録はローカル。attach/read/observe/commit要求が保護操作であり、FeatureをONにしただけでは許可しない |
|
||
| drive | `drive.capabilities`、`drive.root`、`drive.search` / `Workspace`。`drive.metadata`、`drive.list`、`drive.read_text`、`drive.read_chunk`、create/update/delete/relocate/uploadの各完全名 / `DriveEntry`。`drive.request_status` / `DriveRequest` | `WB/drive/backend.rs` のtyped backend。Tool・WIPは同backend、chunk/imageは各読取り、relocateは元entry・移動先parentを検査 | Drive grant、entry/version/hash、chunk条件、mutation CAS、request receipt・upload条件 | 登録でroot取得をしない。任意操作の拒否は下流取得/変更前。DriveはWorkdirでもfilesystem権限でもない |
|
||
| ticket | `ticket.create`、`ticket.query`、`ticket.list`、`ticket.tag.list` 等 / `Workspace`。`ticket.read`、`ticket.edit_item`、`ticket.case.update`、`ticket.assignment.answer`、`ticket.implementation_result.write` 等 / 個別 `Ticket` | `WB/ticket.rs::WorkspaceHttpTicketBackend`、`ticket/assignment_tracking.rs`、`assignment_public.rs`、`notification_diagnostics.rs`。Tool・WIP・typed serviceを照合 | authenticated actor、対象canonical化、assignment/event CAS、operation key・exact replay、対象資源条件。relationは両Ticketを検査 | 登録・service公開だけでは起動認可なし。createは `ticket.create` のみで旧 `ticket` の追加要求なし。起動prompt投影の読取りも保護操作 |
|
||
| objective | `objective.query`、`objective.create` / `Workspace`。`objective.read`、`objective.edit`、`objective.set_state`、`objective.link_ticket`、`objective.unlink_ticket` / `Objective`。リンク情報取得の `ticket.read` / `Ticket` | `WB/objective.rs::WorkspaceHttpObjectiveBackend`、native Tool/WIP adapter | Objective/Ticket対象検証、Backendの更新条件。関連Ticket本文の読取りをObjectiveの権限に含めない | 登録はローカル、明示操作時に認可。関連情報の追加読取りまで証拠を照合する必要あり |
|
||
| merge_request | `merge_request.open` / `Ticket`。`merge_request.read`、`merge_request.readiness`、`merge_request.review`、`merge_request.complete` / `MergeRequest` | `WB/merge_request.rs::MergeRequestTool` とnative WIP dispatch | repository selector、source・Ticket digest・snapshot、review capability、actor、integration evidence | 登録はローカル。操作認可は承認・統合の実証を代替しない |
|
||
| orchestration | 下位の `ticket.read` / `Ticket`、`worker.create` / `Workspace` 等を合成。独立したFeature起動権限なし | `WB/orchestration.rs` → TicketServiceとWorkerLifecycleService | 現行Orchestrator assignment、Ticket targetから導くattachment access、Profile/Flow解決、資源finalization | service依存の登録とspawnの実操作を分ける。Toolだけでなくserviceを直呼びする経路の作用0も照合対象 |
|
||
| memory(Workspace・Subject) | `memory.query`、`memory.document.read`、`memory.document.update` 等 / legacy `Workspace`。Subject側は `memory.query`、`memory.read`、`memory.changes.list`、`memory.resident.read`、`memory.resident.supply`、`memory.staging.write` 等 / Host束縛の `Subject` | `WB/memory.rs` のtyped dispatch、`WorkspaceSubjektivResidentSummarySource::fetch`、`load_initial_checked`・refresh/restore/pre-requestのsupply検査 | Subject本体所有・現行policy、Memory change/proposal条件、Job grant、履歴へのcommit・既存source provenance | Subject resident contextは必須処理、Workspace summaryは任意処理。必須拒否は起動失敗、任意拒否は未開始診断。読取り許可は再供給の許可ではない |
|
||
| memory extraction・surface lifecycle | `memory.extract.read`、`memory.extract.supply`、`memory.extract.commit`、`memory.staging.write`、`memory.consolidation.request`、`memory.surface.supply` 等 / 接続に応じた `Subject` またはlegacy `Workspace` | `WB/memory_lifecycle.rs::MemoryExtractionAuthority`、`memory_surface_lifecycle.rs`、Host側Job要求 | 凍結input範囲、抽出cursor、stage/commit条件、Subject/Workspaceの分離、attempt・writer fence | hook/task登録はローカル。任意背景処理でも開始・各読取り・モデル供給・commit・次の要求で再検査。取消受付と停止完了は別 |
|
||
| Subject Journal・Subject Job入力 | `journal.startup.read`、`journal.startup.supply`、`journal.compaction.read`、`journal.compaction.supply`、`journal.recording.request`、`journal.job.input.read`、`journal.job.input.supply` 等 / Host束縛の `Subject` | `WB/journal.rs`、`WB/backend_job_input.rs`、`W/subjektiv.rs` → `WS/subjektiv_journal.rs`、`subjektiv_job.rs`、`subjektiv_memory_journal.rs` | domain grant、現在の本体、Job immutable batch・origin・attempt・digest・期限・writer、receipt・journal位置 | startup grantがない構成は読取りを開始しない。構成されたstartup contextは必須、recording/compaction補助は各拒否・unavailableを診断。Job入力は各モデル要求とrestore後にも再検査 |
|
||
| MCP(暫定維持) | 既存の完全名 `mcp` / `Feature` | `W/feature.rs::authorize_requested_manifest`、controller discovery、既存activation guard | 既存stdio設定・プロセスspawn/終了・Tool登録・cleanup/retry・restore契約 | discovery前の既存拒否を保持。他Featureの新原則を用いて既存gateを削除しない。新しいserver/Tool/resource別認可や常時接続は対象外 |
|
||
|
||
## 旧grant・Job・文書の整合
|
||
|
||
差分の `ScopedPermission::covers` は操作名を完全一致で比較し、resource containmentはkindを跨がない。`Feature` variantと旧トップレベル名の保存形式は残るが、MCP以外の旧Feature grantは新しい操作の権限にならない。旧Workspace grantも個別Ticket/Subject/Worker等へ展開しない。schemaの自動書換えや全Subjectへの基礎権限付与を移行の説明にしない。
|
||
|
||
`WS/subject_authorization.rs::job_permissions` はJournal/consolidationの限定操作と同じSubject資源に絞り、現行policyとの積集合を取る。`active_grant`、凍結originの現在の本体所有も検査する。一般Jobは空のSubject権限であり、旧Jobのorigin欠落は拒否される。これはJob grantだけで許可する契約でも、Subject policy全体をJobへコピーする契約でもない。権限未設定・domain不一致・失効を非Subject Worker互換へfallbackさせない。
|
||
|
||
調査時点の維持文書 `docs/principle/`・`docs/development/` には、一律のFeature起動認可を要求する旧説明は見つからなかった。principleへ明示的な境界原則を追加した。`docs/report/` は過去の証拠であり、旧状態の記述を現行仕様に書き換えない。所有コードのコメントについては、`W/feature.rs` と `server-api/src/authorization.rs` の差分がMCP限定・操作境界へ更新されている。`worker-runtime/src/worker_backend.rs::saved_subjektiv_authorization_fixture_grants_only_exact_feature_activation` は依然 `subjektiv`・`workdir_catalog` の旧Feature名だけを許可するfixtureであり、新しいSubject resident操作・bound-checkの実接続証拠にはならない。
|
||
|
||
## 生成契約の所有とscope
|
||
|
||
実際の出力は `web/workspace/src/lib/generated/` と `openapi/server-api.json` である。付与された `apps/web/src/generated/` は既存出力先と一致しないため、新規folder作成・生成物コピー・手修正を行わなかった。所有者は `crates/server-api/examples/` と `src/repository_openapi_typescript.rs`、ts-rs系は `src/lib.rs` の対応関数である。
|
||
|
||
- OpenAPIの生成・照合は `cargo run -p server-api --example export_openapi` と `cargo run -p server-api --example export_openapi -- --check`。既定の書込み先は `openapi/server-api.json`。
|
||
- OpenAPI closureからの出力は `cargo run -q -p server-api --example generate_repository_openapi_types`、`generate_workdir_api_types`、`generate_runtime_api_types`、`generate_worker_launch_api_types`、`generate_ticket_api_types`、`generate_companion_api_types`。各exampleの `-- --check` は既存出力との照合。出力名はそれぞれのexampleが参照する定数を正本とし、一般的な `generated/` へredirectしない。
|
||
- Memoryの出力は `cargo run -q -p server-api --features typescript --example generate_memory_api_types > web/workspace/src/lib/generated/memory-api.ts`。同様のts-rs系は `generate_auth_api_types`、`generate_skill_api_types`、`generate_repository_access_types`、`generate_drive_api_types`、`generate_legacy_typescript`。stdout出力と直接書込み型のexampleを混同しない。
|
||
- `server-api/src/lib.rs` の `generated_worker_launch_api_contract_is_current` はOpenAPI closure出力を、`generated_memory_api_contract_is_current` はtypescript feature時のMemory出力を照合する。これらのCargo testはこの調査では実行していない。
|
||
- 追加された `authorization/bound-check` と既存 `authorization/check` は `openapi = false` の内部契約。`PermissionResource` のts-rs deriveがあることだけから、全てのenumが既存Web artifactへ出力されるとは判断しない。新variantの影響するschema closureと実際の生成差分は所有者で確認する必要がある。生成物が古いとも差分不要とも、この読取りだけでは断定しない。
|
||
|
||
## 未確認の接続・coverage
|
||
|
||
以下はコード読取りから必要と判断した確認範囲であり、テスト失敗を観測したという意味ではない。
|
||
|
||
- task-onlyの起動・direct install・restoreでFeature認可HTTPが0、Ticket Tool/WIP/serviceで未付与・範囲外・失効時に下流作用0、許可時に実作用完了を同じ接続で確認する。
|
||
- providerの拒否、delegation失効・policy縮小・Subject本体交代、attachmentの入替え競合を実Host接続で確認する。fake clientで認可callbackを数えた証拠だけでは代替できない。
|
||
- 初期resident入力の拒否時の読取り0・モデル供給0、許可時の取得・commit、optional Workspace summaryの未開始診断と通信障害分類を区別する。`load_initial_checked` が初期化で呼ばれる差分はあるが、その読取りだけでライフサイクル全体の成功を主張しない。
|
||
- 保存済みpromptのsourceが設定変更等で除去されたrestore、同じbodyのcache再供給、Journal compactionの凍結済み参照、Subject Jobの凍結入力にも現行権限が適用されるか確認する。source objectが残る場合のcallback成功だけでは除去後の経路を証明できない。
|
||
- Journal/consolidation Jobの限定grantと現行policy、origin欠落の旧Job、一般Job、current attempt・writer・期限拒否の組合せを確認する。Job入力のpre-request hook追加は、全Job操作のgrant整合の証明ではない。
|
||
- 継続処理について取消要求後の停止確認、途中失敗cleanup、停止後の追加配送・読取り・作用0を確認する。登録時の拒否テストで継続中の権限変更を代替しない。
|
||
- MCPのallow/deny、拒否時discovery spawn0、stdioの発見・各呼出し・restore・cleanup/retryを既存の粗い認可のまま回帰確認する。本Ticketの変更から新しい各呼出し認可を推論しない。
|
||
- 旧保存grantを読めること、新しい操作へ暗黙展開されないこと、明示standalone・非Subject互換・Workspace障害が区別されること、生成契約の整合は実接続/生成チェックが別途必要。
|
||
|
||
この調査でCargo build/testや生成処理は実行していない。文書のみの静的検査は実装の受入判定を代替しない。
|
||
|
||
## 同日・候補安定後の追補
|
||
|
||
上記は棚卸し時点の観測であり、以下はその後に実装担当が行った検証である。独立レビューの判断とは分ける。
|
||
|
||
- `worker-runtime/src/worker_backend.rs` の旧Feature名fixtureを、Subjectの実操作とbound targetを検査するfixtureに更新した。task-onlyのFIFO・receipt replayはHost呼出し0、pending head修復はresident/Journal取得と保護入力checkpointを検査する。既存headの再修復では保護入力を再取得しない。
|
||
- `worker.rs` の `protected_input_tests` はcached prompt、source除去後restore、fork・compaction・rewind、未知provenance拒否とhook後の再検査を扱う。Journalはstartup/compactionを区別し、空payloadは保護入力として偽装しない。追加の `backend_job_input.rs` とcontroller結合テストは、凍結Job入力を各モデル要求前に再検査し、拒否時にモデル要求・結果送信が発生しないことを確認した。
|
||
- `server/tests/subject_authorization_tests.rs` の署名Host接続テストで、unset task、MCPのdiscovery前拒否、Ticket作成の下流作用、alias正規化、provider scopeとの積集合、attachment再接続、本体交代を確認した。`subjektiv_jobs_tests.rs` は限定Job grantと現行policy、origin/attemptの失効を検査する。これは任意のFeatureコードを自動監視できるという主張ではない。
|
||
- 安定候補でroot `cargo check`、変更crateの通常suite(`server-api`、`tools`、`worker`、`worker-runtime`、`yoi-workspace-server`)、`server-api --features typescript` のsuite、変更crateのrustdoc生成、format・差分・状態契約名検査が成功した。restoreを含むsuiteにはcheckout内 `target/restore-test-environment/` 以下の専用config/data/runtimeを使用した。最初のServer再実行は隔離環境変数不足でpreflight失敗し、設定後の全suite再実行が成功した。preflightを削除して通してはいない。
|
||
- OpenAPIと影響する各OpenAPI closure出力は所有exampleの `--check` で一致した。Webの型検査と変更型を使う関連APIテストが成功した。描画変更はなく、browser/E2E・稼働環境更新は実施していない。通常suiteで元から明示選択のignoredテストを実行済みとは扱わない。
|
||
|
||
## 初回レビューで確認されたJob入力供給の不足
|
||
|
||
初回候補の通常suite成功は、凍結Job入力をcompactorへ再供給する経路と、Jobの通常hook後に権限が失効する経路を証明していなかった。正式レビューは実Controllerと捕捉モデルで漏れを再現し、request_changesとした。上記の成功記録をこの境界の成功へ拡張してはならない。
|
||
|
||
修正では、Job種別・Job ID・入力digestの保持義務を既存の保護入力provenanceに追加し、Host由来の実行bindingとの一致と現行認可を共通供給guardで検査する。保存値はgrantではない。attemptは現在のHost正本で毎回検査し、同じ凍結入力への正当な再試行と別Jobへの付替えを区別する。通常hookは早期診断に留まり、hook後とcompactorの各dispatchを代替しない。
|
||
|
||
恒久回帰は `worker_job_input_supply_tests.rs`(rewrite/restoreとcompactor継続)、`tests/controller/subject_job_input_supply.rs`(実Controllerと後続hook失効)、`server/tests/subject_job_model_supply_tests.rs`(署名Host・実policy/Job台帳・捕捉モデル)へ追加した。Journal/consolidation双方で許可時の実供給と拒否時のモデル要求0を観測する。origin切断の履歴fixtureは稼働Controllerの停止確認を主張せず、既存のconnected release検証とは分ける。修正前の恒久回帰失敗と修正後の成功、最終suiteの結果はMRで区別して記録する。
|
||
|
||
件数・生ログ・source識別はMRの検証記録に置く。これらの成功だけで受入条件の網羅、正式承認、統合、Ticketの完了を推論しない。
|