{"slug": "notes-to-self-the-interview-between-an-issue-and-a-spec", "title": "Notes to Self: The Interview Between an Issue and a Spec", "summary": "A developer opened a three-sentence issue on 1 August and had the feature merged 101 minutes later, with a 457-line specification generated in between. The engineer did not write the spec; instead, an AI agent (Claude) read the repository and produced a detailed document, asking the developer to make decisions rather than describe requirements. The process highlights a workflow where agents bridge the gap between terse issue notes and full implementation context.", "body_md": "On 1 August I opened an issue that was three sentences long. A hundred and one minutes later\n\nthe feature was merged, and the document that got it there ran to\n\n[457 lines](https://glitchedpixel.io/specs/feat-0007/).\n\nI didn't write those 457 lines. In fact, I didn't *have* to write any more documentation, and not because I simply allowed Claude to run amok.\n\nHere is the issue in full — `control-api#265`\n\n, 225 characters:\n\n**control-api#265 — Manifest-backed dashboard feeds**\n\n```\nFor each dashboard, auto create a manifest keyed by dashboard_id.\n\nFor each sensor the dashboard uses, tag it to be included in the manifest.\nWhen a dashboard definition is updated, add / remove tags from sensors accordingly.\n```\n\nFrom that genesis moment, this is the lifecycle of the issue all the way through to landing:\n\n| Time (UTC) | Event |\n|---|---|\n| 14:25 | Issue #265 opened — 225 characters |\n| 14:54 |\n`FEAT-0007` spec committed — 457 lines |\n| 15:35 | Spec merged (PR #266) |\n| 15:51 | Implementation committed |\n| 16:06 | Implementation merged (PR #267, 15 files), issue closed |\n\nThe interesting part isn't the speed. It's the step at 14:54 that landed a previously non-existent spec document, and what happened in the twenty-nine minutes before it.\n\nI often write issues like this one...the way most people write shopping lists. *Actuator address is not ensured?*\n\n*Baseline the trace correctly.* *With the pre-rolls, the frame-rate looks out.* They're abbreviated to\n\nthe point of being cryptic to everyone else. I write them this way deliberately: I'm usually mid-something\n\nelse when I notice a problem, or have an idea for a better route to the solution. The cost of a full write-up right at that moment would be a fractured sense of flow. As most engineers will tell you, the transitions into and out of flow are the most disruptive parts of their working day.\n\nThis terse form of issue-writing can be all you need, and it's worth being precise about *why* it works and the trade-offs it includes. It is **not** because \"the issues are good enough\".\n\nThey aren't. When you pick one of these up later, you can reconstruct everything missing from memory.\n\nIn my case with control-api#265, it was a particular panel type I was thinking about, a constraint I hit last week with it, the reason the\n\nobvious approach was off the table, etc... That reconstruction was free and, more importantly, it was\n\n**invisible** to any external observer. When you are the issue filer and its eventual closer, you never experience this rehydration as filling a gap. You see the issue's sparse wording as an aide-memoire for the fuller context that is still cached in your head.\n\nWhat bites here is when you work in a team (of other engineers or coding agents): something has to bridge this gap or the issue will get resolved using a foundation of well intentioned misinterpretation and apparently sensible assumptions.\n\nAn agent has something both better and worse than an engineer's recall — it can read\n\nevery file in the repository, including ones you have forgotten, and it can read exactly nothing\n\nof your latent intentions.\n\nFortunately, the fix is not to write longer issues. Capture is working; it's the handoff that's broken, the context sync.\n\nThe obvious version of this step — \"the agent asks clarifying questions\" — undersells it, and\n\nwould be annoying in practice. Being interrogated about your own bug report is worse than\n\nwriting the report properly in the first place.\n\nWhat makes it worth doing is the ordering. The agent goes and reads first, then comes back\n\nwith what it found and asks you to *decide* — not to *describe*.\n\nYou can see the split in the spec that grew out of my dashboard issue. Its reference list is entirely material the\n\nagent uncovered on its own:\n\n**FEAT-0007 §2 — References (excerpt)**\n\n```\n- `app/repositories/sensor_repo.py:123-126` (`get_sensors_with_tag`, the JSONB\n  `.contains()` query pattern this spec's reconciliation reuses)\n- `app/services/sensor_service.py:42-84,131-174` (`upsert_sensor` /\n  `_fan_out_upsert` — precedent for both the reserved-tag-prefix guard and the\n  \"best-effort, must never fail the primary write\" fan-out posture this spec copies)\n```\n\nNobody asked me where the JSONB containment query lived, or which existing service had already\n\nsettled the question of what a fan-out failure should do to the primary write. Those are\n\nenrichment lookups, and lookups are the agent's half of the job.\n\nWhat came back to me as decisions to make were the things no amount of reading resolves: whether one SSE stream per\n\ndashboard was actually the point, whether a second repository was allowed to be changed for\n\nthis, where the boundary of the work sat. The spec's *Out of Scope* section is five such\n\nrulings written down.\n\nThat's the trade that makes the interview cheap enough to bother with. The expensive half is\n\nalready done by the time it reaches you.\n\nRead my second sentence again: *for each sensor the dashboard uses, tag it.*\n\nThere's an assumption buried in there — that the control-api server can tell which sensors a dashboard\n\nuses. It can't, and the spec says so at length:\n\n**FEAT-0007 — Design Decision (excerpt)**\n\n```\nThe obvious-looking alternative — have control-api decode `layout` itself and derive\nthe sensor set — does not actually work cleanly, for one panel type specifically.\n`chart`/` gauge` panels store `series[].{deviceId,sensorRef}` plus a panel-level\n`dataType`, which *would* parse cleanly. But a `health_stats` panel stores only\n`healthStats: {bodyDeviceId?, heartRateDeviceId?}` (confirmed in\n`serializeDashboardLayout`) — its 7 `sensor_ref` s are frontend constants\n(`BODY_SENSOR_REFS`, `HR_SENSOR_REF` in `useHealthStatsPanel.ts`), and each role's\n`data_type` is discovered at render time from `listDeviceSensors`, not stored anywhere.\n```\n\nWhen I wrote the issue I was picturing chart panels, where my sentence is true. Health-stats\n\npanels store two device IDs and resolve the rest at render time in a *different repository*.\n\nA server-side parser would have to duplicate a list of constants that already lives in the frontend,\n\nwith no shared source of truth and no error when it happens to drift.\n\nSo the spec proposes the opposite: the client sends an explicit `sensors`\n\nlist alongside the\n\nlayout, and the server never parses the layout at all. That decision brings a new API rule\n\nwith it — a `PATCH`\n\nsupplying `layout`\n\nwithout `sensors`\n\nis rejected with a `422`\n\n, so a layout\n\nchange can't silently leave the tag set stale.\n\nNone of that is in my three sentences. One line of it directly contradicts them.\n\nThis is the part I want to defend hardest. An interview process that only *elaborated* what I wrote would be\n\nformatting. This one went and checked, found my premise didn't hold, and brought back a\n\nreversal — before any code existed to be wrong.\n\nSomething else survives in the finished document. Its requirements run FR-1 through FR-10 —\n\nbut there's also an FR-6a, an FR-10a, an NFR-3a, an AC-8a and an AC-8b.\n\nA list written straight through numbers 1 to *n*. Letters mean insertion into a list that had\n\nalready been numbered. Each one marks a place where a later question forced something in\n\nbetween.\n\n`FR-6a`\n\nis the one I'd point at. `FR-6`\n\nhad established that dashboard tags are reserved, so a\n\ncaller's tag edit must preserve them. Then:\n\n**FEAT-0007 — FR-6a (excerpt)**\n\n```\nThe prior-tags read [...] is already wrapped in `try/except Exception:\nlogfire.exception(...)` so it can never break the upsert — but under FR-6, silently\ntreating a failed read as `old_tags = []` would mean `preserved` comes back empty and\nthe caller's list wins outright, wiping every `dashboard-*` tag on that sensor: the\nexact outcome FR-6 exists to prevent.\n```\n\nAn existing `try`\n\n/`except`\n\nin unrelated code turns the new requirement into precisely the\n\nfailure it was written to stop. Follow FR-6 faithfully and you ship the bug. That is not a\n\nquestion anyone thinks to ask about a three-sentence issue, and it was answered in a spec document\n\nbefore any code was written rather than in a post-mortem.\n\nThe whole document is published alongside this article — [FEAT-0007: Manifest-Backed Dashboard\nFeeds](https://glitchedpixel.io/specs/feat-0007/) — so the excerpts above can be read in context.\n\nImplementation merged thirty-one minutes after the spec did, across 15 files. What I want to\n\ndraw out isn't the speed — it's this line from the implementation PR's test plan:\n\nAC-8b (migration's\n\n`server_default`\n\nbehaving correctly against a pre-populated table) has no\n\nautomated test — this repo has no migration-test harness (integration tests use\n\n`metadata.create_all`\n\n, not Alembic). Verified by construction: [...]\n\nOne acceptance criterion, honestly marked unmet, with the reason. That's only possible because\n\nAC-8b existed to be unmet. Without the spec there'd be no gap — just a migration nobody had\n\nthought to test, and no record that anyone noticed.\n\nA spec's most underrated property is that it gives the work something to fail against.\n\nThe shape I'd suggest, in the order that matters:\n\n`docs/specs/FEAT-NNNN-<slug>.md`\n\n, and get their own PR ahead of the implementation.`FEAT-0007`\n\nsurvives because it was\ncommitted; plenty of equally good reasoning hasn't.And the honest limits. This costs about half an hour of agent time and a handful of real\n\ndecisions from you, which is absurd overhead for a typo and roughly break-even for a\n\none-file fix. It leans hard on the agent being able to read *everything* relevant — the\n\ninsight that reversed my issue came out of a sibling repository, and an agent without that\n\nrepository would have cheerfully specified the parser. And it can't manufacture intent: if\n\nyou genuinely don't know what you wanted, the interview surfaces that rather than solving it.\n\nWhich is still better than finding out from the diff.\n\nNone of this is a claim that issues should be specifications. Mine aren't and won't be. The\n\nissue is a pointer, written in the two minutes I could spare, and it's the right artifact for\n\nthat job.\n\nThe interview is just the step that dereferences it — the one I used to run silently, in my\n\nown head, without ever noticing I was running it at all.\n\nNone of the above is specific to working with coding agents. The agent-led interview that spawned the spec doc is recognisably a tech review with a peer, team lead or stakeholder.\n\nAI assisted software development is not so much about learning entirely new paradigms as it is about having the immediate opportunity to enlist the expertise you need to do a job well.", "url": "https://wpnews.pro/news/notes-to-self-the-interview-between-an-issue-and-a-spec", "canonical_source": "https://dev.to/virorum/notes-to-self-the-interview-between-an-issue-and-a-spec-4phc", "published_at": "2026-08-14 12:25:24+00:00", "updated_at": "2026-08-14 12:35:32.829755+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "artificial-intelligence"], "entities": ["Claude", "control-api", "FEAT-0007"], "alternates": {"html": "https://wpnews.pro/news/notes-to-self-the-interview-between-an-issue-and-a-spec", "markdown": "https://wpnews.pro/news/notes-to-self-the-interview-between-an-issue-and-a-spec.md", "text": "https://wpnews.pro/news/notes-to-self-the-interview-between-an-issue-and-a-spec.txt", "jsonld": "https://wpnews.pro/news/notes-to-self-the-interview-between-an-issue-and-a-spec.jsonld"}}