yoi/work-items/closed/20260605-040104-ticket-built-in-feature-tools/artifacts/implementation-report.md

127 lines
4.4 KiB
Markdown

# Implementation report: ticket-built-in-feature-tools
## Worktree / branch
- Worktree: `/home/hare/Projects/yoi/.worktree/ticket-built-in-feature-tools`
- Branch: `work/ticket-built-in-feature-tools`
## Commit
- `afd7f04 feat: add built-in ticket tools`
## Summary
Added the MVP Ticket tool surface as built-in Pod tools while preserving the agreed ownership split:
- `crates/ticket` owns Ticket tool behavior.
- `crates/pod` owns only the built-in feature adapter and backend-root/host-authority wiring.
- `crates/tools` remains unchanged and does not contain Ticket tools.
The implementation exposes Ticket operations through typed `LocalTicketBackend` calls rather than shelling out to `tickets.sh` or granting generic filesystem write access.
## Final module layout
- `crates/ticket/src/tool.rs`
- Ticket tool input/output types.
- JSON-schema-backed tool definitions.
- Bounded JSON output shaping.
- `llm_worker::Tool` implementations.
- `ticket_tools(...)` factory.
- `crates/ticket/src/lib.rs`
- Exports `pub mod tool`.
- Updates `set_status` to append a `status_changed` event so status moves remain doctor-clean.
- `crates/pod/src/feature/builtin/ticket.rs`
- Thin built-in Ticket feature adapter.
- Resolves and validates `<workspace>/work-items`.
- Declares `HostAuthority::TicketBackend { root }`.
- Registers Ticket tools through `FeatureContribution`.
- `crates/pod/src/feature/builtin.rs`
- Exports the built-in Ticket feature adapter.
- `crates/pod/src/controller.rs`
- Installs the Ticket built-in feature alongside existing built-ins.
- `crates/pod/src/feature.rs`
- Adds explicit `HostAuthority::TicketBackend { root }`.
## Tool surface
Implemented tools:
- `TicketCreate`
- `TicketList`
- `TicketShow`
- `TicketComment`
- `TicketReview`
- `TicketStatus`
- `TicketClose`
- `TicketDoctor`
Input schemas are generated from typed serde/schemars structs. Outputs are bounded JSON in `ToolOutput.content` with concise summaries.
Bounds include:
- `TicketList`: default/max `100` / `200`.
- `TicketShow`: recent events default/max `20` / `100`; artifacts default/max `50` / `200`; Markdown body bytes default/max `16 KiB` / `64 KiB`.
- `TicketDoctor`: diagnostics default/max `100` / `500`.
`TicketStatus` intentionally handles `open` and `pending`; `closed` requires `TicketClose` so `resolution.md` is written.
## Backend root / authority wiring
- Pod adapter resolves the local backend root as `<workspace>/work-items`.
- The root is canonicalized and validated to contain `open/`, `pending/`, and `closed/`.
- Missing/unusable roots register no Ticket tools and emit a warning diagnostic; arbitrary directories are not silently created.
- Registered tools require typed `HostAuthority::TicketBackend { root }`, not generic filesystem authority.
- Tool calls still use the normal feature contribution / ToolRegistry / PreToolCall path.
## Changed files
- `Cargo.lock`
- `crates/pod/Cargo.toml`
- `crates/pod/src/controller.rs`
- `crates/pod/src/feature.rs`
- `crates/pod/src/feature/builtin.rs`
- `crates/pod/src/feature/builtin/ticket.rs`
- `crates/ticket/Cargo.toml`
- `crates/ticket/src/lib.rs`
- `crates/ticket/src/tool.rs`
- `package.nix`
## Evidence Ticket tools are not in `crates/tools`
- No files under `crates/tools` were modified.
- Ticket tool implementation is in `crates/ticket/src/tool.rs`.
- Pod only adapts/registers the tools through the feature layer.
## Validation
Coder-reported validation passed:
- `cargo test -p ticket`
- `cargo test -p pod ticket --lib`
- `cargo test -p pod feature --lib`
- `cargo test -p pod --lib`
- `cargo test -p tools --lib`
- `cargo check --workspace --all-targets`
- `cargo fmt --check`
- `git diff --check`
- `./tickets.sh doctor`
- `nix build .#yoi --no-link`
Reviewer-rerun validation passed:
- `git diff --check develop...HEAD`
- `./tickets.sh doctor`
## Review status
External sibling reviewer approved with no blockers.
## Non-blocker follow-ups
- Feature install report currently records Ticket as installed even when backend root is unusable and no tools are registered. Fail-closed behavior is correct, but diagnostics may deserve more visible surfacing later.
- `HostAuthority::TicketBackend { root }` is declared from the pre-canonical backend path while the backend uses the canonicalized root. This is acceptable with the current built-in grant flow, but future explicit grant comparisons should normalize consistently.
## Ready for merge
Yes.