Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ Development contracts:
| Mutating commands | `index`, `backfill-fold`, `optimize`, `vacuum` | These require writable storage and reject read-only database opens. |
| Reusable index artifact | `cdidx export codeindex.cdidx.zip`; `cdidx import codeindex.cdidx.zip --db <path>`; `cdidx import codeindex.cdidx.zip --dry-run --json` | Run export after indexing and upload the archive. Export refuses an existing destination unless `--overwrite` is explicit, publishes atomically from an owner-only temporary file, and verifies POSIX mode `0600`. Successful export JSON adds final archive byte size and SHA-256 plus the complete immutable manifest while retaining the prior result fields. Consumers import before query commands, or use `--dry-run` / `--check` to validate the archive without replacing the destination DB. Use `--prune-paths` when the archive comes from another checkout and the restored DB should advertise the import target project root; imports targeting `.../.cdidx/codeindex.db` use the sibling project directory, while other DB paths fall back to the process current directory. The archive contains only `manifest.json` plus `codeindex.db`; import validates ZIP entry names through `ZipArchiveSafetyPolicy` and rejects absolute, parent-directory, backslash, NUL, non-canonical, duplicate, and extra entries before extraction. The manifest carries bounded summary/readiness metadata including row counts, readiness bits, writer/indexed-head metadata, schema contract stamps, and unknown-extension summary when available. Import validates manifest format, manifest `user_version`, `database_sha256`, present summary counts, and the embedded SQLite file as a CodeIndex database before replacing the destination DB. Import rejects archive `codeindex.db` entries whose compressed or uncompressed metadata exceeds 8 GiB, and the extraction stream is also capped at 8 GiB. |
| Maintenance checkpoint and managed rollback | `cdidx db checkpoint <name> [--dry-run]`; `cdidx db checkpoints --list|--delete <name>|--prune --keep <n> [--dry-run]`; `cdidx db restore <name> [--dry-run] [--no-backup]`; `cdidx db restore-backups --list|--prune --keep <n>|--restore <id> [--dry-run] [--no-backup]` | Checkpoint snapshots `codeindex.db` plus existing WAL/SHM sidecars before risky maintenance. Import and both restore forms create a consistent, verified managed SQLite rollback snapshot before replacing an existing DB unless `--no-backup` is explicit. Managed directories use `<db>.restore-backup-<id>/` and contain a bounded manifest plus one standalone database payload; the manifest records SHA-256, byte count, supported `user_version`, provenance, and an optional source identifier, but no local absolute source path. `restore-backups --list` exposes the ID and provenance while retaining legacy directory metadata; existing prune retention remains compatible. `restore-backups --restore <id>` revalidates the directory boundary, manifest, payload hash, schema, and combined staging/rollback free space, then performs an atomic replacement with transient rollback-on-failure. Its `--dry-run` reports every validation and planned backup without mutation. Checkpoint delete/prune and restore-backup prune require an explicit mutation action, and checkpoint prune skips all deletion if its bounded 1,000-directory scan is truncated. Checkpoints live under `<db>.checkpoints/<name>/`. `backfill-fold` preflights folded rows, persisted folded values, and readiness under the index lock, creates an automatic checkpoint only when a mutation is required, accepts `--checkpoint` to force a snapshot for an already-complete DB, and accepts `--no-checkpoint` to skip mutation protection explicitly. JSON reports `checkpoint_skipped` plus `checkpoint_skipped_reason` (`already_complete`, `dry_run`, or `disabled_by_option`), and human output reports the same decision. |
| Checkpoint operation plan | `cdidx db checkpoint <name> --dry-run [--json]` | Dry-run builds an immutable plan that separates source DB/WAL/SHM files and bytes from every output, including the versioned `manifest.txt`, its SHA-256, estimated final bytes, destination/conflict status and policy, sidecar/compression/metadata policy, and remaining uncertainty. Execution creates a fresh plan from current sources, validates source metadata and SHA-256 before and after copying, verifies every planned output, and refuses atomic publication when inputs drift. Legacy JSON `files` / `bytes` fields remain available; use `source_files` / `source_bytes`, `planned_output_files` / `estimated_output_bytes`, and `final_output_bytes` for the explicit contract. |
| Binary compatibility | [COMPATIBILITY.md](COMPATIBILITY.md) | Database compatibility across `cdidx` binary upgrades and downgrades is documented there. Keep that policy updated whenever readiness bits, `codeindex_meta` contract stamps, or rebuild requirements change. |
| Fold backfill preview and recovery | `backfill-fold --dry-run`; `backfill-fold --checkpoint`; MCP `backfill_fold` with `dry_run: true` or `force: true` | Dry-run previews folded-key rows without mutating the DB or stamping FoldReady. `--checkpoint` explicitly preserves a snapshot even when CLI preflight finds no mutation, while the default completed no-op leaves no checkpoint artifacts. MCP accepts the same preview and can force rewriting all folded keys when an operator needs to recover from suspicious fold metadata or row state even though the stored version/fingerprint appears current. Non-dry-run row rewrites are resumable after interruption: completed row updates remain durable, and final FoldReady metadata is stamped only after verification succeeds. MCP responses include `progress.rows_done`, `progress.rows_total`, and `progress.fraction` so clients can report and retry long backfills. |

