Let a subsection hang under another subsection - #216
Merged
Conversation
A&E asked for a Food subsection holding Beer Reviews, Wine Reviews, Restaurant Reviews and Cooking -- a third level the taxonomy did not have. parent_slug had to name a section, and the rollup was a single non-recursive hop. Depth is a property of the parent chain, not a new kind: both levels stay kind='subsection', so everything that switches on kind -- the public site's slug router, the article filters, the sections screen -- keeps working. MaxTaxonomyDepth caps the chain at three, because the walks are recursive over editor-editable rows. The load-bearing part is the rollup, which is now transitive. One hop would have counted Beer Reviews for Food while dropping it from A&E, leaving a section quietly shorter than the sum of its subsections -- the same silent-omission failure the alias seeding exists to fix. Recounts walk every ancestor for the same reason, and a subsection resolves to its ROOT section, not its parent, since that is what ?section_slug= is checked against. A subsection can be a container now, so its page matches its descendants -- /food alone would render empty, as its articles are filed under the four categories beneath it -- and the delete and slug-change guards, which only asked about sections, now ask about anything with children. SeedFoodSubsection creates Food and moves the four rows, once, under its own flag: legacy_subsections_seeded is already set in production. The move is guarded on the current parent, so a row an editor pulls back out stays where they put it. 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.
A&E asked for a Food subsection holding Beer Reviews, Wine Reviews, Restaurant Reviews and Cooking. That is a third level the taxonomy did not have:
parent_slughad to name a section, and the rollup was a single non-recursive hop.The shape
Depth is a property of the parent chain, not a new kind. Both levels stay
kind='subsection', so everything that switches on kind — the public site's slug router, the article filters, the sections screen — keeps working unchanged.MaxTaxonomyDepthcaps the chain at three, because the walks are recursive over rows editors can edit.What actually mattered
The rollup is now transitive. This is the load-bearing change. One hop would have counted Beer Reviews for Food while dropping it from A&E, leaving a section quietly shorter than the sum of its subsections — the same silent-omission failure the alias seeding exists to fix. Recounts walk every ancestor for the same reason, and a subsection resolves to its root section rather than its parent, since that is what
?section_slug=is checked against.A subsection can be a container.
/foodmatches its descendants; matchingfoodalone would render it empty, as its articles are filed under the four categories beneath it./v1/subsections/<slug>/articlesalso returnssubsectionsnow, so a middle row gets the link strip a section page has.The guards widened. Delete and slug-change only asked about sections. Deleting Food would have stranded four rows pointing at a parent that no longer exists.
One behaviour change worth reviewing: converting a section that has children into a subsection used to be refused outright, on the premise that a subsection could not parent one. It is now allowed when the resulting subtree still fits in three levels. The existing test asserting the old rule was updated to assert the depth rule instead.
Migration
SeedFoodSubsectioncreates Food and moves the four rows, once, under its own flag —legacy_subsections_seededis already set in production. The move is guarded on the current parent, so a row an editor pulls back out stays where they put it.Cooking is the one visible change to a section page readers use today: unlike the three review categories it is a live, visible subsection, so moving it takes its link out of A&E's strip and puts it in Food's. That is the intent.
Testing
Tree-walk unit tests including cycle termination, plus DB-backed tests for the three-level rollup, the fourth-level rejection, and the seed's idempotence against an editor's change. Full Go suite green against MariaDB; frontend 19/19.
Needs DrexelTriangle/Scalene#94 for the public side, which links a subsection's own children in the nav strip.
🤖 Generated with Claude Code