Standard feature bundles: installed by harness init, marked in the features JSON, not removable #157
Labels
No labels
bug
enhancement
needs-triage
ready-for-agent
ready-for-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle#157
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Let a feature bundle be marked standard in its manifest.
harness initinstalls every standard bundle.harness featuresmarks them with astandardfield in--json, so a host can leave them out of its feature checkboxes.harness removerefuses to remove one.categoriesbecomes the first standard bundle, so every new site has categories. Since nothing can remove categories any more, the remove code that only the removal of categories used is deleted.Current behavior
feature.yaml, haslabel,description,versionandallow. It is decoded strictly, so an unknown key is an error (LoadManifestandparseManifestininternal/addcmd).harness initcopies the starter site and skipsfeatures/(buildPlanininternal/initcmd). A new site has no bundle until someone runsharness add.harness add <feature>vendors the bundle, applies itshugo.tomledits and page-type allowances, and writes the receipteditor/features/<feature>.yaml. On an installed feature it fills gaps, or reportsalready-installed.harness features [--site <dir>] [--json]listsname,label,descriptionandversionper bundle, sorted by name. With--siteit addsinstalledandinstalledVersion.harness remove <feature>is driven by the receipt and removes any installed feature. Three parts of it exist only for the categories bundle:/categories/page,content/categories/_index.md) is not "in use", so a remove right after the add needs no--purge. SeeshippedPagesand the "Shipped pages" rule ininternal/removecmd.categoryChanges, theCategoriesRemovedFromfields ofContentUsageandPurgeReport,usage.categoriesRemovedFromin--json, and the "deleted categories removed from" lines of the text output.hugo.tomlstepsdisableKinds,taxonomiesandoutputs(internal/addcmd/taxonomy.go), withrevertContextandtaxonomiesAfterRevertininternal/addcmd/config.go.harness add newsprints tell the user to runharness add categories.harness features --jsononce at startup and shows one checkbox per feature (#145). It ignores fields offormatVersion1 that it doesn't know.Desired behavior
Standard bundles
standard: true. Without it a bundle is optional, as today. The categories manifest sets it, and news stays optional.harness initinstalls every standard bundle after it writes the starter site, in name order, exactly asharness adddoes: files,hugo.tomledits, page-type allowances and the receipt. Its output names each feature it installed.harness initexits 1 with an error that names the feature. Files already written stay, andharness add <feature>completes the install.harness featuresmarks standard features. In--json, every entry has astandardboolean, with and without--site. The text form marks them too, for example[standard]. The field is additive, soformatVersionstays 1.harness addinstalls a standard feature on an existing site. A site without one lists it with"standard": true, "installed": false.A standard feature can't be removed
harness remove <feature>on an installed standard feature changes nothing. It exits 1 with the existing statuserrorand a message saying the feature is standard and cannot be removed.--purgemakes no difference.not-installedand exits 0.Deleting the code only the removal of categories used
Delete, with their tests, the three parts of remove listed under Current behavior: shipped pages, category rewrites and the three config reverts. Keep these:
usage.categoriesRemovedFrominharness remove --json, always[], so the JSON keeps its shape.harness add categoriesstill installs the bundle on a site that lacks it.RevertConfig's rule that a recorded edit it can't act on is kept rather than being an error. An edit whose step has no revert counts as one.pageops.Delete). Deleting a category in the Categories module still removes its slug from every page and element.Hints and docs
harness add newsno longer tells the user to runharness add categories.scaffold/site/AGENTS.md, as the CLAUDE.md rule requires:initinstalls, thestandardJSON field, and the refusal to remove one.harness initskips them"), "The manifest", "Removing:harness remove", "Machine-readable output", "Removing." under "The categories bundle", and "Not covered yet". In AGENTS.md: the opening ("Optional feature bundles"), "Layout" and "Feature bundles".Decisions
harness addand gap filling, so a site created before a feature became standard can get it withharness add. (Maintainer's choice.)formatVersionstays 1, because deckle-hosted ignores version-1 fields it doesn't know.errorstatus because deckle-hosted's status switch is exhaustive: it shows the harness's message forerror, and it would fail on a new status.harness add. (Maintainer's choice.)harness servemust not install one: the editor's publish carries onlycontent/andassets/media/, so files it wrote would never reachmain. No upgrade command is needed while no deckle sites exist (as of 2026-10-06).initwithout rolling back. (Maintainer's choice.) On an empty target directory only I/O errors remain, and a test proves that every standard bundle installs on the starter site.Key interfaces
addcmd.ManifestandparseManifest(internal/addcmd/manifest.go).Catalogue()andaddcmd.Infocarry the flag to the CLI.featureEntryOutputandprintFeatures(cmd/harness/features.go).harness init:initSite(cmd/harness/main.go),initcmd.Run, andaddcmd.Runas the install path.harness remove:removeCmd(cmd/harness/features.go) andinternal/removecmd(Run,scan,shippedPages,categoryChanges,Purge,ContentUsage,PurgeReport).RevertConfig,configOp,featureConfig,revertContextandtaxonomiesAfterRevert(internal/addcmd/config.go), and the revert functions ininternal/addcmd/taxonomy.go.featureHints(internal/addcmd/add.go).TestRunCategories*(internal/removecmd/run_test.go);TestPurgeStripsBeforeDeletingCategories(purge_test.go);CategoriesRemovedFromexpectations inusage_test.go;TestRemoveCmdCategoriesRemovedFromandTestCategoriesCmdRoundTrip(cmd/harness/features_test.go);internal/addcmd/config_test.goandtaxonomy_test.gothat revert the categories steps. The tests of the apply halves stay.Acceptance criteria
standard: true. A manifest with an unknown key is still a load error.harness initin an empty directory writes the starter site with the categories bundle installed, including itshugo.tomledits andeditor/features/categories.yaml. Its output namescategories.harness initbuilds with Hugo and renders/categories/.harness add categoriesright afterharness initexits 0 withalready-installedand changes nothing.harness features --jsongives every entry astandardboolean, with and without--site:trueforcategoriesandfalsefornews, withformatVersion1. The text form markscategoriesas standard.harness remove categorieson a site fromharness init, with and without--purge, exits 1, reports statuserrorin--jsonwith a message naming it a standard feature, and leaves the tree byte-identical.harness remove categorieson a site without its receipt reportsnot-installedand exits 0.harness add newsandharness remove newsbehave as before, andusage.categoriesRemovedFromis present and[]in everyharness remove --jsonobject.harness add newsno longer mentionsharness add categories.RevertConfigreports a recorded edit with no revert as kept.scaffold/site/AGENTS.mddocument standard features and the refusal to remove one, describe categories as installed byharness init, and no longer describe removing categories. The AGENTS.md drift test passes.How to verify
make test. It buildsweb/distfirst, whichgo test ./...needs. The theme's Hugo build tests run only withhugoon PATH (CI installs 0.163.3).cd web && npm test.harness init.harness features --site . --jsonshows categories as standard and installed.harness add categories --jsonreportsalready-installed.harness remove categories --jsonandharness remove categories --purge --jsonboth report statuserror, and the tree is unchanged.harness add news --json, thenharness remove news --json, behave as before.hugobuilds the site.Assumptions to check
internal/addcmd's tests are inpackage addcmdand importinternal/initcmd. Ifinitcmdimportsaddcmd, those tests stop compiling because of an import cycle. Check this before deciding whereinitinstalls standard bundles.initcmd.Runand then add or remove categories, expecting a starter site without categories. Which of them change depends on where the install lives.Out of scope
standard, the maintainer accepts the following:already-installedas an error (addFeatureingitserve/scaffold.go).TestRealHarnessLifecycle(harness/real_test.go) andTestScaffoldRealBinaries(gitserve/scaffold_test.go) fail, because they take the first feature listed, which is nowcategories. Both run only withDECKLE_HOSTED_TEST_HARNESSset. Its other real-binary tests were not checked.initoption to skip standard features.version. The manifest is never copied into a site, so marking the bundle standard changes no site file.Blocked by
None - can start immediately
Standard feature bundles: installed automatically, marked in the features JSONto Standard feature bundles: installed by harness init, marked in the features JSON, not removable