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:
@@ -62,7 +62,7 @@ struct CardDetailsKeyTests {
|
||||
// twice-written `project` reads once, and it reads where its *winning* occurrence sits: the
|
||||
// effective view a duplicate collapses to (`FrontmatterDocument.parse`, last-wins), which is
|
||||
// also the order the file itself takes the moment anything rewrites that key.
|
||||
#expect(rows.map(\.key) == ["labels", "assignees", "due", "remote", "project"])
|
||||
#expect(rows.map(\.key) == ["assignees", "due", "remote", "project"])
|
||||
}
|
||||
|
||||
@Test("Reserved enhanced-schema keys are ordinary unknown keys in this version")
|
||||
@@ -73,9 +73,15 @@ struct CardDetailsKeyTests {
|
||||
// appear here like any other — no special rendering" (05 ▸ Details). The day they gain
|
||||
// meaning they leave this section for a control; until then, hiding them would hide data the
|
||||
// file plainly has.
|
||||
for reserved in ["labels", "assignees", "due", "remote"] {
|
||||
//
|
||||
// **`labels` is the first to leave, and this is the day** (2026-08-09): the owner claimed it
|
||||
// for first-party use, it joined `schemaOwned`, and the Labels section is the control the
|
||||
// sentence above anticipated. Its absence here is therefore the *rule* holding rather than an
|
||||
// exception to it — the three that are still reserved are still here.
|
||||
for reserved in ["assignees", "due", "remote"] {
|
||||
#expect(rows.contains { $0.key == reserved }, "\(reserved) belongs in Details")
|
||||
}
|
||||
#expect(!rows.contains { $0.key == FrontmatterKeys.labels }, "labels has its own section now")
|
||||
}
|
||||
|
||||
@Test("Every schema-owned key is excluded — including the ones the sidebar shows elsewhere")
|
||||
@@ -89,7 +95,7 @@ struct CardDetailsKeyTests {
|
||||
// them would be the same fact stated twice, in a section whose whole premise is "keys the app
|
||||
// does not own".
|
||||
#expect(keys.isDisjoint(with: FrontmatterKeys.schemaOwned))
|
||||
#expect(keys == ["labels", "assignees", "due", "remote", "project"])
|
||||
#expect(keys == ["assignees", "due", "remote", "project"])
|
||||
}
|
||||
|
||||
@Test("A card with no unknown keys has no section at all")
|
||||
@@ -133,8 +139,9 @@ struct CardDetailsKeyTests {
|
||||
let model = try BoardLoader.load(boardRoot: fixture.root).model
|
||||
let card = try #require(model.lanes.first?.cards.first)
|
||||
|
||||
#expect(CardDetails.rows(of: card.document).map(\.key) == ["labels", "assignees", "due", "remote", "project"])
|
||||
#expect(CardDetails.rows(of: card.document).first?.value == "[a, b, c]")
|
||||
#expect(CardDetails.rows(of: card.document).map(\.key) == ["assignees", "due", "remote", "project"])
|
||||
// And the key that left: it is read as a field now, not shown as raw text.
|
||||
#expect(card.labels.value == ["a", "b", "c"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,8 +273,9 @@ struct CardDetailsValueTests {
|
||||
|
||||
""")
|
||||
#expect(document.uneditableShape != nil)
|
||||
#expect(CardDetails.rows(of: document).map(\.key) == ["project", "labels"])
|
||||
#expect(CardDetails.rows(of: document).map(\.value) == ["lanework", "[a, b]"])
|
||||
#expect(CardDetails.rows(of: document).map(\.key) == ["project"])
|
||||
#expect(CardDetails.rows(of: document).map(\.value) == ["lanework"])
|
||||
#expect(document.labels == .valid(["a", "b"]), "and the schema-owned one still reads")
|
||||
}
|
||||
|
||||
@Test("Nothing a parsed document can hold makes a row throw or vanish")
|
||||
|
||||
Reference in New Issue
Block a user