mirror of https://github.com/garrytan/gstack.git
refactor(resolvers): one source for the design-doc discovery block
The #703 repo-doc-preference bash was pasted byte-identically into three plan-review templates and a fourth copy embedded in review.ts — drift there means plan reviews disagree about which design doc wins. Now a {{DESIGN_DOC_DISCOVERY}} resolver; generated output is byte-identical, so no SKILL.md changes ride along.
This commit is contained in:
parent
bebb09b03f
commit
808344ecfd
|
|
@ -138,22 +138,7 @@ Then read CLAUDE.md, TODOS.md, and any existing architecture docs.
|
|||
setopt +o nomatch 2>/dev/null || true # zsh compat
|
||||
SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch')
|
||||
_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1)
|
||||
[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1)
|
||||
# Repo-local docs win when at least as fresh (#703): office-hours dual-writes
|
||||
# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates
|
||||
# see. A stale old repo doc never shadows a newer private session.
|
||||
_REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
_REPODOC=""
|
||||
if [ -n "$_REPOTOP" ]; then
|
||||
[ -f "$_REPOTOP/DESIGN.md" ] && _REPODOC="$_REPOTOP/DESIGN.md"
|
||||
[ -z "$_REPODOC" ] && _REPODOC=$(ls -t "$_REPOTOP"/docs/designs/*.md 2>/dev/null | head -1)
|
||||
fi
|
||||
DESIGN="$_LOCALDOC"
|
||||
if [ -n "$_REPODOC" ] && { [ -z "$_LOCALDOC" ] || [ "$_REPODOC" -nt "$_LOCALDOC" ]; }; then
|
||||
DESIGN="$_REPODOC"
|
||||
fi
|
||||
[ -n "$DESIGN" ] && echo "Design doc found: $DESIGN" || echo "No design doc found"
|
||||
{{DESIGN_DOC_DISCOVERY}}
|
||||
```
|
||||
If a design doc exists (from `/office-hours`), read it. Use it as the source of truth for the problem statement, constraints, and chosen approach. If it has a `Supersedes:` field, note that this is a revised design.
|
||||
|
||||
|
|
|
|||
|
|
@ -99,22 +99,7 @@ Then read:
|
|||
setopt +o nomatch 2>/dev/null || true
|
||||
SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch')
|
||||
_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1)
|
||||
[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1)
|
||||
# Repo-local docs win when at least as fresh (#703): office-hours dual-writes
|
||||
# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates
|
||||
# see. A stale old repo doc never shadows a newer private session.
|
||||
_REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
_REPODOC=""
|
||||
if [ -n "$_REPOTOP" ]; then
|
||||
[ -f "$_REPOTOP/DESIGN.md" ] && _REPODOC="$_REPOTOP/DESIGN.md"
|
||||
[ -z "$_REPODOC" ] && _REPODOC=$(ls -t "$_REPOTOP"/docs/designs/*.md 2>/dev/null | head -1)
|
||||
fi
|
||||
DESIGN="$_LOCALDOC"
|
||||
if [ -n "$_REPODOC" ] && { [ -z "$_LOCALDOC" ] || [ "$_REPODOC" -nt "$_LOCALDOC" ]; }; then
|
||||
DESIGN="$_REPODOC"
|
||||
fi
|
||||
[ -n "$DESIGN" ] && echo "Design doc found: $DESIGN" || echo "No design doc found"
|
||||
{{DESIGN_DOC_DISCOVERY}}
|
||||
```
|
||||
If a design doc exists, read it.
|
||||
|
||||
|
|
|
|||
|
|
@ -112,22 +112,7 @@ When evaluating architecture, think "boring by default." When reviewing tests, t
|
|||
setopt +o nomatch 2>/dev/null || true # zsh compat
|
||||
SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch')
|
||||
_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1)
|
||||
[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1)
|
||||
# Repo-local docs win when at least as fresh (#703): office-hours dual-writes
|
||||
# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates
|
||||
# see. A stale old repo doc never shadows a newer private session.
|
||||
_REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
_REPODOC=""
|
||||
if [ -n "$_REPOTOP" ]; then
|
||||
[ -f "$_REPOTOP/DESIGN.md" ] && _REPODOC="$_REPOTOP/DESIGN.md"
|
||||
[ -z "$_REPODOC" ] && _REPODOC=$(ls -t "$_REPOTOP"/docs/designs/*.md 2>/dev/null | head -1)
|
||||
fi
|
||||
DESIGN="$_LOCALDOC"
|
||||
if [ -n "$_REPODOC" ] && { [ -z "$_LOCALDOC" ] || [ "$_REPODOC" -nt "$_LOCALDOC" ]; }; then
|
||||
DESIGN="$_REPODOC"
|
||||
fi
|
||||
[ -n "$DESIGN" ] && echo "Design doc found: $DESIGN" || echo "No design doc found"
|
||||
{{DESIGN_DOC_DISCOVERY}}
|
||||
```
|
||||
If a design doc exists, read it. Use it as the source of truth for the problem statement, constraints, and chosen approach. If it has a `Supersedes:` field, note that this is a revised design — check the prior version for context on what changed and why.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* {{DESIGN_DOC_DISCOVERY}} — the canonical design-doc discovery block (#703).
|
||||
*
|
||||
* Finds the design doc a plan review should read: newest branch-scoped doc
|
||||
* under ~/.gstack/projects/<slug>/, falling back to newest project-scoped
|
||||
* doc, then lets a repo-local doc (DESIGN.md or docs/designs/*.md) win when
|
||||
* it is at least as fresh. office-hours dual-writes docs/designs/ alongside
|
||||
* ~/.gstack, and the committed copy is what teammates see — but a stale old
|
||||
* repo doc must never shadow a newer private session.
|
||||
*
|
||||
* Single source of truth for the freshness-preference logic that previously
|
||||
* lived verbatim in plan-ceo-review, plan-eng-review, plan-devex-review, and
|
||||
* the prerequisite-skill re-check in review.ts (GStack 2 fork-port wave,
|
||||
* time-attack/gstack). Drift between copies meant plan reviews could
|
||||
* disagree about which design doc wins.
|
||||
*
|
||||
* The fragment carries no code fences — the {{DESIGN_DOC_DISCOVERY}} token
|
||||
* sits inside each caller's ```bash block. Callers must set $SLUG and
|
||||
* $BRANCH first (and `setopt +o nomatch` for zsh); the block sets $DESIGN
|
||||
* and prints "Design doc found: ..." or "No design doc found".
|
||||
*/
|
||||
|
||||
import type { TemplateContext } from './types';
|
||||
|
||||
/**
|
||||
* Raw canonical fragment, exported so TS resolvers (review.ts's prerequisite
|
||||
* re-check) can interpolate it into their own template strings instead of
|
||||
* embedding a drifting copy.
|
||||
*/
|
||||
export const DESIGN_DOC_DISCOVERY_BLOCK = `_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1)
|
||||
[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1)
|
||||
# Repo-local docs win when at least as fresh (#703): office-hours dual-writes
|
||||
# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates
|
||||
# see. A stale old repo doc never shadows a newer private session.
|
||||
_REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
_REPODOC=""
|
||||
if [ -n "$_REPOTOP" ]; then
|
||||
[ -f "$_REPOTOP/DESIGN.md" ] && _REPODOC="$_REPOTOP/DESIGN.md"
|
||||
[ -z "$_REPODOC" ] && _REPODOC=$(ls -t "$_REPOTOP"/docs/designs/*.md 2>/dev/null | head -1)
|
||||
fi
|
||||
DESIGN="$_LOCALDOC"
|
||||
if [ -n "$_REPODOC" ] && { [ -z "$_LOCALDOC" ] || [ "$_REPODOC" -nt "$_LOCALDOC" ]; }; then
|
||||
DESIGN="$_REPODOC"
|
||||
fi
|
||||
[ -n "$DESIGN" ] && echo "Design doc found: $DESIGN" || echo "No design doc found"`;
|
||||
|
||||
export function generateDesignDocDiscovery(_ctx: TemplateContext): string {
|
||||
return DESIGN_DOC_DISCOVERY_BLOCK;
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ import { generateTasksSectionEmit, generateTasksSectionAggregate } from './tasks
|
|||
import { SECTION, SECTION_INDEX } from './sections';
|
||||
import { generateRedactTaxonomyTable, generateRedactInvocationBlock } from './redact-doc';
|
||||
import { generateThirdPartyActions } from './third-party-actions';
|
||||
import { generateDesignDocDiscovery } from './design-doc-discovery';
|
||||
|
||||
export const RESOLVERS: Record<string, ResolverValue> = {
|
||||
SLUG_EVAL: generateSlugEval,
|
||||
|
|
@ -44,6 +45,7 @@ export const RESOLVERS: Record<string, ResolverValue> = {
|
|||
REDACT_TAXONOMY_TABLE: generateRedactTaxonomyTable,
|
||||
REDACT_INVOCATION_BLOCK: generateRedactInvocationBlock,
|
||||
THIRD_PARTY_ACTIONS: generateThirdPartyActions,
|
||||
DESIGN_DOC_DISCOVERY: generateDesignDocDiscovery,
|
||||
COMMAND_REFERENCE: generateCommandReference,
|
||||
SNAPSHOT_FLAGS: generateSnapshotFlags,
|
||||
PREAMBLE: generatePreamble,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
import type { TemplateContext } from './types';
|
||||
import { generateInvokeSkill } from './composition';
|
||||
import { codexPreflight, codexErrorHandling } from './constants';
|
||||
import { DESIGN_DOC_DISCOVERY_BLOCK } from './design-doc-discovery';
|
||||
|
||||
const CODEX_BOUNDARY = 'IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\\n\\n';
|
||||
|
||||
|
|
@ -309,22 +310,7 @@ After /${first} completes, re-run the design doc check:
|
|||
setopt +o nomatch 2>/dev/null || true # zsh compat
|
||||
SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '-' || echo 'no-branch')
|
||||
_LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-$BRANCH-design-*.md 2>/dev/null | head -1)
|
||||
[ -z "$_LOCALDOC" ] && _LOCALDOC=$(ls -t ~/.gstack/projects/$SLUG/*-design-*.md 2>/dev/null | head -1)
|
||||
# Repo-local docs win when at least as fresh (#703): office-hours dual-writes
|
||||
# docs/designs/ alongside ~/.gstack, and the committed copy is what teammates
|
||||
# see. A stale old repo doc never shadows a newer private session.
|
||||
_REPOTOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
_REPODOC=""
|
||||
if [ -n "$_REPOTOP" ]; then
|
||||
[ -f "$_REPOTOP/DESIGN.md" ] && _REPODOC="$_REPOTOP/DESIGN.md"
|
||||
[ -z "$_REPODOC" ] && _REPODOC=$(ls -t "$_REPOTOP"/docs/designs/*.md 2>/dev/null | head -1)
|
||||
fi
|
||||
DESIGN="$_LOCALDOC"
|
||||
if [ -n "$_REPODOC" ] && { [ -z "$_LOCALDOC" ] || [ "$_REPODOC" -nt "$_LOCALDOC" ]; }; then
|
||||
DESIGN="$_REPODOC"
|
||||
fi
|
||||
[ -n "$DESIGN" ] && echo "Design doc found: $DESIGN" || echo "No design doc found"
|
||||
${DESIGN_DOC_DISCOVERY_BLOCK}
|
||||
\`\`\`
|
||||
|
||||
If a design doc is now found, read it and continue the review.
|
||||
|
|
|
|||
Loading…
Reference in New Issue