Repository navigation
feat: strict cache mode and CHTYPES_CACHE_UNUSABLE (#486, part 2) - #505
Merged
Merged
Conversation
…t in cli-parity (#486) The cross-binding tests for public issue #486's strict mode and its one cache-error code, ahead of the implementation, so the run on this commit shows them failing on the unfixed code: - v1-cache-interop part 7: each writer's cache is faulted seven ways (none, root 000, unpacked/sha256 000, an entry 000, a record 000, a garbage record with no blobs, a 0.x registry dir), and every reader runs fetch --offline, list --offline and verify as nobody, in the default mode and with --strict, and again with /opt/chtypes/v1 (a default system dir) holding the build. A positive control proves the reader is refused the faulted path. Every reader must give the same answer: not installed with a warning naming the path (or from the system dir), or exit 9 CHTYPES_CACHE_UNUSABLE naming the path and the reason, never a fall-through. --faults-as-self runs it locally. - cli-parity: verify --strict of an empty cache exits 1, and list --offline --strict and where --strict of a good one succeed, in all four CLIs. Refs #486 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Public issue #486's strict mode and its one cache-error code, in all four bindings: - CHTYPES_CACHE_UNUSABLE (exit 9) joins spec/fetch-v1/constants.json and is generated into all four. It names the path, a reason (unreadable_root, not_a_directory, unreadable_entry, unacceptable_record, layout_0x, unwritable) and the errno name, with one sentence in every binding: Go *ArtifactError{Code: CodeCacheUnusable, Path, Reason, OSError} and ErrCacheUnusable, Python and TypeScript CacheUnusableError, Rust Error::CacheUnusable(CacheFault). - Strict mode, opt-in: Go FetchOptions.StrictCache, Python strict_cache, TypeScript strictCache, Rust strict_cache, CHTYPES_CACHE_STRICT=1, and --strict on every CLI command. Every fault of the cache (K1 to K4) and of an existing system dir (K1, K2) is the new error, checked before any system dir is read, so nothing falls through. where --strict checks the root; verify --strict of nothing exits 1. - The default mode keeps "unreadable is absent" in every binding (Python before 3.14 raised a raw PermissionError, Rust SOURCE_UNREACHABLE) and warns once per path, in Resolved.warnings, the MISSING message and the CLI's list and verify. - A write the fetch layer needed under the cache that failed is the new error with reason unwritable, in every mode: it was Go's and TypeScript's UsageError, a raw Python OSError, and Rust's SOURCE_UNREACHABLE. bindings-v1.md section 4 gains the class row and the fault's fields, fetch-v1.md section 1 "The cache faults", and the parity allowlist the names the doc gives in prose. Each CHANGELOG has the same Added and Changed bullets. Refs #486 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
EricAndrechek
marked this pull request as ready for review
October 6, 2026 16:53
github-merge-queue
Bot
removed this pull request from the merge queue due to invalid changes in the merge commit
Oct 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part 2 of public issue #486: strict mode and one cache-error code, in all four bindings. It is built on #503 (part 1) and carries its commits until #503 merges; merge #503 first. The diff of this part alone is the last two commits.
CHTYPES_CACHE_UNUSABLE, exit status 9, added tospec/fetch-v1/constants.jsonand generated into all four bindings andfetch-v1.md§8. It names the exact path, a reason and the errno name, with one sentence in every binding:<path> is unusable as a cache: <reason> (<errno>).unreadable_rootunpacked/sha256/cannot be listed (strict)not_a_directoryunpacked/sha256/is not a directory (strict)unreadable_entryverified.jsoncannot be read (strict)unacceptable_recordlayout_0xunwritableStrict mode, opt-in: Go
FetchOptions.StrictCache, PythonFetchOptions(strict_cache=True), TypeScriptstrictCache: true, RustFetchOptions::strict_cache, elseCHTYPES_CACHE_STRICT=1(0is off), and--strictonfetch,list,verifyandwhere. Every fault of the cache (K1 to K4), and K1 or K2 of an existing system dir, is the new error, checked before any system dir is read, so nothing falls through.where --strictchecks the root before printing it, andverify --strictthat verified nothing exits 1 (CHTYPES_ARTIFACT_MISSING). Strict by default for an explicit cache is not in this change.The default mode keeps "unreadable is absent", now in every binding and on every Python, and warns once per path:
<path> could not be read (<errno>); treated as not installed. Set CHTYPES_CACHE_STRICT=1 to make this an error.The warning is inResolved.warnings, in the MISSING message, and on stderr from the CLI'slistandverify.What a caller saw before and sees now
"Before" is this branch's base, part 1 (
measuredby the run on the tests-only commit, below, with the Go-written cache read asnobody). A system dir holds the same build in the "+ system dir" cells.PermissionError, exit 1, no code, with or without a system dir. Rust:CHTYPES_SOURCE_UNREACHABLE, exit 3, with or without a system dirunreadable_root, path = the root, with or without a system dirunpacked/sha256000 (K1)unpacked/sha256unreadable_root, path =unpacked/sha256SOURCE_UNREACHABLE, exit 3unreadable_entry, path = the entryunreadable_entry, path = the recordinferred:CHTYPES_ARTIFACT_CORRUPT, from parsing that cache'sindex.json, whose entries carry nomediaTypeorsize)unacceptable_record, path = the recordlayout_0x, path = the dir*UsageError(CLI exit 2), Python a rawOSError(CLI exit 1), TypeScriptUsageError(CLI exit 2), RustCHTYPES_SOURCE_UNREACHABLE(exit 3)CHTYPES_CACHE_UNUSABLE,unwritable, exit 9The new public names, and their doc rows
CodeCacheUnusable,ErrCacheUnusable,ArtifactError.OSError,FetchOptions.StrictCache.CacheUnusableError(withpath,reason,os_error),CODE_CACHE_UNUSABLE,FetchOptions.strict_cache.CacheUnusableError(withpath,reason,osError), theCacheFaulttype,FetchOptions.strictCache.Error::CacheUnusable(CacheFault),CacheFault(withpath,reason,os_error),FetchOptions::strict_cache.bindings-v1.md§4 gains the "cache unusable" class row and "A cache fault" bullet, and §6 names the strict option;fetch-v1.md§1 gains "The cache faults". The names the doc gives in prose are entries inscripts/parity-surface-allow.json, beside the existing fetch-option and code entries.parity-surfaceis green in all four in CI: 0 findings and 0 allowlist problems (Go 266 matched, Python 240, TypeScript 236, Rust 238).CacheUnusableErroris anArtifactErrorlike every other fetch error, andisChtypesErroris true for it; that TypeScript'sArtifactErroris not aChtypesErroris Fetch layer: Go --frozen re-downloads on a warm cache; TS --lock pins one platform; TS ArtifactError isn't a ChtypesError; Python index.json duplicates (measured, 1.0.2) #487's item 3, left to that issue.Test plan
Each new test ran on the unfixed code first: the tests-only commit
2b9cd21ran in CI before the implementation (it is part 1's code with the new tests; its interop job, its ci run).v1-cache-interoppart 7, writer x reader x fault x mode. Each writer's cache is faulted seven ways; each reader runsfetch --offline,list --offlineandverifyasnobody, in the default mode and with--strict, and again with/opt/chtypes/v1(a default system dir) holding the build: 4 x 4 x 7 x 2 x 2 = 448 cells. A positive control provesnobodyis refused the faulted path ("Permission denied") or the row is INVALID. A cell passes only when the reader's exit status, code, unusable path and reason, warned paths and answer equal the expected ones, and every reader in the row gives the same observation. On the base: 356 cells red: every default K1/K2 cell (no warning; Python's raw error; Rust's exit 3), the garbage-record row over the Python-written cache (Rust disagreed), and every strict cell (--strictunknown, exit 2). On the head (job): 448/448 ok, 112 per block (default, strict, each with and without the system dir), and every earlier part of the job ok too (4x4 16/16, the 0.x rows 12/12, both line tables 16/16, concurrency 5/5, read-only 8/8, cross-uid 16/16).cli-parity:verify --strictof an empty cache exits 1,list --offline --strictandwhere --strictof a good one succeed, in all four CLIs. On the base: red in all four (exit 2).resolve_installed,list_installed,verify_installedand an offlineensure(and Go's and TypeScript's probe), eachchmodproved by a refused read first and skipped loudly as root; option-then-environment precedence; a strict, unreadable system dir; a failed write asunwritable; the public class and its fields through the registry; and the CLI's--strict. On the base these do not compile or import (the names are new); their failure is shown by mutants instead, run locally: removing the probe fails 5 Go tests and 19 Python tests, and removing the write mapping fails exactly the Go and the Pythonunwritabletest.Local gates on the head:
go build/vet/test ./...,uv run pytest -q,tsc --noEmit(both configs),cargo check --locked --all-targets(also with--all-features) with clippy and fmt,gen-constants --checkand--selftest,abi-v1/gen.py --check,genfixtures --check,cache-interop.py --selftest, the four lints, markdownlint, dprint,policy-merge-check.py --check-guideand--selftest,check-selftests-wired.py,check-cli-parity.sh go|python,parity-surface.py run --only go python(green), and the Go and Python conformance runners (249/249 each).cache-interop.py --faults-as-selfwith the Go and Python CLIs: 56/56.MERGE NOTES
spec/,scripts/,.github/, the fetch layers), so it does not enqueue itself.v1-cache-interopcreates/opt/chtypes/v1(a default system dir) withsudo installon the hosted runner and leaves it empty.cli-paritygains three--strictcases.index.jsoninto an error in the default mode (it wasSOURCE_UNREACHABLEorARTIFACT_CORRUPT); that is the one-answer rule, and strict mode is where they are errors.Related issues
Refs #486
🤖 Generated with Claude Code