mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-17 15:20:11 +02:00
feat(spec): expansions — flags, archive, quality gate, plan-mode-aware Phase 5, /ship integration, tests
Builds on the @jayzalowitz foundation (commit a4e6ee38) with the full
expansion set from CEO + Eng + DX review (24 user decisions + 23 of 28
codex adversarial findings).
spec/SKILL.md.tmpl additions:
- Flag reference table (--dedupe / --no-gate / --audit / --execute /
--no-execute / --file-only / --plan-file / --sync-archive).
- Phase 1b --dedupe (default ON): gh issue list --search with graceful
skip on gh-not-installed / unauthed / rate-limited / other errors.
AskUserQuestion when matches found (merge / file-new / cancel).
- Phase 3 HARD requirement: agent MUST grep/read at least one piece of
evidence before asking. Project-level fallback prose for prompts with
no concrete file mapping. Greenfield escape clause.
- Phase 4.5 quality gate (default ON): codex adversarial dispatch with
fail-closed redaction (AWS/GitHub/Anthropic/OpenAI/private-key regex),
hard <<<USER_SPEC>>> delimiters + instruction boundary (prompt-injection
defense), score 0-10 with <7 block, up to 3 iterations, AskUserQuestion
escape on persistent <7 (ship anyway / save draft / one more try).
- Phase 5 plan-mode-aware dispatch: reads GSTACK_PLAN_MODE env. Active
→ file-only + load into plan file. Inactive → file + --execute spawn
by default. CLI overrides for explicit control.
- Archive block via eval $(gstack-paths) → $GSTACK_STATE_ROOT/projects/
$SLUG/specs/<datetime>-<pid>-<slug>.md. Atomic .tmp/mv write. Sync
excluded by default; --sync-archive to opt in.
- --execute path: dirty-worktree gate (porcelain check + 3-option AUQ
continue/stash/cancel), TOCTOU re-check after AUQ answer, SHA pin
via git rev-parse HEAD, unique branch spec/<slug>-$$ + PID-suffixed
worktree, mandatory final-confirm gate, stash policy with restore
safety (preserve ref, never auto-drop).
- TTHW timestamps captured at Phase 1 / first citation / file-or-spawn,
emitted as ttfc_ms + tthw_ms in preamble telemetry envelope.
Cross-system plumbing:
- scripts/resolvers/preamble/generate-preamble-bash.ts: emit
GSTACK_PLAN_MODE=active|inactive based on CLAUDE_PLAN_FILE presence.
- scripts/resolvers/preamble/generate-routing-injection.ts: add /spec
to the routing block injected into project CLAUDE.md.
- ship/SKILL.md.tmpl: new "Linked Spec" PR-body section. Reads archive
frontmatter spec_issue_number and adds Closes #N when full delivery
confirmed by existing plan-completion gate (codex F4 — conditional).
Branch-name inference NOT used (codex F3 — fragile under rebase).
Tests (W7):
- test/spec-template-invariants.test.ts: 35 deterministic assertions
covering Phase 1 hard gate, Phase 3 hard-grep mandate, --dedupe
graceful-skip paths, --execute race + security hardening (TOCTOU,
SHA pin, unique branch), quality-gate redaction + BLOCKED path,
archive atomic write + sync exclusion, plan-mode-aware Phase 5.
- test/spec-template-sync.test.ts: regen + byte-identical check.
- test/skill-e2e-spec-execute.test.ts (periodic-tier scaffold).
- test/skill-llm-eval-spec.test.ts (periodic-tier scaffold).
- test/helpers/touchfiles.ts: register both periodics in E2E_TIERS +
LLM_JUDGE_TOUCHFILES.
37/37 /spec tests pass. Full bun test exit 0 (pre-existing
url-validation timeout unrelated to /spec).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -90,6 +90,19 @@ _CHECKPOINT_MODE=$(${ctx.paths.binDir}/gstack-config get checkpoint_mode 2>/dev/
|
||||
_CHECKPOINT_PUSH=$(${ctx.paths.binDir}/gstack-config get checkpoint_push 2>/dev/null || echo "false")
|
||||
echo "CHECKPOINT_MODE: $_CHECKPOINT_MODE"
|
||||
echo "CHECKPOINT_PUSH: $_CHECKPOINT_PUSH"
|
||||
# Plan-mode hint for skills like /spec that branch behavior on plan-mode state.
|
||||
# Claude Code exposes plan mode via system reminders; we detect best-effort
|
||||
# from CLAUDE_PLAN_FILE (set by the harness when plan mode is active) and
|
||||
# fall back to "inactive". Codex hosts and Claude execution mode both end up
|
||||
# inactive, which is the safe default (defaults to file+execute pipeline).
|
||||
if [ -n "\${CLAUDE_PLAN_FILE:-}\${GSTACK_PLAN_MODE_FORCE:-}" ]; then
|
||||
export GSTACK_PLAN_MODE="active"
|
||||
elif [ "\${GSTACK_PLAN_MODE:-}" = "active" ]; then
|
||||
export GSTACK_PLAN_MODE="active"
|
||||
else
|
||||
export GSTACK_PLAN_MODE="inactive"
|
||||
fi
|
||||
echo "GSTACK_PLAN_MODE: $GSTACK_PLAN_MODE"
|
||||
[ -n "$OPENCLAW_SESSION" ] && echo "SPAWNED_SESSION: true" || true${ctx.host === 'gbrain' || ctx.host === 'hermes' ? `
|
||||
if command -v gbrain &>/dev/null; then
|
||||
_BRAIN_JSON=$(gbrain doctor --fast --json 2>/dev/null || echo '{}')
|
||||
|
||||
@@ -33,6 +33,7 @@ Key routing rules:
|
||||
- Ship/deploy/PR → invoke /ship or /land-and-deploy
|
||||
- Save progress → invoke /context-save
|
||||
- Resume context → invoke /context-restore
|
||||
- Author a backlog-ready spec/issue → invoke /spec
|
||||
\`\`\`
|
||||
|
||||
Then commit the change: \`git add CLAUDE.md && git commit -m "chore: add gstack skill routing rules to CLAUDE.md"\`
|
||||
|
||||
Reference in New Issue
Block a user