8.1 KiB
External review: ticket-config-role-profile-mapping
1. Result: request changes
Request changes. The implementation is otherwise close to the ticket, but one validation gap fails the requested alignment with existing SpawnPod.profile selector rules and should be fixed before merge.
2. Summary of implementation
The coder commit 767870a4fbf12f942a8b270e1cc316d7f35d3ef6 adds crates/ticket/src/config.rs and exports it from the ticket crate. The new parser reads .yoi/ticket.config.toml, defaults missing config to <workspace>/work-items plus fixed role defaults, models the fixed roles intake, orchestrator, coder, reviewer, and investigator, and stores profile / launch prompt / workflow references as lightweight strings without introducing pod or manifest dependencies.
The Pod built-in Ticket feature now loads TicketConfig from the Pod working directory, uses the configured backend root for LocalTicketBackend, and refuses to register Ticket tools when the config is malformed or the backend root is unusable. The implementation does not add Pod spawning, TUI actions, workflow state, system-instruction overlays, role registries, external trackers, or scheduler behavior.
3. Requirement-by-requirement assessment
.yoi/ticket.config.tomlpath and schema: mostly satisfied. The parser uses the fixed path.yoi/ticket.config.toml, supports[backend] kind/root, and uses fixed[roles.<role>]sections withprofile, optionallaunch_prompt, and optionalworkflow.- Fixed roles only: satisfied. Unknown role names are rejected during config resolution.
- No
system_instructionrole field: satisfied.deny_unknown_fieldsrejects it and a test checks this. - Missing config defaults: satisfied. Missing file returns local backend
<workspace>/work-items, all role profilesinherit, no launch prompts, and the documented workflow defaults. - Relative backend roots: satisfied. Relative roots are joined to the workspace root.
- Backend directories not auto-created: satisfied in the Pod adapter path. The adapter canonicalizes/checks the root and required
open/,pending/, andclosed/directories before registering tools. - Unknown roles/fields and malformed refs: mostly satisfied, but see blocker below for an accepted path-like profile selector that
SpawnPod.profilerejects. - Crate dependency boundary: satisfied.
ticketaddstomlbut does not depend onpodormanifest; profile/prompt/workflow refs remain string wrappers. - Pod adapter configured root / fail-closed behavior: satisfied. Config parse errors and unusable roots produce diagnostics and no Ticket tools are registered.
- HostAuthority root consistency: acceptable but imperfect. The backend uses the canonicalized usable root, while
HostAuthority::TicketBackend { root }is built from the pre-canonicalized configured path; see follow-up. - Explicit non-goals: satisfied. I found no added Pod spawning, TUI action, workflow engine, prompt injection, Profile semantic change,
system_instructionoverlay, arbitrary role registry, storage rename, external tracker, or scheduler work. Cargo.lock/package.nix: changes are limited to adding the existing workspacetomldependency toticketand updating the Nix cargo hash. That is necessary and looks safe.- Tests: broadly cover missing/full/partial config, unknown role/field, relative root, unsupported backend kind, malformed profile path, and Pod adapter root/no-register behavior. They do not cover the blocker case below.
4. Blockers
-
ProfileSelectorRefacceptslegacy.nix/*.nixas a valid role profile selector, butSpawnPod.profileexplicitly rejects*.nixas path-like.The ticket requires role profile selector syntax to stay aligned with existing
SpawnPod/profileselectors where possible, and the review checklist asks that malformed refs be rejected or clearly reported.crates/pod/src/spawn/tool.rsrejects path-like profile values includinglegacy.nix, whilecrates/ticket/src/config.rscurrently rejectspath:, dot-prefixed values, values containing/, and*.lua, but not*.nix. Because role config values are meant to be later usable by role launch code, accepting a selector that the existing launch boundary rejects is a config-validation failure.Expected fix: reject
*.nixinProfileSelectorRef::newand add a focused test alongside the existing malformed ref test.
5. Non-blockers / follow-ups
HostAuthority::TicketBackend { root }is derived fromself.backend_root.display()before canonicalization, while the actualLocalTicketBackendis built fromusable_rootaftercanonicalize(). This can make the granted/audited authority root differ from the root used by tools when the configured path includes..components or symlinks. The current implementation still requires matching host authority on the contributed tools and fail-closes on unusable roots, so I am not blocking on it, but the adapter should prefer a validated/canonical authority root where practical.- The Pod adapter test for configured backend root checks feature root selection and tool registration count. It does not execute a tool against the configured root. The code path is straightforward (
LocalTicketBackend::new(usable_root)), so this is acceptable, but an execution-level regression test would be stronger.
6. Validation assessed or rerun
Rerun/read-only checks:
cd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --stat develop...HEADcd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --name-status develop...HEADcd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --check develop...HEADcd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git show --stat --oneline --decorate 767870a4fbf12f942a8b270e1cc316d7f35d3ef6
Assessed by inspection:
- Ticket requirements, investigation/plan, and thread.
crates/ticket/src/config.rscrates/ticket/src/lib.rscrates/ticket/Cargo.tomlcrates/pod/src/feature/builtin/ticket.rsCargo.lockpackage.nix- Relevant existing
SpawnPod.profileselector validation incrates/pod/src/spawn/tool.rs.
Not rerun: cargo test, cargo check, cargo fmt --check, ./tickets.sh doctor, or nix build. The review request allowed focused read-only validation, and rerunning these would write build/test artifacts outside the review artifact path in this scoped sibling review.
7. Residual risk
After the *.nix selector rejection is fixed, residual risk is mainly around future launch integration: prompt/workflow refs are intentionally lightweight strings and will need runtime validation when the role launcher resolves them. The configured backend root is wired into the current Ticket tools, but authority-root canonicalization should be tightened before relying on HostAuthority root strings for security/audit semantics beyond this feature gate.
Re-review of blocker fix: 8fab67b
Result: approve
The blocker is resolved, and I found no new blocker in the focused fix commit.
Assessment
ProfileSelectorRef::newnow rejects values ending in.nixalongside other path-like selectors (path:, dot-prefixed selectors, slash-containing selectors, and.lua). This aligns the Ticket role profile config validation with the existingSpawnPod.profilepath-selector rejection boundary for the reported case.- A focused test,
nix_profile_selector_refs_are_rejected, was added forprofile = "legacy.nix"and asserts that the config load fails with the path-selector rejection message. - The fix is limited to
crates/ticket/src/config.rsand does not introduce source-boundary, runtime behavior, dependency, or scope expansion changes.
Validation assessed
Rerun/read-only checks:
cd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git show --stat --oneline HEAD && git diff develop...HEAD -- crates/ticket/src/config.rscd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git show --stat --oneline HEAD && git show --unified=8 -- crates/ticket/src/config.rs
Blockers
None.