mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-20 00:30:10 +02:00
b5c65c70cc
The /plan-eng-review skill failed to fire AskUserQuestion on a real plan review and surfaced 4 calibration decisions via prose instead. Investigation traced this to a "fallback when neither variant is callable" clause in the preamble that the model rationalizes around as a general escape hatch from "fanning out round-trip AUQs," even when an AUQ variant IS callable. Codex review confirmed the fallback exists in 8 inline sites with 2 surviving escape hatches the original narrowing missed (a "genuinely trivial" exception duplicated across all 4 plan-* templates, and a "outside plan mode, output as prose and stop" branch in the preamble itself). Net deletion in skill text. Closes both branches of the deleted fallback (plan-file write AND prose-and-stop) and the trivial-fix exception with a single hard rule: If no AskUserQuestion variant appears in your tool list, this skill is BLOCKED. Stop, report `BLOCKED — AskUserQuestion unavailable`, and wait for the user. Honest about being a model directive, not a runtime guard — none of the PTY harness helpers enforce BLOCKED today. The architectural improvement is that the model has fewer alternatives to obey it against. Runtime enforcement is a follow-up TODO. Sources changed: - scripts/resolvers/preamble/generate-ask-user-format.ts: delete both fallback branches; replace with 1-line BLOCKED rule - scripts/resolvers/preamble/generate-completion-status.ts: delete fallback in generatePlanModeInfo - plan-eng-review/SKILL.md.tmpl: delete fallback at Step 0 + Sections 1-4 (5 instances) + delete trivial-fix exception - office-hours/SKILL.md.tmpl: delete fallback in approach-selection - plan-ceo-review/SKILL.md.tmpl: delete trivial-fix exception - plan-design-review/SKILL.md.tmpl: delete trivial-fix exception - plan-devex-review/SKILL.md.tmpl: delete trivial-fix exception Generated SKILL.md regen lands in a follow-up commit per the bisect convention (template changes separate from regenerated output). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
88 lines
5.1 KiB
TypeScript
88 lines
5.1 KiB
TypeScript
import type { TemplateContext } from '../types';
|
|
|
|
/**
|
|
* Plan-mode-skill semantics block.
|
|
*
|
|
* Lives at the TOP of the preamble (position 1) so models read the authoritative
|
|
* plan-mode rule before any other instructions. Replaces the vestigial
|
|
* generate-plan-mode-handshake.ts that used to sit at this position and told
|
|
* interactive review skills to emit an exit-and-rerun handshake instead of
|
|
* running their interactive STOP-Ask workflow.
|
|
*
|
|
* Text is the same "Plan Mode Safe Operations" + "Skill Invocation During Plan
|
|
* Mode" blocks that previously lived at the tail of generateCompletionStatus().
|
|
* Only the position changes. All skills (not just interactive: true) see this.
|
|
*
|
|
* Composition position: index 1 in scripts/resolvers/preamble.ts — after
|
|
* generatePreambleBash (so _SESSION_ID / _BRANCH / _TEL env vars exist before
|
|
* any plan-mode-aware telemetry) and before generateUpgradeCheck + onboarding
|
|
* gates. See ceo-plan 2026-04-24 "remove vestigial plan-mode handshake" for
|
|
* the full rationale.
|
|
*/
|
|
export function generatePlanModeInfo(_ctx: TemplateContext): string {
|
|
return `## Plan Mode Safe Operations
|
|
|
|
In plan mode, allowed because they inform the plan: \`$B\`, \`$D\`, \`codex exec\`/\`codex review\`, writes to \`~/.gstack/\`, writes to the plan file, and \`open\` for generated artifacts.
|
|
|
|
## Skill Invocation During Plan Mode
|
|
|
|
If the user invokes a skill in plan mode, the skill takes precedence over generic plan mode behavior. **Treat the skill file as executable instructions, not reference.** Follow it step by step starting from Step 0; the first AskUserQuestion is the workflow entering plan mode, not a violation of it. AskUserQuestion (any variant — \`mcp__*__AskUserQuestion\` or native; see "AskUserQuestion Format → Tool resolution") satisfies plan mode's end-of-turn requirement. If no variant is callable, the skill is BLOCKED — stop and report \`BLOCKED — AskUserQuestion unavailable\` per the AskUserQuestion Format rule. At a STOP point, stop immediately. Do not continue the workflow or call ExitPlanMode there. Commands marked "PLAN MODE EXCEPTION — ALWAYS RUN" execute. Call ExitPlanMode only after the skill workflow completes, or if the user tells you to cancel the skill or leave plan mode.`;
|
|
}
|
|
|
|
export function generateCompletionStatus(ctx: TemplateContext): string {
|
|
return `## Completion Status Protocol
|
|
|
|
When completing a skill workflow, report status using one of:
|
|
- **DONE** — completed with evidence.
|
|
- **DONE_WITH_CONCERNS** — completed, but list concerns.
|
|
- **BLOCKED** — cannot proceed; state blocker and what was tried.
|
|
- **NEEDS_CONTEXT** — missing info; state exactly what is needed.
|
|
|
|
Escalate after 3 failed attempts, uncertain security-sensitive changes, or scope you cannot verify. Format: \`STATUS\`, \`REASON\`, \`ATTEMPTED\`, \`RECOMMENDATION\`.
|
|
|
|
## Operational Self-Improvement
|
|
|
|
Before completing, if you discovered a durable project quirk or command fix that would save 5+ minutes next time, log it:
|
|
|
|
\`\`\`bash
|
|
${ctx.paths.binDir}/gstack-learnings-log '{"skill":"SKILL_NAME","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"source":"observed"}'
|
|
\`\`\`
|
|
|
|
Do not log obvious facts or one-time transient errors.
|
|
|
|
## Telemetry (run last)
|
|
|
|
After workflow completion, log telemetry. Use skill \`name:\` from frontmatter. OUTCOME is success/error/abort/unknown.
|
|
|
|
**PLAN MODE EXCEPTION — ALWAYS RUN:** This command writes telemetry to
|
|
\`~/.gstack/analytics/\`, matching preamble analytics writes.
|
|
|
|
Run this bash:
|
|
|
|
\`\`\`bash
|
|
_TEL_END=$(date +%s)
|
|
_TEL_DUR=$(( _TEL_END - _TEL_START ))
|
|
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
|
|
# Session timeline: record skill completion (local-only, never sent anywhere)
|
|
~/.claude/skills/gstack/bin/gstack-timeline-log '{"skill":"SKILL_NAME","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true
|
|
# Local analytics (gated on telemetry setting)
|
|
if [ "$_TEL" != "off" ]; then
|
|
echo '{"skill":"SKILL_NAME","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
|
|
fi
|
|
# Remote telemetry (opt-in, requires binary)
|
|
if [ "$_TEL" != "off" ] && [ -x ~/.claude/skills/gstack/bin/gstack-telemetry-log ]; then
|
|
~/.claude/skills/gstack/bin/gstack-telemetry-log \\
|
|
--skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \\
|
|
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
|
|
fi
|
|
\`\`\`
|
|
|
|
Replace \`SKILL_NAME\`, \`OUTCOME\`, and \`USED_BROWSE\` before running.
|
|
|
|
## Plan Status Footer
|
|
|
|
In plan mode before ExitPlanMode: if the plan file lacks \`## GSTACK REVIEW REPORT\`, run \`~/.claude/skills/gstack/bin/gstack-review-read\` and append the standard runs/status/findings table. With \`NO_REVIEWS\` or empty, append a 5-row placeholder with verdict "NO REVIEWS YET — run \`/autoplan\`". If a richer report exists, skip.
|
|
|
|
PLAN MODE EXCEPTION — always allowed (it's the plan file).`;
|
|
}
|