mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-05-14 02:56:38 +02:00
MAJOR (security/correctness): - commands/gsd/debug.md: add Write to allowed-tools (session file creation requires it — workflow explicitly says 'use Write tool, never heredoc') - workflows/debug.md: add SLUG sanitization guard to steps 1b+1c (status/ continue subcommands used raw user input in file paths — path traversal) - workflows/thread.md: sanitize $ARGUMENTS in RESUME mode before file path construction (was bypassing the sanitization guard in CLOSE/STATUS modes) MINOR (consistency/correctness): - docs/INVENTORY-MANIFEST.json: remove stale top-level 'workflows' array (duplicate of families.workflows introduced in earlier update) - commands/gsd/resume-work.md: normalize process to 'Execute end-to-end.' - commands/gsd/settings.md: normalize process to 'Execute end-to-end.' - commands/gsd/update.md: normalize otherwise branch to 'execute end-to-end.' - docs/adr/0002: add Status: Accepted + Date header (ADR convention) - workflows/extract-learnings.md: rename step extract_learnings → extract-learnings - tests/extract-learnings.test.cjs: tighten step-name assertion to exact name ARCHITECTURE: - scripts/command-contract-helpers.cjs: extract CANONICAL_TOOLS, parseFrontmatter, executionContextRefs as shared module — single source of truth consumed by both lint script and test suite (prevents silent lint/test disagreement) - scripts/lint-command-contract.cjs: require() helpers instead of duplicating - tests/command-contract.test.cjs: require() helpers; move readFileSync calls inside test() callbacks (registration-time throws surface as named failures)
39 lines
3.1 KiB
Markdown
39 lines
3.1 KiB
Markdown
# Command Contract Validation Module
|
|
|
|
- **Status:** Accepted
|
|
- **Date:** 2026-05-05
|
|
|
|
We decided to centralize the `commands/gsd/*.md` file contract into a single validation seam enforced at two layers: a fast lint script (`scripts/lint-command-contract.cjs`) that runs as a pre-test CI step, and a behavioral regression test (`tests/command-contract.test.cjs`) that validates the full contract against the live filesystem.
|
|
|
|
## Decision
|
|
|
|
The command file contract defines what makes a valid `commands/gsd/*.md`:
|
|
|
|
- `name:` field present, non-empty, matches `gsd:*` or `gsd-*` (ns- commands use `gsd-`)
|
|
- `description:` field present and non-empty
|
|
- `allowed-tools:` block present and non-empty, all entries from the canonical tool set
|
|
- Every `@`-reference inside `<execution_context>` blocks resolves to an existing file on disk
|
|
- `@`-references inside `<execution_context>` blocks appear on their own line (no trailing prose)
|
|
|
|
## Context
|
|
|
|
Before this ADR, the command contract was enforced inconsistently:
|
|
- `tests/enh-2790-skill-consolidation.test.cjs` checked existence and frontmatter of specific post-consolidation commands
|
|
- `tests/bug-3135-capture-backlog-workflow.test.cjs` checked `execution_context` @-ref resolution (added 2026-05-05)
|
|
- No test checked `allowed-tools` validity, `name:` convention, or `description:` non-emptiness across all commands simultaneously
|
|
|
|
This meant any PR touching a command file could break the contract without a single test catching it. The `add-backlog.md` gap (#3135) is a concrete example: the workflow file was missing for the full consolidation cycle before a targeted regression test was written.
|
|
|
|
Additionally, 40 of 65 command files contained redundant prose @-references — the same path appearing once in `<execution_context>` (which loads the file) and again in `<process>` body text (inert). This added ~900 tokens of dead weight per invocation and created a drift seam where prose refs could go stale independently of the executable `execution_context` ref.
|
|
|
|
The two largest commands (`debug.md`, `thread.md`) embedded their full implementation inline rather than delegating to workflow files, causing ~4,400 tokens of implementation detail to load as part of the skills index description on every session regardless of whether those commands are used.
|
|
|
|
## Consequences
|
|
|
|
- A single `lint-command-contract.cjs` script enforces frontmatter invariants across all 65 commands in milliseconds, runs before the test suite in CI
|
|
- `tests/command-contract.test.cjs` replaces the scattered contract coverage in `enh-2790` and `bug-3135`, becoming the authoritative behavioral contract test for the entire command surface
|
|
- Redundant prose @-refs removed from 40 command files (~900 tokens/invocation recovered)
|
|
- `debug.md` and `thread.md` refactored to the workflow-delegation pattern (~4,400 tokens removed from eager system-prompt load)
|
|
- `workflows/extract_learnings.md` renamed to `workflows/extract-learnings.md` to align with the hyphen convention used by all other workflow files
|
|
- The `execution_context` block is the single authoritative declaration of what a command loads — no duplication in prose
|