feat(resolver): close v0.10.0 resolver-backed source identity - #134
Merged
Conversation
v0.10.0 phase 5 required stable diagnostics for the seven resolver and cache categories the resolver-backed source contract publishes. Only one of them was emitted, and one of them - identity changed - was not observable at all: a changed validation token produced a different single-level cache key, so a superseded revision was indistinguishable from a source never generated. Split the cache layout into a generation directory chosen by what would be generated and an entry chosen by which revision was read, so revisions of the same source collect side by side. Source size and modification time move to the identity half with the validation token, since a source that changes size must still land beside the entry it supersedes. Both path components stay hashes, so no resolved identifier or validation token reaches the filesystem. Add usdgeo::cache::CacheDecision with stable names and fixed, transport-neutral messages, report decisions out of the authoring cache bridge, and project them onto four COPC codes that each carry their exact category. Cover the vocabulary, the layout split, superseded-entry detection, and the rule that no manifest persists source identity material. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every declared cell was a per-plugin bundle build rooted at a standalone project() that never declares USDGEO_BUILD_TESTS, so pointcloudCopc_tests and the memory-backed resolver test double were compiled only by the local root build. Tier 1 was therefore a local gate wearing a CI gate's description. OpenStrata 0.22.2 has `kind: workspace` cells, which configure the repository root - where USDGEO_BUILD_TESTS defaults to ON - and run its CTest suite. Add one per host on both lanes and regenerate the workflow. The cells need no external resolver repository, which is the property the tier split exists to protect. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The v0.10.0 exit gate requires Tier 2 recorded against a released external resolver before the tag, and remote baselines including bytes fetched over source size. Both were outstanding. Add a loopback origin that honours Range and logs every request, and a harness that composes it with usd-http-resolver v0.4.0 and the COPC FileFormat. Each scenario runs in a fresh interpreter against a fresh origin, so a row's byte count is that row's cost. Recorded against the 81 MB Autzen COPC: a metadata open costs 3 requests and 0.15% of the asset, a full read costs 277 requests and exactly 1.0, and local, remote, and second-revision reads author the same 10,653,336 points under the same digest. A weak validator classifies as unstable and reports COPC009 while authoring identical output, which is the conservative fallback demonstrated against a real resolver rather than a test double. The report also states what the baseline does not measure: no COPC read has a generated entry to hit, because the converter accepts .las and .laz only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Close the resolver-backed source identity milestone in the documents that carry it, and bump every version declaration. Two claims are corrected rather than restated. RESOLVER_SOURCE.md described usd-pointcloud-convert as accepting resolver-addressable identifiers; it accepts .las and .laz local paths, so nothing publishes a generated entry a COPC read could hit, and that is now marked not implemented and recorded as open work alongside the release notes' known limitations. WORKSPACE.md listed COPC among the bundles declaring an OST smoke fixture; it declares none, so its L3 and L4 checks skip. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review found the two-level cache layout could not do the job it was added for. The generation key included the resolved georeference, whose local origin is the source bounding box, and the conversion tool put its tile-plan key - computed by scanning the source - in the same half. A revision that moved either therefore landed in an unrelated generation directory, where HasSupersededIdentityEntry could not see it superseded anything: COPC011 would never fire, and the old entry was orphaned beyond Invalidate's reach. That is exactly the case the split exists to make observable. Restate the split as one rule. Caller intent chooses the generation directory; everything read out of the source chooses the entry inside it. coordinateTransform moves to the identity half, Descriptor gains a sourceDerived group, and the converter's tile-plan key moves into it. The caller's explicit coordinate arguments are a different value and stay in the generation key with the rest of the normalized arguments, so two differing requests are still not siblings. A unit test now holds both directions and fails if either is broken; it was written against the defect first and observed to fail. Also from review: - The Tier 2 harness bound port 0 per scenario, so "three revisions of one identifier" were three URLs and the published baseline claim was false. All origins now share one reserved port and one cache root, and the harness fails if the identifier turns out not to be single. Re-recorded. - The baseline said what the record could not show. It now states that COPC011 and a cache hit are unreachable from this harness because nothing publishes a COPC entry. - The COPC adjacency assertion rebuilt the layout from the original georeference, so it held by construction. It recomputes from the changed header the way a read does; the fixture's header bounds are fixed, so the moved-georeference case is covered at the cache layer instead. - The decision-message test asserted a string it had just built. The projection moved into the diagnostics header, and the test asserts code, text, category suffix, and severity as the plugin emits them. - CacheDecision::ReuseDisabled was unreachable while three documents listed it under COPC009. A remote source with a relative payload directory now reports it, which is a real refusal that was previously silent. - Origin.__init__ could raise after Popen and orphan the server, holding the reserved port for the rest of the run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Closes the
v0.10.0milestone: the two phases that were still open — diagnostics and secrets, and validation and baselines — plus the review fixes that followed.What was missing
Phase 5 and Phase 6 of the resolver-backed source contract were unchecked. One diagnostic category out of seven was emitted, Tier 1 was a local gate wearing a CI gate's description, and Tier 2 had never been run.
Diagnostics
usdgeo::cache::CacheDecisionpublishes the seven stable, transport-neutral categories the contract names. Messages are fixed constants owned byusdgeo::cache, so a transport detail cannot reach one by accident. COPC projects them onto four codes,COPC009–COPC012, and every message names its exact category.resolver-identity-changedwas not observable at all. A changed validation token produced a different single-level cache key, so a superseded revision was indistinguishable from a source never generated before. The entry layout is now two levels:Caller intent chooses the directory; everything read out of the source chooses the entry inside it. That rule is load-bearing: the georeference is source-derived (its local origin is the source bounding box), and so is the conversion tool's tile-plan key, so both live in the identity half. A unit test holds both directions and was written against the defect first, observed to fail, then fixed.
Both path components are hashes, which is also how a signed URL stays unreadable from a cache root.
Tier 1 as a CI gate
Every declared cell was a per-plugin bundle build rooted at a standalone
project()that never declaresUSDGEO_BUILD_TESTS, sopointcloudCopc_testsand the resolver test double were compiled only by the local root build. OpenStrata 0.22.2'skind: workspacecells configure the repository root; six of them now run on every host and both lanes, with no external resolver repository involved.Tier 2, recorded
Composed at runtime with
usd-http-resolverv0.4.0over the 81 MB Autzen COPC. Neither repository is in the other's build graph.Local, remote, and second-revision reads author the same 10,653,336 points under the same SHA-256. Three revisions are served at one identifier and differ only in the validator, so equal identifiers not implying equal content is demonstrated rather than asserted. The weak-validator row is the conservative fallback proven against a real resolver rather than a test double — and it still authors identical output, because a disabled cache changes what is reused, never what is read.
Two corrections, recorded rather than papered over
RESOLVER_SOURCE.md§3.2 described the converter as accepting resolver-addressable identifiers. It accepts.las/.lazlocal paths, so nothing publishes a generated entry for a COPC source and a generated-cache hit ratio is not measurable end to end. Marked not implemented, and the reason a hit ratio is absent from the baseline.WORKSPACE.mdlisted COPC among the bundles declaring an OST smoke fixture. It declares none, so its L3/L4 checks skip.Both are pre-existing gaps outside this milestone's scope, now open work in implementation-status.md.
Breaking change
A
v0.9.0cache root is never looked up under the new layout, so the first run after upgrading regenerates. Entries are derived data. Tooling that enumerated entries with a single-level glob needs a second level — see MIGRATION.md.Verification
ost build,ost test(16/16),ost plugin testfor all four bundles,check_release_metadata.py,ost lock --check, andost ci validateall pass locally on Windowscy2026/usd.The
v0.10.0tag is not yet created; it belongs on the merge commit.🤖 Generated with Claude Code