You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8 lines
3.5 KiB
JSON
8 lines
3.5 KiB
JSON
{
|
|
"title": "Remove id field from ticket JSON body",
|
|
"body": "The ticket ID is already encoded in the filename (`a3f9c2.json`). Storing it redundantly inside the JSON body creates a potential consistency hazard (the two could disagree) and wastes space. The filename should be the sole source of truth for the ID.\n\n## Motivation\n\n- Eliminates a redundancy: filename stem already IS the id.\n- Removes the risk of id mismatch (e.g. if a file is renamed manually).\n- Simplifies the JSON schema — consumers only need the body fields, not a duplicated key.\n\n## Serde approach\n\nIn `ticket.rs`, annotate the `id` field with `#[serde(skip)]`:\n\n```rust\n#[derive(Serialize, Deserialize, Debug, Clone)]\npub struct Ticket {\n #[serde(skip)]\n pub id: String,\n // ...\n}\n```\n\n`#[serde(skip)]` means:\n- **Serialise:** the `id` field is omitted from JSON output entirely.\n- **Deserialise:** the field is not read from JSON; it is initialised with `String::default()` (empty string) and must be set manually after deserialization.\n\nBecause serde ignores unknown fields by default, **existing files with `\"id\": \"...\"` in the JSON body continue to deserialise without error** — the field is simply discarded. This means the change is backwards-compatible for reads; existing stores work immediately. A separate `nbd migrate` command (see companion ticket) cleans up the stale `id` field from disk.\n\n## store.rs changes\n\n`read_ticket(root, id)` — inject id from the `id` parameter after deserialising:\n```rust\nlet mut ticket: Ticket = serde_json::from_slice(&bytes)?;\nticket.id = id.to_string(); // authoritative source: the filename\nOk(ticket)\n```\n\n`list_tickets(root)` — inject id from each file's stem:\n```rust\nlet stem = path.file_stem().and_then(|s| s.to_str()).ok_or(\"invalid filename\")?;\nlet mut ticket: Ticket = serde_json::from_slice(&bytes)?;\nticket.id = stem.to_string();\ntickets.push(ticket);\n```\n\n`write_ticket` — no change needed; `#[serde(skip)]` already prevents `id` from being written.\n\n`ticket_path` — no change; it already takes `id: &str` as a separate parameter.\n\n## Impact on other tickets\n\n- The `nbd migrate` companion ticket (see deps) provides the command to scrub the old `id` field from existing files.\n- Partial ID matching (`resolve_id`) is unaffected — it works on filenames, not JSON content.\n- All display, list, and read commands continue to work; `ticket.id` is populated from the filename in every read path.\n\n## Tests\n\nUnit tests (`src/tests.rs`):\n- `write_ticket` output does NOT contain the `\"id\"` key.\n- `read_ticket` with a file that has NO `id` field correctly sets `ticket.id` from the parameter.\n- `read_ticket` with an old-format file (has `\"id\"` in JSON) still sets `ticket.id` from the parameter (ignores JSON value).\n- `list_tickets` injects correct ids from filenames for all tickets.\n- Serialisation roundtrip: write then read, id is preserved via filename not JSON.\n\nIntegration tests (`tests/integration.rs`):\n- `nbd create` output (tabular and `--json`) contains the correct ID.\n- The created `.json` file on disk does NOT contain the `\"id\"` key.\n- `nbd read <id>` displays the correct ID.\n\n## Files touched\n- `src/ticket.rs` — add `#[serde(skip)]` to `id`\n- `src/store.rs` — `read_ticket` and `list_tickets` inject id from filename\n- `src/tests.rs` — update and add unit tests\n- `tests/integration.rs` — add assertion that written files lack `\"id\"` key",
|
|
"priority": 9,
|
|
"status": "done",
|
|
"dependencies": [],
|
|
"ticket_type": "task"
|
|
} |