feat: publish source material, one document at a time - #74
Merged
Conversation
khaneight
force-pushed
the
feat/export-gate
branch
from
August 27, 2026 02:21
92aaed7 to
4f90592
Compare
"Others can view your clone and its originating source material" needs a way to say which material. `raw/` holds whatever its owner put there — work under someone else's copyright, private notes, correspondence, drafts nobody was meant to see — and nothing about a file tells the tool which of those it is. So there is no flag that publishes the directory, only `sentinel sources <doc> --publish`, recorded per document and defaulting to false. Opting in and publishing stay separate acts: `--publish` says a document *may* go out, `export --with-sources` puts it there. Marking something safe should not be the same keystroke as putting it on the internet. Published articles gain a Sources section linking only to documents a reader can open — a link naming a withheld file is the worst kind of dead end, because it names the file and then denies it. Building this turned up a leak that predated it. The published copy of an article carried its `sources:` frontmatter verbatim, putting the `raw/` path of every cited document on the site — including withheld ones, whose *filenames* are often the private part; "therapy-notes-2019.md" says plenty without being opened. `export` now rewrites the field to name only what was published, and removes it when that is nothing, since `sources: []` claims an article cites nothing rather than declining to say. `--clean` reckons with copied sources too. They are not markdown-only and carry no article slug, so the existing staleness rule could not see them — and a withdrawn document left readable in the destination is the exact failure this opt-in exists to prevent. `export::run` took eight positional arguments, five of them bools. At that width a caller can transpose `clean` and `flat` with the compiler perfectly happy, which for a command that deletes files in a destination is not a risk worth carrying for brevity. It takes an `Options` struct. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
khaneight
force-pushed
the
feat/publish-sources
branch
from
August 27, 2026 02:23
846a0b8 to
3e3f7bc
Compare
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.
Stacked on #73. Safeguard 6 — and the "originating source material" half of the brief.
Why there is no flag that publishes
raw/That directory holds whatever its owner put there: work under someone else's
copyright, private notes, correspondence, drafts nobody was meant to see.
Nothing about a file tells the tool which of those it is. So the decision is
per document, made by hand, recorded in the manifest, and false by default.
Opting in and publishing stay separate acts.
--publishsays a document maygo out;
export --with-sourcesputs it there. Marking something safe should notbe the same keystroke as putting it on the internet.
Published articles gain a
## Sourcessection linking only to documents areader can actually open — a link naming a withheld file is the worst kind of
dead end, because it names the file and then denies it.
A leak that predated this PR
The published copy of an article carried its
sources:frontmatter verbatim,putting the
raw/path of every cited document on the site — including withheldones. Filenames are often the private part;
therapy-notes-2019.mdsays plentywithout being opened.
exportnow rewrites the field to name only what was published, and removes itwhen that is nothing —
sources: []claims an article cites nothing, which is adifferent statement from declining to say. The rewrite is textual and confined
to the frontmatter block, like
mv's, with its own unit tests (block lists,inline lists, a same-named key nested under something else, a document with no
block).
I found this because the test asserting a withheld document is never named
failed while the one asserting it is never copied passed.
--cleanreckons with sourcesCopied sources are not markdown-only and carry no article slug, so the existing
staleness rule could not see them — and a withdrawn document left readable in
the destination is the exact failure this opt-in exists to prevent. A file under
sources/whose path matches a manifest entry is one an export produced.Also
export::runtook eight positional arguments, five of them bools. At that widtha caller can transpose
cleanandflatand the compiler is perfectly happy,which for a command that deletes files in a destination is not a risk worth
carrying for brevity. It takes an
Optionsstruct now — clippy flagged it, andthe fix was the right one rather than an
allow.sentinel sourcesjoinsexportandreviewinNOT_FOR_AGENTS: whether adocument may be published is a judgement about copyright and privacy that
nothing in the file can make.
525 tests (+19), clippy and fmt clean.
🤖 Generated with Claude Code