ticket: use base32 project record ids
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
# Implementation report: ticket-config-role-profile-mapping
|
||||
|
||||
## Worktree / branch
|
||||
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping`
|
||||
- Branch: `work/ticket-config-role-profile-mapping`
|
||||
|
||||
## Commits
|
||||
|
||||
- `767870a ticket: add workspace ticket config`
|
||||
- `8fab67b ticket: reject nix profile selectors`
|
||||
|
||||
## Summary
|
||||
|
||||
Implemented `.yoi/ticket.config.toml` as workspace-local Ticket orchestration configuration with fixed Ticket role slots and wired the configured backend root into the existing Ticket built-in feature adapter.
|
||||
|
||||
The implementation keeps Ticket role configuration narrow:
|
||||
|
||||
- fixed roles only: `intake`, `orchestrator`, `coder`, `reviewer`, `investigator`;
|
||||
- role fields: `profile`, optional `launch_prompt`, optional `workflow`;
|
||||
- no `system_instruction` role field;
|
||||
- durable role/system behavior remains owned by the selected Profile.
|
||||
|
||||
## Final module/API layout
|
||||
|
||||
Added `crates/ticket/src/config.rs`, exported as `ticket::config`.
|
||||
|
||||
Main public API:
|
||||
|
||||
- `TicketConfig`
|
||||
- `load_workspace(workspace_root)`
|
||||
- `default_for_workspace(workspace_root)`
|
||||
- `backend_root()`
|
||||
- `role(role)`
|
||||
- `profile_for(role)`
|
||||
- `launch_prompt_for(role)`
|
||||
- `workflow_for(role)`
|
||||
- `TicketBackendConfig`
|
||||
- `TicketBackendKind`
|
||||
- `TicketRole`
|
||||
- `ProfileSelectorRef`
|
||||
- `PromptRef`
|
||||
- `WorkflowRef`
|
||||
- `TicketConfigError`
|
||||
- `TICKET_CONFIG_RELATIVE_PATH = ".yoi/ticket.config.toml"`
|
||||
|
||||
The `ticket` crate keeps lightweight string refs and does not depend on `pod` or `manifest`.
|
||||
|
||||
## Schema/defaults implemented
|
||||
|
||||
Config path:
|
||||
|
||||
```toml
|
||||
.yoi/ticket.config.toml
|
||||
```
|
||||
|
||||
Backend:
|
||||
|
||||
```toml
|
||||
[backend]
|
||||
kind = "local"
|
||||
root = "work-items"
|
||||
```
|
||||
|
||||
Role example:
|
||||
|
||||
```toml
|
||||
[roles.coder]
|
||||
profile = "project:coder"
|
||||
launch_prompt = "$workspace/prompts/ticket-coder"
|
||||
workflow = "multi-agent-workflow"
|
||||
```
|
||||
|
||||
Defaults when the config file is missing:
|
||||
|
||||
- backend: local `<workspace>/work-items`;
|
||||
- all role profiles: `inherit`;
|
||||
- launch prompts: none;
|
||||
- workflows:
|
||||
- intake: `ticket-intake-workflow`;
|
||||
- orchestrator: `ticket-orchestrator-routing`;
|
||||
- coder: `multi-agent-workflow`;
|
||||
- reviewer: `multi-agent-workflow`;
|
||||
- investigator: `ticket-orchestrator-routing`.
|
||||
|
||||
Validation rejects unknown top-level fields, unknown backend fields, unknown role fields, unknown roles, unsupported backend kinds, malformed/empty refs, path-like profile selector values, `.lua`, and `.nix` profile selector values.
|
||||
|
||||
## Pod Ticket feature adapter wiring
|
||||
|
||||
Updated `crates/pod/src/feature/builtin/ticket.rs` so `TicketFeature::for_workspace(...)` loads `ticket::config::TicketConfig`.
|
||||
|
||||
Behavior:
|
||||
|
||||
- missing config uses documented defaults, preserving previous `<workspace>/work-items` behavior;
|
||||
- valid config uses configured `[backend].root`;
|
||||
- malformed config fails closed: Ticket tools are not registered and a feature diagnostic is emitted;
|
||||
- missing/unusable backend root preserves existing no-register behavior;
|
||||
- tool authority continues to use `HostAuthority::TicketBackend { root }` for the configured backend root.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `Cargo.lock`
|
||||
- `crates/pod/src/feature/builtin/ticket.rs`
|
||||
- `crates/ticket/Cargo.toml`
|
||||
- `crates/ticket/src/config.rs`
|
||||
- `crates/ticket/src/lib.rs`
|
||||
- `package.nix`
|
||||
|
||||
## Review status
|
||||
|
||||
External sibling review initially requested one blocker fix:
|
||||
|
||||
- `ProfileSelectorRef` accepted `*.nix` profile selectors while existing `SpawnPod.profile` validation rejects them.
|
||||
|
||||
The blocker was fixed by commit `8fab67b` and re-review approved with no blockers.
|
||||
|
||||
Remaining non-blocker follow-ups:
|
||||
|
||||
- `HostAuthority::TicketBackend { root }` is derived from the configured path while the actual backend uses a canonicalized usable root; future explicit grant/audit comparisons should normalize consistently.
|
||||
- Pod adapter root usage could be strengthened with an execution-level tool test against the configured root.
|
||||
|
||||
## Validation
|
||||
|
||||
Coder-reported validation for the main implementation passed:
|
||||
|
||||
- `cargo test -p ticket`
|
||||
- `cargo test -p pod ticket --lib`
|
||||
- `cargo test -p pod feature --lib`
|
||||
- `cargo check --workspace --all-targets`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
- `./tickets.sh doctor`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Coder-reported validation for the blocker fix passed:
|
||||
|
||||
- `cargo test -p ticket config`
|
||||
- `cargo test -p ticket`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
|
||||
## Ready for merge
|
||||
|
||||
Yes.
|
||||
@@ -0,0 +1,292 @@
|
||||
# Investigation and plan: Ticket config role profile mapping
|
||||
|
||||
## Conclusion
|
||||
|
||||
Implement `.yoi/ticket.config.toml` as Ticket orchestration configuration with fixed Ticket role slots. Do not build a generic Role registry.
|
||||
|
||||
The initial implementation should parse/validate the config, provide defaults, expose role-to-profile and prompt/workflow references, and wire the configured backend root into the existing Ticket built-in feature adapter. Pod spawning, TUI actions, and workflow state should remain follow-up work.
|
||||
|
||||
## Design position
|
||||
|
||||
Use fixed Ticket roles:
|
||||
|
||||
- `intake`
|
||||
- `orchestrator`
|
||||
- `coder`
|
||||
- `reviewer`
|
||||
- `investigator`
|
||||
|
||||
These are not arbitrary user-defined roles. They are the roles required by the Ticket feature/workflows.
|
||||
|
||||
Keep the boundary:
|
||||
|
||||
- Profile: Pod runtime recipe, including durable role behavior/system instruction when using role-specific profiles.
|
||||
- Ticket role config: binds a fixed Ticket role to a Profile selector and optional launch prompt/workflow refs.
|
||||
- Launch prompt: first committed task/user message for a concrete Ticket/action.
|
||||
- Workflow: procedural flow, later possibly stateful.
|
||||
|
||||
## Current code map
|
||||
|
||||
### Ticket backend/tools
|
||||
|
||||
- `crates/ticket/src/lib.rs`
|
||||
- Owns Ticket domain/backend and `LocalTicketBackend`.
|
||||
- Current backend root is supplied by callers.
|
||||
- `crates/ticket/src/tool.rs`
|
||||
- Owns Ticket tool input/output and `llm_worker::Tool` implementations.
|
||||
- `crates/pod/src/feature/builtin/ticket.rs`
|
||||
- Thin built-in feature adapter.
|
||||
- Currently resolves `<workspace>/work-items` directly.
|
||||
- This is the first integration point for `.yoi/ticket.config.toml` backend root.
|
||||
|
||||
### Feature/host authority
|
||||
|
||||
- `crates/pod/src/feature.rs`
|
||||
- Defines `HostAuthority::TicketBackend { root }`.
|
||||
- Feature descriptor/install path already supports requested host authority and tool contribution wiring.
|
||||
|
||||
### Profile selection
|
||||
|
||||
- `crates/manifest/src/profile.rs`
|
||||
- Owns Profile registry/selector resolution.
|
||||
- `SpawnPod.profile` already accepts selectors such as `inherit`, default/source-qualified/unambiguous registry names.
|
||||
- `crates/pod/src/spawn/tool.rs`
|
||||
- Implements `SpawnPod` tool input with optional profile selector and `inherit` semantics.
|
||||
- This should remain the actual spawning boundary; config should not duplicate full profile resolution behavior.
|
||||
|
||||
### Workflow resources
|
||||
|
||||
- `.yoi/workflow/*.md`
|
||||
- Current workflow files are project-authored resources.
|
||||
- `ticket-intake-workflow.md`, `ticket-orchestrator-routing.md`, `ticket-preflight-workflow.md`, and `multi-agent-workflow.md` are the relevant workflow refs.
|
||||
- `crates/workflow/src/workflow.rs`
|
||||
- Parses workflow frontmatter/body records.
|
||||
- No stateful workflow runner exists yet.
|
||||
|
||||
### Prompt resources / launch prompts
|
||||
|
||||
- `crates/pod/src/prompt/loader.rs`
|
||||
- Resolves instruction-file references like `$yoi/...` and `$user/...` for current startup/instruction use.
|
||||
- Prompt catalog/resources are currently separate from workflow state.
|
||||
- There is no implemented role-specific launch prompt engine yet.
|
||||
- Role-specific durable system behavior should remain in the selected Profile for the MVP; this config should not override Profile system instruction.
|
||||
|
||||
## Important constraint
|
||||
|
||||
Do not make `ticket` depend on `pod`.
|
||||
|
||||
Possible dependency choices:
|
||||
|
||||
1. Put config parsing in `ticket` crate with raw profile/prompt/workflow string refs.
|
||||
- Pros: Ticket config is close to Ticket backend concept.
|
||||
- Cons: `ticket` learns about profile/prompt/workflow reference strings, but not their runtime resolution.
|
||||
|
||||
2. Put config parsing in `pod`.
|
||||
- Pros: avoids exposing prompt/profile concepts from `ticket`.
|
||||
- Cons: Ticket config becomes less reusable by future CLI/TUI code unless those crates also depend on `pod`.
|
||||
|
||||
Recommended MVP:
|
||||
|
||||
- Add config domain/parser to `crates/ticket`, using lightweight string wrapper types such as `ProfileSelectorRef`, `PromptRef`, and `WorkflowRef` without depending on `manifest` or `pod`.
|
||||
- In the MVP, `PromptRef` is for launch prompts only. Do not add role-level `system_instruction` here; the selected Profile owns durable role system behavior.
|
||||
- `pod` consumes this config and performs runtime interpretation where needed.
|
||||
|
||||
This preserves:
|
||||
|
||||
```text
|
||||
ticket -> llm-worker / serde / toml only
|
||||
pod -> ticket
|
||||
```
|
||||
|
||||
and avoids:
|
||||
|
||||
```text
|
||||
ticket -> pod
|
||||
```
|
||||
|
||||
## Proposed schema
|
||||
|
||||
```toml
|
||||
[backend]
|
||||
kind = "local"
|
||||
root = "work-items"
|
||||
|
||||
[roles.intake]
|
||||
profile = "project:intake"
|
||||
launch_prompt = "$workspace/ticket/intake/launch"
|
||||
workflow = "ticket-intake-workflow"
|
||||
|
||||
[roles.orchestrator]
|
||||
profile = "project:orchestrator"
|
||||
launch_prompt = "$workspace/ticket/orchestrator/launch"
|
||||
workflow = "ticket-orchestrator-routing"
|
||||
|
||||
[roles.coder]
|
||||
profile = "inherit"
|
||||
launch_prompt = "$workspace/ticket/coder/launch"
|
||||
workflow = "multi-agent-workflow"
|
||||
|
||||
[roles.reviewer]
|
||||
profile = "project:reviewer"
|
||||
launch_prompt = "$workspace/ticket/reviewer/launch"
|
||||
workflow = "multi-agent-workflow"
|
||||
|
||||
[roles.investigator]
|
||||
profile = "inherit"
|
||||
launch_prompt = "$workspace/ticket/investigator/launch"
|
||||
workflow = "ticket-orchestrator-routing"
|
||||
```
|
||||
|
||||
The specific prompt ref syntax should be accepted as opaque strings in this ticket. Runtime prompt resolution belongs to the later role launcher.
|
||||
|
||||
## Defaults
|
||||
|
||||
When `.yoi/ticket.config.toml` is missing:
|
||||
|
||||
- backend kind: `local`
|
||||
- backend root: `work-items`
|
||||
- role profiles: `inherit`
|
||||
- workflow defaults:
|
||||
- intake: `ticket-intake-workflow`
|
||||
- orchestrator: `ticket-orchestrator-routing`
|
||||
- coder: `multi-agent-workflow`
|
||||
- reviewer: `multi-agent-workflow`
|
||||
- investigator: `ticket-orchestrator-routing`
|
||||
- launch prompt: none
|
||||
|
||||
When a role section exists but omits optional prompt/workflow refs:
|
||||
|
||||
- keep configured profile;
|
||||
- fill workflow default for the fixed role;
|
||||
- leave prompt refs as none.
|
||||
|
||||
## Implementation plan
|
||||
|
||||
### Phase 1: Config model/parser in `ticket`
|
||||
|
||||
Add a module such as `crates/ticket/src/config.rs`.
|
||||
|
||||
Types:
|
||||
|
||||
```rust
|
||||
pub struct TicketConfig {
|
||||
pub backend: TicketBackendConfig,
|
||||
pub roles: TicketRoleProfiles,
|
||||
}
|
||||
|
||||
pub struct TicketBackendConfig {
|
||||
pub kind: TicketBackendKind,
|
||||
pub root: PathBuf,
|
||||
}
|
||||
|
||||
pub enum TicketBackendKind {
|
||||
Local,
|
||||
}
|
||||
|
||||
pub enum TicketRole {
|
||||
Intake,
|
||||
Orchestrator,
|
||||
Coder,
|
||||
Reviewer,
|
||||
Investigator,
|
||||
}
|
||||
|
||||
pub struct TicketRoleProfile {
|
||||
pub profile: ProfileSelectorRef,
|
||||
pub launch_prompt: Option<PromptRef>,
|
||||
pub workflow: WorkflowRef,
|
||||
}
|
||||
```
|
||||
|
||||
Use string wrapper types for selectors/refs to avoid depending on `manifest`/`pod`.
|
||||
|
||||
Parsing behavior:
|
||||
|
||||
- `TicketConfig::load_workspace(workspace_root: &Path)` reads `.yoi/ticket.config.toml` if present.
|
||||
- Missing file returns defaults.
|
||||
- Relative backend root resolves against workspace root.
|
||||
- Unknown roles are errors.
|
||||
- Unknown top-level fields should be diagnostics/errors rather than silently ignored.
|
||||
- Backend kind supports only `local` for now.
|
||||
|
||||
### Phase 2: Wire backend root into Pod Ticket feature adapter
|
||||
|
||||
Update `crates/pod/src/feature/builtin/ticket.rs`:
|
||||
|
||||
- Load `TicketConfig` from workspace root.
|
||||
- Use `config.backend.root` instead of hard-coded `workspace/work-items`.
|
||||
- Preserve current fail-closed behavior if root is missing/unusable.
|
||||
- Keep `HostAuthority::TicketBackend { root }` consistent with the validated/canonical root where practical.
|
||||
|
||||
This directly improves existing Ticket tools without introducing role spawning yet.
|
||||
|
||||
### Phase 3: Tests
|
||||
|
||||
Ticket crate tests:
|
||||
|
||||
- missing config -> defaults;
|
||||
- full config parses;
|
||||
- partial role config uses role workflow defaults;
|
||||
- unknown role rejects;
|
||||
- unsupported backend kind rejects;
|
||||
- relative backend root resolves against workspace;
|
||||
- malformed profile/ref diagnostics are bounded.
|
||||
|
||||
Pod tests:
|
||||
|
||||
- Ticket built-in feature uses configured backend root;
|
||||
- missing/unusable configured backend root does not register tools;
|
||||
- default missing config still uses `<workspace>/work-items`.
|
||||
|
||||
### Phase 4: Documentation/example
|
||||
|
||||
Add one of:
|
||||
|
||||
- a short `.yoi/ticket.config.example.toml`, or
|
||||
- a documented snippet under the ticket implementation report / docs if adding tracked config now is too early.
|
||||
|
||||
For this repository, adding actual `.yoi/ticket.config.toml` should be considered carefully. If added, defaults should likely use `inherit` profiles until dedicated profiles exist.
|
||||
|
||||
## Deferred follow-ups
|
||||
|
||||
### `ticket-role-pod-launcher`
|
||||
|
||||
- Take TicketRole + Ticket context + role config.
|
||||
- Build `SpawnPod` requests.
|
||||
- Resolve selected Profile using existing Profile registry; role-specific system behavior comes from that Profile.
|
||||
- Resolve launch prompt separately from the selected Profile's system instruction.
|
||||
- Commit launch prompt as the first user/task message, not hidden context.
|
||||
- Include workflow ref in launch/task context.
|
||||
|
||||
### `tui-ticket-role-actions`
|
||||
|
||||
- Add TUI actions for fixed Ticket roles:
|
||||
- Intake/refine Ticket;
|
||||
- Route Ticket;
|
||||
- Investigate;
|
||||
- Implement;
|
||||
- Review.
|
||||
- Use the launcher rather than building SpawnPod requests inside UI code.
|
||||
|
||||
### Stateful workflow engine
|
||||
|
||||
- Persist workflow phase/state.
|
||||
- Gate allowed tools by phase.
|
||||
- Inject phase prompts only by committing them to history first.
|
||||
- Keep Profile/SystemInstruction role-stable and task/phase prompts dynamic.
|
||||
|
||||
## Validation for implementation
|
||||
|
||||
Required:
|
||||
|
||||
- `cargo test -p ticket`
|
||||
- `cargo test -p pod ticket --lib`
|
||||
- `cargo test -p pod feature --lib`
|
||||
- `cargo check --workspace --all-targets`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
- `./tickets.sh doctor`
|
||||
|
||||
Optional if feasible:
|
||||
|
||||
- `nix build .#yoi --no-link`
|
||||
@@ -0,0 +1,91 @@
|
||||
# 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.toml` path and schema: mostly satisfied. The parser uses the fixed path `.yoi/ticket.config.toml`, supports `[backend] kind/root`, and uses fixed `[roles.<role>]` sections with `profile`, optional `launch_prompt`, and optional `workflow`.
|
||||
- Fixed roles only: satisfied. Unknown role names are rejected during config resolution.
|
||||
- No `system_instruction` role field: satisfied. `deny_unknown_fields` rejects it and a test checks this.
|
||||
- Missing config defaults: satisfied. Missing file returns local backend `<workspace>/work-items`, all role profiles `inherit`, 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/`, and `closed/` 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.profile` rejects.
|
||||
- Crate dependency boundary: satisfied. `ticket` adds `toml` but does not depend on `pod` or `manifest`; 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_instruction` overlay, arbitrary role registry, storage rename, external tracker, or scheduler work.
|
||||
- `Cargo.lock` / `package.nix`: changes are limited to adding the existing workspace `toml` dependency to `ticket` and 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
|
||||
|
||||
1. `ProfileSelectorRef` accepts `legacy.nix`/`*.nix` as a valid role profile selector, but `SpawnPod.profile` explicitly rejects `*.nix` as path-like.
|
||||
|
||||
The ticket requires role profile selector syntax to stay aligned with existing `SpawnPod/profile` selectors where possible, and the review checklist asks that malformed refs be rejected or clearly reported. `crates/pod/src/spawn/tool.rs` rejects path-like profile values including `legacy.nix`, while `crates/ticket/src/config.rs` currently rejects `path:`, 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 `*.nix` in `ProfileSelectorRef::new` and add a focused test alongside the existing malformed ref test.
|
||||
|
||||
## 5. Non-blockers / follow-ups
|
||||
|
||||
- `HostAuthority::TicketBackend { root }` is derived from `self.backend_root.display()` before canonicalization, while the actual `LocalTicketBackend` is built from `usable_root` after `canonicalize()`. 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...HEAD`
|
||||
- `cd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --name-status develop...HEAD`
|
||||
- `cd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --check develop...HEAD`
|
||||
- `cd /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.rs`
|
||||
- `crates/ticket/src/lib.rs`
|
||||
- `crates/ticket/Cargo.toml`
|
||||
- `crates/pod/src/feature/builtin/ticket.rs`
|
||||
- `Cargo.lock`
|
||||
- `package.nix`
|
||||
- Relevant existing `SpawnPod.profile` selector validation in `crates/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::new` now rejects values ending in `.nix` alongside other path-like selectors (`path:`, dot-prefixed selectors, slash-containing selectors, and `.lua`). This aligns the Ticket role profile config validation with the existing `SpawnPod.profile` path-selector rejection boundary for the reported case.
|
||||
- A focused test, `nix_profile_selector_refs_are_rejected`, was added for `profile = "legacy.nix"` and asserts that the config load fails with the path-selector rejection message.
|
||||
- The fix is limited to `crates/ticket/src/config.rs` and 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.rs`
|
||||
- `cd /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.
|
||||
@@ -0,0 +1,146 @@
|
||||
---
|
||||
title: "Ticket config role profile mapping"
|
||||
state: "closed"
|
||||
created_at: "2026-06-05T17:33:22Z"
|
||||
updated_at: "2026-06-05T18:48:15Z"
|
||||
---
|
||||
|
||||
## Background
|
||||
|
||||
Ticket orchestration now has typed Ticket backend/tools and workflows for Intake and Orchestrator routing. The next step before TUI role actions is to make the workspace's Ticket orchestration configuration explicit.
|
||||
|
||||
The project should not introduce an arbitrary Role registry. The roles needed here are fixed by the Ticket feature/workflows:
|
||||
|
||||
- intake
|
||||
- orchestrator
|
||||
- coder
|
||||
- reviewer
|
||||
- investigator
|
||||
|
||||
Each fixed role needs to select a Profile and, later, a first launch prompt and workflow binding. Role-specific durable behavior should live in the selected Profile, not in this config file. This is Ticket orchestration configuration, not a generic Profile replacement.
|
||||
|
||||
## Goal
|
||||
|
||||
Add workspace-local Ticket configuration at `.yoi/ticket.config.toml` and a typed parser/resolver for fixed Ticket role profile mappings.
|
||||
|
||||
The MVP should establish the configuration file, fixed role schema, backend root configuration, validation, and role-to-profile selector resolution. It should not yet spawn Pods or add TUI actions.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Add typed Ticket orchestration config support for `.yoi/ticket.config.toml`.
|
||||
- Keep roles fixed, not arbitrary:
|
||||
- `intake`
|
||||
- `orchestrator`
|
||||
- `coder`
|
||||
- `reviewer`
|
||||
- `investigator`
|
||||
- Support backend configuration:
|
||||
- local backend kind;
|
||||
- root path, defaulting to `work-items` relative to the workspace.
|
||||
- Support per-role configuration:
|
||||
- `profile` selector string;
|
||||
- optional launch/initial prompt reference;
|
||||
- optional workflow slug/reference.
|
||||
- Keep `profile` selector syntax aligned with existing SpawnPod/profile selectors where possible:
|
||||
- `inherit`
|
||||
- `default`
|
||||
- `builtin:<name>`
|
||||
- `user:<name>`
|
||||
- `project:<name>`
|
||||
- unqualified registry selector when accepted by existing profile resolution.
|
||||
- Preserve the conceptual separation:
|
||||
- Profile = Pod runtime recipe, including durable role behavior/system instruction when using role-specific profiles.
|
||||
- launch prompt = first committed task/user message for a specific Ticket/action.
|
||||
- workflow = procedural flow, later potentially stateful.
|
||||
- Validate known fields and reject/diagnose unknown roles or malformed fields.
|
||||
- Resolve relative backend roots against workspace root.
|
||||
- Do not auto-create backend directories in this ticket.
|
||||
- Update the existing Ticket built-in feature adapter to use the configured backend root when available, falling back to `work-items`.
|
||||
- Expose a reusable resolver API for later Pod launch/TUI code:
|
||||
- role -> profile selector;
|
||||
- role -> optional launch prompt ref;
|
||||
- role -> optional workflow slug;
|
||||
- backend root.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Arbitrary role registry.
|
||||
- Pod spawning or role launcher implementation.
|
||||
- TUI action implementation.
|
||||
- Stateful workflow engine.
|
||||
- Per-phase workflow prompt injection.
|
||||
- Changing Profile authoring/resolution semantics.
|
||||
- Replacing `profiles.toml`.
|
||||
- Renaming `work-items/`.
|
||||
- External tracker integration.
|
||||
- Scheduler/lease/queue automation.
|
||||
|
||||
## Suggested schema
|
||||
|
||||
```toml
|
||||
[backend]
|
||||
kind = "local"
|
||||
root = "work-items"
|
||||
|
||||
[roles.intake]
|
||||
profile = "project:intake"
|
||||
launch_prompt = "$workspace/ticket/intake/launch"
|
||||
workflow = "ticket-intake-workflow"
|
||||
|
||||
[roles.orchestrator]
|
||||
profile = "project:orchestrator"
|
||||
launch_prompt = "$workspace/ticket/orchestrator/launch"
|
||||
workflow = "ticket-orchestrator-routing"
|
||||
|
||||
[roles.coder]
|
||||
profile = "inherit"
|
||||
launch_prompt = "$workspace/ticket/coder/launch"
|
||||
workflow = "multi-agent-workflow"
|
||||
|
||||
[roles.reviewer]
|
||||
profile = "project:reviewer"
|
||||
launch_prompt = "$workspace/ticket/reviewer/launch"
|
||||
workflow = "multi-agent-workflow"
|
||||
|
||||
[roles.investigator]
|
||||
profile = "inherit"
|
||||
launch_prompt = "$workspace/ticket/investigator/launch"
|
||||
workflow = "ticket-orchestrator-routing"
|
||||
```
|
||||
|
||||
MVP may make all role fields optional except `profile` when a role section is present. Missing file and missing role sections should fall back to builtin defaults.
|
||||
|
||||
## Default behavior
|
||||
|
||||
When `.yoi/ticket.config.toml` is absent:
|
||||
|
||||
- backend kind: local
|
||||
- backend root: `<workspace>/work-items`
|
||||
- all role profiles: `inherit`
|
||||
- workflow defaults:
|
||||
- intake: `ticket-intake-workflow`
|
||||
- orchestrator: `ticket-orchestrator-routing`
|
||||
- coder: `multi-agent-workflow`
|
||||
- reviewer: `multi-agent-workflow`
|
||||
- investigator: `ticket-orchestrator-routing`
|
||||
- launch prompt refs: none
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `.yoi/ticket.config.toml` can be parsed from a workspace root.
|
||||
- Missing config falls back to documented defaults.
|
||||
- Fixed role sections parse correctly.
|
||||
- Unknown roles are rejected or reported as configuration errors.
|
||||
- Relative backend root resolves against workspace root.
|
||||
- Backend root from config is used by the Ticket built-in feature adapter.
|
||||
- Role profile selector strings are retained/parsed in a form later usable by role launching code.
|
||||
- Optional `launch_prompt` and `workflow` refs are parsed and exposed without trying to run a workflow engine.
|
||||
- Tests cover missing config, full config, partial role config, unknown role, relative backend root, and adapter backend-root usage.
|
||||
- `cargo test -p ticket` and focused `cargo test -p pod ticket --lib` pass.
|
||||
- `cargo check --workspace --all-targets`, `cargo fmt --check`, `git diff --check`, and `./tickets.sh doctor` pass.
|
||||
|
||||
## Follow-up tickets
|
||||
|
||||
- `ticket-role-pod-launcher`: construct role-specific `SpawnPod` requests from Ticket context, role config, selected Profile, launch prompt, workflow binding, and scope policy.
|
||||
- `tui-ticket-role-actions`: expose fixed Ticket role actions in TUI using the launcher.
|
||||
- Later workflow-state engine: persisted workflow phase/state, phase-specific allowed tools, and phase prompts committed to history before model use.
|
||||
@@ -0,0 +1,53 @@
|
||||
Ticket config role profile mapping is complete and merged.
|
||||
|
||||
Implementation:
|
||||
|
||||
- `767870a ticket: add workspace ticket config`
|
||||
- `8fab67b ticket: reject nix profile selectors`
|
||||
- merge commit: `9910df4 merge: add ticket config roles`
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `.yoi/ticket.config.toml` support through `crates/ticket/src/config.rs`.
|
||||
- Added fixed Ticket roles only:
|
||||
- `intake`
|
||||
- `orchestrator`
|
||||
- `coder`
|
||||
- `reviewer`
|
||||
- `investigator`
|
||||
- Added role config fields:
|
||||
- `profile`
|
||||
- optional `launch_prompt`
|
||||
- optional `workflow`
|
||||
- Did not add role-level `system_instruction`; durable role/system behavior remains owned by the selected Profile.
|
||||
- Added backend config for local Ticket storage:
|
||||
- `kind = "local"`
|
||||
- `root = "work-items"`
|
||||
- Missing config defaults to local `<workspace>/work-items`, all role profiles `inherit`, no launch prompts, and documented workflow defaults.
|
||||
- Unknown roles/fields, unsupported backend kinds, malformed refs, path-like profile refs, `.lua`, and `.nix` profile refs are rejected.
|
||||
- Wired the configured backend root into `crates/pod/src/feature/builtin/ticket.rs`.
|
||||
- Preserved fail-closed/no-register behavior for malformed config or unusable backend roots.
|
||||
- Kept dependency direction clean: `pod -> ticket`; `ticket` does not depend on `pod` or `manifest`.
|
||||
|
||||
Review:
|
||||
|
||||
- External sibling review initially requested one blocker fix: reject `*.nix` profile selectors to align with `SpawnPod.profile` validation.
|
||||
- Coder fixed it in `8fab67b` and added a focused `legacy.nix` rejection test.
|
||||
- Re-review approved with no blockers.
|
||||
|
||||
Non-blocker follow-ups:
|
||||
|
||||
- Normalize `HostAuthority::TicketBackend { root }` and canonical backend root consistently before relying on root strings for stricter security/audit comparison.
|
||||
- Add an execution-level Pod adapter test that runs a Ticket tool against the configured backend root.
|
||||
- Later role launcher should resolve Profile selectors/prompt refs/workflow refs at runtime and commit launch prompts as user/task messages.
|
||||
|
||||
Post-merge validation passed:
|
||||
|
||||
- `cargo test -p ticket`
|
||||
- `cargo test -p pod ticket --lib`
|
||||
- `cargo test -p pod feature --lib`
|
||||
- `cargo check --workspace --all-targets`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
- `./tickets.sh doctor`
|
||||
- `nix build .#yoi --no-link`
|
||||
@@ -0,0 +1,382 @@
|
||||
<!-- event: create author: tickets.sh at: 2026-06-05T17:33:22Z -->
|
||||
|
||||
## Created
|
||||
|
||||
Created by tickets.sh create.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: hare at: 2026-06-05T17:35:08Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Decision: implement `.yoi/ticket.config.toml` as Ticket orchestration configuration with fixed Ticket role slots.
|
||||
|
||||
Use fixed roles, not an arbitrary Role registry:
|
||||
|
||||
- intake
|
||||
- orchestrator
|
||||
- coder
|
||||
- reviewer
|
||||
- investigator
|
||||
|
||||
The config maps these fixed Ticket roles to Profile selector strings and optional role system instruction / launch prompt / workflow refs. This keeps Profile as the Pod runtime recipe while Ticket orchestration owns the role-to-profile binding.
|
||||
|
||||
The first implementation should parse/validate config and wire the configured backend root into Ticket tools. It should not spawn Pods, add TUI actions, or implement a stateful workflow engine yet.
|
||||
|
||||
Detailed investigation and implementation plan: `artifacts/investigation-plan.md`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: plan author: hare at: 2026-06-05T17:35:08Z -->
|
||||
|
||||
## Plan
|
||||
|
||||
Plan:
|
||||
|
||||
1. Add Ticket config model/parser, probably in `crates/ticket/src/config.rs`, using lightweight string wrapper types for Profile/prompt/workflow refs so `ticket` does not depend on `pod`.
|
||||
2. Parse `.yoi/ticket.config.toml` from a workspace root, with defaults when missing.
|
||||
3. Support `[backend]` local root and fixed `[roles.*]` sections.
|
||||
4. Wire the configured backend root into `crates/pod/src/feature/builtin/ticket.rs` so Ticket tools no longer hard-code `<workspace>/work-items`.
|
||||
5. Add focused tests in `ticket` and `pod`.
|
||||
6. Defer Pod role launching, TUI actions, and workflow-state/prompt sequencing to follow-up tickets.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: hare at: 2026-06-05T18:15:02Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Decision update: remove `system_instruction` from the MVP `.yoi/ticket.config.toml` role schema.
|
||||
|
||||
Rationale:
|
||||
|
||||
- The selected Profile already owns durable role behavior and system/instruction configuration.
|
||||
- Adding `system_instruction` to Ticket role config would create an unclear override/merge boundary with Profile.
|
||||
- Ticket role config should bind fixed Ticket roles to Profile selectors, workflow refs, and launch prompts only.
|
||||
- Launch prompts remain useful here because they are per-action first committed task/user messages, unlike role-stable system behavior.
|
||||
|
||||
Updated MVP role fields:
|
||||
|
||||
- `profile`
|
||||
- optional `launch_prompt`
|
||||
- optional `workflow`
|
||||
|
||||
If system-level role overlays are needed later, design them explicitly as a separate prompt/context ticket, likely with an overlay name and clear history/cache semantics. Do not add an implicit system instruction override in this ticket.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: hare at: 2026-06-05T18:45:41Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
# 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.toml` path and schema: mostly satisfied. The parser uses the fixed path `.yoi/ticket.config.toml`, supports `[backend] kind/root`, and uses fixed `[roles.<role>]` sections with `profile`, optional `launch_prompt`, and optional `workflow`.
|
||||
- Fixed roles only: satisfied. Unknown role names are rejected during config resolution.
|
||||
- No `system_instruction` role field: satisfied. `deny_unknown_fields` rejects it and a test checks this.
|
||||
- Missing config defaults: satisfied. Missing file returns local backend `<workspace>/work-items`, all role profiles `inherit`, 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/`, and `closed/` 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.profile` rejects.
|
||||
- Crate dependency boundary: satisfied. `ticket` adds `toml` but does not depend on `pod` or `manifest`; 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_instruction` overlay, arbitrary role registry, storage rename, external tracker, or scheduler work.
|
||||
- `Cargo.lock` / `package.nix`: changes are limited to adding the existing workspace `toml` dependency to `ticket` and 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
|
||||
|
||||
1. `ProfileSelectorRef` accepts `legacy.nix`/`*.nix` as a valid role profile selector, but `SpawnPod.profile` explicitly rejects `*.nix` as path-like.
|
||||
|
||||
The ticket requires role profile selector syntax to stay aligned with existing `SpawnPod/profile` selectors where possible, and the review checklist asks that malformed refs be rejected or clearly reported. `crates/pod/src/spawn/tool.rs` rejects path-like profile values including `legacy.nix`, while `crates/ticket/src/config.rs` currently rejects `path:`, 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 `*.nix` in `ProfileSelectorRef::new` and add a focused test alongside the existing malformed ref test.
|
||||
|
||||
## 5. Non-blockers / follow-ups
|
||||
|
||||
- `HostAuthority::TicketBackend { root }` is derived from `self.backend_root.display()` before canonicalization, while the actual `LocalTicketBackend` is built from `usable_root` after `canonicalize()`. 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...HEAD`
|
||||
- `cd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --name-status develop...HEAD`
|
||||
- `cd /home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping && git diff --check develop...HEAD`
|
||||
- `cd /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.rs`
|
||||
- `crates/ticket/src/lib.rs`
|
||||
- `crates/ticket/Cargo.toml`
|
||||
- `crates/pod/src/feature/builtin/ticket.rs`
|
||||
- `Cargo.lock`
|
||||
- `package.nix`
|
||||
- Relevant existing `SpawnPod.profile` selector validation in `crates/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::new` now rejects values ending in `.nix` alongside other path-like selectors (`path:`, dot-prefixed selectors, slash-containing selectors, and `.lua`). This aligns the Ticket role profile config validation with the existing `SpawnPod.profile` path-selector rejection boundary for the reported case.
|
||||
- A focused test, `nix_profile_selector_refs_are_rejected`, was added for `profile = "legacy.nix"` and asserts that the config load fails with the path-selector rejection message.
|
||||
- The fix is limited to `crates/ticket/src/config.rs` and 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.rs`
|
||||
- `cd /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.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: hare at: 2026-06-05T18:45:41Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
# Implementation report: ticket-config-role-profile-mapping
|
||||
|
||||
## Worktree / branch
|
||||
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/ticket-config-role-profile-mapping`
|
||||
- Branch: `work/ticket-config-role-profile-mapping`
|
||||
|
||||
## Commits
|
||||
|
||||
- `767870a ticket: add workspace ticket config`
|
||||
- `8fab67b ticket: reject nix profile selectors`
|
||||
|
||||
## Summary
|
||||
|
||||
Implemented `.yoi/ticket.config.toml` as workspace-local Ticket orchestration configuration with fixed Ticket role slots and wired the configured backend root into the existing Ticket built-in feature adapter.
|
||||
|
||||
The implementation keeps Ticket role configuration narrow:
|
||||
|
||||
- fixed roles only: `intake`, `orchestrator`, `coder`, `reviewer`, `investigator`;
|
||||
- role fields: `profile`, optional `launch_prompt`, optional `workflow`;
|
||||
- no `system_instruction` role field;
|
||||
- durable role/system behavior remains owned by the selected Profile.
|
||||
|
||||
## Final module/API layout
|
||||
|
||||
Added `crates/ticket/src/config.rs`, exported as `ticket::config`.
|
||||
|
||||
Main public API:
|
||||
|
||||
- `TicketConfig`
|
||||
- `load_workspace(workspace_root)`
|
||||
- `default_for_workspace(workspace_root)`
|
||||
- `backend_root()`
|
||||
- `role(role)`
|
||||
- `profile_for(role)`
|
||||
- `launch_prompt_for(role)`
|
||||
- `workflow_for(role)`
|
||||
- `TicketBackendConfig`
|
||||
- `TicketBackendKind`
|
||||
- `TicketRole`
|
||||
- `ProfileSelectorRef`
|
||||
- `PromptRef`
|
||||
- `WorkflowRef`
|
||||
- `TicketConfigError`
|
||||
- `TICKET_CONFIG_RELATIVE_PATH = ".yoi/ticket.config.toml"`
|
||||
|
||||
The `ticket` crate keeps lightweight string refs and does not depend on `pod` or `manifest`.
|
||||
|
||||
## Schema/defaults implemented
|
||||
|
||||
Config path:
|
||||
|
||||
```toml
|
||||
.yoi/ticket.config.toml
|
||||
```
|
||||
|
||||
Backend:
|
||||
|
||||
```toml
|
||||
[backend]
|
||||
kind = "local"
|
||||
root = "work-items"
|
||||
```
|
||||
|
||||
Role example:
|
||||
|
||||
```toml
|
||||
[roles.coder]
|
||||
profile = "project:coder"
|
||||
launch_prompt = "$workspace/prompts/ticket-coder"
|
||||
workflow = "multi-agent-workflow"
|
||||
```
|
||||
|
||||
Defaults when the config file is missing:
|
||||
|
||||
- backend: local `<workspace>/work-items`;
|
||||
- all role profiles: `inherit`;
|
||||
- launch prompts: none;
|
||||
- workflows:
|
||||
- intake: `ticket-intake-workflow`;
|
||||
- orchestrator: `ticket-orchestrator-routing`;
|
||||
- coder: `multi-agent-workflow`;
|
||||
- reviewer: `multi-agent-workflow`;
|
||||
- investigator: `ticket-orchestrator-routing`.
|
||||
|
||||
Validation rejects unknown top-level fields, unknown backend fields, unknown role fields, unknown roles, unsupported backend kinds, malformed/empty refs, path-like profile selector values, `.lua`, and `.nix` profile selector values.
|
||||
|
||||
## Pod Ticket feature adapter wiring
|
||||
|
||||
Updated `crates/pod/src/feature/builtin/ticket.rs` so `TicketFeature::for_workspace(...)` loads `ticket::config::TicketConfig`.
|
||||
|
||||
Behavior:
|
||||
|
||||
- missing config uses documented defaults, preserving previous `<workspace>/work-items` behavior;
|
||||
- valid config uses configured `[backend].root`;
|
||||
- malformed config fails closed: Ticket tools are not registered and a feature diagnostic is emitted;
|
||||
- missing/unusable backend root preserves existing no-register behavior;
|
||||
- tool authority continues to use `HostAuthority::TicketBackend { root }` for the configured backend root.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `Cargo.lock`
|
||||
- `crates/pod/src/feature/builtin/ticket.rs`
|
||||
- `crates/ticket/Cargo.toml`
|
||||
- `crates/ticket/src/config.rs`
|
||||
- `crates/ticket/src/lib.rs`
|
||||
- `package.nix`
|
||||
|
||||
## Review status
|
||||
|
||||
External sibling review initially requested one blocker fix:
|
||||
|
||||
- `ProfileSelectorRef` accepted `*.nix` profile selectors while existing `SpawnPod.profile` validation rejects them.
|
||||
|
||||
The blocker was fixed by commit `8fab67b` and re-review approved with no blockers.
|
||||
|
||||
Remaining non-blocker follow-ups:
|
||||
|
||||
- `HostAuthority::TicketBackend { root }` is derived from the configured path while the actual backend uses a canonicalized usable root; future explicit grant/audit comparisons should normalize consistently.
|
||||
- Pod adapter root usage could be strengthened with an execution-level tool test against the configured root.
|
||||
|
||||
## Validation
|
||||
|
||||
Coder-reported validation for the main implementation passed:
|
||||
|
||||
- `cargo test -p ticket`
|
||||
- `cargo test -p pod ticket --lib`
|
||||
- `cargo test -p pod feature --lib`
|
||||
- `cargo check --workspace --all-targets`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
- `./tickets.sh doctor`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Coder-reported validation for the blocker fix passed:
|
||||
|
||||
- `cargo test -p ticket config`
|
||||
- `cargo test -p ticket`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
|
||||
## Ready for merge
|
||||
|
||||
Yes.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-05T18:48:15Z status: closed -->
|
||||
|
||||
## Closed
|
||||
|
||||
Ticket config role profile mapping is complete and merged.
|
||||
|
||||
Implementation:
|
||||
|
||||
- `767870a ticket: add workspace ticket config`
|
||||
- `8fab67b ticket: reject nix profile selectors`
|
||||
- merge commit: `9910df4 merge: add ticket config roles`
|
||||
|
||||
Summary:
|
||||
|
||||
- Added `.yoi/ticket.config.toml` support through `crates/ticket/src/config.rs`.
|
||||
- Added fixed Ticket roles only:
|
||||
- `intake`
|
||||
- `orchestrator`
|
||||
- `coder`
|
||||
- `reviewer`
|
||||
- `investigator`
|
||||
- Added role config fields:
|
||||
- `profile`
|
||||
- optional `launch_prompt`
|
||||
- optional `workflow`
|
||||
- Did not add role-level `system_instruction`; durable role/system behavior remains owned by the selected Profile.
|
||||
- Added backend config for local Ticket storage:
|
||||
- `kind = "local"`
|
||||
- `root = "work-items"`
|
||||
- Missing config defaults to local `<workspace>/work-items`, all role profiles `inherit`, no launch prompts, and documented workflow defaults.
|
||||
- Unknown roles/fields, unsupported backend kinds, malformed refs, path-like profile refs, `.lua`, and `.nix` profile refs are rejected.
|
||||
- Wired the configured backend root into `crates/pod/src/feature/builtin/ticket.rs`.
|
||||
- Preserved fail-closed/no-register behavior for malformed config or unusable backend roots.
|
||||
- Kept dependency direction clean: `pod -> ticket`; `ticket` does not depend on `pod` or `manifest`.
|
||||
|
||||
Review:
|
||||
|
||||
- External sibling review initially requested one blocker fix: reject `*.nix` profile selectors to align with `SpawnPod.profile` validation.
|
||||
- Coder fixed it in `8fab67b` and added a focused `legacy.nix` rejection test.
|
||||
- Re-review approved with no blockers.
|
||||
|
||||
Non-blocker follow-ups:
|
||||
|
||||
- Normalize `HostAuthority::TicketBackend { root }` and canonical backend root consistently before relying on root strings for stricter security/audit comparison.
|
||||
- Add an execution-level Pod adapter test that runs a Ticket tool against the configured backend root.
|
||||
- Later role launcher should resolve Profile selectors/prompt refs/workflow refs at runtime and commit launch prompts as user/task messages.
|
||||
|
||||
Post-merge validation passed:
|
||||
|
||||
- `cargo test -p ticket`
|
||||
- `cargo test -p pod ticket --lib`
|
||||
- `cargo test -p pod feature --lib`
|
||||
- `cargo check --workspace --all-targets`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check`
|
||||
- `./tickets.sh doctor`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user