Conversation
…gests `TestContentHashContract` covers `verified_bytes`, which the accessor and the pre-write re-verify share. It does not reach the other place the rule is written down: adoption hashes the bytes it reads off disk with an expression of its own and compares that to `content_hash`. That one decides whether an unmanaged file is claimed or refused, so a comparison that normalized would adopt a planted file whose bytes merely *normalize* to the delivered content, leave those foreign bytes in place, and report `skipped_current` — an action documented to mean the opposite. Pins it against the same literal digest, with the same three alterations asserted to be refused rather than adopted. The fixture writes bytes rather than `write_text`, whose text mode translates `\n` to `os.linesep`: a no-op on POSIX, but on Windows it would rewrite the CRLF these cases are about before the test ran. Also documents the three fixture `_hash` helpers. Each is the expression the implementation uses, which is what makes it useless as an oracle, and the docstring says so and names where the rule is actually pinned. Matches the TypeScript SDK, which carries the same two suites, so neither implementation is the only one holding the cross-service rule. Verified by mutation on the adoption comparison: normalizing line endings and appending a final newline each refuse the exact match that should adopt; NFC-normalizing adopts the NFD-planted file as `skipped_current`, which only the refusal cases catch. 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.
Follow-on to
test(client): pin the content-hash rule to the service's own digests(already onxie/agent-skills), closing the half of that rule it doesnot reach.
TestContentHashContractpinsverified_bytes, which the accessor and thepre-write re-verify share. Adoption does not go through it: it hashes the bytes
it read off disk with an expression of its own —
hashlib.sha256(on_disk).hexdigest() == content_hashinskills_fs.py— and soit is a second statement of the same rule that the accessor-side test cannot
reach.
It is also the statement with the most riding on it. Adoption decides whether an
unmanaged file is claimed or refused, so a comparison that normalized would
adopt a planted file whose bytes merely normalize to the delivered content,
leave those foreign bytes on disk, and report
skipped_current— an actiondocumented to mean that the bytes on disk already are the resolved content.
What this adds
TestAdoptionContentHashContractintest_skills_fs.py, beside the existingadoption class, using the same literal digest
TestContentHashContractpins:as
skipped_currentand recorded;decomposition — each planted on disk and paired with the unaltered digest,
which must be refused rather than adopted, with the planted bytes left
untouched and nothing claimed into the manifest.
The digest is copied rather than imported, and the hazard content is written
with a
éescape rather than the literal character. A literal's wholevalue is that it is not derived from anything, and an escape cannot be changed
by a tool that re-normalizes the source file.
The fixture writes bytes, not text.
Path.write_textopens in text mode,where
newline=Nonetranslates\ntoos.linesep— a no-op on POSIX, but onWindows it would rewrite the CRLF these cases are entirely about before the test
ran. The implementation is already careful in the other direction:
_read_regular_filepassesO_BINARYso a Windows descriptor does nottranslate CRLF on the read.
Two of the three variants are longer than the hazard content, so they are only
sound because the compare read stops at
max_bytes + 1; at exactlymax_bytestheir leading bytes would be the hazard content, hash equal, and wrongly adopt.
The fixture
_hashhelpers now say what they are. All three recompute therule with the implementation's own expression, which is what makes them useless
as an oracle. Each carries a docstring saying so and naming where the rule is
actually pinned.
Verification
By mutation on the adoption comparison. The source was restored and confirmed
clean afterwards.
skipped_currentThe third is the hole itself, and only the refusal cases catch it — which is
what confirms they are not redundant with the positive control.
ruff format --checkandruff checkclean,mypy packages/*/srcclean(57 files), full suite 2166 passed / 11 skipped. Tests only — no
src/changes.Parity
The TypeScript SDK carries the same two suites against the same two literal
digests (launchdarkly/js-ai-sdk#102). Both SDKs had closed the accessor half and
left adoption open; this closes it on this side.
Based on
xie/agent-skillsrather thanmain, which does not have the skillsfeature.
🤖 Generated with Claude Code
Note
Overview
Tests-only follow-up that pins the filesystem adoption content-hash rule—the path that hashes on-disk bytes in
skills_fsand is separate fromTestContentHashContract/verified_bytes.Adds
TestAdoptionContentHashContractintest_skills_fs.pywith the same literal hazard content and LaunchDarkly service digest as the accessor contract (copied, not imported). It asserts byte-exact unmanaged files are adopted asskipped_current, while CRLF→LF, an extra trailing newline, or NFD Unicode decomposition are refused (error, no manifest claim, bytes unchanged). Introduces_plant_unmanagedusingwrite_bytesso Windows text mode does not rewrite CRLF fixtures.Documents
_hashintest_skills.py,test_skills_fdv2.py, andtest_skills_fs.pyas fixture convenience only—not an independent oracle—and points readers to the literal digest contract tests.Reviewed by Cursor Bugbot for commit d6b0d77. Bugbot is set up for automated code reviews on this repo. Configure here.