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:
2026-08-09 12:06:01 -04:00
parent fd31ed24f4
commit da37ed61bf
24 changed files with 1928 additions and 29 deletions
+9 -3
View File
@@ -109,7 +109,11 @@ struct BoardWriterPreservationTests {
#expect(after.contains("title: Renamed\n"))
let document = try FrontmatterDocument.parse(after)
#expect(document.unknownFields.map(\.key) == ["project", "sphere", "labels"])
// `labels` left this list on 2026-08-09 it is schema-owned now (`FrontmatterKeys.labels`),
// which is exactly why the `keys` and `rawValue` assertions below still name it: the write path
// preserves it verbatim like any other key it did not touch, and only its *classification*
// moved.
#expect(document.unknownFields.map(\.key) == ["project", "sphere"])
#expect(document.keys == [
"schema", "title", "order", "project", "sphere", "labels", "created", "modified",
])
@@ -1169,7 +1173,8 @@ struct BoardWriterMoveTests {
#expect(document.created == source.created)
#expect(document.modifiedBy == .missing)
#expect(abs(try #require(document.modified.value).timeIntervalSinceNow) < 60)
#expect(document.unknownFields.map(\.key) == ["project", "labels"])
#expect(document.unknownFields.map(\.key) == ["project"], "`labels` is schema-owned since 2026-08-09")
#expect(document.rawValue(for: FrontmatterKeys.labels) == "[a, b, c]", "and still preserved verbatim")
#expect(after.contains("project: lanework # agent overlay\n"))
// The move rewrites exactly one file: a destination sibling is not even opened.
@@ -1529,7 +1534,8 @@ struct BoardWriterCopyTests {
#expect(document.created == sourceDocument.created)
#expect(document.modifiedBy == .missing)
#expect(abs(try #require(document.modified.value).timeIntervalSinceNow) < 60)
#expect(document.unknownFields.map(\.key) == ["project", "labels"])
#expect(document.unknownFields.map(\.key) == ["project"], "`labels` is schema-owned since 2026-08-09")
#expect(document.rawValue(for: FrontmatterKeys.labels) == "[a, b, c]", "and still preserved verbatim")
#expect(document.body == "Card One body — with *markdown*.\n")
// The source is never touched, on any path.