* test(#3602): guard every spawned gsd-* subagent has a model resolution * fix(#3602): bind model resolution for every workflow subagent spawn * test(#3602): merge drift-ack entries into their owning fragments * fix(#3602): address review findings - docs-update verifier binding, ack merge, guard residuals * chore(#3602): backfill changeset pr number --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -98,11 +98,20 @@ For each **auto-fixable** finding (up to `--max`, ordered by severity desc):
|
||||
|
||||
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
||||
|
||||
```bash
|
||||
EXECUTOR_MODEL=$(gsd_run query resolve-model gsd-executor --raw)
|
||||
```
|
||||
|
||||
<!-- #2517 model-omit-on-inherit -->
|
||||
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`EXECUTOR_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
|
||||
**a. Spawn executor agent** (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)**:**
|
||||
```
|
||||
Agent(
|
||||
prompt="Fix finding {ID}: {description}. Files: {file_refs}. Make the minimal change to resolve this specific finding. Do not refactor surrounding code.",
|
||||
subagent_type="gsd-executor"
|
||||
subagent_type="gsd-executor",
|
||||
model="{EXECUTOR_MODEL}"
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
@@ -124,6 +124,9 @@ fi
|
||||
# Re-record after the base-check degrade, immediately before the spawn below, so the
|
||||
# #3045 sentinel matches the dispatch the guard is about to see (#3045).
|
||||
gsd_run query dispatch-isolation --raw --force-isolation "$ISOLATION" >/dev/null 2>&1 || true
|
||||
|
||||
# Model resolution for the debugger spawns below (#3602).
|
||||
DEBUGGER_MODEL=$(gsd_run query resolve-model gsd-debugger --raw)
|
||||
```
|
||||
|
||||
**Spawn debug agents — parallel only when each one is isolated:**
|
||||
@@ -157,10 +160,15 @@ placeholder, not a shell variable.
|
||||
|
||||
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
||||
|
||||
<!-- #2517 model-omit-on-inherit -->
|
||||
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`DEBUGGER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
|
||||
```
|
||||
Agent(
|
||||
prompt=filled_debug_subagent_prompt + "\n\n" + WORKTREE_GUARD + "\n\n<required_reading>\n- {phase_dir}/{phase_num}-UAT.md\n- {state_path}\n</required_reading>\n${AGENT_SKILLS_DEBUGGER}",
|
||||
subagent_type="gsd-debugger",
|
||||
model="{DEBUGGER_MODEL}",
|
||||
{harnessFlag}
|
||||
description="Debug: {truth_short}"
|
||||
)
|
||||
|
||||
@@ -22,10 +22,11 @@ AGENT_SKILLS=$(gsd_run query agent-skills gsd-doc-writer)
|
||||
# only the section_manifest field (gates dispatch_monorepo_packages).
|
||||
INIT_DOCS_UPDATE=$(gsd_run query init.docs-update)
|
||||
if [[ "$INIT_DOCS_UPDATE" == @file:* ]]; then INIT_DOCS_UPDATE=$(cat "${INIT_DOCS_UPDATE#@file:}"); fi
|
||||
DOC_VERIFIER_MODEL=$(gsd_run query resolve-model gsd-doc-verifier --raw)
|
||||
```
|
||||
|
||||
Extract from init JSON:
|
||||
- `doc_writer_model` — model string to pass to each spawned agent (never hardcode a model name)
|
||||
- `doc_writer_model` — model string for the doc-writer spawns (never hardcode a model name); the doc-verifier spawn resolves its own `DOC_VERIFIER_MODEL`
|
||||
- `commit_docs` — whether to commit generated files when done
|
||||
- `existing_docs` — array of `{path, has_gsd_marker}` objects for existing Markdown files
|
||||
- `project_type` — object with boolean signals: `has_package_json`, `has_api_routes`, `has_cli_bin`, `is_open_source`, `has_deploy_config`, `is_monorepo`, `has_tests`
|
||||
@@ -394,7 +395,7 @@ Use `run_in_background=true` for all three to enable parallel execution.
|
||||
|
||||
<!-- #2517 model-omit-on-inherit -->
|
||||
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`doc_writer_model`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`doc_writer_model`, `DOC_VERIFIER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
|
||||
```
|
||||
Agent(
|
||||
@@ -932,7 +933,7 @@ Continue to scan_for_secrets.
|
||||
Invoke the gsd-doc-verifier agent in read-only mode for each file in `existing_docs` from the init JSON:
|
||||
|
||||
1. For each doc in `existing_docs`:
|
||||
a. Spawn `gsd-doc-verifier` (or invoke sequentially if Task tool is unavailable) with:
|
||||
a. Spawn `gsd-doc-verifier` (or invoke sequentially if Task tool is unavailable), passing `model="{DOC_VERIFIER_MODEL}"` as the Task/Agent call's `model` parameter — not part of the `<verify_assignment>` prompt — so `dynamic_routing`/`model_profile` tiers apply instead of the caller's session model (#3602). Omit the parameter entirely when the value is `"inherit"` or empty (#2517). Each spawn carries:
|
||||
```xml
|
||||
<verify_assignment>
|
||||
doc_path: {doc.path}
|
||||
|
||||
@@ -204,13 +204,22 @@ Delegate validation to gsd-plan-checker:
|
||||
|
||||
Print: "Delegating to gsd-plan-checker (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)"
|
||||
|
||||
```bash
|
||||
CHECKER_MODEL=$(gsd_run query resolve-model gsd-plan-checker --raw)
|
||||
```
|
||||
|
||||
<!-- #2508 runtime-aware-dispatch -->
|
||||
|
||||
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
||||
|
||||
<!-- #2517 model-omit-on-inherit -->
|
||||
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`CHECKER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "gsd-plan-checker",
|
||||
model: "{CHECKER_MODEL}",
|
||||
prompt: "Validate: ${phase_dir}/{plan}-PLAN.md — check frontmatter completeness, task structure, and GSD conventions. Report any issues."
|
||||
})
|
||||
```
|
||||
|
||||
@@ -56,6 +56,9 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
|
||||
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/dev/null || echo "")
|
||||
INIT=$(gsd_run init ingest-docs)
|
||||
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
||||
CLASSIFIER_MODEL=$(gsd_run query resolve-model gsd-doc-classifier --raw)
|
||||
SYNTHESIZER_MODEL=$(gsd_run query resolve-model gsd-doc-synthesizer --raw)
|
||||
ROADMAPPER_MODEL=$(gsd_run query resolve-model gsd-roadmapper --raw)
|
||||
```
|
||||
|
||||
**If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
||||
@@ -174,6 +177,10 @@ mkdir -p .planning/intel/classifications/
|
||||
|
||||
For each discovered doc, spawn `gsd-doc-classifier` in parallel. In Claude Code, issue all Task calls in a single message with multiple tool uses so the harness runs them concurrently. For Copilot / sequential runtimes, fall back to sequential dispatch.
|
||||
|
||||
<!-- #2517 model-omit-on-inherit -->
|
||||
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`CLASSIFIER_MODEL`, `SYNTHESIZER_MODEL`, `ROADMAPPER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
|
||||
Per-spawn prompt fields:
|
||||
- `FILEPATH` — absolute path to the doc
|
||||
- `OUTPUT_DIR` — `{intel_dir}/classifications` (absolute — from `init ingest-docs`; #2376: a spawned classifier's own cwd may differ from the orchestrator's)
|
||||
@@ -181,6 +188,8 @@ Per-spawn prompt fields:
|
||||
- `MANIFEST_PRECEDENCE` — the precedence integer from the manifest if present, else omit
|
||||
- `<required_reading>` — `agents/gsd-doc-classifier.md` (the agent definition itself)
|
||||
|
||||
**Model on every classifier spawn (#3602):** `model="{CLASSIFIER_MODEL}"` is a parameter of each Task/Agent call — not a prompt field, never folded into the prompt text — so `dynamic_routing`/`model_profile` tiers apply instead of the caller's session model. Omit the parameter per the rule above when the value is `"inherit"` or empty.
|
||||
|
||||
Collect the one-line confirmations from each classifier. If any classifier errors out, surface the error and abort without touching `.planning/` further.
|
||||
|
||||
</step>
|
||||
@@ -196,6 +205,7 @@ Spawn `gsd-doc-synthesizer` once (runs in a subagent — no output until it retu
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "gsd-doc-synthesizer",
|
||||
model: "{SYNTHESIZER_MODEL}",
|
||||
prompt: "
|
||||
CLASSIFICATIONS_DIR: {intel_dir}/classifications
|
||||
INTEL_DIR: {intel_dir}
|
||||
@@ -263,6 +273,7 @@ Delegate to `gsd-roadmapper` (runs in a subagent — no output until it returns,
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "gsd-roadmapper",
|
||||
model: "{ROADMAPPER_MODEL}",
|
||||
prompt: "
|
||||
Mode: new-project-from-ingest
|
||||
Intel: {intel_dir}/SYNTHESIS.md (entry point)
|
||||
|
||||
@@ -166,9 +166,17 @@ Display: "✓ Sampled N messages from M projects"
|
||||
|
||||
Display: "◆ Analyzing patterns..."
|
||||
|
||||
```bash
|
||||
PROFILER_MODEL=$(gsd_run query resolve-model gsd-user-profiler --raw)
|
||||
```
|
||||
|
||||
<!-- #2517 model-omit-on-inherit -->
|
||||
|
||||
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`PROFILER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
||||
|
||||
**Spawn gsd-user-profiler agent using Task tool:**
|
||||
|
||||
Use the Task tool to spawn the `gsd-user-profiler` agent. Provide it with:
|
||||
Use the Task tool to spawn the `gsd-user-profiler` agent, passing `model="{PROFILER_MODEL}"` (omit the parameter per the rule above when the value is `"inherit"` or empty). Provide it with:
|
||||
- The sampled JSONL file path from profile-sample output
|
||||
- The user-profiling reference doc at `$HOME/.claude/gsd-core/references/user-profiling.md`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user