Tickets can now be stored in four formats, selected with --ftype:
json (.json) — pretty-printed JSON, default, unchanged
md (.md) — Markdown body with TOML frontmatter
toml (.toml) — full TOML
jsonb (.jsonb) — CBOR binary via ciborium
Changes:
- store.rs: FileFormat enum, detect_format(), find_ticket_path(),
per-format serialize/deserialize helpers; read_ticket/list_tickets/
resolve_id/migrate_tickets all scan all known extensions
- main.rs: --ftype on create (default "json") and update (optional,
converts format and removes old file); archive/update preserve
existing format when --ftype is absent
- tests.rs: update write_ticket/ticket_path call sites; add TOML,
Markdown, and CBOR roundtrip unit tests
- integration.rs: 8 new format tests covering create, list, update
conversion, format preservation, body roundtrip, unknown-ftype error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ticket id is now stored only in the filename stem (.nbd/tickets/{id}.json).
`id` is annotated with `#[serde(skip)]` so it is never written to disk,
eliminating the consistency hazard of id-in-body vs. filename disagreement.
- ticket.rs: add `#[serde(skip)]` to `Ticket::id`
- store.rs: `read_ticket` and `list_tickets` inject id from filename stem
- display.rs: `ticket_to_json_value` re-inserts id for CLI `--json` output
- tests.rs: new unit tests for omission, injection, and old-format compat
- integration.rs: assert written files lack "id"; assert read --json has id
Backwards-compatible: old files with "id" in JSON body still parse correctly
(serde ignores the unknown field), so existing stores work without migration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>