Claudinite growth: convert two on-device-privacy prose rules to checks - #54
Closed
missingbulb wants to merge 1 commit into
Closed
Claudinite growth: convert two on-device-privacy prose rules to checks#54missingbulb wants to merge 1 commit into
missingbulb wants to merge 1 commit into
Conversation
#42) The prose-to-checks sweep over `.claudinite/local/packs`. Two RULES.md rules were always-testable but enforced only by prose; both are checks now, each with a fixture that fires on a violation and stays quiet on the real tree. - `on-device-privacy/single-home-directory` — "everything lives in one deletable directory". Scans `laughcounter/**.py` for home-anchored path literals (`Path.home() / "…"`, `"~/…"`) that land outside `~/.laughcounter`, and `mac/Sources/**.swift` for Foundation standard directories other than Application Support, an Application Support base never narrowed to `LaughCounter/`, and `NSHomeDirectory()`. `~/Library/LaunchAgents` is exempt by name — launchd mandates that location and the app only prints the plist. - `on-device-privacy/json-content-type-guard` — "any new mutating endpoint keeps that guard". Cuts each `do_POST`/`do_PUT`/`do_PATCH`/`do_DELETE` body out by indentation and requires an `application/json` content-type check inside it, ahead of any body read. Parsing the handler rather than grepping the file is what makes it confident: `application/json` appears all over dashboard.py as a *response* type. Seen to fail against the real sources, not just the fixtures: moving the Python home to `~/.cache`, dropping Store.swift's `LaughCounter` narrowing, switching it to `.cachesDirectory`, deleting dashboard.py's content-type guard, hoisting the body read above it, and adding an unguarded `do_DELETE` each produce exactly one finding. RULES.md's two paragraphs are trimmed to the rationale the checks can't hold; README.md's enforcement table moves both rows off "prose". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xuv7SEg18SGzavEFRgMhcu
This was referenced Jul 28, 2026
Owner
Author
|
Superseded by #55, which merges this PR and #51 — two independent runs of the same prose-to-checks sweep over #55 keeps this PR's Swift coverage on Closing in favour of #55. Generated by Claude Code |
This was referenced Jul 28, 2026
Closed
missingbulb
added a commit
that referenced
this pull request
Jul 29, 2026
…eck (#69) RULES.md's audio-persistence promise was always-testable but only ever enforced as prose. Two prior sweeps (#51, #54) left it as prose, reasoning that "does this new field carry audio" is a judgment about meaning. This sidesteps that framing entirely: instead of classifying fields, it bans the known audio-file-writing APIs directly (AVAudioFile(forWriting:), AVAudioRecorder, ExtAudioFileCreateWithURL, AudioFileCreateWithURL) in mac/Sources/**.swift — the same absolute-ban shape no-network-client already uses for egress. AVAudioFile(forReading:) is deliberately excluded (loading a bundled sound asset isn't persistence); a fixture pins that false alarm. Refs #42. Claude-Session: https://claude.ai/code/session_013T5fxiwvVP7REPbFNL174j Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Aug 2, 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.
The
prose-to-checks-sweeprun over.claudinite/local/packs(the only local pack here ison-device-privacy). Two of itsRULES.mdrules were always-testable but enforced only by prose. Both are checks now; the other three prose rules stay prose (see below).Tracker: #42
Converted
"Everything lives in one deletable directory." →
on-device-privacy/single-home-directory(blocking)Scans
laughcounter/**.pyfor home-anchored path literals (Path.home() / "…", quoted"~/…") that land outside~/.laughcounter, andmac/Sources/**.swiftfor a Foundation standard directory other than Application Support, an Application Support base never narrowed withappendingPathComponent("LaughCounter"), andNSHomeDirectory().~/Library/LaunchAgentsis exempt by name and the reason is in the check: launchd mandates that location, andlaughcounter serviceonly prints the plist for the user to redirect."Any new mutating endpoint keeps that guard." →
on-device-privacy/json-content-type-guard(blocking)Cuts each
do_POST/do_PUT/do_PATCH/do_DELETEbody out by indentation and requires anapplication/jsoncontent-type check inside it, positioned ahead of any body read. Parsing the handler rather than grepping the file is what makes it confident —application/jsonappears throughoutdashboard.pyas a response content type, and a whole-file grep would accept those.See-it-fail
Beyond the fixtures, each check was run against the real sources with a realistic regression applied, and each produced exactly one finding:
config.pyhome →~/.cache/laughcounter~/.cacheStore.swiftdrops theLaughCounternarrowingStore.swift→.cachesDirectory.cachesDirectorydashboard.pycontent-type guard deleteddo_POSTnever requiresapplication/jsondashboard.pybody read hoisted above the guarddo_POSTreads the body before checking the typedo_DELETEaddeddo_DELETEnever requiresapplication/jsonnode --test .claudinite/local/packs/on-device-privacy/pack.test.mjs— 11/11 pass.check_the_worldandcheck_the_workboth exit 0.Left as prose
no-network-client; the positive half ("is this new egress acceptable") is a decision, not a condition.Prose trimmed
RULES.md's two converted paragraphs drop the mechanical statement and keep only the rationale the checks can't hold;README.md's enforcement table moves both rows off "prose" and gains the new content-type row.Generated by Claude Code