-- Frontmatter edit surface (tech-spec §8.3): a node buffer opens with an -- editable YAML block on top, and saving routes each changed field to the right -- structured RPC (rename / set_attention / set_schedule / set_project / -- tag.add). The body itself still round-trips through node.update. local h = require("e2e.helpers") -- Replace `key: …` in the frontmatter `lines`, or insert it before the closing -- `---` fence when the key isn't present yet. local function set_field(lines, key, value) for i, line in ipairs(lines) do if line:match("^" .. key .. ":") then lines[i] = key .. ": " .. value return end end local fences = 0 for i, line in ipairs(lines) do if line == "---" then fences = fences + 1 if fences == 2 then table.insert(lines, i, key .. ": " .. value) return end end end end describe("frontmatter edit surface", function() local ctx before_each(function() ctx = h.start() end) after_each(function() h.stop(ctx) end) it("renders an editable block atop a node body", function() local doc = h.create_doc("Roof", "# Roof\n\nnotes") local buf = h.open(doc.id) local first = vim.api.nvim_buf_get_lines(buf, 0, 1, false)[1] assert.are.equal("---", first, "buffer should open with a frontmatter fence") assert.is_truthy(h.find(buf, "^title: Roof"), "title not in frontmatter") assert.is_truthy(h.find(buf, "# Roof"), "body content missing below frontmatter") end) it("routes frontmatter edits to structured RPCs on save", function() local proj = ctx.q:call("node.create", { kind = "project", title = "Camano" }) local task = ctx.q:call("task.create", { title = "Fix roof", attention = "red" }) local ctxid for _, l in ipairs(ctx.q:call("links.outgoing", { id = task.node_id })) do if l.link_type == "canonical-context" then ctxid = l.dst_id end end local buf = h.open(ctxid) local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) set_field(lines, "title", "Fix the roof") -- rename the (doc) node set_field(lines, "attention", "blue") -- → task.set_attention set_field(lines, "tags", "[roofing]") -- → tag.add on the doc set_field(lines, "project", "Camano") -- → task.set_project set_field(lines, "do_date", "2026-06-10") -- → task.set_schedule vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) h.save(buf) -- The task picked up attention, project, and a do-date. local t = ctx.q:call("task.get", { id = task.node_id }) assert.are.equal("blue", t.attention) assert.is_truthy(t.do_date, "do_date should be set") local filed = false for _, l in ipairs(ctx.q:call("links.outgoing", { id = task.node_id })) do if l.link_type == "in-project" and l.dst_id == proj.id then filed = true end end assert.is_true(filed, "task should be filed under Camano") -- The opened node was renamed and tagged. assert.are.equal("Fix the roof", ctx.q:call("node.get", { id = ctxid }).title) local tags = ctx.q:call("tag.list", { node_id = ctxid }) assert.are.equal(1, #tags) assert.are.equal("roofing", tags[1]) end) end)