A reserved key comes to life — the card window's sidebar grows a Labels section, and labels stops being somebody else's
`labels` has been a reserved tracker key since the rewrite: preserved verbatim, never interpreted, drawn only as an anonymous row in the Details section beside `assignees` and `due`. The owner's cards claim it for first-party use, so it joins the schema — read leniently (a list of names, a bare scalar coercing to one, a mapping malformed and preserved), written canonically (a quoted flow list in the order the user arranged, no auto-sort), and removed outright when the last label goes, the way an expanded lane drops `collapsed`. Identity is case-insensitive and display is case-preserving, so a card carries `bug` once however many ways the board spells it, and entries the reading cannot name ride through the write untouched at the tail. The section sits second, above Details — which is the point rather than a layout preference: Details is where keys the app does *not* own are shown, and this key just stopped being one. Rows rather than chips, because the sidebar is twenty-six characters wide. The add field autocompletes against the board's own used-labels universe, derived from every live and trashed card with no store beside the files, and says out loud when Return would mint a word the board has never used. Writes ride a `.relabel` operation of their own, because the commit composer has said "Relabel card 'X'" since long before there was a control to press — and now the undo row says it too. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -593,6 +593,42 @@ public enum FrontmatterKeys {
|
||||
/// the reason it always did — it is Lanework's to interpret, not an unknown key riding along.
|
||||
public static let hero = "hero"
|
||||
|
||||
/// **A card's labels** (01-storage-format.md § Frontmatter's card table — the amendment this key's
|
||||
/// activation owes; `CardLabels`, `FrontmatterDocument.labels`) — a YAML list of names:
|
||||
/// `labels: ["bug", "ui"]`.
|
||||
///
|
||||
/// ### It used to be reserved, and that reversal is the design event
|
||||
///
|
||||
/// Through 2026-08-09 this was one of the **reserved tracker keys** beside `assignees`, `due`,
|
||||
/// `remote` and `remote-state` (01 § Enhanced schema): "the pathfinder shipped them natively; the
|
||||
/// rewrite reserves them instead", preserved verbatim, never interpreted, and shown only as an
|
||||
/// anonymous row in the card window's Details section like any other unknown key. The owner's cards
|
||||
/// ("in card window sidebar add ability to manage card's labels", "add labels submenu to card
|
||||
/// context menu") claim it for **first-party use**, which retires the reservation for this one name
|
||||
/// — `assignees`, `due` and the two `remote` keys are untouched and stay exactly as reserved as they
|
||||
/// were.
|
||||
///
|
||||
/// **It therefore joins `schemaOwned`**, which is the whole of what stops the Details section
|
||||
/// drawing a second, raw copy of a field the sidebar now renders properly (`CardDetails.rows`
|
||||
/// subtracts exactly that set). `hero`'s precedent, and for `hero`'s reason: it is Lanework's to
|
||||
/// interpret, not an unknown key riding along.
|
||||
///
|
||||
/// ### The grammar
|
||||
///
|
||||
/// **Read leniently, written canonically** — the shape of every lenient field here, one collection
|
||||
/// up. A sequence reads as its string entries in file order; a bare scalar coerces to a
|
||||
/// one-element list (`labels: bug`); a mapping has no list reading at all and is `.malformed`.
|
||||
/// Names are **case-preserving for display and case-insensitively unique within a card**, and
|
||||
/// entries the reading cannot make a name of are preserved on the way out but never rendered
|
||||
/// (`CardLabels`).
|
||||
///
|
||||
/// **Written as a flow list, in the user's own order** — no auto-sort: the order is the order of
|
||||
/// addition, which is a thing the user arranged and the app has no business restating
|
||||
/// alphabetically. **Removing the last label removes the key**, the remove-at-default family's rule
|
||||
/// beside `collapsed`'s expand and the None well's `background`: an absent key is the no-labels
|
||||
/// reading, so `labels: []` written by the app would be noise every unlabelled card had to carry.
|
||||
public static let labels = "labels"
|
||||
|
||||
public static let created = "created"
|
||||
public static let modified = "modified"
|
||||
public static let modifiedBy = "modified-by"
|
||||
@@ -620,7 +656,8 @@ public enum FrontmatterKeys {
|
||||
public static let kind = "kind"
|
||||
|
||||
/// The reserved tracker keys — `remote` (board, card) and `remote-state` (lane) — of the enhanced
|
||||
/// schema's future connectors (01-storage-format.md § Enhanced schema).
|
||||
/// schema's future connectors (01-storage-format.md § Enhanced schema). **`labels` left this
|
||||
/// family on 2026-08-09** when the owner claimed it for first-party use; see that key above.
|
||||
///
|
||||
/// **Named here without joining `schemaOwned`**, which is the ruling rather than an oversight: 01
|
||||
/// says the app "treats reserved keys as ordinary unknown keys (preserved verbatim, invisible in
|
||||
@@ -652,7 +689,7 @@ public enum FrontmatterKeys {
|
||||
public static let author = "author"
|
||||
|
||||
public static let schemaOwned: Set<String> = [
|
||||
schema, title, order, width, collapsed, hero, created, modified, modifiedBy, deleted,
|
||||
schema, title, order, width, collapsed, hero, labels, created, modified, modifiedBy, deleted,
|
||||
background, icon, iconColor, kind,
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user