-- allium: 1 -- bDS Navigation Menu -- Scope: core (read for rendering), extension Bucket F (menu editor UI) -- File-only model: no DB table. Loaded from meta/menu.opml into a -- transient value, mutated in memory, written back to OPML on save. surface MenuManagementSurface { facing _: MenuOperator provides: MenuLoadRequested(project_id) UpdateMenuRequested(items) SyncMenuFromFilesystemRequested(project_id) } value MenuItem { kind: page | submenu | category_archive | home label: String slug: String? -- pageSlug for page/home, categoryName for category_archive children: List? -- present only for submenu kind } value Menu { items: List -- Derived home_entry: items.first -- always home after normalization } surface MenuSurface { context menu: Menu exposes: menu.items.count menu.home_entry.label } invariant HomeAlwaysFirst { -- Normalization guarantees home is always the first item. -- UpdateMenu strips any home entries from input, then prepends one. for menu in Menus: menu.items.first.kind = home } invariant MenuPersistedAsOpml { -- meta/menu.opml is the sole persistent store (no DB table). -- OPML outline attributes: text (label), type (kind), -- pageSlug (slug for page/home), categoryName (slug for category_archive). -- Nested elements represent submenu children. parse_opml(read_file("meta/menu.opml")) = menu.items } rule LoadMenu { when: MenuLoadRequested(project_id) -- Reads meta/menu.opml; if file missing, returns default (home-only) menu. -- Normalizes: strips home entries from body, prepends canonical home. ensures: MenuLoaded(project_id, normalize(parse_opml_or_empty(project_id))) } rule UpdateMenu { when: UpdateMenuRequested(items) -- Normalizes Home entry: strips all home items, prepends canonical home. -- Writes normalized menu back to meta/menu.opml. let without_home = items where kind != home ensures: MenuFileWritten(normalize(without_home)) } rule SyncMenuFromFilesystem { when: SyncMenuFromFilesystemRequested(project_id) -- Reloads menu from OPML, normalizes, writes back (round-trip repair). ensures: MenuLoaded(project_id, _) ensures: MenuFileWritten(_) }