Checkpoint plan drift detection covers DB/WAL/SHM content changes and sidecar appearance or disappearance through the final pre-publication validation. The plan's `uncertainty` value records the remaining post-validation race; copied outputs are independently hash-verified against the plan before atomic publication. DB/WAL/SHM candidates must pass native regular-file type validation before hashing so Unix FIFOs cannot block planning. `metadata_policy` reports `owner_only_files_and_directories` on POSIX and the actually inherited `inherited_windows_acls` policy on Windows. A database payload whose output name collides with `manifest.txt`, including filesystem-equivalent casing, makes the plan not ready and is rejected before mutation.

## Filesystem Permissions

| Artifact | POSIX permission and behavior |
Expand Down Expand Up @@ -3406,9 +3409,12 @@ net9 CI lane に合わせる場合は `FRAMEWORK=net9.0 make test` を使いま
| 変更系コマンド | `index`、`backfill-fold`、`optimize`、`vacuum` | 書き込み可能な storage を必要とし、read-only database open を拒否します。 |
| 再利用可能な index artifact | `cdidx export codeindex.cdidx.zip`; `cdidx import codeindex.cdidx.zip --db <path>`; `cdidx import codeindex.cdidx.zip --dry-run --json` | CI job では index 後に export して archive を upload します。export は `--overwrite` を明示しない限り既存 destination を拒否し、owner-only temporary file から atomic に publish して POSIX mode `0600` を検証します。export 成功時の JSON は従来 field を維持し、最終 archive の byte 数と SHA-256、完全で immutable な manifest を追加します。利用側は query コマンドの前に import でき、`--dry-run` / `--check` で destination DB を置き換えず archive を検証できます。別 checkout 由来の archive を import 先 project root として扱いたい場合は `--prune-paths` を使います。`.../.cdidx/codeindex.db` を import 先にした場合は sibling の project directory を使い、それ以外の DB path では process current directory に fallback します。archive は `manifest.json` と `codeindex.db` だけを含みます。import は ZIP entry 名を `ZipArchiveSafetyPolicy` で検証し、absolute path、parent-directory segment、backslash、NUL、non-canonical name、duplicate entry、extra entry を extraction 前に拒否します。manifest は row count、readiness bit、writer / indexed-head metadata、schema contract stamp、利用可能な unknown-extension summary などの bounded summary/readiness metadata を持ちます。import は manifest format、manifest `user_version`、`database_sha256`、存在する summary count、embedded SQLite file が CodeIndex database であることを検証してから destination DB を置き換えます。archive の `codeindex.db` entry は compressed / uncompressed metadata と extraction stream の双方で 8 GiB を上限に拒否されます。 |
| maintenance checkpoint と managed rollback | `cdidx db checkpoint <name> [--dry-run]`; `cdidx db checkpoints --list|--delete <name>|--prune --keep <n> [--dry-run]`; `cdidx db restore <name> [--dry-run] [--no-backup]`; `cdidx db restore-backups --list|--prune --keep <n>|--restore <id> [--dry-run] [--no-backup]` | 危険な maintenance の前に `codeindex.db` と既存 WAL/SHM sidecar の checkpoint を作成できます。import と2種類の restore は、既存 DB を置き換える前に consistent かつ検証済みの managed SQLite rollback snapshot を既定で作成し、`--no-backup` を明示した場合だけ省略します。managed directory は `<db>.restore-backup-<id>/` で、bounded manifest と standalone database payload 1個を含みます。manifest は SHA-256、byte 数、対応する `user_version`、provenance、任意の source identifier を記録しますが、local absolute source path は記録しません。`restore-backups --list` は従来 directory metadata との互換性を維持しつつ ID と provenance を表示し、既存 prune retention もそのまま利用できます。`restore-backups --restore <id>` は directory 境界、manifest、payload hash、schema、staging と rollback を合わせた free space を再検証してから、失敗時の transient rollback を伴う atomic replacement を実行します。`--dry-run` は変更せず、すべての検証と作成予定 backup を報告します。checkpoint の delete / prune と restore-backup の prune は明示的な変更 action を必要とし、checkpoint prune の bounded scan が truncated の場合は削除をすべて skip します。checkpoint は `<db>.checkpoints/<name>/` に置かれます。`backfill-fold` は index lock 内で folded row、永続化されたfolded値、readiness を事前確認し、mutation が必要な場合だけ automatic checkpoint を作ります。完了済みDBでもsnapshotを明示的に残すには `--checkpoint`、mutation protectionを明示的に省略するには `--no-checkpoint` を使います。JSON は `checkpoint_skipped` と `checkpoint_skipped_reason`(`already_complete`、`dry_run`、`disabled_by_option`)を返し、human output も同じ判断を表示します。 |
| checkpoint operation plan | `cdidx db checkpoint <name> --dry-run [--json]` | dry-run は immutable な plan を作成し、source DB/WAL/SHM の file と byte 数を、version 付き `manifest.txt`、その SHA-256、最終 byte 数の見積もり、destination/conflict の状態と policy、sidecar/compression/metadata policy、残る不確実性を含む全 output から分けて報告します。実行時は現在の source から新しい plan を作成し、copy 前後の source metadata と SHA-256、および作成予定の全 output を検証して、入力が変化した場合は atomic publish を拒否します。従来の JSON `files` / `bytes` field は維持されます。明示的な contract には `source_files` / `source_bytes`、`planned_output_files` / `estimated_output_bytes`、`final_output_bytes` を使用してください。 |
| binary compatibility | [COMPATIBILITY.md](COMPATIBILITY.md) | `cdidx` binary の upgrade / downgrade をまたぐ database compatibility を記載します。readiness bit、`codeindex_meta` contract stamp、rebuild requirement を変える場合は、この policy も更新してください。 |
| Fold backfill の preview / recovery | `backfill-fold --dry-run`; `backfill-fold --checkpoint`; MCP `backfill_fold` の `dry_run: true` または `force: true` | dry-run は DB を変更せず FoldReady stamp も書かずに、rewrite 対象の folded-key row をプレビューします。CLI preflight でmutation不要と判断された場合でもsnapshotを明示的に保存するには `--checkpoint` を使います。既定の完了済みno-opはcheckpoint artifactを作りません。MCP も同じ preview を受け付け、stored version / fingerprint が current に見える場合でも suspicious な fold metadata や row state を復旧するため `force: true` を受け付けます。non-dry-run rewrite は中断後に resume でき、完了済み row update は durable に残り、最終 FoldReady metadata は verification 成功後にだけ stamp されます。MCP response は `progress.rows_done`、`progress.rows_total`、`progress.fraction` を含みます。 |

