fix(skills): reconcile team-template skill names so role bindings actually bind
Every skill reference in every team template was failing to resolve. The TOMLs used snake_case slugs (`write_rust`, `index_selection`) while the authored skills under `skills/**/*.md` declare kebab-case names (`write-rust-current-edition`, `postgres-index-selection`), so `get_by_name` missed on all of them: 128 skipped bindings across 51 distinct names, and no mission agent received any of its template's skills. The mirror-image half was equally invisible: ten authored skills — including `int-xx-marker-protocol`, whose own `when_to_use` says "pin on every coding role" — were referenced by no role at all, so nothing could ever load them. - Rename the 14 references that have authored skills behind them, and dedupe the two that now collapse onto the commit-protocol skill. - Attach all ten orphaned skills to the roles their `when_to_use` names. All 23 authored skills now reach at least one role. - Aggregate the loader's per-name logging into one line per template. The old per-name spam is why this went unnoticed; a bound/unresolved count is noticeable. References with no authored skill are kept and listed — they record intent for skills not yet written. - Two regression tests: no authored skill may be orphaned, and every authored skill must be referenced by its exact name. Also clears the two standing clippy warnings: group `mint_team_from_template`'s eight positional args into `TeamMint`, and make `provider_alias_for` branch on `is_exact_provider_match` so the helper is live code and the two can't disagree about what counts as an exact family match. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
95bd65540c
commit
2eb0880fc0
@@ -186,13 +186,15 @@ pub async fn on_launch(
|
||||
mission.title, purpose, template.template.name
|
||||
);
|
||||
let team_id = mint_team_from_template(
|
||||
pool,
|
||||
workspace_id,
|
||||
user_id,
|
||||
provisioner.as_ref(),
|
||||
&template,
|
||||
&team_name,
|
||||
"claude-sonnet-5",
|
||||
TeamMint {
|
||||
pool,
|
||||
workspace_id,
|
||||
user_id,
|
||||
provisioner: provisioner.as_ref(),
|
||||
template: &template,
|
||||
team_name: &team_name,
|
||||
default_model: "claude-sonnet-5",
|
||||
},
|
||||
&mut provisioned_claws,
|
||||
)
|
||||
.await?;
|
||||
@@ -298,16 +300,33 @@ pub async fn on_launch(
|
||||
Ok(Some(team_id))
|
||||
}
|
||||
|
||||
async fn mint_team_from_template(
|
||||
pool: &PgPool,
|
||||
/// The read-only inputs for minting a team. Grouped into a struct so the
|
||||
/// signature stays readable as the orchestrator accumulates context — the
|
||||
/// growing positional list was also easy to mis-order at the call site,
|
||||
/// since `team_name` and `default_model` are both `&str`.
|
||||
struct TeamMint<'a> {
|
||||
pool: &'a PgPool,
|
||||
workspace_id: WorkspaceId,
|
||||
user_id: cm_domain::UserId,
|
||||
provisioner: Option<&RuntimeProvisioner>,
|
||||
template: &TeamTemplateDetail,
|
||||
team_name: &str,
|
||||
default_model: &str,
|
||||
provisioner: Option<&'a RuntimeProvisioner>,
|
||||
template: &'a TeamTemplateDetail,
|
||||
team_name: &'a str,
|
||||
default_model: &'a str,
|
||||
}
|
||||
|
||||
async fn mint_team_from_template(
|
||||
mint: TeamMint<'_>,
|
||||
provisioned_claws: &mut Vec<cm_domain::AgentId>,
|
||||
) -> Result<Uuid, String> {
|
||||
let TeamMint {
|
||||
pool,
|
||||
workspace_id,
|
||||
user_id,
|
||||
provisioner,
|
||||
template,
|
||||
team_name,
|
||||
default_model,
|
||||
} = mint;
|
||||
// Build the topology graph from role slots so the team's `graph`
|
||||
// NOT NULL column is satisfied + downstream topology executors
|
||||
// have a valid shape to iterate over.
|
||||
|
||||
Reference in New Issue
Block a user