Repository navigation
ArtifactRef: one spelling for artifact:[<store>/]<key>[@<sha256>], plus ArtifactStore.resolve - #95
Merged
Merged
Conversation
…us ArtifactStore.resolve an and reelee each spelled a reference to an ArtifactStore artifact their own way. ArtifactRef.parse/format is the one parser and formatter; locate() decides the store segment against a mall (an's rule, since the text alone cannot tell store/key from a key with a slash), and ArtifactStore.resolve(ref) returns the record and bytes, reading a pinned blob even after its key was re-saved and checking it hashes to the pin. Closes #90 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h in ResolvedArtifact, resolve_in_mall - content_hash_of(record): asset_id, else content_hash, else None; used by count_refs, from_sql's default, resolve and the holder scan. A record with no content yet raises KeyError. - ArtifactStore.keys_with_content: a lazy catalog scan that skips damaged records. resolve checks ref.key first and scans only when the key no longer holds the pin. - ResolvedArtifact(key, record, content_hash, data); resolve(ref, *, read=True) with read=False checking existence only (no pin hash check). blobs=None raises KeyError. - resolve_in_mall(ref, mall, *, default_store, read=True). - is_artifact_ref is exactly "parse succeeds"; parse raises one ValueError, chained to the key's error; locate splits only when the rest is a key. - Exports ARTIFACT_REF_PREFIX, content_hash_of, resolve_in_mall; module note on differences from an's parse_artifact_ref. Refs #90 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…locate, private scan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 27, 2026
Closed
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 #90
One spelling for a reference to an
ArtifactStoreartifact,artifact:[<store>/]<key>[@<sha256>], and one way to read what it names.API (
lacing.artifact_ref,lacing.artifact_store; exported fromlacing):ArtifactRef(key, store=None, pin=None), a frozen dataclass:.parse(text, *, require_prefix=True):require_prefix=Falsealso reads an's unprefixed manifest form<store>/<key>@<sha256>..format()..locate(mall, *, default_store): decides the store segment against a mall (an's rule). The text alone cannot telltakes/a(keyaof storetakes) from a keytakes/a, soparsekeeps the whole name askey. Any reference thatformatwrites reads back as itself; the constructor refuses one that would not.ArtifactStore.resolve(ref, *, read=True) -> ResolvedArtifact(key, record, content_hash, data):savecomputes it).read=Falsechecks that the bytes exist without reading them, for streaming callers (iter_blob,blob_path).resolve_in_mall(ref, mall, *, default_store, read=True)does locate-then-resolve. "No such store" raises a plainLookupError, distinct fromKeyError.content_hash_of(record):asset_id, elsecontent_hash(reelee's records). This is now the one rule used bycount_refs,from_sqlandresolve.ARTIFACT_REF_PREFIX.is_artifact_refstays inlacing.artifact_refand is not exported fromlacing, because an's predicate also acceptsArtifactobjects.Acceptance. an and reelee parse and format through the helper, and a pinned reference round-trips (tests). Adoption in an and reelee is filed in those repos; other workers hold them. The differences from an's
parse_artifact_refare listed in the module docstring:takes/andtakes//ago to the default store;require_prefix=False;artifact: xwith a space is refused.reelee ids with inner whitespace cannot be formatted as references.
Review (per the burn's rule):
resolverefused every reelee record (content_hash, notasset_id).ref.storewas silently ignored, with no mall-level path.ResolvedArtifactlacked key and hash and forced full reads.is_artifact_refandparsecould disagree.content_hash_ofshared withcount_refsandfrom_sql, the key-first lazy holder scan, the newResolvedArtifactandread=False,resolve_in_mall, the SHA-256 pin doc, and 66 tests.require_prefix=False.locatecalledbool()on the default store, which lists a catalog: nowis None.keys_with_contentbroke a delete-while-iterating loop and hid damaged records: now private.KeyError: nowLookupErrorvsKeyError.AttributeError: nowFalse/TypeError.__str__ = formathid the parts: dropped.is_artifact_refis no longer exported fromlacing.CI: Windows tests are off for this repo (
test_on_windows = false), so that job skips, as on every PR here.Follow-ups filed after merge:
🤖 Generated with Claude Code