checkpoint plan の drift 検出は、publish 前の最終検証までに起きる DB/WAL/SHM content の変更と sidecar の出現・消失を対象にします。plan の `uncertainty` 値は最終検証後に残る race を記録し、copy 済み output は atomic publish 前に plan の hash と個別に照合されます。DB/WAL/SHM 候補は hash 読み取り前に native regular-file type validation を通すため、Unix FIFO が plan 作成を停止させることはありません。`metadata_policy` は POSIX では `owner_only_files_and_directories`、Windows では実際に継承される `inherited_windows_acls` policy を報告します。database payload の output 名が filesystem 上で同一の大小文字を含め `manifest.txt` と衝突する場合、plan は not ready となり、変更前に拒否されます。

## ファイルシステム権限

| artifact | POSIX permission / behavior |
Expand Down
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,7 @@ Use `docs/test-doc-maintenance-plan.md` before moving oversized suites or adding
- Cap issue lifecycle tests should reuse one indexed fixture across full-scan and update transitions when they assert the issue after each low/high boundary change.
- Unreadable-directory full-scan coverage keeps JSON and human diagnostics, purge protection, checkpoint non-creation, and successful rescan retry in one fixture so the shared partial scan setup is not rebuilt.
- Legacy-checkpoint coverage proves the save hook is never called, manually seeds the old file, and covers both deletion after a stable-snapshot file-read failure and bounded delete-failure warnings so authoritative full scans cannot resume from HEAD-only state.
- Database-checkpoint planning coverage keeps dry-run and execution in one fixed-clock fixture so source DB/WAL/SHM bytes, every planned output, manifest schema/hash, estimated and final bytes, and storage policies must agree. Separate focused fixtures cover missing sidecars in human output, destination conflicts, source drift refusal before publish, and native rejection of a Unix FIFO sidecar before hashing.
- HEAD freshness coverage uses one two-commit fixture to prove a `--files` refresh remains stale before a `--commits HEAD` refresh marks the current head matched.
- Hook timeout identity coverage uses a one-second callback budget so the healthy duplicate has cold worker-startup margin while the selected 30-second hook still times out well below the production-sized five-second budget.
- SSE oversized-frame coverage uses the minimum practical keep-alive interval because the frame-size rejection, not elapsed idle time, is the contract; retain bounded polling for stream removal instead of a production-scale interval.
Expand Down Expand Up @@ -1647,6 +1648,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
- cap issue lifecycle test は low/high boundary の変更ごとに issue を assertion する場合、full-scan と update の遷移で 1 つの indexed fixture を再利用してください。
- unreadable-directory の full-scan coverage は JSON/human diagnostics、purge protection、checkpoint 非作成、全体を再走査する successful retry を 1 fixture に保ち、共通の partial scan setup を再構築しないでください。
- legacy checkpoint coverage は save hook が呼ばれないことを固定し、旧fileを手動で配置してstable-snapshotのfile read failure後にも削除される経路とboundedなdelete-failure warningの両方を扱い、authoritative full scanがHEADだけの状態から再開しないことを検証してください。
- database checkpoint plan の coverage は fixed clock の同一 fixture で dry-run と実行を扱い、source DB/WAL/SHM の byte 数、作成予定の全 output、manifest schema/hash、見積もりと最終 byte 数、storage policy が一致することを固定します。human output での sidecar 不在、destination conflict、publish 前の source drift 拒否、hash 前の Unix FIFO sidecar の native 拒否は、それぞれ焦点を絞った fixture で検証します。
- HEAD freshness coverage は 1 つの two-commit fixture で、`--files` refresh 後は stale のまま、`--commits HEAD` refresh 後は current head が matched になることを検証してください。
- hook timeoutのidentity coverageは1秒のcallback budgetを使い、正常なduplicate workerのcold startupに余裕を残しつつ、選択した30秒hookを本番相当の5秒budgetより十分早くtimeoutさせます。
- SSE oversized-frame coverage は、経過idle時間ではなくframe-size rejectionが契約なので、実用上最小のkeep-alive intervalを使います。stream除去は本番相当intervalではなく境界付きpollingで検証してください。
Expand Down
Loading
Loading