* fix(#373): replace unquoted $GSD_SDK with space-safe gsd_run launcher Workflow bash blocks resolved the runtime as GSD_SDK="node $GSD_TOOLS" and invoked it unquoted ($GSD_SDK query ...). On install paths containing spaces (e.g. /Volumes/Mini Me/...) the unquoted expansion word-split into `node /Volumes/Mini gsd-tools.cjs ...`, failing with "Cannot find module '/Volumes/Mini'" and getting masked by `2>/dev/null || echo "{}"` into a silent empty state. Replace the string variable with a single-line shell launcher that defines a gsd_run function, invokes the runtime with a fully-quoted path and "$@", and preserves the local-cjs / installed-gsd-tools-on-PATH fallback (#3668) plus the loud not-found error and install hint. The launcher uses _GSD_SHIM_NAME indirection so no workflow emits the /gsd-tools substring that the do.md dispatcher-parity scanner would misread, and is single-line to stay within the per-file progressive-disclosure line budgets (#2551). The canonical launcher lives in get-shit-done/workflows/_runtime-launcher.snippet.sh, is propagated once per file by scripts/sync-runtime-launcher.cjs, and is locked by tests/runtime-launcher-parity.test.cjs (fails CI on drift, on a reappearing $GSD_SDK token, or on a /gsd-tools substring). Dependent workflow-assertion tests are updated from $GSD_SDK to gsd_run, and the runtime launcher is registered in CONTEXT.md. Fixes #373 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(#373): add changeset fragment and allow-test-rule for parity guard The runtime-launcher parity test is a structural drift guard that reads workflow markdown to assert the canonical launcher is present and the retired $GSD_SDK / /gsd-tools tokens are absent; annotate it with allow-test-rule per the no-source-grep lint escape hatch. Add the required .changeset fragment for this user-facing fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(#373): make parity PATH-fallback assertion cross-platform (Windows) Subtest (E) compared GSD_TOOLS against the Node-side absolute temp path, but the value originates from git-bash which reports the POSIX form, so the prefix comparison failed on windows-latest while the launcher itself worked (the installed stub was invoked). Assert the resolved binary by normalized suffix (/bin/gsd-tools, not .cjs) instead of the absolute prefix; the behavioral stub-invocation assertion is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
179 lines
6.8 KiB
Markdown
179 lines
6.8 KiB
Markdown
<purpose>
|
|
Autonomous audit-to-fix pipeline. Runs an audit, parses findings, classifies each as
|
|
auto-fixable vs manual-only, spawns executor agents for fixable issues, runs tests
|
|
after each fix, and commits atomically with finding IDs for traceability.
|
|
</purpose>
|
|
|
|
<available_agent_types>
|
|
- gsd-executor — executes a specific, scoped code change
|
|
</available_agent_types>
|
|
|
|
<process>
|
|
|
|
<step name="parse-arguments">
|
|
Extract flags from the user's invocation:
|
|
|
|
- `--max N` — maximum findings to fix (default: **5**)
|
|
- `--severity high|medium|all` — minimum severity to process (default: **medium**)
|
|
- `--dry-run` — classify findings without fixing (shows classification table only)
|
|
- `--source <audit>` — which audit to run (default: **audit-uat**)
|
|
|
|
Validate `--source` is a supported audit. Currently supported:
|
|
- `audit-uat`
|
|
|
|
If `--source` is not supported, stop with an error:
|
|
```
|
|
Error: Unsupported audit source "{source}". Supported sources: audit-uat
|
|
```
|
|
</step>
|
|
|
|
<step name="run-audit">
|
|
Invoke the source audit command and capture output.
|
|
|
|
For `audit-uat` source:
|
|
```bash
|
|
_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi
|
|
INIT=$(gsd_run query audit-uat 2>/dev/null || echo "{}")
|
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
```
|
|
|
|
Read existing UAT and verification files to extract findings:
|
|
- Glob: `.planning/phases/*/*-UAT.md`
|
|
- Glob: `.planning/phases/*/*-VERIFICATION.md`
|
|
|
|
Parse each finding into a structured record:
|
|
- **ID** — sequential identifier (F-01, F-02, ...)
|
|
- **description** — concise summary of the issue
|
|
- **severity** — high, medium, or low
|
|
- **file_refs** — specific file paths referenced in the finding
|
|
</step>
|
|
|
|
<step name="classify-findings">
|
|
For each finding, classify as one of:
|
|
|
|
- **auto-fixable** — clear code change, specific file referenced, testable fix
|
|
- **manual-only** — requires design decisions, ambiguous scope, architectural changes, user input needed
|
|
- **skip** — severity below the `--severity` threshold
|
|
|
|
**Classification heuristics** (err on manual-only when uncertain):
|
|
|
|
Auto-fixable signals:
|
|
- References a specific file path + line number
|
|
- Describes a missing test or assertion
|
|
- Missing export, wrong import path, typo in identifier
|
|
- Clear single-file change with obvious expected behavior
|
|
|
|
Manual-only signals:
|
|
- Uses words like "consider", "evaluate", "design", "rethink"
|
|
- Requires new architecture or API changes
|
|
- Ambiguous scope or multiple valid approaches
|
|
- Requires user input or design decisions
|
|
- Cross-cutting concerns affecting multiple subsystems
|
|
- Performance or scalability issues without clear fix
|
|
|
|
**When uncertain, always classify as manual-only.**
|
|
</step>
|
|
|
|
<step name="present-classification">
|
|
Display the classification table:
|
|
|
|
```
|
|
## Audit-Fix Classification
|
|
|
|
| # | Finding | Severity | Classification | Reason |
|
|
|---|---------|----------|---------------|--------|
|
|
| F-01 | Missing export in index.ts | high | auto-fixable | Specific file, clear fix |
|
|
| F-02 | No error handling in payment flow | high | manual-only | Requires design decisions |
|
|
| F-03 | Test stub with 0 assertions | medium | auto-fixable | Clear test gap |
|
|
```
|
|
|
|
If `--dry-run` was specified, **stop here and exit**. The classification table is the
|
|
final output — do not proceed to fixing.
|
|
</step>
|
|
|
|
<step name="fix-loop">
|
|
For each **auto-fixable** finding (up to `--max`, ordered by severity desc):
|
|
|
|
**a. Spawn executor agent:**
|
|
```
|
|
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"
|
|
)
|
|
```
|
|
|
|
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
|
|
|
|
**b. Run tests:**
|
|
```bash
|
|
AUDIT_TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true)
|
|
if [ -z "$AUDIT_TEST_CMD" ]; then
|
|
if [ -f "Makefile" ] && grep -q "^test:" Makefile; then
|
|
AUDIT_TEST_CMD="make test"
|
|
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
|
AUDIT_TEST_CMD="just test"
|
|
elif [ -f "package.json" ]; then
|
|
AUDIT_TEST_CMD="npm test"
|
|
elif [ -f "Cargo.toml" ]; then
|
|
AUDIT_TEST_CMD="cargo test"
|
|
elif [ -f "go.mod" ]; then
|
|
AUDIT_TEST_CMD="go test ./..."
|
|
elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
|
|
AUDIT_TEST_CMD="python -m pytest -x -q --tb=short"
|
|
else
|
|
AUDIT_TEST_CMD="true"
|
|
fi
|
|
fi
|
|
eval "$AUDIT_TEST_CMD" 2>&1 | tail -20
|
|
```
|
|
|
|
**c. If tests pass** — commit atomically:
|
|
```bash
|
|
git add {changed_files}
|
|
git commit -m "fix({scope}): resolve {ID} — {description}"
|
|
```
|
|
The commit message **must** include the finding ID (e.g., F-01) for traceability.
|
|
|
|
**d. If tests fail** — revert changes, mark finding as `fix-failed`, and **stop the pipeline**:
|
|
```bash
|
|
git checkout -- {changed_files} 2>/dev/null
|
|
```
|
|
Log the failure reason and stop processing — do not continue to the next finding.
|
|
A test failure indicates the codebase may be in an unexpected state, so the pipeline
|
|
must halt to avoid cascading issues. Remaining auto-fixable findings will appear in the
|
|
report as `not-attempted`.
|
|
</step>
|
|
|
|
<step name="report">
|
|
Present the final summary:
|
|
|
|
```
|
|
## Audit-Fix Complete
|
|
|
|
**Source:** {audit_command}
|
|
**Findings:** {total} total, {auto} auto-fixable, {manual} manual-only
|
|
**Fixed:** {fixed_count}/{auto} auto-fixable findings
|
|
**Failed:** {failed_count} (reverted)
|
|
|
|
| # | Finding | Status | Commit |
|
|
|---|---------|--------|--------|
|
|
| F-01 | Missing export | Fixed | abc1234 |
|
|
| F-03 | Test stub | Fix failed | (reverted) |
|
|
|
|
### Manual-only findings (require developer attention):
|
|
- F-02: No error handling in payment flow — requires design decisions
|
|
```
|
|
</step>
|
|
|
|
</process>
|
|
|
|
<success_criteria>
|
|
- Auto-fixable findings processed sequentially until --max reached or a test failure stops the pipeline
|
|
- Tests pass after each committed fix (no broken commits)
|
|
- Failed fixes are reverted cleanly (no partial changes left)
|
|
- Pipeline stops after the first test failure (no cascading fixes)
|
|
- Every commit message contains the finding ID
|
|
- Manual-only findings are surfaced for developer attention
|
|
- --dry-run produces a useful standalone classification table
|
|
</success_criteria>
|