* test(#2856): add failing-first suite for the live-dom-uat capability Binds the approved triage shape before any of it exists: - containment — the execute:wave:post hook must not render unless workflow.live_dom_uat is true AND the capability resolves active (fail-closed on a missing state entry, and on a non-boolean value) - criterion 4 — agents/gsd-executor.md carries no browser MCP family; asserted as an absence, which is the only way it is observable - Hyrum guard — the pre-existing mcp__playwright__* branch must stay outside the key-gated block, or upgrading silently removes working automated UI verification for every current Playwright-MCP user - parity — the browser glob list now lives in two surfaces (agent frontmatter + workflow detection block); the assertion fails if either gains or loses a family without the other Red by construction: the capability, agent and workflow block do not exist yet. Verified on the remote runner. Refs #2856 * enhance(#2856): add default-off live-DOM UAT capability A phase whose acceptance criteria needed a live DOM could not be finished by the agent that executed it: gsd-executor carries no browser tools, so it correctly returned checkpoint:human-action even though the work was not human-only, just tool-less. Every such phase degraded to "executed, then finished by hand in the orchestrator", and autonomous: false could not distinguish "a human must judge this" from "the executor lacks the tool". Implements the shape approved at triage, not the one reported. The executor's tools: line is NOT widened, in any configuration: for a first-party agent the static list is the only control that exists (ADR-1244 D2, ADR-857 D4, no per-dispatch override). Instead one default-off capability owns the key, the agent, and the step: - capabilities/live-dom-uat/ — activationKey workflow.live_dom_uat (boolean, default false), one additive step at execute:wave:post (onError: skip, gates: []), so it can never halt a wave - agents/gsd-dom-verifier.md — the only GSD agent carrying browser MCP globs, in its own tools: line, with no Bash - verify-work automated_ui_verification — a gsd:live-dom-families block naming both new families AND the key; presence alone never activates Two independent fail-closed gates: isCapabilityActive renders a hook only on state.active === true, plus the step's own `when`. The pre-existing mcp__playwright__* branch keeps the gating it already had and stays outside the new block. Pulling it behind a default-off key would have silently removed working automated UI verification from every current Playwright-MCP user on upgrade. Also closes a host gap this surfaced: execute:wave:post dispatched only contribution + gate, so ANY registered step was declared and silently never run — exactly the single-kind hand-roll loop-hook-dispatch.md names. Step 5.75 now dispatches every kind == "step". The browser-profile lock is tolerated, not coordinated: --isolated is a flag on the operator's own MCP-server registration that GSD neither launches nor parameterizes, so the verifier reports could_not_look / profile_locked, names the flag, and stops. DOM-VERIFY.md keeps could_not_look and nothing_to_report distinct behind a closed reason enum — collapsing them is the ambiguous-run-notes defect reported. Verified on the remote runner. Closes #2856 * fix(#2856): apply review findings from the orthogonal passes Correctness pass (blocker): - delete detectionBlockIsCrlfSafe. It was pass-always: it read the file, replaced LF with CRLF, then indexOf'd marker strings that contain no newline, so the replacement could not change the result and the assertion could never fail for the reason it stated. There is no real CRLF risk on this surface either — the gsd:live-dom-families block has no parser, only human and agent readers. Deleted rather than replaced, per the repo's pass-always-test rule. Isolated security pass (two minors, both real): - execute-phase.md step 5.75: this change is what first activates kind == "step" dispatch at execute:wave:post, which newly opens the ref.command shell path at that loop point. Our own step uses ref.agent and never touches it, but the door is now open, so the step-dispatch line carries the same in-context validate-before-shell warning the sibling gate-dispatch line directly below it already carries. - gsd-dom-verifier: quoted page text in DOM-VERIFY.md is attacker influenced. Require it wrapped in inline code or a fence, kept short, and never left reading as a directive to the next reader. Verified on the remote runner. Refs #2856 * fix(#2856): settle the new-agent roster ripple Checkpoint 2 returned 28 failures, none in the new suite — all of them the guards that exist to make adding an agent a deliberate act. Each is a real boundary that had to move: - docs/AGENTS.md: Tools row must copy the frontmatter verbatim (#2526), so the browser globs lose their backticks; primary-agent counts 21->22, roster 33/34->34/35, Verifiers category 1->2 - docs/INVENTORY.md: roster completeness requires every agents/gsd-*.md to be classified exactly once - gsd-dom-verifier: add the anti-heredoc instruction and the commented hooks: frontmatter pattern both agent gates require - gsd-core/bin/shared/model-catalog.json: every shipped agent needs a profile entry (#3229) - copilot-install / kilo-upgrades / qwen-upgrades: expected agent list and the 34->35 roster boundary - execute-wave-post-gate-pipeline-e2e: execute:wave:post legitimately carries one step now. Asserted as an exact shape — one step, capId live-dom-uat, ref.agent gsd-dom-verifier, onError skip — so it stays a real guard against accidental change rather than being relaxed Two findings worth naming: mcp-tool-inheritance (#2526) rejected the agent for documenting mcp__playwright__* while its tools: line withholds it — a dead instruction that invites the agent to claim a path it cannot take. The prose now names the Playwright MCP family without the dispatchable token, in both the agent and the capability fragment. runtime-launcher-parity rejected the new gsd_run call: each fenced block is its own shell, so a workflow step file invoking gsd_run needs its own canonical preamble. Propagated with scripts/sync-runtime-launcher.cjs. That script also normalizes explore.md, which is unrelated pre-existing drift the parity check tolerates, so it is reverted to keep this diff scoped. The emitted-drift ack supersedes the spent #3370 entry for execute-phase.md — it is merged into next, so its ripple is absorbed at the base and it can no longer clear anything. That is the same supersede the #3370 entry itself performed on the spent #3324 fragment. Its unrelated execute-plan.md entry is untouched. Verified on the remote runner. Refs #2856 * fix(#2856): drop the stale emitted-drift ack entry The automated-ui-verification.md entry was written speculatively rather than from a reported growth, and the check names that precisely: an ack "written or reworded in THIS diff, but nothing here needed it, so it explains nothing". The growth tier keys on the bare filename as it appears under gsd-core/workflows/ or agents/. automated-ui-verification.md is nested under verify-work/steps/, so it was never in the tracked set — only execute-phase.md was ever reported, both before and after the launcher preamble landed. Only ack what the check actually reports. Verified on the remote runner. Refs #2856 * chore(#2856): backfill changeset pr number pr:0 -> 3716. The placeholder fails both changeset-lint (fail_invalid_fragment) and docs-lint (fail_malformed_fragment) by design and can only be resolved once the PR number exists. Both now report ok against GITHUB_BASE_REF=next. Refs #2856 --------- Co-authored-by: sim <sim@local>
13 KiB
13 KiB
Agent Contracts
Completion markers and handoff schemas for all GSD agents. Workflows use these markers to detect agent completion and route accordingly.
This doc describes what IS, not what should be. Casing inconsistencies are documented as they appear in agent source files.
Agent Registry
| Agent | Role | Completion Markers | Consumed by | Kind |
|---|---|---|---|---|
| gsd-ai-researcher | AI framework research | No marker (writes the AI-SPEC.md framework section via Edit) | gsd-core/workflows/ai-integration-phase.md reads the AI-SPEC.md section after the agent returns |
artifact+query |
| gsd-planner | Plan creation | ## PLANNING COMPLETE, ## OUTLINE COMPLETE, ## PHASE SPLIT RECOMMENDED, ## ⚠ Source Audit, ## CHECKPOINT REACHED, ## PLANNING INCONCLUSIVE |
gsd-core/workflows/plan-phase.md, gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md, gsd-core/workflows/plan-review-convergence.md, gsd-core/workflows/quick.md |
sentinel-match |
| gsd-executor | Plan execution | ## PLAN COMPLETE, ## CHECKPOINT REACHED |
gsd-core/workflows/plan-phase.md, gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md, agents/gsd-debug-session-manager.md, agents/gsd-debugger.md |
sentinel-match |
| gsd-phase-researcher | Phase-scoped research | ## RESEARCH COMPLETE, ## RESEARCH BLOCKED |
gsd-core/workflows/plan-phase.md, gsd-core/workflows/quick/steps/research-phase.md, agents/gsd-project-researcher.md |
sentinel-match |
| gsd-project-researcher | Project-wide research | ## RESEARCH COMPLETE, ## RESEARCH BLOCKED |
gsd-core/workflows/plan-phase.md, gsd-core/workflows/quick/steps/research-phase.md, agents/gsd-phase-researcher.md |
sentinel-match |
| gsd-plan-checker | Plan validation | ## VERIFICATION PASSED, ## ISSUES FOUND |
gsd-core/workflows/plan-phase.md, gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md, gsd-core/workflows/quick/steps/plan-checker-loop.md, gsd-core/workflows/ui-phase.md, gsd-core/workflows/verify-work.md, agents/gsd-ui-checker.md |
sentinel-match |
| gsd-research-synthesizer | Multi-research synthesis | ## SYNTHESIS COMPLETE, ## SYNTHESIS BLOCKED (unconsumed: blocked-research return — spawners detect failure via the #222 SUMMARY.md-on-disk check, no dispatch branch keys on the marker) |
gsd-core/workflows/new-milestone.md, gsd-core/workflows/new-project.md |
sentinel-match |
| gsd-debugger | Debug investigation | ## DEBUG COMPLETE, ## ROOT CAUSE FOUND, ## CHECKPOINT REACHED, ## INVESTIGATION INCONCLUSIVE, ## TDD CHECKPOINT, ## FIX REJECTED BY GUARDRAIL |
agents/gsd-debug-session-manager.md, gsd-core/workflows/diagnose-issues.md, gsd-core/workflows/plan-phase.md, agents/gsd-executor.md |
sentinel-match |
| gsd-debug-session-manager | Debug checkpoint loop | ## DEBUG SESSION COMPLETE, ## CONTINUE_REQUIRED |
gsd-core/workflows/debug.md |
sentinel-match |
| gsd-roadmapper | Roadmap creation/revision | ## ROADMAP CREATED, ## ROADMAP REVISED, ## ROADMAP BLOCKED, ## ROADMAP DRAFT (unconsumed: draft-presentation format the shipped execution flow never invokes — Step 8 returns ## ROADMAP CREATED; retained for interactive draft review) |
gsd-core/workflows/new-milestone.md, gsd-core/workflows/new-project.md |
sentinel-match |
| gsd-ui-auditor | UI review | ## UI REVIEW COMPLETE |
gsd-core/workflows/ui-review.md |
sentinel-match |
| gsd-dom-verifier | Live-DOM UAT verification | No marker (writes {phase}-DOM-VERIFY.md directly; the frontmatter outcome / reason scalars carry the verdict, and could_not_look is never conflated with nothing_to_report) |
{phase}-DOM-VERIFY.md artifact, written by the live-dom-uat capability's execute:wave:post step dispatched from gsd-core/workflows/execute-phase.md |
artifact+query |
| gsd-ui-checker | UI validation | ## ISSUES FOUND, ## UI-SPEC VERIFIED |
gsd-core/workflows/plan-phase.md, gsd-core/workflows/quick/steps/plan-checker-loop.md, gsd-core/workflows/ui-phase.md, gsd-core/workflows/verify-work.md, agents/gsd-plan-checker.md |
sentinel-match |
| gsd-ui-researcher | UI spec creation | ## UI-SPEC COMPLETE, ## UI-SPEC BLOCKED |
gsd-core/workflows/ui-phase.md |
sentinel-match |
| gsd-verifier | Post-execution verification | ## Verification Complete (unconsumed: Marker Rule 2 recorded decision — intentional title-case marker; completion is detected via the artifact route, nothing matches the marker) |
*-VERIFICATION.md artifact + gsd_run query verification.status in gsd-core/workflows/verify-work.md |
artifact+query |
| gsd-integration-checker | Cross-phase integration check | ## Integration Check Complete (unconsumed: Marker Rule 2 recorded decision — intentional title-case marker; the auditor reads the inline report, nothing matches the marker) |
gsd-core/workflows/audit-milestone.md reads the agent's inline return text directly (agent has no Write tool -- it cannot write an artifact) |
structured-return |
| gsd-nyquist-auditor | Sampling audit | ## PARTIAL, ## ESCALATE, ## GAPS FILLED (non-standard) |
gsd-core/workflows/validate-phase.md, gsd-core/workflows/secure-phase.md, agents/gsd-security-auditor.md |
sentinel-match |
| gsd-security-auditor | Security audit | ## OPEN_THREATS, ## ESCALATE, ## SECURED (non-standard) |
gsd-core/workflows/secure-phase.md, gsd-core/workflows/validate-phase.md, agents/gsd-nyquist-auditor.md |
sentinel-match |
| gsd-codebase-mapper | Codebase analysis | No marker (writes docs directly) | .planning/codebase/*.md artifacts, checked via ls/wc -l in gsd-core/workflows/map-codebase.md |
artifact+query |
| gsd-code-fixer | Applies code-review fixes | No marker (fix commits + REVIEW.md updates) | gsd-core/workflows/code-review-fix.md reads REVIEW.md resolution state + git log |
artifact+query |
| gsd-code-reviewer | Source-code review | No marker (writes REVIEW.md) | gsd-core/workflows/code-review.md reads REVIEW.md |
artifact+query |
| gsd-assumptions-analyzer | Assumption extraction | No marker (returns ## Assumptions sections) |
gsd-core/workflows/discuss-phase-assumptions.md reads the inline ## Assumptions sections from the agent's return |
structured-return |
| gsd-doc-classifier | Planning-doc classification | No marker (writes .planning/intel/classifications/*.json) |
gsd-core/workflows/ingest-docs.md reads the classification JSON |
artifact+query |
| gsd-doc-verifier | Doc validation | No marker (writes JSON to .planning/tmp/) |
.planning/tmp/verify-{doc_filename}.json artifact, read by gsd-core/workflows/docs-update.md |
artifact+query |
| gsd-doc-writer | Doc generation | No marker (writes docs directly) | generated doc files, consumed by gsd-core/workflows/docs-update.md and gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md |
artifact+query |
| gsd-domain-researcher | Domain research | No marker (writes the AI-SPEC.md domain section via Edit) | gsd-core/workflows/ai-integration-phase.md reads the AI-SPEC.md section after the agent returns |
artifact+query |
| gsd-eval-auditor | Evaluation coverage audit | No marker (writes the REVIEW.md audit section) | gsd-core/workflows/eval-review.md reads REVIEW.md |
artifact+query |
| gsd-eval-planner | Evaluation strategy design | No marker (writes the AI-SPEC.md evaluation section via Edit) | gsd-core/workflows/ai-integration-phase.md reads the AI-SPEC.md section after the agent returns |
artifact+query |
| gsd-framework-selector | Framework decision matrix | No marker (returns the interactive decision matrix inline) | gsd-core/workflows/ai-integration-phase.md reads the returned matrix |
structured-return |
| gsd-advisor-researcher | Advisory research | No marker (utility agent) | gsd-core/workflows/discuss-phase/modes/advisor.md reads the inline comparison table from the agent's return |
structured-return |
| gsd-user-profiler | User profiling | No marker (returns JSON in analysis tags) | gsd-core/workflows/profile-user.md extracts the inline <analysis> JSON block from the agent's return |
structured-return |
| gsd-intel-updater | Codebase intelligence analysis | No marker (.planning/intel/*.json artifacts) |
.planning/intel/*.json artifacts, read via gsd_run intel query / intel validate (no *.md workflow currently spawns this agent -- see docs/adr/22-plan-drift-guard.md, "never auto-spawned") |
artifact+query |
| gsd-mempalace-curator | Ship-time MemPalace curation | No marker (writes the session diary + cross-links) | gsd-core/workflows/ship.md reads the diary artifacts |
artifact+query |
| gsd-pattern-mapper | Codebase pattern mapping | ## PATTERN MAPPING COMPLETE |
gsd-core/workflows/plan-phase.md (also spawned by gsd-core/workflows/settings.md) |
sentinel-match |
| gsd-doc-synthesizer | Doc synthesis for /gsd:ingest-docs |
No marker (SYNTHESIS.md and INGEST-CONFLICTS.md artifacts) | .planning/intel/SYNTHESIS.md and .planning/INGEST-CONFLICTS.md artifacts, read by gsd-core/workflows/ingest-docs.md |
artifact+query |
Marker Rules
- ALL-CAPS markers (e.g.,
## PLANNING COMPLETE) are the standard convention - Title-case markers in gsd-verifier and gsd-integration-checker are intentional as-is, not bugs — a recorded decision. Their rows are
artifact+query/structured-return(completion is detected through the row'sKindroute), and the markers are carried as(unconsumed: Marker Rule 2 recorded decision …)annotations: an auditable exemption, never deleted and never silently passed.## Synthesis Completein gsd-doc-synthesizer was NOT covered by this rule; #3565 deleted it deliberately because it case-collides with gsd-research-synthesizer's## SYNTHESIS COMPLETEand nothing matched it - Non-standard markers (e.g.,
## PARTIAL,## ESCALATE) in audit agents indicate partial results requiring orchestrator judgment Kinddescribes how a caller actually detects an agent's completion, and is exactly one of:sentinel-match-- a workflow, command, or another agent detects completion by an exact-case string match against a declared markerartifact+query-- the agent writes a file (report, JSON, generated doc) and the caller reads or queries that artifact instead of matching any marker textstructured-return-- the agent has no way to write files (noWritetool) or simply doesn't; it returns parseable sections, a table, or JSON inline, and the caller reads that return text directly
- Markers must appear as H2 headings (
##) at the start of a line in the agent's final output - The
Consumed by/Kindcolumns are machine-enforced bycheck:contract-drift(scripts/check-contract-drift.cjs), which cross-checks this table against what eachagents/*.mdfile actually emits in-fence and what everygsd-core/workflows/**,commands/**, andagents/**file actually consumes. Update this table whenever an agent's return contract changes -- a stale row is a violation the check will report, not something to leave for later. - A marker entry annotated
(unconsumed: <reason>)is emitted deliberately but matched by no workflow, command, or agent — e.g.## ROADMAP DRAFT, a presentation format a human approves interactively. The check still verifies the marker is declared and emitted, and still counts it for case-collision purposes; only the consumer requirement is waived. Use it for display formats, never to silence a real orphan.
Key Handoff Contracts
Planner -> Executor (via PLAN.md)
| Field | Required | Description |
|---|---|---|
| Frontmatter | Yes | phase, plan, type, wave, depends_on, files_modified, autonomous, requirements |
<objective> |
Yes | What the plan achieves |
<tasks> |
Yes | Ordered task list with type, files, action, verify, acceptance_criteria |
<verification> |
Yes | Overall verification steps |
<success_criteria> |
Yes | Measurable completion criteria |
Executor -> Verifier (via SUMMARY.md)
| Field | Required | Description |
|---|---|---|
| Frontmatter | Yes | phase, plan, subsystem, tags, key-files, metrics |
| Commits table | Yes | Per-task commit hashes and descriptions |
| Deviations section | Yes | Auto-fixed issues or "None" |
| Self-Check | Yes | PASSED or FAILED with details |
Workflow Regex Patterns
Workflows match these markers to detect agent completion:
plan-phase.md matches:
## RESEARCH COMPLETE/## RESEARCH BLOCKED(researcher output)## PLANNING COMPLETE(planner output)## CHECKPOINT REACHED(planner/executor pause)## VERIFICATION PASSED/## ISSUES FOUND(plan-checker output)
execute-phase.md matches:
## PHASE COMPLETE(all plans in phase done)## Self-Check: FAILED(summary self-check)
NOTE:
## PLAN COMPLETEis the gsd-executor's completion marker but execute-phase.md does not regex-match it. Instead, it detects executor completion via spot-checks (SUMMARY.md existence, git commit state). This is intentional behavior, not a mismatch.