Let a harvest be taken back out - #23
Merged
Merged
Conversation
The store could only ever grow. A harvest can be the wrong project, a partial
copy, or a table of contents stored as though it were the documentation -- and
there was no way to remove one. kb_store had delete() on both backends the
whole time; nothing could ask it to. The capability was stranded with no
route, no UI, no CLI and no tool.
Three human surfaces, because the person who harvested something is the one
who should decide it was a mistake.
DocsStore. Each version row gets a delete control and the card gets a second
one for the whole technology. Both take two clicks: the button becomes the
confirmation and reverts on its own after four seconds, which suits the weight
of the act better than a modal. Icon-only until armed, then it says "Really
delete?" in the danger colour. Verified in Chromium at 1280 and 420 in both
themes: no console errors, no horizontal overflow.
The CLI, for clearing several at once:
docsforge --forget pydantic@1.10
docsforge --forget astro
docsforge --forget a --forget b --yes
It prints what it is about to remove -- pages and characters -- and does
nothing without a typed "yes" or --yes. isatty() alone is not enough of a
guard: a pipe or a harness can look like a terminal and still hand back EOF,
so anything other than a person typing yes is read as no. `url` becomes
optional to make room for this, with a clear usage error when neither is
given.
HTTP DELETE on /api/library/{tech} and /api/library/{tech}/{version}, which is
what the UI drives.
The model gets no such power by default. Deleting is the one irreversible
thing DocsForge does, and a model that has just mis-resolved a name is the
last caller who should hold that lever -- 703 pages of Effect are one
confident hallucination away. DOCSFORGE_ALLOW_DELETE=1 adds a
forget_documentation tool for anyone who wants it, and the tool description
says plainly that re-harvesting does not need it: harvesting the same name
again replaces that version on its own.
Also fixed while in the version list: a null `complete` rendered as "partial
harvest". Three states need three labels, and "coverage unknown" is a
different warning from a copy known to be incomplete.
375 passed, 22 skipped across both backends, with coverage for each surface --
one version removed while the others survive, the files actually gone from
disk rather than merely unlisted, a spelling like "Effect.ts" resolving to the
stored `effect` before deleting, and refusing to act on an unconfirmed prompt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01APThnqHvfP2oBjBCBxBhd6
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 store could only ever grow. A harvest can be the wrong project, a partial
copy, or a table of contents stored as though it were the documentation — and
there was no way to remove one.
kb_storehas haddelete()on both backends the whole time. Nothing could askit to: no route, no UI, no CLI, no tool. The capability was stranded.
There is a live example of why this matters. The
astrocurrently in thestore is 194 blog pages and 1 documentation page out of 323, marked
complete: True— harvested before the fixes in #22. Until now there was no wayto clear it.
Three human surfaces
DocsStore. Each version row gets a delete control; the card gets a second
one for the whole technology. Two clicks — the button becomes the
confirmation and reverts on its own after four seconds, which suits the weight
of the act better than a modal. Icon-only until armed, then it says "Really
delete?" in the danger colour.
The CLI, which is the one to reach for when clearing several:
It prints what it is about to remove — pages and characters — and does nothing
without a typed
yesor--yes.HTTP, which is what the UI drives:
The model gets no such power by default
Deleting is the one irreversible thing DocsForge does, and a model that has
just mis-resolved a name is the last caller who should hold that lever — 703
pages of Effect are one confident hallucination away.
DOCSFORGE_ALLOW_DELETE=1adds a
forget_documentationtool for anyone who wants it.The tool description also says plainly that re-harvesting does not need it:
harvesting the same name again replaces that version on its own. "Refresh this"
should never route through a delete.
Two details worth calling out
isatty()is not a sufficient guard. A pipe or a test harness can look likea terminal and still hand back EOF, which raised
EOFErrorin the middle of theconfirmation prompt on the first attempt. Anything other than a person typing
yesis now read as no — the alternative is deleting someone's corpus on thestrength of a closed stdin.
A
nullcompleterendered as "partial harvest" in the version list. Threestates need three labels; "coverage unknown" is a different warning from a copy
known to be incomplete. Fixed while I was in there.
Verified
surface: one version removed while the others survive, the files actually
gone from disk rather than merely unlisted, a spelling like
Effect.tsresolving to the stored
effectbefore deleting, and the CLI refusing to acton an unconfirmed prompt.
no console errors, no horizontal overflow.