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:
@@ -271,6 +271,25 @@ public struct Card: Identifiable, Sendable, Equatable {
|
||||
/// key, and the bytes stay as written.
|
||||
public let hero: FieldValue<String>
|
||||
|
||||
/// **The card's labels** — the names the card is tagged with (`FrontmatterKeys.labels`, whose doc
|
||||
/// comment carries the key's own story; `CardLabels` has the rules; the reading is
|
||||
/// `FrontmatterDocument.labels`).
|
||||
///
|
||||
/// **Card-level only**, `hero`'s posture and for its kind of reason: a label is a property of a
|
||||
/// piece of work, and neither a lane nor a board is one. The key on a lane or a board stays an
|
||||
/// ordinary unknown one, preserved verbatim and shown in no sidebar the way it always was.
|
||||
///
|
||||
/// The *shape* rather than the answer, so the coerce tier can report a value that had no list
|
||||
/// reading at all (a mapping); `.missing` and `.valid([])` are both "no labels" and render
|
||||
/// identically, which is why nothing in the app branches on the difference — but the two are
|
||||
/// distinct bytes on disk and the field keeps them apart.
|
||||
///
|
||||
/// **The board face does not draw these** (as of the activation, 2026-08-09). Chips on the card
|
||||
/// face are their own design question — the attachments and comments chips set that vocabulary and
|
||||
/// a label list is a different shape of thing — so this rides in the snapshot for the card window's
|
||||
/// sidebar, the context menu's submenu, and the board-wide used-labels universe those two share.
|
||||
public let labels: FieldValue<[String]>
|
||||
|
||||
/// Rank within its lane, ascending = top-to-bottom — the reading, not necessarily the key. See
|
||||
/// `Lane.order`'s doc comment; the same reasoning applies here, and a card is where it matters
|
||||
/// most: the minimum legal agent card is a `mkdir` plus one `index.md` with no `order` at all
|
||||
|
||||
Reference in New Issue
Block a user