* chore(#2994): fragmentize progress.md forensic audit onto the fragment model Extract the --forensic-gated forensic_audit step to workflows/progress/steps/forensic-audit.md behind a section marker, and repair progress.md's init line to forward --forensic so the atom is actually true in production rather than only under direct CLI tests. progress.md shrinks 32630 -> 27207 bytes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): fragmentize the four manifest-wired workflows new-project, quick, new-milestone and progress each already had a dedicated cmdInit* entry point but zero marked sections. Extract nine gated bodies to workflows/<wf>/steps/ behind section markers and repair each init line to forward its flags. Fold --full into the discuss/research/validate facts inside cmdInitQuick so the when= grammar never sees an OR, per the chunked-mode precedent. Fixes found while working, per the no-defer rule: - cmdInitProgress passed no phase info to buildSectionManifestField, so state:phase-mvp-mode was permanently false — an atom in the vocabulary whose fact could never be computed. - the quick init router folded flag tokens into the free-text description, which the new forwarding would have corrupted. - a #2508 dispatch note was nested inside quick.md's Agent(prompt=) fence, leaking orchestrator guidance into the subagent prompt. - progress.md had a 3-vs-4 backtick outer-fence imbalance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): fragmentize verify-work.md and admit state:ui-phase-active Wire cmdInitVerifyWork to buildSectionManifestField — it was a dedicated entry point that never emitted a manifest — and mark two sections. state:ui-phase-active folds (plan:pre hooks include an active ui step) OR (the phase dir holds a *-UI-SPEC.md) into one boolean in init.cts, so the grammar still sees a single operator-free atom. The inner Playwright-MCP check stays as prose inside the fragment: it is live session state and no init seam can precompute it. The MVP false-branch note is a real fallback, not redundant prose, so it sits outside the marker — gating it away would delete the text needed precisely when MVP mode is off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(#2994): follow moved workflow content in drift guards Retarget every guard that asserted on content this branch moved into workflows/<wf>/steps/, mirroring 815b3d897. Each retargeted assertion was verified to still fail when its step file is blanked, so none was weakened into vacuity. Three assertions in verify-mvp-uat were genuinely red. Three more were worse than red — passing for the wrong reason: - quick-commit-boundary and worktree-cleanup anchored on indexOf('Step 5.6'), which matched a later cross-reference and sliced 16069 chars that coincidentally held the asserted substrings. Replaced with an expandWorkflowSections helper that splices step content back in place. - phase6-review-capabilities lost its end boundary and widened to EOF. - playwright-ui-verify matched 'UI' in an unrelated bullet and 'fall back' in a subagent-dispatch line after the real content moved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): fragmentize code-review and complete-milestone, admit three atoms Add dedicated cmdInitCodeReview and cmdInitCompleteMilestone entry points alongside the shared generic ones rather than modifying them — init.phase-op and init.manager carry a CRITICAL blast radius (179 dependents, 24 processes) and stay byte-identical for their other callers. Admit flag:--fix, state:fallow-enabled and state:git-create-tag, each with a consuming section and a fact its own entry point computes. Both sections had the resolver-in-body hazard: the fallow config-gate and the git.create_tag check each sat inside the very block being gated, so gating would have disabled the resolver that decides the gate. Both are hoisted into init and the bodies now consume the resolved fact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(#2994): retarget code-review and milestone drift guards, fix two red tests Retarget guards that asserted on content moved into steps/, proving non-vacuity by blanking each step file and confirming failure. Also fixes two genuinely red tests found while working, per the no-defer rule: - workflow-fragments' frozen-vocabulary lock was missing state:ui-phase-active, so commit 7ef7f8336 shipped red. Lint and build both passed over it, which is why neither is sufficient verification. - code-review's quick.md capability-hook assertion carried a stale delimiter after the 18ff35d20 extraction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): fragmentize autonomous.md and admit state:plan-strategy-converge Five sections share one atom, the pattern plan-phase already uses for flag:--research-phase. The atom folds --converge OR --cross-ai into a single boolean in cmdInitAutonomous so the grammar stays operator-free. cmdInitAutonomous is additive; init.milestone-op, init.manager and init.phase-op are untouched and still consumed. The $PLAN_STRATEGY bash resolver is deliberately retained — ungated local-planning bullets still read it, so the init-side fact supplements it rather than replacing it. converge-fail-fast required splitting one bash fence so the always-run CONVERGENCE_ARGS construction stays outside the marker. All three flag-absent fallbacks were left outside their markers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): fragmentize review and discuss-phase-assumptions Admit state:reviewer-instances-configured (two peripheral notes share it; the core reviewer-lane dispatch stays unmarked — it is the workflow's primary always-evaluated logic, not an optional branch) and state:auto-advance-active, which folds --auto OR two config keys into one boolean so the grammar stays operator-free. discuss-phase-assumptions was the highest-risk edit in this PR. Its auto_advance step is a full if/elif/else; gating it whole would have deleted the flag-absent fallback needed exactly when --auto is off. Split verified exact: resolvers 636-651 and the 'End here' fallback 668-669 both stay outside the marker; only 653-667 is gated. Adds emitted-drift acks for the two files that grew — review.md (+55 B) and autonomous.md (+737 B from 80799211c, which had none and would have red-gated the push. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): fragmentize docs-update, update, transition and new-milestone Part A Completes the 13-workflow rollout. Three of these had no init call at all and gained a dedicated entry point plus their first gsd_run query line. Admits state:is-monorepo and adds state:next-channel, state:workstream-active and state:flat-mode. Vocabulary 26 -> 30 atoms. Part A of new-milestone applies when NO workstream is active — the negation of state:workstream-active. Rather than teach the grammar negation, which is the Greenspun drift the frozen list exists to prevent, it gets a separate positively-phrased atom whose fact is the inverse. Part B, which always runs, stays outside the marker. flag:--verify-only is deliberately NOT admitted: docs-update has no contiguous purely-additive region for it, and an atom without a consuming section is dead vocabulary. Evidence recorded in the slice report. update.md reuses its existing resolved $GSD_TOOLS rather than prepending the canonical preamble, which would have clobbered it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(#2994): stop automated-ui-verification re-resolving its own gate, retire dead vocabulary Two defects the new tests caught. The automated-ui-verification step re-ran gsd_run loop render-hooks and recomputed UI_PHASE_ACTIVE inside a body that is only read when that fact is already true — the circular self-disabling pattern this design forbids, introduced by 3c654b168. cmdInitVerifyWork now exposes ui_phase_active and the step consumes it. Its launcher preamble goes too: no gsd_run remains. The Playwright-MCP check stays as prose — that is live session state. Dead vocabulary predating this PR: flag:--full and state:needs-codebase-map were admitted with a gate-1 claim that never materialized. flag:--full is removed, redundant once quick folds it into discuss/research/validate. state:needs-codebase-map gets the real consumer it always lacked, gating new-project's codebase-map offer. Vocabulary 30 -> 29, and no atom is now without a consuming section. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(#2994): add the atom-admission, inversion and resolver-hoist gates The two existing parity guards prove vocabulary/predicate symmetry but never that a fact is computed — an atom no cmdInit* assembles evaluates false forever. These close that hole: - per-atom satisfiability for all 29 atoms, plus an anti-vacuity assertion so the loop cannot silently cover zero atoms - dead-vocabulary check against the shipped manifest - inversion guard: the flag-absent fallbacks in discuss-phase-assumptions and verify-work must stay outside their markers - data-driven resolver-hoist guard over the shipped manifest, so a future extraction cannot reintroduce the circular class - compound-fold coverage (--full, --cross-ai, --rc, config-only --auto) - null-vs-[] degraded/computed distinction, and flag value shapes Also repairs the frozen-vocabulary lock, which was stale and red for the seven atoms earlier commits on this branch shipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2994): add changeset for the fragment-model rollout Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(#2994): cite the issue on the two new allow-test-rule exemptions ADR-456 requires an issue ref on the same line as the annotation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2994): correct the atom-count claims after retiring flag:--full The vocabulary doc comments still said 30 entries; it is 29 since flag:--full was removed as dead vocabulary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(#2994): dedupe the phase-fallback block and harden --ws parsing Review findings. MAJOR: the three new init entry points each pasted a verbatim copy of the guardedFindPhase/guardedGetRoadmapPhase fallback, taking the repo from four copies to seven — DEFECT.GENERATIVE-FIX. Extracted applyRoadmapFallback and folded six of the seven; each call site keeps its own field-set via a closure. Duplication removed rather than papered over with a parity test. cmdInitPhaseOp stays out: its fallback omits has_reviews, so it is not a byte-identical copy, and it is CRITICAL-radius. LOW, pre-existing: GSD_WS captured [^[:space:]]+ and expands unquoted, so a workstream name holding glob metacharacters would expand against the filesystem. Narrowed to [A-Za-z0-9._-]+. The unquoted expansion is kept — it must word-split into two args and vanish when empty. Also restores the vocabulary ordering convention, and fixes a masked test bug the mandated run surfaced: the flag-forwarding guard checked only the first init line per workflow, but new-milestone has two, so a real failure was reporting exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(#2994): drop the stale new-milestone emitted-drift ack new-milestone.md was acked for a +406 B growth measured against an intermediate commit. Net against origin/next it SHRANK by 8 bytes, so nothing needed the ack and it explained nothing — which the differential attribution check reports as a stale acknowledgment, not a pass. update.md's entry stays: it genuinely grew +703 B. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(#2994): resolve the 15 failures from the full matrix run All 15 were real and identical on both lanes. REAL REGRESSION: autonomous.md hit 41479 chars against the #2196 guard's 40960 cap — a CHARS cap distinct from the LARGE tier byte cap, which the five section stubs pushed it over. Extracted the 3a.5 UI Design Contract body to references/; now 39968 chars, and the file nets -795 B vs base, so its growth ack is deleted rather than left stale. REAL DEFECT: docs referenced /gsd-transition, which is not a live registered command. Reworded. STALE FIXTURE: the emission byte-identity test hardcoded two marked workflows; this branch legitimately marks fifteen. Fixture corrected — the source was right. The rest were drift guards over the eight workflows the earlier sweep did not cover, retargeted at where the content now lives with non-vacuity proven by blanking each step file and confirming failure. The GSD_WS forwarding guard was checked as a possible real break and is not one: the charclass narrowing is intact and forwarding works end to end. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(#2994): drop the ack for a newly-added reference file A new file's emitted ripple is attributable to the diff that adds it, so the acknowledgment explained nothing and the differential check reports it as stale. Removing the last entry removes the fragment — an empty one signals nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(#2994): retarget the UI-contract guards and clear two transitive advisories The §3a.5 extraction that brought autonomous.md under the #2196 char cap moved its body to references/autonomous-ui-design-contract.md, so ten guards in autonomous-ui-steps and check-ui-safety-gate were asserting it against the host. Retargeted via a combined read, each proven non-vacuous by blanking the reference file and confirming failure. This class had already bitten twice on this branch because each sweep was scoped to the workflows touched at that moment, so this one was exhaustive: ~70 test files across all 13 workflows, zero further broken or vacuous assertions found. Also clears two high transitive advisories the matrix flagged on one lane — fast-uri GHSA-7p8r-x3mc-p8w7 and three ip-address SSRF/trust-boundary issues. Both pre-date this branch: package-lock.json was untouched until now, so the production tree was byte-identical to the base. Lockfile-only, package.json unchanged, verified against a real npm ci install. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2994): backfill changeset pr number to 3030 --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,14 @@ const WORKFLOW_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'autonomous.
|
||||
const COMMANDS_DOC_PATH = path.join(REPO_ROOT, 'docs', 'COMMANDS.md');
|
||||
const HOW_TO_PATH = path.join(REPO_ROOT, 'docs', 'how-to', 'run-phases-autonomously.md');
|
||||
const TOOLS = path.join(REPO_ROOT, 'gsd-core', 'bin', 'gsd-tools.cjs');
|
||||
// #2994: fragmentization moved the five converge-gated regions out of the host
|
||||
// autonomous.md into dedicated step files (state:plan-strategy-converge) —
|
||||
// see docs/reference/workflow-fragments.md. Tests that assert on this moved
|
||||
// content read the step file directly rather than the host.
|
||||
const STEP_FAIL_FAST_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'autonomous', 'steps', 'converge-fail-fast.md');
|
||||
const STEP_DISPATCH_BG_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'autonomous', 'steps', 'converge-dispatch-bg.md');
|
||||
const STEP_DISPATCH_INLINE_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'autonomous', 'steps', 'converge-dispatch-inline.md');
|
||||
const STEP_LOOP_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'autonomous', 'steps', 'converge-loop.md');
|
||||
|
||||
function read(filePath) {
|
||||
return fs.readFileSync(filePath, 'utf8');
|
||||
@@ -47,30 +55,50 @@ describe('autonomous --converge flag (#711)', () => {
|
||||
});
|
||||
|
||||
test('workflow fails fast when convergence is requested but disabled', () => {
|
||||
// #2994: this check lives in the converge-fail-fast step file now
|
||||
// (state:plan-strategy-converge) — the host only carries the gated
|
||||
// conditional-read stub.
|
||||
const workflow = read(WORKFLOW_PATH);
|
||||
const step = read(STEP_FAIL_FAST_PATH);
|
||||
|
||||
assert.match(
|
||||
workflow,
|
||||
/config-get workflow\.plan_review_convergence/,
|
||||
'workflow should check workflow.plan_review_convergence before planning',
|
||||
/gsd:section id="converge-fail-fast" when="state:plan-strategy-converge"/,
|
||||
'workflow should gate the fail-fast check behind state:plan-strategy-converge',
|
||||
);
|
||||
assert.match(
|
||||
workflow,
|
||||
step,
|
||||
/config-get workflow\.plan_review_convergence/,
|
||||
'converge-fail-fast step should check workflow.plan_review_convergence before planning',
|
||||
);
|
||||
assert.match(
|
||||
step,
|
||||
/gsd config-set workflow\.plan_review_convergence true/,
|
||||
'workflow should print the enable command instead of silently downgrading',
|
||||
'converge-fail-fast step should print the enable command instead of silently downgrading',
|
||||
);
|
||||
});
|
||||
|
||||
test('workflow routes planning through plan-review-convergence when enabled', () => {
|
||||
// #2994: the converge dispatch/loop bodies live in dedicated step files
|
||||
// now (state:plan-strategy-converge) — only the local-planning fallback
|
||||
// remains inline in the host.
|
||||
const workflow = read(WORKFLOW_PATH);
|
||||
const dispatchInline = read(STEP_DISPATCH_INLINE_PATH);
|
||||
const loop = read(STEP_LOOP_PATH);
|
||||
const dispatchBg = read(STEP_DISPATCH_BG_PATH);
|
||||
|
||||
assert.match(
|
||||
workflow,
|
||||
dispatchInline,
|
||||
/Skill\(skill="gsd-plan-review-convergence", args="\$\{PHASE_NUM\} \$\{CONVERGENCE_ARGS\}"\)/,
|
||||
'non-interactive converge mode should call gsd-plan-review-convergence',
|
||||
'inline converge dispatch step should call gsd-plan-review-convergence',
|
||||
);
|
||||
assert.match(
|
||||
workflow,
|
||||
loop,
|
||||
/Skill\(skill="gsd-plan-review-convergence", args="\$\{PHASE_NUM\} \$\{CONVERGENCE_ARGS\}"\)/,
|
||||
'default converge loop step should call gsd-plan-review-convergence',
|
||||
);
|
||||
assert.match(
|
||||
dispatchBg,
|
||||
/Run plan convergence for phase \$\{PHASE_NUM\}: Skill\(skill=\\"gsd-plan-review-convergence\\"/,
|
||||
'interactive converge mode should dispatch plan convergence in the background agent',
|
||||
);
|
||||
|
||||
@@ -12,13 +12,32 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'autonomous.md');
|
||||
const UI_DESIGN_CONTRACT_REF_PATH = path.join(
|
||||
__dirname, '..', 'gsd-core', 'references', 'autonomous-ui-design-contract.md'
|
||||
);
|
||||
|
||||
/**
|
||||
* #2994 fragmentization moved §3a.5's body out of autonomous.md into
|
||||
* gsd-core/references/autonomous-ui-design-contract.md, leaving an
|
||||
* unconditional `Read and execute:` pointer in the host. Splice the
|
||||
* reference file's content back in at the pointer's position so §3a.5
|
||||
* slicing/ordering assertions still see the real step body.
|
||||
*/
|
||||
function readAutonomousCombined() {
|
||||
const raw = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
|
||||
const pointerRe = /Read and execute: `\$HOME\/\.claude\/gsd-core\/references\/autonomous-ui-design-contract\.md`/;
|
||||
assert.ok(pointerRe.test(raw), 'autonomous.md must still contain the §3a.5 reference pointer');
|
||||
const refContent = fs.readFileSync(UI_DESIGN_CONTRACT_REF_PATH, 'utf-8');
|
||||
return raw.replace(pointerRe, refContent);
|
||||
}
|
||||
|
||||
describe('autonomous workflow ui-phase and ui-review integration (#1375)', () => {
|
||||
let content;
|
||||
|
||||
beforeEach(() => {
|
||||
assert.ok(fs.existsSync(WORKFLOW_PATH), 'workflows/autonomous.md should exist');
|
||||
content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
|
||||
assert.ok(fs.existsSync(UI_DESIGN_CONTRACT_REF_PATH), 'references/autonomous-ui-design-contract.md should exist');
|
||||
content = readAutonomousCombined();
|
||||
});
|
||||
|
||||
describe('step 3a.5 — UI design contract before planning', () => {
|
||||
|
||||
@@ -301,9 +301,25 @@ const { cleanup } = require('./helpers.cjs');
|
||||
const HELPER_PATH = path.join(__dirname, '..', 'bin', 'lib', 'ui-safety-gate.cjs');
|
||||
const PLAN_PHASE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'plan-phase.md');
|
||||
const AUTONOMOUS_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'autonomous.md');
|
||||
const AUTONOMOUS_UI_DESIGN_CONTRACT_REF_PATH = path.join(
|
||||
__dirname, '..', 'gsd-core', 'references', 'autonomous-ui-design-contract.md'
|
||||
);
|
||||
|
||||
const { checkUiPresence } = require(HELPER_PATH);
|
||||
|
||||
/**
|
||||
* #2994 fragmentization moved §3a.5's body out of autonomous.md into
|
||||
* gsd-core/references/autonomous-ui-design-contract.md, leaving an
|
||||
* unconditional `Read and execute:` pointer in the host. Read host +
|
||||
* reference file combined so the structural guards below still see the
|
||||
* real §3a.5 body (and its absence of the retired ui-safety-gate.cjs /
|
||||
* RUNTIME_DIR / LC_ALL=C grep patterns).
|
||||
*/
|
||||
function readAutonomousCombined() {
|
||||
return fs.readFileSync(AUTONOMOUS_PATH, 'utf-8') +
|
||||
'\n' + fs.readFileSync(AUTONOMOUS_UI_DESIGN_CONTRACT_REF_PATH, 'utf-8');
|
||||
}
|
||||
|
||||
// ── Helper ────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -362,7 +378,7 @@ describe('Workflow .md structural guard (#3718)', () => {
|
||||
// was intentionally removed — cross-shell portability is provided by the CLI layer.
|
||||
test('autonomous.md must invoke check ui-plan-gate (capability-driven UI gate — #1031)', () => {
|
||||
const label = 'autonomous.md';
|
||||
const content = fs.readFileSync(AUTONOMOUS_PATH, 'utf-8');
|
||||
const content = readAutonomousCombined();
|
||||
|
||||
// §3a.5 must delegate to the capability-driven gate, not inline shell code
|
||||
assert.ok(
|
||||
|
||||
@@ -235,6 +235,18 @@ describe('#3727 — parseCodeReviewFlags: typed IR for code-review argv', () =>
|
||||
|
||||
describe('#3727 — code-review.md structural dispatch contract', () => {
|
||||
const src = fs.readFileSync(WORKFLOW_PATH, 'utf8');
|
||||
// #2994: dispatch_fix moved wholly into a marker-gated step file
|
||||
// (gsd-core/workflows/code-review/steps/dispatch-fix.md, when="flag:--fix")
|
||||
// — the host now carries only the gsd:section marker + read-or-skip stub.
|
||||
const DISPATCH_FIX_STEP_PATH = path.join(
|
||||
ROOT,
|
||||
'gsd-core',
|
||||
'workflows',
|
||||
'code-review',
|
||||
'steps',
|
||||
'dispatch-fix.md',
|
||||
);
|
||||
const dispatchFixSrc = fs.readFileSync(DISPATCH_FIX_STEP_PATH, 'utf8');
|
||||
|
||||
test('initialize step references code-review-flags.cjs for flag parsing', () => {
|
||||
const initStart = src.indexOf('<step name="initialize">');
|
||||
@@ -247,20 +259,21 @@ describe('#3727 — code-review.md structural dispatch contract', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('workflow has a <step name="dispatch_fix"> step', () => {
|
||||
test('workflow gates a dispatch-fix section (flag:--fix) whose step file has the dispatch_fix step', () => {
|
||||
assert.ok(
|
||||
src.includes('<step name="dispatch_fix">'),
|
||||
'code-review.md must have a dispatch_fix step (missing = --fix is silently no-op)'
|
||||
src.includes('<!-- gsd:section id="dispatch-fix" when="flag:--fix" -->') &&
|
||||
src.includes('gsd-core/workflows/code-review/steps/dispatch-fix.md'),
|
||||
'code-review.md must gate a dispatch-fix section pointing at dispatch-fix.md (missing = --fix is silently no-op)'
|
||||
);
|
||||
assert.ok(
|
||||
dispatchFixSrc.includes('<step name="dispatch_fix">'),
|
||||
'dispatch-fix.md step file must contain the dispatch_fix step'
|
||||
);
|
||||
});
|
||||
|
||||
test('dispatch_fix step delegates to code-review-fix.md when fix flag is true', () => {
|
||||
const stepStart = src.indexOf('<step name="dispatch_fix">');
|
||||
const stepEnd = src.indexOf('</step>', stepStart);
|
||||
assert.ok(stepStart !== -1, 'dispatch_fix step must exist');
|
||||
const stepSection = src.slice(stepStart, stepEnd);
|
||||
assert.ok(
|
||||
stepSection.includes('code-review-fix.md'),
|
||||
dispatchFixSrc.includes('code-review-fix.md'),
|
||||
'dispatch_fix step must reference code-review-fix.md workflow'
|
||||
);
|
||||
});
|
||||
@@ -268,11 +281,8 @@ describe('#3727 — code-review.md structural dispatch contract', () => {
|
||||
test('dispatch_fix step references gsd-code-fixer agent (via code-review-fix.md chain)', () => {
|
||||
// The dispatch step must show that fixing will occur, either directly or
|
||||
// by loading code-review-fix.md (which in turn spawns gsd-code-fixer).
|
||||
const stepStart = src.indexOf('<step name="dispatch_fix">');
|
||||
const stepEnd = src.indexOf('</step>', stepStart);
|
||||
const stepSection = src.slice(stepStart, stepEnd);
|
||||
assert.ok(
|
||||
stepSection.includes('gsd-code-fixer') || stepSection.includes('code-review-fix.md'),
|
||||
dispatchFixSrc.includes('gsd-code-fixer') || dispatchFixSrc.includes('code-review-fix.md'),
|
||||
'dispatch_fix step must reference gsd-code-fixer agent or code-review-fix.md workflow'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -531,7 +531,14 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
test('quick.md resolves code-review capability hook', () => {
|
||||
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, 'quick.md'), 'utf-8');
|
||||
const start = content.indexOf('**Step 6.25: Code review (auto)**');
|
||||
const end = content.indexOf('**Step 6.5: Verification', start);
|
||||
// #2994 (pre-existing since #2994's earlier quick-verification.md extraction,
|
||||
// 18ff35d20): Step 6.5's content moved into
|
||||
// gsd-core/workflows/quick/steps/quick-verification.md behind a
|
||||
// `<!-- gsd:section id="quick-verification" -->` marker, so the literal
|
||||
// "**Step 6.5: Verification" heading text no longer follows Step 6.25 in
|
||||
// this file — the marker is the correct end-of-step delimiter now (mirrors
|
||||
// phase6-review-capabilities.test.cjs's identical retarget for the same move).
|
||||
const end = content.indexOf('<!-- gsd:section id="quick-verification"', start);
|
||||
assert.ok(start !== -1 && end !== -1, 'quick.md missing Step 6.25 code review section');
|
||||
const reviewContent = content.slice(start, end);
|
||||
|
||||
|
||||
@@ -1672,10 +1672,16 @@ describe('bug-853 — manager/autonomous gate background dispatch by runtime', (
|
||||
assert.match(AUTONOMOUS, /If `FLATTEN` is `false`[\s\S]{0,1200}?run_in_background=true[\s\S]{0,600}?gsd-plan-phase/);
|
||||
// Background block: run_in_background=true appears within the FLATTEN=false branch and gsd-execute-phase is nearby
|
||||
assert.match(AUTONOMOUS, /If `FLATTEN` is `false`[\s\S]{0,3000}?run_in_background=true[\s\S]{0,200}?gsd-execute-phase/);
|
||||
// Inline is the otherwise/else branch for plan — anchored on FLATTEN=true language (not runtime name)
|
||||
// Inline is the otherwise/else branch for plan — anchored on FLATTEN=true language (not runtime name).
|
||||
// #2994: the window between `FLATTEN` and the inline Skill() call widened
|
||||
// past manager.md's 400 because this branch now carries a
|
||||
// state:plan-strategy-converge conditional-read stub (converge-dispatch-inline,
|
||||
// gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md) ahead of
|
||||
// the local-planning fallback — the stub's full step-file path is more
|
||||
// verbose than the terse `Skill()` call it replaced.
|
||||
assert.match(
|
||||
AUTONOMOUS,
|
||||
/Otherwise[\s\S]{0,100}?`FLATTEN`[\s\S]{0,400}?Skill\(skill="gsd-plan-phase"/,
|
||||
/Otherwise[\s\S]{0,100}?`FLATTEN`[\s\S]{0,700}?Skill\(skill="gsd-plan-phase"/,
|
||||
);
|
||||
// Inline is the otherwise/else branch for execute — anchored on FLATTEN=true language (not runtime name)
|
||||
assert.match(
|
||||
|
||||
@@ -943,48 +943,60 @@ describe('feat-3210 / #1012: code-review workflow invokes fallow with the real C
|
||||
path.join(ROOT, 'gsd-core', 'workflows', 'code-review.md'),
|
||||
'utf8',
|
||||
);
|
||||
// #2994: the actual fallow invocation (audit --format json, --changed-since,
|
||||
// --max-crap, verdict-based exit handling) moved to a marker-gated step file
|
||||
// (gsd-core/workflows/code-review/steps/structural-pre-pass.md, when=
|
||||
// "state:fallow-enabled") — read it for the invocation-specific assertions
|
||||
// below; the negative "removed flags" assertion checks BOTH files.
|
||||
const fallowStepSrc = fs.readFileSync(
|
||||
path.join(ROOT, 'gsd-core', 'workflows', 'code-review', 'steps', 'structural-pre-pass.md'),
|
||||
'utf8',
|
||||
);
|
||||
const combinedSrc = workflowSrc + '\n' + fallowStepSrc;
|
||||
|
||||
test('uses audit --format json and --quiet (real fallow 2.x flags)', () => {
|
||||
assert.ok(
|
||||
workflowSrc.includes('audit --format json'),
|
||||
fallowStepSrc.includes('audit --format json'),
|
||||
'workflow must invoke: audit --format json',
|
||||
);
|
||||
assert.ok(
|
||||
workflowSrc.includes('--quiet'),
|
||||
fallowStepSrc.includes('--quiet'),
|
||||
'workflow must pass --quiet to suppress progress output',
|
||||
);
|
||||
});
|
||||
|
||||
test('does NOT use removed flags: --json , --profile, --stdin-files', () => {
|
||||
assert.ok(
|
||||
!workflowSrc.includes('--json '),
|
||||
!combinedSrc.includes('--json '),
|
||||
'workflow must not use old --json flag (note trailing space to avoid matching --format json)',
|
||||
);
|
||||
assert.ok(
|
||||
!workflowSrc.includes('--profile'),
|
||||
!combinedSrc.includes('--profile'),
|
||||
'workflow must not use --profile (fallow has no native profile concept)',
|
||||
);
|
||||
assert.ok(
|
||||
!workflowSrc.includes('--stdin-files'),
|
||||
!combinedSrc.includes('--stdin-files'),
|
||||
'workflow must not use --stdin-files (removed in fallow 2.x)',
|
||||
);
|
||||
});
|
||||
|
||||
test('uses --max-crap for threshold control (profile maps to max-crap)', () => {
|
||||
assert.ok(
|
||||
workflowSrc.includes('--max-crap'),
|
||||
fallowStepSrc.includes('--max-crap'),
|
||||
'workflow must use --max-crap to control threshold (profile mapped to this flag)',
|
||||
);
|
||||
});
|
||||
|
||||
test('scopes phase via --changed-since (native fallow git-ref scoping)', () => {
|
||||
assert.ok(
|
||||
workflowSrc.includes('--changed-since'),
|
||||
fallowStepSrc.includes('--changed-since'),
|
||||
'workflow must use --changed-since for phase scoping',
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizes fallow output via normalizeFallowReportFile before embedding', () => {
|
||||
// Still in the host (spawn_reviewer step, unconditional) — not gated by
|
||||
// state:fallow-enabled, since the reviewer prompt assembly always runs.
|
||||
assert.ok(
|
||||
workflowSrc.includes('normalizeFallowReportFile'),
|
||||
'workflow must call normalizeFallowReportFile to normalize before embedding into reviewer prompt',
|
||||
@@ -993,7 +1005,7 @@ describe('feat-3210 / #1012: code-review workflow invokes fallow with the real C
|
||||
|
||||
test('exit-handling gates on valid JSON (verdict in o), not on exit code', () => {
|
||||
assert.ok(
|
||||
workflowSrc.includes("'verdict' in o"),
|
||||
fallowStepSrc.includes("'verdict' in o"),
|
||||
"workflow exit-handling must use 'verdict' in o to decide success (not exit code)",
|
||||
);
|
||||
});
|
||||
@@ -1047,6 +1059,13 @@ describe('feat-3210: workflow and config contracts', () => {
|
||||
// The workflow .md uses XML-like <step> tags as its runtime DSL; we parse the step block
|
||||
// structurally and assert on structural properties, not on prose strings.
|
||||
test('code-review workflow structural_pre_pass step is parseable and references FALLOW.json output', () => {
|
||||
// #2994: structural_pre_pass's gated execution (fallow binary resolve + run
|
||||
// + FALLOW.json persistence) moved to a marker-gated step file
|
||||
// (gsd-core/workflows/code-review/steps/structural-pre-pass.md, when=
|
||||
// "state:fallow-enabled"). The config-gate resolver itself — previously an
|
||||
// inline `gsd_run query config-get code_quality.fallow.enabled` call inside
|
||||
// this step's own body (a circular self-disabling gate) — was hoisted into
|
||||
// `detectFallowConfig` (src/init.cts), consumed by `cmdInitCodeReview`.
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(ROOT, 'gsd-core', 'workflows', 'code-review.md'),
|
||||
'utf8',
|
||||
@@ -1061,16 +1080,30 @@ describe('feat-3210: workflow and config contracts', () => {
|
||||
|
||||
const stepBody = stepMatch[1];
|
||||
|
||||
// Structural property: the step body must reference the FALLOW.json output artifact
|
||||
// Structural property: the host stub gates the FALLOW.json-producing
|
||||
// execution behind state:fallow-enabled and points at the step file.
|
||||
assert.ok(
|
||||
stepBody.includes('FALLOW.json'),
|
||||
'structural_pre_pass step body must reference the FALLOW.json output artifact',
|
||||
stepBody.includes('when="state:fallow-enabled"') &&
|
||||
stepBody.includes('gsd-core/workflows/code-review/steps/structural-pre-pass.md'),
|
||||
'structural_pre_pass step must gate its FALLOW.json-producing execution behind state:fallow-enabled',
|
||||
);
|
||||
|
||||
// Structural property: the step body must gate on the fallow enabled config key
|
||||
const stepFile = fs.readFileSync(
|
||||
path.join(ROOT, 'gsd-core', 'workflows', 'code-review', 'steps', 'structural-pre-pass.md'),
|
||||
'utf8',
|
||||
);
|
||||
assert.ok(
|
||||
stepBody.includes('code_quality.fallow.enabled'),
|
||||
'structural_pre_pass step body must gate on code_quality.fallow.enabled',
|
||||
stepFile.includes('FALLOW.json'),
|
||||
'structural-pre-pass.md step file must reference the FALLOW.json output artifact',
|
||||
);
|
||||
|
||||
// Structural property: the config-gate fact is resolved from the real
|
||||
// code_quality.fallow.enabled config key — checked against the resolver
|
||||
// it was hoisted into (src/init.cts's detectFallowConfig).
|
||||
const initSource = fs.readFileSync(path.join(ROOT, 'src', 'init.cts'), 'utf8');
|
||||
assert.ok(
|
||||
/detectFallowConfig[\s\S]{0,600}'code_quality'[\s\S]{0,40}'fallow'[\s\S]{0,40}'enabled'/.test(initSource),
|
||||
'detectFallowConfig (src/init.cts) must gate on code_quality.fallow.enabled',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1884,15 +1884,38 @@ describe('#3086: git.create_tag config key', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('D. complete-milestone.md contains <config-check> gate for git.create_tag', () => {
|
||||
test('D. complete-milestone.md gates git_tag behind state:git-create-tag (#2994: <config-check> hoisted into cmdInitCompleteMilestone)', () => {
|
||||
// #2994: the inline <config-check> (`gsd-tools.cjs query config-get
|
||||
// git.create_tag ... || echo "true"`) that used to gate the git_tag step's
|
||||
// own inclusion was hoisted into `detectGitCreateTag` (src/init.cts),
|
||||
// consumed by the new `cmdInitCompleteMilestone` entry point and exposed
|
||||
// as the init-bundle's `git_create_tag` field / the `state:git-create-tag`
|
||||
// when= atom. The workflow markdown no longer contains a literal
|
||||
// <config-check> block or `git.create_tag` string — it gates the whole
|
||||
// git_tag step behind a gsd:section marker instead.
|
||||
const content = fs.readFileSync(WORKFLOW_PATH, 'utf8');
|
||||
assert.ok(
|
||||
content.includes('git.create_tag'),
|
||||
'complete-milestone.md must reference git.create_tag in a <config-check> block',
|
||||
content.includes('<!-- gsd:section id="git-tag" when="state:git-create-tag" -->'),
|
||||
'complete-milestone.md must gate the git_tag step behind the state:git-create-tag section marker',
|
||||
);
|
||||
assert.ok(
|
||||
content.includes('<config-check>'),
|
||||
'complete-milestone.md must have a <config-check> block in the git_tag step',
|
||||
content.includes('gsd-core/workflows/complete-milestone/steps/git-tag.md'),
|
||||
'complete-milestone.md must point the git-tag section at its step file',
|
||||
);
|
||||
|
||||
const stepFile = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'complete-milestone', 'steps', 'git-tag.md'),
|
||||
'utf8',
|
||||
);
|
||||
assert.ok(
|
||||
stepFile.includes('<step name="git_tag">') && stepFile.includes('git tag -a'),
|
||||
'git-tag.md step file must contain the git_tag step body (git tag creation)',
|
||||
);
|
||||
|
||||
const initSource = fs.readFileSync(path.join(__dirname, '..', 'src', 'init.cts'), 'utf8');
|
||||
assert.ok(
|
||||
/detectGitCreateTag[\s\S]{0,300}'git'[\s\S]{0,40}'create_tag'/.test(initSource),
|
||||
'src/init.cts detectGitCreateTag must resolve the git.create_tag config key',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"paths": {
|
||||
"update.md": "#2994 (epic #1671 Phase 6.3, FINAL slice): fragmentizes update.md onto the marker grammar, admitting `state:next-channel` (channel-banner section) and a new dedicated `init.update` entry point (cmdInitUpdate). update.md previously carried NO `gsd_run query init.*` call at all; the new INIT_UPDATE fetch (reusing the already-resolved $GSD_TOOLS from get_installed_version, dual .cjs/PATH-shim invocation style, matching the pre-existing update-context call) plus its surrounding comment outweighs the single `<!-- gsd:section -->` marker-pair stub that replaces the extracted channel-banner prose (now living in gsd-core/workflows/update/steps/channel-banner.md). Net SOURCE growth is +703 bytes (26,024 -> 26,727). The pre-existing TAG=\"next\"/TAG=\"latest\" case-statement in parse_update_channel is deliberately left byte-identical — issue #815's regression test (tests/issue-815-update-next-channel.test.cjs) asserts that literal text stays in the workflow, since the npm dist-tag selection must run in the workflow's own shell before any gsd_run round-trip. The EMITTED artifact composeWorkflow produces at install time still includes the extracted prose verbatim (markers strip, gap+section bodies re-join byte-for-byte) when the atom is unresolved (section_manifest null -> read-everything fallback), so installed behavior is unchanged; only the SOURCE file's on-disk byte count moves."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"paths": {
|
||||
"review.md": "#2994 (epic #1671 Phase 6.3, further amendment): fragmentizes review.md onto the marker grammar, admitting `state:reviewer-instances-configured` (shared by two peripheral notes, `reviewer-instances-note-1` in detect_clis and `reviewer-instances-note-2` in invoke_reviewers — the core reviewer-lane dispatch itself stays unmarked). Also retargets the init line from the shared `init.phase-op` to a new dedicated `init.review` entry point (cmdInitReview), which computes the reviewer-instances-configured fact via `review.reviewer_instances` config presence. Net SOURCE growth is +55 bytes (29,063 -> 29,118): two `<!-- gsd:section -->` marker-pair stubs (~331 B and ~195 B) replace their extracted prose bodies (328 B and 277 B respectively, now living in gsd-core/workflows/review/steps/*.md), and `init.phase-op` shrinks by 2 bytes to `init.review` on the gather_context init line. The EMITTED artifact composeWorkflow produces at install time still includes the extracted prose verbatim (markers strip, gap+section bodies re-join byte-for-byte) when the atom is unresolved (section_manifest null -> read-everything fallback), so installed behavior is unchanged; only the SOURCE file's on-disk byte count moves."
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,11 @@ describe('#2287 cmdAuditUat: deferred-items.md awareness', () => {
|
||||
|
||||
// ─── forensic_audit workflow-prose source-contract guard ──────────────────
|
||||
|
||||
const PROGRESS_MD = path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md');
|
||||
// #2994 fragmentization moved the --forensic-gated forensic_audit step out of
|
||||
// progress.md into gsd-core/workflows/progress/steps/forensic-audit.md behind
|
||||
// a section marker. Read that step file directly — it is the sole remaining
|
||||
// source of the forensic_audit step body these guards assert on.
|
||||
const PROGRESS_MD = path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress', 'steps', 'forensic-audit.md');
|
||||
|
||||
describe('#2287 progress.md forensic_audit: deferred-items.md contract', () => {
|
||||
const content = fs.readFileSync(PROGRESS_MD, 'utf-8');
|
||||
@@ -237,7 +241,7 @@ describe('#2287 progress.md forensic_audit: deferred-items.md contract', () => {
|
||||
const section = stepStart !== -1 && stepEnd !== -1 ? content.slice(stepStart, stepEnd) : '';
|
||||
|
||||
test('forensic_audit step exists', () => {
|
||||
assert.notEqual(stepStart, -1, 'progress.md must contain the forensic_audit step');
|
||||
assert.notEqual(stepStart, -1, 'progress.md (or its extracted progress/steps/forensic-audit.md) must contain the forensic_audit step');
|
||||
});
|
||||
|
||||
test('forensic_audit now runs 7 checks (was 6) and globs deferred-items.md', () => {
|
||||
|
||||
29
tests/fixtures/install-tree/antigravity.json
vendored
29
tests/fixtures/install-tree/antigravity.json
vendored
@@ -56,6 +56,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -221,15 +222,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -246,6 +256,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -282,7 +293,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -306,12 +322,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -330,14 +355,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/augment.json
vendored
29
tests/fixtures/install-tree/augment.json
vendored
@@ -127,6 +127,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -292,15 +293,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -317,6 +327,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -353,7 +364,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -377,12 +393,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -401,14 +426,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/claude-local.json
vendored
29
tests/fixtures/install-tree/claude-local.json
vendored
@@ -126,6 +126,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -291,15 +292,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -316,6 +326,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -352,7 +363,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -376,12 +392,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -400,14 +425,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/claude.json
vendored
29
tests/fixtures/install-tree/claude.json
vendored
@@ -55,6 +55,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -220,15 +221,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -245,6 +255,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -281,7 +292,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -305,12 +321,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -329,14 +354,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/cline.json
vendored
29
tests/fixtures/install-tree/cline.json
vendored
@@ -59,6 +59,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -224,15 +225,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -249,6 +259,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -285,7 +296,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -309,12 +325,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -333,14 +358,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"scripts/changeset/README.md",
|
||||
"scripts/changeset/cli.cjs",
|
||||
"scripts/changeset/github-release-notes.cjs",
|
||||
|
||||
29
tests/fixtures/install-tree/codebuddy.json
vendored
29
tests/fixtures/install-tree/codebuddy.json
vendored
@@ -127,6 +127,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -292,15 +293,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -317,6 +327,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -353,7 +364,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -377,12 +393,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -401,14 +426,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/codex.json
vendored
29
tests/fixtures/install-tree/codex.json
vendored
@@ -162,6 +162,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -327,15 +328,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -352,6 +362,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -388,7 +399,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -412,12 +428,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -436,14 +461,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-context-monitor.js",
|
||||
|
||||
29
tests/fixtures/install-tree/copilot.json
vendored
29
tests/fixtures/install-tree/copilot.json
vendored
@@ -57,6 +57,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -222,15 +223,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -247,6 +257,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -283,7 +294,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -307,12 +323,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -331,14 +356,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-session.json",
|
||||
"scripts/changeset/README.md",
|
||||
"scripts/changeset/cli.cjs",
|
||||
|
||||
29
tests/fixtures/install-tree/cursor.json
vendored
29
tests/fixtures/install-tree/cursor.json
vendored
@@ -56,6 +56,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -221,15 +222,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -246,6 +256,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -282,7 +293,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -306,12 +322,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -330,14 +355,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-cursor-post-tool.js",
|
||||
"hooks/gsd-cursor-pre-tool.js",
|
||||
"hooks/gsd-cursor-session-start.js",
|
||||
|
||||
29
tests/fixtures/install-tree/hermes.json
vendored
29
tests/fixtures/install-tree/hermes.json
vendored
@@ -56,6 +56,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -221,15 +222,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -246,6 +256,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -282,7 +293,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -306,12 +322,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -330,14 +355,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/kilo.json
vendored
29
tests/fixtures/install-tree/kilo.json
vendored
@@ -127,6 +127,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -292,15 +293,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -317,6 +327,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -353,7 +364,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -377,12 +393,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -401,14 +426,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/kimi-code.json
vendored
29
tests/fixtures/install-tree/kimi-code.json
vendored
@@ -86,6 +86,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -251,15 +252,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -276,6 +286,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -312,7 +323,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -336,12 +352,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -360,14 +385,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"scripts/changeset/README.md",
|
||||
"scripts/changeset/cli.cjs",
|
||||
"scripts/changeset/github-release-notes.cjs",
|
||||
|
||||
29
tests/fixtures/install-tree/kimi.json
vendored
29
tests/fixtures/install-tree/kimi.json
vendored
@@ -122,6 +122,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -287,15 +288,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -312,6 +322,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -348,7 +359,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -372,12 +388,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -396,14 +421,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"scripts/changeset/README.md",
|
||||
"scripts/changeset/cli.cjs",
|
||||
"scripts/changeset/github-release-notes.cjs",
|
||||
|
||||
29
tests/fixtures/install-tree/opencode.json
vendored
29
tests/fixtures/install-tree/opencode.json
vendored
@@ -127,6 +127,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -292,15 +293,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -317,6 +327,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -353,7 +364,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -377,12 +393,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -401,14 +426,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/pi.json
vendored
29
tests/fixtures/install-tree/pi.json
vendored
@@ -24,6 +24,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -189,15 +190,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -214,6 +224,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -250,7 +261,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -274,12 +290,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -298,14 +323,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/qwen.json
vendored
29
tests/fixtures/install-tree/qwen.json
vendored
@@ -56,6 +56,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -221,15 +222,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -246,6 +256,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -282,7 +293,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -306,12 +322,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -330,14 +355,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-check-update-worker.js",
|
||||
"hooks/gsd-check-update.js",
|
||||
"hooks/gsd-config-reload.js",
|
||||
|
||||
29
tests/fixtures/install-tree/trae.json
vendored
29
tests/fixtures/install-tree/trae.json
vendored
@@ -56,6 +56,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -221,15 +222,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -246,6 +256,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -282,7 +293,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -306,12 +322,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -330,14 +355,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"scripts/changeset/README.md",
|
||||
"scripts/changeset/cli.cjs",
|
||||
"scripts/changeset/github-release-notes.cjs",
|
||||
|
||||
29
tests/fixtures/install-tree/windsurf.json
vendored
29
tests/fixtures/install-tree/windsurf.json
vendored
@@ -56,6 +56,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -221,15 +222,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -246,6 +256,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -282,7 +293,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -306,12 +322,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -330,14 +355,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"hooks/gsd-windsurf-pre-command.js",
|
||||
"hooks/gsd-windsurf-pre-write.js",
|
||||
"hooks/package.json",
|
||||
|
||||
29
tests/fixtures/install-tree/zcode.json
vendored
29
tests/fixtures/install-tree/zcode.json
vendored
@@ -127,6 +127,7 @@
|
||||
"gsd-core/references/api-coverage.md",
|
||||
"gsd-core/references/artifact-types.md",
|
||||
"gsd-core/references/autonomous-smart-discuss.md",
|
||||
"gsd-core/references/autonomous-ui-design-contract.md",
|
||||
"gsd-core/references/checkpoints.md",
|
||||
"gsd-core/references/common-bug-patterns.md",
|
||||
"gsd-core/references/context-budget.md",
|
||||
@@ -292,15 +293,24 @@
|
||||
"gsd-core/workflows/audit-milestone.md",
|
||||
"gsd-core/workflows/audit-uat.md",
|
||||
"gsd-core/workflows/autonomous.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-banner.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-fail-fast.md",
|
||||
"gsd-core/workflows/autonomous/steps/converge-loop.md",
|
||||
"gsd-core/workflows/check-todos.md",
|
||||
"gsd-core/workflows/cleanup.md",
|
||||
"gsd-core/workflows/code-review-fix.md",
|
||||
"gsd-core/workflows/code-review.md",
|
||||
"gsd-core/workflows/code-review/steps/dispatch-fix.md",
|
||||
"gsd-core/workflows/code-review/steps/structural-pre-pass.md",
|
||||
"gsd-core/workflows/complete-milestone.md",
|
||||
"gsd-core/workflows/complete-milestone/steps/git-tag.md",
|
||||
"gsd-core/workflows/debug.md",
|
||||
"gsd-core/workflows/diagnose-issues.md",
|
||||
"gsd-core/workflows/discovery-phase.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions.md",
|
||||
"gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md",
|
||||
"gsd-core/workflows/discuss-phase-power.md",
|
||||
"gsd-core/workflows/discuss-phase.md",
|
||||
"gsd-core/workflows/discuss-phase/modes/advisor.md",
|
||||
@@ -317,6 +327,7 @@
|
||||
"gsd-core/workflows/discuss-phase/templates/discussion-log.md",
|
||||
"gsd-core/workflows/do.md",
|
||||
"gsd-core/workflows/docs-update.md",
|
||||
"gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md",
|
||||
"gsd-core/workflows/edit-phase.md",
|
||||
"gsd-core/workflows/eval-review.md",
|
||||
"gsd-core/workflows/execute-phase.md",
|
||||
@@ -353,7 +364,12 @@
|
||||
"gsd-core/workflows/milestone-summary.md",
|
||||
"gsd-core/workflows/mvp-phase.md",
|
||||
"gsd-core/workflows/new-milestone.md",
|
||||
"gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md",
|
||||
"gsd-core/workflows/new-milestone/steps/reset-phase-safety.md",
|
||||
"gsd-core/workflows/new-project.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-config.md",
|
||||
"gsd-core/workflows/new-project/steps/auto-mode-detection.md",
|
||||
"gsd-core/workflows/new-project/steps/codebase-map-offer.md",
|
||||
"gsd-core/workflows/new-workspace.md",
|
||||
"gsd-core/workflows/next.md",
|
||||
"gsd-core/workflows/node-repair.md",
|
||||
@@ -377,12 +393,21 @@
|
||||
"gsd-core/workflows/pr-branch.md",
|
||||
"gsd-core/workflows/profile-user.md",
|
||||
"gsd-core/workflows/progress.md",
|
||||
"gsd-core/workflows/progress/steps/forensic-audit.md",
|
||||
"gsd-core/workflows/progress/steps/mvp-display.md",
|
||||
"gsd-core/workflows/quick.md",
|
||||
"gsd-core/workflows/quick/steps/discussion-phase.md",
|
||||
"gsd-core/workflows/quick/steps/plan-checker-loop.md",
|
||||
"gsd-core/workflows/quick/steps/quick-verification.md",
|
||||
"gsd-core/workflows/quick/steps/research-phase.md",
|
||||
"gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md",
|
||||
"gsd-core/workflows/reapply-patches.md",
|
||||
"gsd-core/workflows/remove-phase.md",
|
||||
"gsd-core/workflows/remove-workspace.md",
|
||||
"gsd-core/workflows/resume-project.md",
|
||||
"gsd-core/workflows/review.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-1.md",
|
||||
"gsd-core/workflows/review/steps/reviewer-instances-note-2.md",
|
||||
"gsd-core/workflows/scan.md",
|
||||
"gsd-core/workflows/section-manifest.json",
|
||||
"gsd-core/workflows/secure-phase.md",
|
||||
@@ -401,14 +426,18 @@
|
||||
"gsd-core/workflows/sync-skills.md",
|
||||
"gsd-core/workflows/thread.md",
|
||||
"gsd-core/workflows/transition.md",
|
||||
"gsd-core/workflows/transition/steps/workstream-collision-check.md",
|
||||
"gsd-core/workflows/ui-phase.md",
|
||||
"gsd-core/workflows/ui-review.md",
|
||||
"gsd-core/workflows/ultraplan-phase.md",
|
||||
"gsd-core/workflows/undo.md",
|
||||
"gsd-core/workflows/update.md",
|
||||
"gsd-core/workflows/update/steps/channel-banner.md",
|
||||
"gsd-core/workflows/validate-phase.md",
|
||||
"gsd-core/workflows/verify-phase.md",
|
||||
"gsd-core/workflows/verify-work.md",
|
||||
"gsd-core/workflows/verify-work/steps/automated-ui-verification.md",
|
||||
"gsd-core/workflows/verify-work/steps/mvp-uat-framing.md",
|
||||
"scripts/changeset/README.md",
|
||||
"scripts/changeset/cli.cjs",
|
||||
"scripts/changeset/github-release-notes.cjs",
|
||||
|
||||
@@ -715,29 +715,40 @@ describe('workflow gsd_run query init.<workflow> invocations forward every flag:
|
||||
const workflowMdPath = path.join(ROOT, 'gsd-core', 'workflows', `${workflow}.md`);
|
||||
const content = fs.readFileSync(workflowMdPath, 'utf8');
|
||||
|
||||
const initLineRe = new RegExp(`^.*gsd_run query init\\.${workflow}\\b.*$`, 'm');
|
||||
const initLineMatch = content.match(initLineRe);
|
||||
assert.ok(initLineMatch, `${workflow}.md must contain a "gsd_run query init.${workflow}" invocation line`);
|
||||
const initLine = initLineMatch[0];
|
||||
|
||||
// Everything up to and including the invocation line: real workflows
|
||||
// parse $ARGUMENTS into a param variable earlier in the same bash
|
||||
// block, then reference that variable on the INIT= line itself.
|
||||
const scope = content.slice(0, content.indexOf(initLine) + initLine.length);
|
||||
const referencedVars = varsReferencedIn(initLine);
|
||||
// A workflow may call `gsd_run query init.<workflow>` more than once
|
||||
// (e.g. new-milestone.md's early INIT_EARLY call, whose section_manifest
|
||||
// gates ONLY project-md-milestone-write per its own prose, followed by
|
||||
// a later full INIT call that gates every other flag-gated section and
|
||||
// does forward the flag). Every occurrence is a candidate carrier —
|
||||
// a flagAtom only needs forwarding by AT LEAST ONE invocation line,
|
||||
// not necessarily the first.
|
||||
const initLineRe = new RegExp(`^.*gsd_run query init\\.${workflow}\\b.*$`, 'mg');
|
||||
const initLineMatches = [...content.matchAll(initLineRe)];
|
||||
assert.ok(initLineMatches.length > 0, `${workflow}.md must contain a "gsd_run query init.${workflow}" invocation line`);
|
||||
|
||||
for (const atomFlag of flagAtoms) {
|
||||
const directlyPresent = initLine
|
||||
.split(/\s+/)
|
||||
.includes(atomFlag);
|
||||
const carriers = varsCarryingFlagToken(scope, atomFlag);
|
||||
const forwardedViaVar = [...carriers].some((v) => referencedVars.has(v));
|
||||
const forwardedByAnyInvocation = initLineMatches.some((match) => {
|
||||
const initLine = match[0];
|
||||
// Everything up to and including this invocation line: real
|
||||
// workflows parse $ARGUMENTS into a param variable earlier in the
|
||||
// same bash block, then reference that variable on the INIT= line
|
||||
// itself.
|
||||
const scope = content.slice(0, match.index + initLine.length);
|
||||
const referencedVars = varsReferencedIn(initLine);
|
||||
|
||||
const directlyPresent = initLine
|
||||
.split(/\s+/)
|
||||
.includes(atomFlag);
|
||||
const carriers = varsCarryingFlagToken(scope, atomFlag);
|
||||
const forwardedViaVar = [...carriers].some((v) => referencedVars.has(v));
|
||||
return directlyPresent || forwardedViaVar;
|
||||
});
|
||||
|
||||
assert.ok(
|
||||
directlyPresent || forwardedViaVar,
|
||||
`${workflow}.md's "gsd_run query init.${workflow}" invocation line must forward a parameter for ` +
|
||||
forwardedByAnyInvocation,
|
||||
`${workflow}.md's "gsd_run query init.${workflow}" invocation line(s) must forward a parameter for ` +
|
||||
`${atomFlag} (its gated section is otherwise permanently excluded — see BLOCKER, epic #1671 Phase 6.2). ` +
|
||||
`Invocation line: ${initLine}`,
|
||||
`Invocation line(s): ${initLineMatches.map((m) => m[0]).join(' | ')}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const fc = require('./helpers/fast-check-setup.cjs');
|
||||
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
const { runGsdTools, createTempProject, cleanup, readWorkflowCombined } = require('./helpers.cjs');
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
const WORKFLOWS = path.join(ROOT, 'gsd-core', 'workflows');
|
||||
@@ -49,12 +49,20 @@ function statesOmitRule(content) {
|
||||
* reported green across 15 non-compliant files for no better reason than that
|
||||
* nobody had added them to it. Deriving the set is what makes a 16th file
|
||||
* impossible to add silently.
|
||||
*
|
||||
* #2994: `content` is read via `readWorkflowCombined` (host + its
|
||||
* `workflows/<wf>/steps/*.md` fragments), not the bare host file. The
|
||||
* fragment model can move a workflow's own omit-rule prose (e.g.
|
||||
* quick.md's rule lives in `quick/steps/research-phase.md` behind a
|
||||
* `<!-- gsd:section -->` stub) out of the host without moving its
|
||||
* `model="{…}"` dispatch site, so a host-only read would report a
|
||||
* false positive for a workflow that still documents the rule.
|
||||
*/
|
||||
function workflowsThatDispatchWithAModel() {
|
||||
return fs
|
||||
.readdirSync(WORKFLOWS)
|
||||
.filter((f) => f.endsWith('.md'))
|
||||
.map((f) => ({ file: f, content: fs.readFileSync(path.join(WORKFLOWS, f), 'utf8') }))
|
||||
.map((f) => ({ file: f, content: readWorkflowCombined(path.join(WORKFLOWS, f)) }))
|
||||
.filter((w) => /model="\{/.test(w.content));
|
||||
}
|
||||
|
||||
|
||||
@@ -580,6 +580,37 @@ describe('new-milestone.md: workstream-aware PROJECT.md guard (#2308)', () => {
|
||||
// would break bash mid-script (DEFECT.TEST-SHELL-PIPELINE-NONPORTABLE, #2650).
|
||||
const content = readFileNormalized(workflowPath);
|
||||
|
||||
// #2994 fragmentization moved the 7.5 reset-phase-safety section (including
|
||||
// its "/gsd:new-milestone --reset-phase-numbers ${GSD_WS}" rerun hint) out
|
||||
// of new-milestone.md into gsd-core/workflows/new-milestone/steps/reset-phase-safety.md
|
||||
// behind a section marker. Only the routing-interpolation test below needs
|
||||
// that moved text, so it reads host + step file combined instead of
|
||||
// widening `content` (used for host-only fence extraction elsewhere in
|
||||
// this describe block).
|
||||
const contentWithSteps = content + '\n' + fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'new-milestone', 'steps', 'reset-phase-safety.md'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
// #2994 final slice: Step 4's "Part A" milestone-state write moved out of
|
||||
// new-milestone.md into gsd-core/workflows/new-milestone/steps/
|
||||
// project-md-milestone-write.md behind a section marker. The
|
||||
// "step 4 scopes the workstream skip" test below asserts on Part A's
|
||||
// actual body (GSD_WS mentions, the workstream skip description) — rather
|
||||
// than widen `content` for every test in this block, SPLICE the step
|
||||
// file's content into the marker's exact position so partAIdx/partBIdx
|
||||
// position-sensitive slicing below still works. A non-vacuity check
|
||||
// (blank the step file, confirm the splice fails, restore) backs this.
|
||||
const PROJECT_MD_STEP_PATH = path.join(
|
||||
__dirname, '..', 'gsd-core', 'workflows', 'new-milestone', 'steps', 'project-md-milestone-write.md'
|
||||
);
|
||||
const PROJECT_MD_MARKER_RE = /<!-- gsd:section id="project-md-milestone-write"[\s\S]*?<!-- \/gsd:section -->/;
|
||||
function contentWithProjectMdStepSpliced() {
|
||||
const stepBody = fs.readFileSync(PROJECT_MD_STEP_PATH, 'utf8');
|
||||
assert.match(content, PROJECT_MD_MARKER_RE, 'project-md-milestone-write marker not found in new-milestone.md');
|
||||
return content.replace(PROJECT_MD_MARKER_RE, stepBody);
|
||||
}
|
||||
|
||||
// Locate the first ```bash fence strictly between two headings.
|
||||
function extractFenceBetween(markdown, startHeading, endHeading) {
|
||||
const startIdx = markdown.indexOf(startHeading);
|
||||
@@ -677,7 +708,7 @@ describe('new-milestone.md: workstream-aware PROJECT.md guard (#2308)', () => {
|
||||
|
||||
test('routing interpolations still propagate ${GSD_WS} at the documented lines', () => {
|
||||
assert.ok(
|
||||
content.includes('/gsd:new-milestone --reset-phase-numbers ${GSD_WS}'),
|
||||
contentWithSteps.includes('/gsd:new-milestone --reset-phase-numbers ${GSD_WS}'),
|
||||
'reset-phase-numbers rerun hint should propagate ${GSD_WS}'
|
||||
);
|
||||
assert.ok(
|
||||
@@ -699,10 +730,11 @@ describe('new-milestone.md: workstream-aware PROJECT.md guard (#2308)', () => {
|
||||
});
|
||||
|
||||
test('step 4 scopes the workstream skip to the milestone-state write only; Evolution repair always runs (finding 2)', () => {
|
||||
const step4Idx = content.indexOf('## 4. Update PROJECT.md');
|
||||
const step5Idx = content.indexOf('## 5. Update STATE.md');
|
||||
const splicedContent = contentWithProjectMdStepSpliced();
|
||||
const step4Idx = splicedContent.indexOf('## 4. Update PROJECT.md');
|
||||
const step5Idx = splicedContent.indexOf('## 5. Update STATE.md');
|
||||
assert.ok(step4Idx !== -1 && step5Idx !== -1 && step4Idx < step5Idx, 'steps 4 and 5 should be locatable');
|
||||
const step4Body = content.slice(step4Idx, step5Idx);
|
||||
const step4Body = splicedContent.slice(step4Idx, step5Idx);
|
||||
|
||||
const partAIdx = step4Body.indexOf('Part A');
|
||||
const partBIdx = step4Body.indexOf('Part B');
|
||||
|
||||
@@ -53,8 +53,27 @@ describe('new-project — MVP mode prompt', () => {
|
||||
// the #3784 two-question split already shipped for /gsd:settings. new-project.md has no
|
||||
// <step> tags, so blocks are located by the `header: "AI Models"` marker.
|
||||
|
||||
// #2994 fragmentization moved the Step 2a "AI Models" auto-mode prompt (and its
|
||||
// config-new-project example payload) out of new-project.md into
|
||||
// gsd-core/workflows/new-project/steps/auto-mode-config.md behind a section
|
||||
// marker (Step 5's interactive prompt stays in the host). Read host + every
|
||||
// step file combined so the "at least two AI Models prompts" / "both example
|
||||
// payloads" counts are preserved across the split rather than reduced.
|
||||
const NEW_PROJECT_STEPS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows', 'new-project', 'steps');
|
||||
function readNewProjectCombined() {
|
||||
let combined = fs.readFileSync(WORKFLOW, 'utf8');
|
||||
if (fs.existsSync(NEW_PROJECT_STEPS_DIR)) {
|
||||
for (const entry of fs.readdirSync(NEW_PROJECT_STEPS_DIR).sort()) {
|
||||
if (entry.endsWith('.md')) {
|
||||
combined += '\n' + fs.readFileSync(path.join(NEW_PROJECT_STEPS_DIR, entry), 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
describe('bug #1516: new-project AI Models prompt exposes all 5 model profiles', () => {
|
||||
const content = fs.readFileSync(WORKFLOW, 'utf-8');
|
||||
const content = readNewProjectCombined();
|
||||
|
||||
// Locate every `header: "AI Models"` AskUserQuestion block and grab a window large
|
||||
// enough to include its conditional Q2 successor (the standard-tier picker).
|
||||
|
||||
@@ -116,7 +116,13 @@ describe('ADR-857 phase 6 verification and review capability migration', () => {
|
||||
|
||||
test('quick full-mode code review resolves execute:post hooks instead of inlining code_review config', () => {
|
||||
const content = workflow('quick.md');
|
||||
const section = sectionBetween(content, '**Step 6.25: Code review (auto)**', '**Step 6.5: Verification');
|
||||
// #2994 fragmentization moved Step 6.5 (Verification) out of quick.md into
|
||||
// gsd-core/workflows/quick/steps/quick-verification.md; the parent now marks
|
||||
// that boundary with a `<!-- gsd:section id="quick-verification" -->` comment
|
||||
// immediately after Step 6.25's content, so it remains the correct
|
||||
// end-of-step delimiter (mirrors the execute-phase.md gap-closure-artifacts
|
||||
// pattern above) instead of bleeding to end-of-file.
|
||||
const section = sectionBetween(content, '**Step 6.25: Code review (auto)**', '<!-- gsd:section id="quick-verification"');
|
||||
|
||||
assert.ok(section.includes('loop render-hooks execute:post'));
|
||||
assert.ok(section.includes('gsd-code-reviewer'));
|
||||
|
||||
@@ -1161,12 +1161,22 @@ describe('feat-22-surfacing-docs', () => {
|
||||
});
|
||||
|
||||
test('new-project workflow has Drift Guard default-yes option', () => {
|
||||
const content = fs.readFileSync(NEW_PROJECT_PATH, 'utf-8');
|
||||
// #2994 fragmentization moved the Step 2a auto-mode AI/Drift-Guard
|
||||
// AskUserQuestion block (the sole holder of this exact phrasing, even
|
||||
// pre-fragmentization — Step 5's interactive block uses different wording)
|
||||
// out of new-project.md into
|
||||
// gsd-core/workflows/new-project/steps/auto-mode-config.md. Read host +
|
||||
// step combined so this count is preserved across the split.
|
||||
const content = fs.readFileSync(NEW_PROJECT_PATH, 'utf-8') +
|
||||
'\n' + fs.readFileSync(
|
||||
path.join(ROOT, 'gsd-core', 'workflows', 'new-project', 'steps', 'auto-mode-config.md'),
|
||||
'utf-8'
|
||||
);
|
||||
// Both question blocks (auto and interactive) should have the yes option
|
||||
const count = (content.match(/Yes \(Recommended\).*catches hallucinated names/g) || []).length;
|
||||
assert.ok(
|
||||
count >= 1,
|
||||
'new-project.md must have at least one Drift Guard "Yes (Recommended)" option'
|
||||
'new-project.md (host + new-project/steps/*.md) must have at least one Drift Guard "Yes (Recommended)" option'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -7,14 +7,25 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// #2994 fragmentization moved the automated_ui_verification step out of
|
||||
// verify-work.md into gsd-core/workflows/verify-work/steps/automated-ui-verification.md
|
||||
// behind a section marker (`state:ui-phase-active`). The host no longer
|
||||
// contains any "playwright" mention at all — reading the host alone now
|
||||
// only passes these two assertions via unrelated substring coincidences
|
||||
// ("automated"/"UI" from the section-marker id and an unrelated "User-facing
|
||||
// changes - UI" bullet; "fall back" from an unrelated subagent-dispatch
|
||||
// line), which is vacuous. Read the step file directly — it is the sole
|
||||
// remaining source of the real Playwright content.
|
||||
const AUTOMATED_UI_VERIFICATION_STEP_PATH = path.join(
|
||||
__dirname, '..', 'gsd-core', 'workflows', 'verify-work', 'steps', 'automated-ui-verification.md'
|
||||
);
|
||||
|
||||
describe('Playwright-MCP UI verification integration', () => {
|
||||
test('verify-work.md mentions automated UI verification', () => {
|
||||
const content = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work.md'), 'utf-8'
|
||||
);
|
||||
const content = fs.readFileSync(AUTOMATED_UI_VERIFICATION_STEP_PATH, 'utf-8');
|
||||
assert.ok(
|
||||
content.toLowerCase().includes('playwright') || content.includes('automated') && content.includes('UI'),
|
||||
'verify-work.md should mention automated UI verification option'
|
||||
'verify-work.md (or its extracted verify-work/steps/automated-ui-verification.md) should mention automated UI verification option'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -39,9 +50,7 @@ describe('Playwright-MCP UI verification integration', () => {
|
||||
});
|
||||
|
||||
test('automated verification is optional/conditional (falls back to manual)', () => {
|
||||
const verifyContent = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work.md'), 'utf-8'
|
||||
);
|
||||
const verifyContent = fs.readFileSync(AUTOMATED_UI_VERIFICATION_STEP_PATH, 'utf-8');
|
||||
// Must include a fallback / "if available" conditional
|
||||
const hasConditional =
|
||||
verifyContent.includes('if available') ||
|
||||
|
||||
@@ -14,6 +14,16 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// #2994 fragmentization moved the --forensic-gated forensic_audit step out of
|
||||
// progress.md into gsd-core/workflows/progress/steps/forensic-audit.md behind
|
||||
// a section marker. Tests that need the step BODY read that step file
|
||||
// directly (it is the sole remaining source of the step's content); the
|
||||
// step-presence check below is the only one that must also confirm the host
|
||||
// still wires up the marker that reads it.
|
||||
const FORENSIC_AUDIT_STEP_PATH = path.join(
|
||||
__dirname, '..', 'gsd-core', 'workflows', 'progress', 'steps', 'forensic-audit.md'
|
||||
);
|
||||
|
||||
describe('#2189: progress --forensic flag', () => {
|
||||
test('progress command argument-hint includes --forensic', () => {
|
||||
const command = fs.readFileSync(
|
||||
@@ -26,20 +36,19 @@ describe('#2189: progress --forensic flag', () => {
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md'), 'utf8'
|
||||
);
|
||||
const step = fs.readFileSync(FORENSIC_AUDIT_STEP_PATH, 'utf8');
|
||||
assert.ok(
|
||||
workflow.includes('<step name="forensic_audit">'),
|
||||
'workflow should have a forensic_audit step'
|
||||
workflow.includes('id="forensic-audit"'),
|
||||
'progress.md must wire up the forensic-audit section marker'
|
||||
);
|
||||
assert.ok(
|
||||
step.includes('<step name="forensic_audit">'),
|
||||
'progress/steps/forensic-audit.md should have a forensic_audit step'
|
||||
);
|
||||
});
|
||||
|
||||
test('forensic_audit step is only triggered when --forensic is present', () => {
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md'), 'utf8'
|
||||
);
|
||||
const forensicStep = workflow.slice(
|
||||
workflow.indexOf('<step name="forensic_audit">'),
|
||||
workflow.indexOf('</step>', workflow.indexOf('<step name="forensic_audit">'))
|
||||
);
|
||||
const forensicStep = fs.readFileSync(FORENSIC_AUDIT_STEP_PATH, 'utf8');
|
||||
assert.ok(
|
||||
forensicStep.includes('--forensic'),
|
||||
'forensic_audit step should be gated on --forensic flag'
|
||||
@@ -51,13 +60,7 @@ describe('#2189: progress --forensic flag', () => {
|
||||
});
|
||||
|
||||
test('forensic_audit step includes all 6 checks', () => {
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md'), 'utf8'
|
||||
);
|
||||
const forensicStep = workflow.slice(
|
||||
workflow.indexOf('<step name="forensic_audit">'),
|
||||
workflow.indexOf('</step>', workflow.indexOf('<step name="forensic_audit">'))
|
||||
);
|
||||
const forensicStep = fs.readFileSync(FORENSIC_AUDIT_STEP_PATH, 'utf8');
|
||||
// Check 1: STATE vs artifact consistency
|
||||
assert.ok(
|
||||
forensicStep.includes('STATE') && (forensicStep.includes('artifact') || forensicStep.includes('consistent')),
|
||||
@@ -91,13 +94,7 @@ describe('#2189: progress --forensic flag', () => {
|
||||
});
|
||||
|
||||
test('forensic_audit step produces a CLEAN or INTEGRITY ISSUE(S) FOUND verdict', () => {
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md'), 'utf8'
|
||||
);
|
||||
const forensicStep = workflow.slice(
|
||||
workflow.indexOf('<step name="forensic_audit">'),
|
||||
workflow.indexOf('</step>', workflow.indexOf('<step name="forensic_audit">'))
|
||||
);
|
||||
const forensicStep = fs.readFileSync(FORENSIC_AUDIT_STEP_PATH, 'utf8');
|
||||
assert.ok(
|
||||
forensicStep.includes('CLEAN'),
|
||||
'forensic step should produce a CLEAN verdict when all checks pass'
|
||||
@@ -109,14 +106,8 @@ describe('#2189: progress --forensic flag', () => {
|
||||
});
|
||||
|
||||
test('forensic_audit step does not change default progress behavior', () => {
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md'), 'utf8'
|
||||
);
|
||||
// The forensic step must explicitly say default behavior is unchanged
|
||||
const forensicStep = workflow.slice(
|
||||
workflow.indexOf('<step name="forensic_audit">'),
|
||||
workflow.indexOf('</step>', workflow.indexOf('<step name="forensic_audit">'))
|
||||
);
|
||||
const forensicStep = fs.readFileSync(FORENSIC_AUDIT_STEP_PATH, 'utf8');
|
||||
assert.ok(
|
||||
forensicStep.includes('unchanged') || forensicStep.includes('standard report'),
|
||||
'forensic step should clarify that default behavior is unchanged'
|
||||
|
||||
@@ -7,6 +7,27 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const WORKFLOW = path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress.md');
|
||||
const PROGRESS_STEPS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows', 'progress', 'steps');
|
||||
|
||||
/**
|
||||
* progress.md was fragmented (#2994) into gsd-core/workflows/progress/steps/*.md.
|
||||
* The mvp_display step (and its MVP-mode display contract) now lives in
|
||||
* progress/steps/mvp-display.md, only read at all when state:phase-mvp-mode is
|
||||
* true. Read host + every step file combined so this contract guard keeps
|
||||
* seeing the full picture regardless of which file the content physically
|
||||
* lives in.
|
||||
*/
|
||||
function readProgressCombined() {
|
||||
let combined = fs.readFileSync(WORKFLOW, 'utf8');
|
||||
if (fs.existsSync(PROGRESS_STEPS_DIR)) {
|
||||
for (const entry of fs.readdirSync(PROGRESS_STEPS_DIR).sort()) {
|
||||
if (entry.endsWith('.md')) {
|
||||
combined += '\n' + fs.readFileSync(path.join(PROGRESS_STEPS_DIR, entry), 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
function parseProgressContract(content) {
|
||||
const lines = content.split(/\r?\n/);
|
||||
@@ -24,7 +45,7 @@ function parseProgressContract(content) {
|
||||
}
|
||||
|
||||
describe('progress — MVP mode display', () => {
|
||||
const contract = parseProgressContract(fs.readFileSync(WORKFLOW, 'utf-8'));
|
||||
const contract = parseProgressContract(readProgressCombined());
|
||||
|
||||
test('workflow declares MVP_MODE branch', () => {
|
||||
assert.ok(contract.hasMvpModeVariable, 'must declare MVP_MODE');
|
||||
|
||||
@@ -77,13 +77,39 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const QUICK_MD = path.join(__dirname, '..', 'gsd-core', 'workflows', 'quick.md');
|
||||
const REPO_ROOT_FOR_SECTIONS = path.join(__dirname, '..');
|
||||
|
||||
/**
|
||||
* #2994 fragmentization moved Steps 4.5/4.75/5.5/5.6/6.5 out of quick.md into
|
||||
* gsd-core/workflows/quick/steps/*.md behind section markers. A plain
|
||||
* `content.indexOf('Step 5.6')` against the host now matches an unrelated
|
||||
* later CROSS-REFERENCE to "Step 5.6" (a mention inside the worktree-branch
|
||||
* guard prose), not the real heading — silently vacuous, since that
|
||||
* mis-anchored slice still happens to contain USE_WORKTREES/commit_docs/
|
||||
* PLAN.md/git add/git commit substrings from unrelated surrounding text.
|
||||
* Expand each `<!-- gsd:section id="X" ... -->...<!-- /gsd:section -->`
|
||||
* marker IN PLACE with its step file's content so Step 5.5/5.6/6/6.5 land
|
||||
* back at their original logical positions and ordering/slicing assertions
|
||||
* see the real step bodies again.
|
||||
*/
|
||||
function expandWorkflowSections(workflowPath) {
|
||||
const raw = fs.readFileSync(workflowPath, 'utf8');
|
||||
const markerRe = /<!-- gsd:section id="[\w-]+" when="[^"]*" -->[\s\S]*?<!-- \/gsd:section -->/g;
|
||||
return raw.replace(markerRe, (block) => {
|
||||
const pathMatch = block.match(/`([^`]+\.md)`/);
|
||||
if (!pathMatch) return block;
|
||||
const stepPath = path.join(REPO_ROOT_FOR_SECTIONS, pathMatch[1]);
|
||||
if (!fs.existsSync(stepPath)) return block;
|
||||
return fs.readFileSync(stepPath, 'utf8');
|
||||
});
|
||||
}
|
||||
|
||||
describe('quick.md pre-dispatch PLAN.md commit (#2432)', () => {
|
||||
let content;
|
||||
|
||||
test('quick.md exists', () => {
|
||||
assert.ok(fs.existsSync(QUICK_MD), 'gsd-core/workflows/quick.md must exist');
|
||||
content = fs.readFileSync(QUICK_MD, 'utf-8');
|
||||
content = expandWorkflowSections(QUICK_MD);
|
||||
});
|
||||
|
||||
test('Step 5.6 exists between Step 5.5 and Step 6', () => {
|
||||
|
||||
@@ -16,6 +16,27 @@ const { runGsdTools, createTempProject, cleanup, absPlanningPath } = require('./
|
||||
|
||||
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
|
||||
const WORKFLOWS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows');
|
||||
const REPO_ROOT_FOR_SECTIONS = path.join(__dirname, '..');
|
||||
|
||||
/**
|
||||
* #2994 fragmentization moved Steps 4.5/4.75/5.5/5.6/6.5 out of quick.md into
|
||||
* gsd-core/workflows/quick/steps/*.md behind section markers. Position-based
|
||||
* slicing here (`indexOf('Step 4.75')` .. `indexOf('Step 5:')`, etc.) needs
|
||||
* those step headings back at their original logical position, not appended
|
||||
* at the end — so expand each `<!-- gsd:section id="X" ... -->...
|
||||
* <!-- /gsd:section -->` marker IN PLACE with its step file's content.
|
||||
*/
|
||||
function expandWorkflowSections(workflowPath) {
|
||||
const raw = fs.readFileSync(workflowPath, 'utf8');
|
||||
const markerRe = /<!-- gsd:section id="[\w-]+" when="[^"]*" -->[\s\S]*?<!-- \/gsd:section -->/g;
|
||||
return raw.replace(markerRe, (block) => {
|
||||
const pathMatch = block.match(/`([^`]+\.md)`/);
|
||||
if (!pathMatch) return block;
|
||||
const stepPath = path.join(REPO_ROOT_FOR_SECTIONS, pathMatch[1]);
|
||||
if (!fs.existsSync(stepPath)) return block;
|
||||
return fs.readFileSync(stepPath, 'utf8');
|
||||
});
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Command frontmatter: --research flag advertised
|
||||
@@ -67,11 +88,11 @@ describe('quick workflow: research step', () => {
|
||||
|
||||
test('workflow file exists', () => {
|
||||
assert.ok(fs.existsSync(workflowPath), 'workflows/quick.md should exist');
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
});
|
||||
|
||||
test('purpose mentions --research flag', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
const purposeMatch = content.match(/<purpose>([\s\S]*?)<\/purpose>/);
|
||||
assert.ok(purposeMatch, 'should have <purpose> section');
|
||||
assert.ok(
|
||||
@@ -81,7 +102,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('step 1 parses --research flag', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
assert.ok(
|
||||
content.includes('$RESEARCH_MODE'),
|
||||
'workflow should reference $RESEARCH_MODE variable'
|
||||
@@ -89,7 +110,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('step 4.75 research phase exists', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
assert.ok(
|
||||
content.includes('Step 4.75'),
|
||||
'workflow should contain Step 4.75 (research phase)'
|
||||
@@ -97,7 +118,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('research step spawns gsd-phase-researcher', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
const researchSection = content.substring(
|
||||
content.indexOf('Step 4.75'),
|
||||
content.indexOf('Step 5:')
|
||||
@@ -109,7 +130,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('research step writes RESEARCH.md', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
const researchSection = content.substring(
|
||||
content.indexOf('Step 4.75'),
|
||||
content.indexOf('Step 5:')
|
||||
@@ -121,7 +142,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('planner context includes RESEARCH.md when research mode', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
const plannerSection = content.substring(
|
||||
content.indexOf('Step 5: Spawn planner'),
|
||||
content.indexOf('Step 5.5')
|
||||
@@ -133,7 +154,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('file commit list includes RESEARCH.md', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
const commitSection = content.substring(
|
||||
content.indexOf('Step 8:'),
|
||||
content.indexOf('</process>')
|
||||
@@ -145,7 +166,7 @@ describe('quick workflow: research step', () => {
|
||||
});
|
||||
|
||||
test('success criteria includes research items', () => {
|
||||
content = fs.readFileSync(workflowPath, 'utf-8');
|
||||
content = expandWorkflowSections(workflowPath);
|
||||
const criteriaMatch = content.match(/<success_criteria>([\s\S]*?)<\/success_criteria>/);
|
||||
assert.ok(criteriaMatch, 'should have <success_criteria> section');
|
||||
assert.ok(
|
||||
|
||||
163
tests/resolver-hoist-guard.test.cjs
Normal file
163
tests/resolver-hoist-guard.test.cjs
Normal file
@@ -0,0 +1,163 @@
|
||||
'use strict';
|
||||
|
||||
// allow-test-rule: source-text-is-the-product see #2994 — G5 below asserts that an
|
||||
// extracted step file's raw text does not contain the literal resolver call
|
||||
// for the SAME fact that gates its own admission (a circular, self-disabling
|
||||
// section). There is no typed/structural representation of "this step body
|
||||
// re-derives its own gate" other than the text itself; G2 asserts a specific
|
||||
// resolver variable's source line is retained verbatim because a STILL-LIVE
|
||||
// consumer elsewhere in the same host file reads it literally.
|
||||
|
||||
/**
|
||||
* Resolver-hoist guard — #2994 (epic #1671 Phase 6.3) matrix §G
|
||||
* (`.gsd/phase/chore-2994-fragment-model-workflows/50-test-matrix.md`):
|
||||
* "did the hoist break the ungated path?" and "did the hoist actually
|
||||
* happen?" — a gated section whose own extracted body STILL resolves its own
|
||||
* gating fact is a circular, self-disabling section (the `plan-phase.md:125-158`
|
||||
* precedent named in `40-design.md`'s negative space).
|
||||
*
|
||||
* G5 generalizes G1-G4 into ONE data-driven assertion over the SHIPPED
|
||||
* `gsd-core/workflows/section-manifest.json`, so a FUTURE extraction cannot
|
||||
* reintroduce the class without this test catching it: for every gated
|
||||
* section whose `when=` atom has a documented, config-key-backed (or
|
||||
* detector-backed) resolution — per `src/section-manifest.cts`'s
|
||||
* `InvocationFacts` JSDoc and `src/init.cts`'s `detect*`/`buildSectionManifestField`
|
||||
* comments, both read directly rather than re-guessed — its own step file
|
||||
* must not contain the literal resolver call for that SAME fact. Where no
|
||||
* generic rule is derivable (e.g. `state:workstream-active`'s env/pointer
|
||||
* resolution, `state:is-monorepo`'s glob-detector, `state:next-channel`'s
|
||||
* flag-only resolution), the atom is simply absent from the map below and
|
||||
* skipped — per the matrix's own "where a generic rule is impossible, encode
|
||||
* the specific known pairs" instruction.
|
||||
*/
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const SHIPPED_MANIFEST_PATH = path.join(ROOT, 'gsd-core', 'workflows', 'section-manifest.json');
|
||||
|
||||
function readShippedManifest() {
|
||||
return JSON.parse(fs.readFileSync(SHIPPED_MANIFEST_PATH, 'utf8'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenated content of every ```-fenced code block in `content` (fence
|
||||
* markers themselves excluded). A LIVE resolver call (an actual `gsd_run
|
||||
* query ...`/`gsd_run loop ...` invocation the runtime would execute) only
|
||||
* ever appears inside a fenced bash block; a PROSE mention of the same
|
||||
* config key or command name (e.g. documenting why a resolver was
|
||||
* deliberately removed, or naming a config key in a sentence) appears in
|
||||
* single-backtick inline code within ordinary prose, never inside a fence.
|
||||
* Restricting the forbidden-substring search below to fenced content is what
|
||||
* lets G5 tell "this step file still executes the resolver" apart from
|
||||
* "this step file's prose merely talks about the resolver" — both
|
||||
* `mvp-display.md` and `reviewer-instances-note-1.md` do the latter
|
||||
* (explaining, in prose, why they do NOT re-resolve), which a plain
|
||||
* whole-file substring search cannot distinguish from the former.
|
||||
*/
|
||||
function fencedCodeOnly(content) {
|
||||
const parts = content.split('```');
|
||||
// parts[0] is text before the first fence, parts[1] is inside the first
|
||||
// fence, parts[2] is between fence 1's close and fence 2's open, etc. —
|
||||
// odd indices are fence interiors (matches this repo's other fence-aware
|
||||
// helpers' `%2===1` convention).
|
||||
return parts.filter((_, i) => i % 2 === 1).join('\n');
|
||||
}
|
||||
|
||||
// ─── G5: no gated section's own step file resolves its own gating fact ────
|
||||
|
||||
/**
|
||||
* Known {when atom -> forbidden literal substring(s)} pairs: the exact
|
||||
* resolver invocation each atom's fact is documented as being hoisted FROM
|
||||
* (`src/init.cts`'s `detectFallowConfig`/`detectGitCreateTag`/`readConfigJsonBoolean`
|
||||
* call sites, and `src/section-manifest.cts`'s matching `InvocationFacts`
|
||||
* JSDoc for each field). A step file gated on the atom must never contain
|
||||
* that substring — if it does, the section re-derives the same fact its own
|
||||
* marker already gates on, instead of consuming the init-resolved value.
|
||||
*/
|
||||
const ATOM_FORBIDDEN_RESOLVER_SUBSTRINGS = Object.freeze({
|
||||
'state:fallow-enabled': ['code_quality.fallow.enabled'],
|
||||
'state:git-create-tag': ['git.create_tag'],
|
||||
'state:chunked-mode': ['workflow.plan_chunked'],
|
||||
'state:worktrees-enabled': ['workflow.use_worktrees'],
|
||||
'state:reviewer-instances-configured': ['review.reviewer_instances'],
|
||||
'state:phase-mvp-mode': ['phase.mvp-mode'],
|
||||
// #2994: detectUiPhaseActive (src/init.cts) resolves this fact via
|
||||
// `resolveLoopHooks({point:'plan:pre', ...})` — the CLI-facing equivalent
|
||||
// of that SAME resolution is `gsd_run loop render-hooks plan:pre`.
|
||||
'state:ui-phase-active': ['render-hooks plan:pre'],
|
||||
});
|
||||
|
||||
describe('no gated section resolves its own gating fact (matrix row G5, data-driven over the shipped manifest)', () => {
|
||||
const manifest = readShippedManifest();
|
||||
|
||||
for (const [workflow, sections] of Object.entries(manifest.workflows)) {
|
||||
for (const section of sections) {
|
||||
const forbidden = ATOM_FORBIDDEN_RESOLVER_SUBSTRINGS[section.when];
|
||||
if (!forbidden) continue; // no generic rule for this atom — see module doc comment.
|
||||
|
||||
test(`${workflow}.md § "${section.id}" (when="${section.when}") does not re-resolve its own gate`, () => {
|
||||
const stepFilePath = path.join(ROOT, section.read);
|
||||
const stepContent = fencedCodeOnly(fs.readFileSync(stepFilePath, 'utf8'));
|
||||
for (const token of forbidden) {
|
||||
assert.ok(
|
||||
!stepContent.includes(token),
|
||||
`${section.read} (gated on "${section.when}") must not itself call the resolver for that fact ` +
|
||||
`(found forbidden substring "${token}") — this is a circular, self-disabling section: the init-resolved ` +
|
||||
`fact already gates this file's own inclusion, so re-deriving it inside the file is dead weight at best ` +
|
||||
`and a divergent second resolver at worst`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
test('the forbidden-substring map itself covers at least one atom actually present in the shipped manifest (anti-vacuity)', () => {
|
||||
const usedAtoms = new Set();
|
||||
for (const sections of Object.values(manifest.workflows)) {
|
||||
for (const section of sections) usedAtoms.add(section.when);
|
||||
}
|
||||
const coveredAndUsed = Object.keys(ATOM_FORBIDDEN_RESOLVER_SUBSTRINGS).filter((atom) => usedAtoms.has(atom));
|
||||
assert.ok(coveredAndUsed.length > 0, 'the forbidden-substring map must exercise at least one atom the shipped manifest actually gates a section on');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── G2: autonomous.md's $PLAN_STRATEGY resolver survives the converge hoist
|
||||
// because ungated "local" bullets still consume it literally ─────────────
|
||||
|
||||
describe('autonomous.md retains its $PLAN_STRATEGY resolver — still consumed by ungated content (matrix row G2)', () => {
|
||||
const filePath = path.join(ROOT, 'gsd-core', 'workflows', 'autonomous.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
test('the PLAN_STRATEGY resolver (local/converge assignment) is present verbatim', () => {
|
||||
assert.ok(content.includes('PLAN_STRATEGY="local"'), 'the default-local assignment must survive the converge-hoist');
|
||||
assert.ok(content.includes('PLAN_STRATEGY="converge"'), 'the converge-branch assignment must survive the converge-hoist');
|
||||
});
|
||||
|
||||
test('an ungated "PLAN_STRATEGY=local" consumer exists OUTSIDE any converge-* gated section', () => {
|
||||
const { parseWorkflowSections } = require('../gsd-core/bin/lib/workflow-fragments.cjs');
|
||||
const sections = parseWorkflowSections(content, 'gsd-core/workflows/autonomous.md');
|
||||
|
||||
const CONSUMER_TEXT = 'If `PLAN_STRATEGY=local`, run the regular planner:';
|
||||
assert.ok(content.includes(CONSUMER_TEXT), 'the ungated local-strategy consumer text must exist in the host file');
|
||||
|
||||
const gatedConvergeSections = sections.filter((s) => s.explicit && s.when === 'state:plan-strategy-converge');
|
||||
assert.ok(gatedConvergeSections.length > 0, 'sanity: autonomous.md must have at least one state:plan-strategy-converge gated section');
|
||||
for (const gated of gatedConvergeSections) {
|
||||
assert.ok(
|
||||
!gated.body.includes(CONSUMER_TEXT),
|
||||
`the ungated PLAN_STRATEGY=local consumer must not live inside gated section "${gated.id}" — deleting that section must never remove the local-planning path`,
|
||||
);
|
||||
}
|
||||
|
||||
// Deleting the resolver would break this ungated consumer — assert the
|
||||
// resolver assignment and the consumer are BOTH present outside every
|
||||
// converge-gated section (i.e. in the always-composed remainder).
|
||||
const gapText = sections.filter((s) => !s.explicit).map((s) => s.body).join('');
|
||||
assert.ok(gapText.includes('PLAN_STRATEGY="local"'));
|
||||
assert.ok(gapText.includes(CONSUMER_TEXT));
|
||||
});
|
||||
});
|
||||
310
tests/section-manifest-init-facts.test.cjs
Normal file
310
tests/section-manifest-init-facts.test.cjs
Normal file
@@ -0,0 +1,310 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Prod-shape integration tests for `src/init.cts`'s `buildSectionManifestField`
|
||||
* seam (compiled into `gsd-core/bin/lib/init.cjs`) — #2994 (epic #1671 Phase
|
||||
* 6.3), `.gsd/phase/chore-2994-fragment-model-workflows/50-test-matrix.md`
|
||||
* sections B (compound-fact folding), D (flag value shapes), and E (the
|
||||
* `null` vs `[]` distinction).
|
||||
*
|
||||
* Every test drives the REAL CLI (`runGsdTools`, spawns `gsd-tools.cjs`) —
|
||||
* never a direct `require()` of `cmdInit*`, since `buildSectionManifestField`
|
||||
* itself is not exported and the whole point of this suite is proving the
|
||||
* flag/config plumbing that only exists at the CLI seam (`init-command-router.cjs`'s
|
||||
* `parseNamedArgs` calls) actually reaches `section_manifest`.
|
||||
*
|
||||
* Group E uses the `GSD_SECTION_MANIFEST` env override
|
||||
* (`gsd-core/bin/lib/init.cjs`'s `_sectionManifestCandidatePath`) to point the
|
||||
* CLI at a temp fixture manifest instead of the shipped
|
||||
* `gsd-core/workflows/section-manifest.json` — this is the ONLY way to
|
||||
* exercise "workflow absent from the manifest" today, because every
|
||||
* `cmdInit*` this repo currently wires (#2994's own completion) already has
|
||||
* an explicit key in the shipped artifact; Groups B and D deliberately do NOT
|
||||
* override it, driving the shipped manifest directly per the matrix's own
|
||||
* "drive from the shipped artifact wherever possible" rule.
|
||||
*/
|
||||
|
||||
const { describe, test, beforeEach, afterEach } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const { runGsdTools, cleanup, createTempDir, createTempProject } = require('./helpers.cjs');
|
||||
const { seedPhase } = require('./fixtures/index.cjs');
|
||||
|
||||
function writeConfig(tmpDir, config) {
|
||||
fs.mkdirSync(path.join(tmpDir, '.planning'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'config.json'), JSON.stringify(config, null, 2));
|
||||
}
|
||||
|
||||
function runInitJson(argv, cwd, env = {}) {
|
||||
const result = runGsdTools(argv, cwd, env);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
return JSON.parse(result.output);
|
||||
}
|
||||
|
||||
// ─── Group E: the null vs [] distinction (matrix rows E1/E2/E3/E5/E6) ──────
|
||||
|
||||
describe('section_manifest: null (degraded) vs [] (computed, nothing applicable) — matrix §E', () => {
|
||||
let tmpDir;
|
||||
let manifestDir;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = createTempProject('section-manifest-e-');
|
||||
manifestDir = createTempDir('section-manifest-e-manifest-');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup(tmpDir);
|
||||
cleanup(manifestDir);
|
||||
});
|
||||
|
||||
test('a manifest with no "quick" key degrades section_manifest to null (row E1)', () => {
|
||||
const manifestPath = path.join(manifestDir, 'manifest.json');
|
||||
fs.writeFileSync(manifestPath, JSON.stringify({ workflows: {} }));
|
||||
|
||||
const output = runInitJson(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: manifestPath });
|
||||
assert.equal(output.section_manifest, null, 'an absent workflow key must degrade to null, never []');
|
||||
});
|
||||
|
||||
test('a manifest with an explicit empty "quick" section list yields a computed [] (row E2)', () => {
|
||||
const manifestPath = path.join(manifestDir, 'manifest.json');
|
||||
fs.writeFileSync(manifestPath, JSON.stringify({ workflows: { quick: [] } }));
|
||||
|
||||
const output = runInitJson(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: manifestPath });
|
||||
assert.notEqual(output.section_manifest, null, 'a present (even empty) workflow key must NOT degrade to null');
|
||||
assert.deepEqual(output.section_manifest.included, []);
|
||||
assert.deepEqual(output.section_manifest.excluded, []);
|
||||
assert.deepEqual(output.section_manifest.read, []);
|
||||
});
|
||||
|
||||
test('null and the computed [] shape are DIFFERENT values, not interchangeable (row E3)', () => {
|
||||
const absentKeyManifest = path.join(manifestDir, 'absent.json');
|
||||
fs.writeFileSync(absentKeyManifest, JSON.stringify({ workflows: {} }));
|
||||
const emptyListManifest = path.join(manifestDir, 'empty.json');
|
||||
fs.writeFileSync(emptyListManifest, JSON.stringify({ workflows: { quick: [] } }));
|
||||
|
||||
const degraded = runInitJson(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: absentKeyManifest });
|
||||
const computed = runInitJson(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: emptyListManifest });
|
||||
|
||||
assert.equal(degraded.section_manifest, null);
|
||||
assert.notEqual(computed.section_manifest, null);
|
||||
assert.notDeepEqual(degraded.section_manifest, computed.section_manifest, 'null must never compare equal to the computed {included:[],excluded:[],...} shape');
|
||||
});
|
||||
|
||||
test('a section list where every when= evaluates false is still the computed [] shape, not null (row E2, second case)', () => {
|
||||
// "Applicable" is a FACTS question, not a shape question: a real section
|
||||
// whose gating flag was simply never passed on this invocation must still
|
||||
// be the computed {included:[],...} object, never collapse to null.
|
||||
const manifestPath = path.join(manifestDir, 'manifest.json');
|
||||
fs.writeFileSync(manifestPath, JSON.stringify({
|
||||
workflows: {
|
||||
quick: [{ id: 'discussion-phase', when: 'flag:--discuss', read: 'gsd-core/workflows/quick/steps/discussion-phase.md' }],
|
||||
},
|
||||
}));
|
||||
|
||||
const output = runInitJson(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: manifestPath });
|
||||
assert.notEqual(output.section_manifest, null);
|
||||
assert.deepEqual(output.section_manifest.included, []);
|
||||
assert.deepEqual(output.section_manifest.excluded, ['discussion-phase']);
|
||||
});
|
||||
|
||||
test('a missing manifest file degrades to null without throwing (row E5)', () => {
|
||||
const neverCreatedPath = path.join(manifestDir, 'does-not-exist.json');
|
||||
assert.equal(fs.existsSync(neverCreatedPath), false, 'sanity: file must not exist');
|
||||
|
||||
const result = runGsdTools(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: neverCreatedPath });
|
||||
assert.ok(result.success, `a missing manifest file must not crash the command: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.equal(output.section_manifest, null);
|
||||
});
|
||||
|
||||
test('a malformed-JSON manifest file degrades to null without throwing (row E6)', () => {
|
||||
const manifestPath = path.join(manifestDir, 'malformed.json');
|
||||
fs.writeFileSync(manifestPath, '{ this is not valid JSON');
|
||||
|
||||
const result = runGsdTools(['init', 'quick', 'desc'], tmpDir, { GSD_SECTION_MANIFEST: manifestPath });
|
||||
assert.ok(result.success, `a malformed manifest file must not crash the command: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.equal(output.section_manifest, null);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Group B: compound-fact folding lives in init.cts, never the grammar ──
|
||||
|
||||
describe('compound-fact folding at the init seam — matrix §B', () => {
|
||||
let tmpDir;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = createTempProject('section-manifest-b-');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup(tmpDir);
|
||||
});
|
||||
|
||||
// B1-B4: cmdInitQuick folds --full into --discuss/--research/--validate BEFORE
|
||||
// buildSectionManifestField evaluates flag:--discuss/flag:--research/flag:--validate.
|
||||
describe('cmdInitQuick folds --full into each mode fact (rows B1-B4)', () => {
|
||||
test('--discuss alone includes discussion-phase (row B1, baseline)', () => {
|
||||
const output = runInitJson(['init', 'quick', 'desc', '--discuss'], tmpDir);
|
||||
assert.ok(output.section_manifest.included.includes('discussion-phase'));
|
||||
});
|
||||
|
||||
test('--full alone (no --discuss) STILL includes discussion-phase — the fold this PR exists to prove (row B2)', () => {
|
||||
const output = runInitJson(['init', 'quick', 'desc', '--full'], tmpDir);
|
||||
assert.ok(
|
||||
output.section_manifest.included.includes('discussion-phase'),
|
||||
'--full must imply --discuss for section-gating purposes, folded in cmdInitQuick before evaluation',
|
||||
);
|
||||
assert.ok(output.section_manifest.included.includes('research-phase'), '--full must also imply --research');
|
||||
assert.ok(output.section_manifest.included.includes('plan-checker-loop'), '--full must also imply --validate (plan-checker-loop)');
|
||||
assert.ok(output.section_manifest.included.includes('quick-verification'), '--full must also imply --validate (quick-verification)');
|
||||
});
|
||||
|
||||
test('neither --discuss nor --full excludes discussion-phase (row B3)', () => {
|
||||
const output = runInitJson(['init', 'quick', 'desc'], tmpDir);
|
||||
assert.ok(output.section_manifest.excluded.includes('discussion-phase'));
|
||||
});
|
||||
|
||||
test('--full AND --discuss together still include discussion-phase exactly once, no double-counting (row B4)', () => {
|
||||
const output = runInitJson(['init', 'quick', 'desc', '--full', '--discuss'], tmpDir);
|
||||
const occurrences = output.section_manifest.included.filter((id) => id === 'discussion-phase');
|
||||
assert.equal(occurrences.length, 1, 'discussion-phase must appear exactly once in included, never duplicated by the fold');
|
||||
});
|
||||
});
|
||||
|
||||
// B5-B6: cmdInitAutonomous folds --converge OR --cross-ai into one plan_strategy_converge fact.
|
||||
describe('cmdInitAutonomous folds --converge OR --cross-ai (rows B5-B6)', () => {
|
||||
test('--converge alone drives state:plan-strategy-converge sections into included (row B5)', () => {
|
||||
const output = runInitJson(['init', 'autonomous', '--converge'], tmpDir);
|
||||
assert.equal(output.plan_strategy_converge, true);
|
||||
assert.ok(output.section_manifest.included.includes('converge-fail-fast'));
|
||||
assert.ok(output.section_manifest.included.includes('converge-banner'));
|
||||
});
|
||||
|
||||
test('--cross-ai alone (the documented alias, no --converge) ALSO drives inclusion (row B6)', () => {
|
||||
const output = runInitJson(['init', 'autonomous', '--cross-ai'], tmpDir);
|
||||
assert.equal(output.plan_strategy_converge, true);
|
||||
assert.ok(output.section_manifest.included.includes('converge-fail-fast'));
|
||||
assert.ok(output.section_manifest.included.includes('converge-loop'));
|
||||
});
|
||||
|
||||
test('neither flag excludes every converge-* section', () => {
|
||||
const output = runInitJson(['init', 'autonomous'], tmpDir);
|
||||
assert.equal(output.plan_strategy_converge, false);
|
||||
for (const id of ['converge-fail-fast', 'converge-banner', 'converge-dispatch-bg', 'converge-dispatch-inline', 'converge-loop']) {
|
||||
assert.ok(output.section_manifest.excluded.includes(id), `expected "${id}" excluded when neither --converge nor --cross-ai is set`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// B7: cmdInitUpdate folds --next OR --rc into one next_channel fact.
|
||||
describe('cmdInitUpdate folds --next OR --rc (row B7)', () => {
|
||||
test('--rc alone (not --next) drives channel-banner into included', () => {
|
||||
const output = runInitJson(['init', 'update', '--rc'], tmpDir);
|
||||
assert.equal(output.next_channel, true);
|
||||
assert.ok(output.section_manifest.included.includes('channel-banner'));
|
||||
});
|
||||
|
||||
test('--next alone also drives channel-banner into included (the other half of the OR)', () => {
|
||||
const output = runInitJson(['init', 'update', '--next'], tmpDir);
|
||||
assert.equal(output.next_channel, true);
|
||||
assert.ok(output.section_manifest.included.includes('channel-banner'));
|
||||
});
|
||||
|
||||
test('neither flag excludes channel-banner', () => {
|
||||
const output = runInitJson(['init', 'update'], tmpDir);
|
||||
assert.equal(output.next_channel, false);
|
||||
assert.ok(output.section_manifest.excluded.includes('channel-banner'));
|
||||
});
|
||||
});
|
||||
|
||||
// B8: cmdInitDiscussPhaseAssumptions folds --auto OR consolidated auto-mode config.
|
||||
describe('cmdInitDiscussPhaseAssumptions folds --auto flag OR config auto-mode (row B8)', () => {
|
||||
test('no --auto flag, but config workflow._auto_chain_active=true, still includes auto-advance-dispatch', () => {
|
||||
writeConfig(tmpDir, { workflow: { _auto_chain_active: true } });
|
||||
const output = runInitJson(['init', 'discuss-phase-assumptions', '99'], tmpDir);
|
||||
assert.ok(output.section_manifest.included.includes('auto-advance-dispatch'));
|
||||
});
|
||||
|
||||
test('no --auto flag, but config workflow.auto_advance=true, still includes auto-advance-dispatch (the other config source)', () => {
|
||||
writeConfig(tmpDir, { workflow: { auto_advance: true } });
|
||||
const output = runInitJson(['init', 'discuss-phase-assumptions', '99'], tmpDir);
|
||||
assert.ok(output.section_manifest.included.includes('auto-advance-dispatch'));
|
||||
});
|
||||
|
||||
test('--auto flag present with no config also includes auto-advance-dispatch', () => {
|
||||
const output = runInitJson(['init', 'discuss-phase-assumptions', '99', '--auto'], tmpDir);
|
||||
assert.ok(output.section_manifest.included.includes('auto-advance-dispatch'));
|
||||
});
|
||||
|
||||
test('neither --auto nor either config key excludes auto-advance-dispatch', () => {
|
||||
const output = runInitJson(['init', 'discuss-phase-assumptions', '99'], tmpDir);
|
||||
assert.ok(output.section_manifest.excluded.includes('auto-advance-dispatch'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Group D: flag value shapes — token presence, not value truthiness ────
|
||||
|
||||
describe('flag value shapes drive section_manifest by truthiness, not semantic value — matrix §D', () => {
|
||||
let tmpDir;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = createTempProject('section-manifest-d-');
|
||||
seedPhase(tmpDir, '01-sample', { '01-CONTEXT.md': '# Phase Context\n' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup(tmpDir);
|
||||
});
|
||||
|
||||
test('absent boolean flag (--reviews never passed) does not mark reviews-prerequisite present (row D1)', () => {
|
||||
const output = runInitJson(['init', 'plan-phase', '1'], tmpDir);
|
||||
assert.ok(output.section_manifest.excluded.includes('reviews-prerequisite'));
|
||||
assert.ok(!output.section_manifest.included.includes('reviews-prerequisite'));
|
||||
});
|
||||
|
||||
test('empty-string value flag (--prd "") excludes prd-express-gate — an empty value is not a branch selection (row D2)', () => {
|
||||
const output = runInitJson(['init', 'plan-phase', '1', '--prd', ''], tmpDir);
|
||||
assert.ok(output.section_manifest.excluded.includes('prd-express-gate'));
|
||||
});
|
||||
|
||||
test('string-"0" value flag (--prd "0") INCLUDES prd-express-gate — token-presence semantics, not value truthiness (row D3)', () => {
|
||||
const output = runInitJson(['init', 'plan-phase', '1', '--prd', '0'], tmpDir);
|
||||
assert.ok(output.section_manifest.included.includes('prd-express-gate'), '--prd "0" is a non-empty string and must be treated as present');
|
||||
});
|
||||
|
||||
test('whitespace-only value flag (--prd " ") includes prd-express-gate, asserted deliberately (row D4)', () => {
|
||||
const output = runInitJson(['init', 'plan-phase', '1', '--prd', ' '], tmpDir);
|
||||
assert.ok(output.section_manifest.included.includes('prd-express-gate'));
|
||||
});
|
||||
|
||||
test('duplicate flag tokens (--prd a --prd b) resolve to a single membership, no crash (row D5)', () => {
|
||||
const result = runGsdTools(['init', 'plan-phase', '1', '--prd', 'a', '--prd', 'b'], tmpDir);
|
||||
assert.ok(result.success, `duplicate --prd tokens must not crash the command: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.ok(output.section_manifest.included.includes('prd-express-gate'));
|
||||
const occurrences = output.section_manifest.included.filter((id) => id === 'prd-express-gate');
|
||||
assert.equal(occurrences.length, 1, 'must be a single membership, not one entry per duplicate token');
|
||||
});
|
||||
|
||||
test('flag-shaped value (--prd --weird) does not crash and deterministically excludes prd-express-gate (row D6)', () => {
|
||||
// parseNamedArgs treats a token starting with "--" as the NEXT flag, never
|
||||
// as this flag's value — so --prd here resolves to null (absent), not the
|
||||
// literal string "--weird".
|
||||
const result = runGsdTools(['init', 'plan-phase', '1', '--prd', '--weird'], tmpDir);
|
||||
assert.ok(result.success, `a flag-shaped value must not crash the command: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.ok(output.section_manifest.excluded.includes('prd-express-gate'), '--prd immediately followed by another --flag token must resolve to absent, per parseNamedArgs');
|
||||
});
|
||||
|
||||
test('unicode / very long value does not crash and is included as present (row D7)', () => {
|
||||
const longUnicodeValue = `产品需求文档-🚀-${'x'.repeat(2000)}`;
|
||||
const result = runGsdTools(['init', 'plan-phase', '1', '--prd', longUnicodeValue], tmpDir);
|
||||
assert.ok(result.success, `a unicode/very-long --prd value must not crash the command: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.ok(output.section_manifest.included.includes('prd-express-gate'));
|
||||
});
|
||||
});
|
||||
@@ -86,6 +86,24 @@ const factsArb = fc.record({
|
||||
// InvocationFacts — must also participate in the partition/totality
|
||||
// properties below, not just the six pre-existing fact keys.
|
||||
chunkedMode: fc.boolean(),
|
||||
// #2994 (epic #1671 Phase 6.3, matrix §K gap-fill): ten further boolean
|
||||
// facts shipped alongside the widened WHEN_VOCABULARY (30 atoms total).
|
||||
// Without these, `whenArb` (drawn from the FULL WHEN_VOCABULARY) can still
|
||||
// generate sections gated on e.g. `state:plan-strategy-converge`, but every
|
||||
// generated `facts` value left that field `undefined` — falsy under
|
||||
// totality — so those sections were NEVER driven into `included` by this
|
||||
// property, silently narrowing the partition/order-preservation coverage
|
||||
// to the pre-#2994 atom set even though `whenArb` claimed full coverage.
|
||||
uiPhaseActive: fc.boolean(),
|
||||
fallowEnabled: fc.boolean(),
|
||||
gitCreateTag: fc.boolean(),
|
||||
planStrategyConverge: fc.boolean(),
|
||||
reviewerInstancesConfigured: fc.boolean(),
|
||||
autoAdvanceActive: fc.boolean(),
|
||||
isMonorepo: fc.boolean(),
|
||||
nextChannel: fc.boolean(),
|
||||
workstreamActive: fc.boolean(),
|
||||
flatMode: fc.boolean(),
|
||||
});
|
||||
|
||||
// ─── Row 25: exact partition ────────────────────────────────────────────────
|
||||
@@ -136,8 +154,12 @@ describe('property: never throws for vocabulary-valid when and arbitrary facts',
|
||||
|
||||
test('neverThrowsWhenFactsAreMissingKeysEntirely', () => {
|
||||
// Totality also over PARTIAL facts objects (row 19's property-level
|
||||
// twin): dropping zero or more of the seven fact keys must never throw.
|
||||
const factKeys = ['flags', 'phaseNumber', 'hasPriorPhases', 'needsCodebaseMap', 'phaseMvpMode', 'worktreesEnabled', 'chunkedMode'];
|
||||
// twin): dropping zero or more of the fact keys must never throw.
|
||||
const factKeys = [
|
||||
'flags', 'phaseNumber', 'hasPriorPhases', 'needsCodebaseMap', 'phaseMvpMode', 'worktreesEnabled', 'chunkedMode',
|
||||
'uiPhaseActive', 'fallowEnabled', 'gitCreateTag', 'planStrategyConverge', 'reviewerInstancesConfigured',
|
||||
'autoAdvanceActive', 'isMonorepo', 'nextChannel', 'workstreamActive', 'flatMode',
|
||||
];
|
||||
fc.assert(
|
||||
fc.property(sectionsArb, factsArb, fc.subarray(factKeys), (sections, facts, keysToKeep) => {
|
||||
const partialFacts = {};
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const { selectSections, WHEN_PREDICATES, REASON } = require('../gsd-core/bin/lib/section-manifest.cjs');
|
||||
const { WHEN_VOCABULARY } = require('../gsd-core/bin/lib/workflow-fragments.cjs');
|
||||
@@ -262,7 +264,7 @@ describe('flags set cardinality (#2992 row B14)', () => {
|
||||
const sections = Object.freeze([
|
||||
{ id: 'a', when: 'flag:--auto' },
|
||||
{ id: 'b', when: 'flag:--discuss' },
|
||||
{ id: 'c', when: 'flag:--full' },
|
||||
{ id: 'c', when: 'flag:--fix' },
|
||||
]);
|
||||
|
||||
test('zeroFlagsExcludesEveryFlagSection', () => {
|
||||
@@ -276,7 +278,7 @@ describe('flags set cardinality (#2992 row B14)', () => {
|
||||
});
|
||||
|
||||
test('manyFlagsIncludeEveryMatchingSection', () => {
|
||||
const result = selectSections(sections, facts({ flags: new Set(['--auto', '--discuss', '--full', '--irrelevant']) }));
|
||||
const result = selectSections(sections, facts({ flags: new Set(['--auto', '--discuss', '--fix', '--irrelevant']) }));
|
||||
assert.deepEqual(result, { included: ['a', 'b', 'c'], excluded: [] });
|
||||
});
|
||||
});
|
||||
@@ -450,6 +452,161 @@ describe('state:chunked-mode predicate (row A8)', () => {
|
||||
// they were predicates, silently including the section or throwing an
|
||||
// untyped error instead of failing closed with REASON.UNKNOWN_WHEN.
|
||||
|
||||
// ─── #2994 (epic #1671 Phase 6.3) matrix §A: atom admission — the gate-2 hole ──
|
||||
//
|
||||
// The two load-time parity guards above (rows 21-23) prove WHEN_VOCABULARY <->
|
||||
// WHEN_PREDICATES symmetry — every atom has SOME predicate function. Neither
|
||||
// proves the predicate's underlying FACT is ever computed by a real cmdInit*
|
||||
// caller: an atom whose fact no caller assembles evaluates false forever,
|
||||
// which is the silent-wrong-answer class this PR exists to prevent (matrix
|
||||
// row A/#8). This block closes that hole by driving every one of the 30
|
||||
// frozen atoms to both a TRUE and a FALSE outcome via a constructed
|
||||
// InvocationFacts, entirely at this module's own boundary (never reaching
|
||||
// into src/init.cts, which is covered separately in
|
||||
// tests/section-manifest-init-facts.test.cjs).
|
||||
|
||||
/**
|
||||
* Per-atom recipe: how to build an `InvocationFacts` fragment that drives
|
||||
* `WHEN_PREDICATES[atom]` to `true`, and a second fragment that drives it to
|
||||
* `false`. `flag` atoms derive their token mechanically (`atom.slice('flag:'.length)`,
|
||||
* the same derivation B11 above already established as test-only-legal); every
|
||||
* `state:` atom's backing fact FIELD is a hand-written literal here — same
|
||||
* discipline as `WHEN_PREDICATES` itself (module doc comment "The evaluator is
|
||||
* a LOOKUP, not a parser"): there is no mechanical way to derive
|
||||
* `chunkedMode` from `"state:chunked-mode"` without inventing a tokenizer.
|
||||
* `'always'` is the one structural exception: its predicate is `() => true`
|
||||
* unconditionally (it backs every synthesized gap fragment), so no `facts`
|
||||
* value can ever drive it to `false` — handled as its own branch below, not
|
||||
* silently dropped from the 30-atom set A5 checks against.
|
||||
*/
|
||||
const STATE_ATOM_FACT_FIELD = Object.freeze({
|
||||
'state:has-prior-phases': 'hasPriorPhases',
|
||||
'state:auto-advance-active': 'autoAdvanceActive',
|
||||
'state:chunked-mode': 'chunkedMode',
|
||||
'state:fallow-enabled': 'fallowEnabled',
|
||||
'state:git-create-tag': 'gitCreateTag',
|
||||
'state:needs-codebase-map': 'needsCodebaseMap',
|
||||
'state:phase-mvp-mode': 'phaseMvpMode',
|
||||
'state:plan-strategy-converge': 'planStrategyConverge',
|
||||
'state:reviewer-instances-configured': 'reviewerInstancesConfigured',
|
||||
'state:ui-phase-active': 'uiPhaseActive',
|
||||
'state:worktrees-enabled': 'worktreesEnabled',
|
||||
'state:is-monorepo': 'isMonorepo',
|
||||
'state:next-channel': 'nextChannel',
|
||||
'state:workstream-active': 'workstreamActive',
|
||||
'state:flat-mode': 'flatMode',
|
||||
});
|
||||
|
||||
/** `state:gap-closure-phase` is the one atom keyed off `phaseNumber`, not a plain boolean field. */
|
||||
const GAP_CLOSURE_ATOM = 'state:gap-closure-phase';
|
||||
|
||||
/** @returns {{truthy: object, falsy: object | null}} fact FRAGMENTS (merged onto `facts({})` by the caller) for `atom`; `falsy: null` marks the `'always'` exception. */
|
||||
function factFragmentsFor(atom) {
|
||||
if (atom === 'always') {
|
||||
return { truthy: {}, falsy: null };
|
||||
}
|
||||
if (atom === GAP_CLOSURE_ATOM) {
|
||||
return { truthy: { phaseNumber: '3.1' }, falsy: { phaseNumber: '3' } };
|
||||
}
|
||||
if (atom.startsWith('flag:--')) {
|
||||
const token = atom.slice('flag:'.length);
|
||||
return { truthy: { flags: new Set([token]) }, falsy: { flags: new Set() } };
|
||||
}
|
||||
const field = STATE_ATOM_FACT_FIELD[atom];
|
||||
if (!field) {
|
||||
throw new Error(`factFragmentsFor: atom "${atom}" has no fact-field mapping — update STATE_ATOM_FACT_FIELD`);
|
||||
}
|
||||
return { truthy: { [field]: true }, falsy: { [field]: false } };
|
||||
}
|
||||
|
||||
describe('every when= atom is satisfiable by some InvocationFacts (#2994 matrix rows A1/A2/A5)', () => {
|
||||
// A5 anti-vacuity: the atom set this describe block iterates must be
|
||||
// non-empty AND exactly equal to WHEN_VOCABULARY's full 29-entry set — an
|
||||
// A1/A2 loop over an empty or partial collection would be a green test
|
||||
// proving nothing (ADR-1671 eval-gate rot, named explicitly in the design).
|
||||
test('atom satisfiability set is non-empty and equals the full frozen WHEN_VOCABULARY (row A5)', () => {
|
||||
assert.ok(WHEN_VOCABULARY.length > 0, 'WHEN_VOCABULARY must not be empty');
|
||||
const coveredAtoms = [...WHEN_VOCABULARY].sort();
|
||||
// Every atom must resolve via factFragmentsFor without throwing — this is
|
||||
// the completeness check on STATE_ATOM_FACT_FIELD itself: an atom added
|
||||
// to WHEN_VOCABULARY without a corresponding entry here throws loudly
|
||||
// instead of silently narrowing the set A1/A2 below actually cover.
|
||||
for (const atom of WHEN_VOCABULARY) {
|
||||
assert.doesNotThrow(() => factFragmentsFor(atom), `factFragmentsFor must resolve "${atom}"`);
|
||||
}
|
||||
assert.deepEqual(coveredAtoms, [...WHEN_VOCABULARY].sort(), 'the covered atom set must be exactly WHEN_VOCABULARY');
|
||||
assert.equal(WHEN_VOCABULARY.length, 29, 'sanity: the frozen vocabulary is expected at 29 entries for #2994 — update this literal alongside a deliberate vocabulary widening');
|
||||
});
|
||||
|
||||
for (const atom of WHEN_VOCABULARY) {
|
||||
test(`atom "${atom}" is included when its fact is true, excluded when false (rows A1/A2)`, () => {
|
||||
const { truthy, falsy } = factFragmentsFor(atom);
|
||||
const sections = [{ id: 'target', when: atom }];
|
||||
|
||||
// A1: some constructed InvocationFacts drives this section into `included`.
|
||||
const includedResult = selectSections(sections, facts(truthy));
|
||||
assert.deepEqual(includedResult, { included: ['target'], excluded: [] }, `expected "${atom}" included under its truthy facts`);
|
||||
|
||||
if (falsy === null) {
|
||||
// The 'always' exception: no facts value can ever exclude it — assert
|
||||
// that deliberately, rather than silently skipping the atom (which
|
||||
// would violate A5's "set is non-empty" guarantee for THIS assertion).
|
||||
const stillIncluded = selectSections(sections, facts({}));
|
||||
assert.deepEqual(stillIncluded, { included: ['target'], excluded: [] }, '"always" must remain included under every facts value — it has no false branch');
|
||||
return;
|
||||
}
|
||||
|
||||
// A2: some constructed InvocationFacts drives the SAME section into `excluded`.
|
||||
const excludedResult = selectSections(sections, facts(falsy));
|
||||
assert.deepEqual(excludedResult, { included: [], excluded: ['target'] }, `expected "${atom}" excluded under its falsy facts`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ─── #2994 matrix row A3: no admitted atom lacks a consuming section ───────
|
||||
//
|
||||
// An atom present in WHEN_VOCABULARY with zero consuming `when=` markers
|
||||
// anywhere in the SHIPPED gsd-core/workflows/section-manifest.json is dead
|
||||
// vocabulary: cardinality without a section, the exact rot the frozen list's
|
||||
// "no atom is admitted without a consumer, in the same commit" discipline
|
||||
// exists to prevent (40-design.md "Vocabulary growth"). Driven from the real
|
||||
// installed-shape artifact — never a hand-built fixture — per the matrix's
|
||||
// prime directive ("a hand-built manifest proves a property no real caller
|
||||
// exercises").
|
||||
|
||||
describe('no admitted atom lacks a consuming section in the shipped manifest (#2994 matrix row A3)', () => {
|
||||
const SHIPPED_MANIFEST_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'section-manifest.json');
|
||||
|
||||
test('every WHEN_VOCABULARY atom is used as a when= value by at least one shipped section', () => {
|
||||
const manifest = JSON.parse(fs.readFileSync(SHIPPED_MANIFEST_PATH, 'utf8'));
|
||||
const usedAtoms = new Set();
|
||||
for (const sections of Object.values(manifest.workflows)) {
|
||||
for (const section of sections) {
|
||||
usedAtoms.add(section.when);
|
||||
}
|
||||
}
|
||||
|
||||
// `always` is a NAMED, single exemption — not a blanket skip. It is the
|
||||
// implicit gap-fragment default (a section with no `when=` marker at all
|
||||
// is treated as unconditionally included) and is structural, not a
|
||||
// marker atom: `gen-section-manifest.cjs`'s `explicitSections` filter
|
||||
// (`s.explicit`) deliberately EXCLUDES it from the generated
|
||||
// section-manifest.json, so no shipped section's `when=` value can ever
|
||||
// literally read `"always"` — the atom is real (WHEN_PREDICATES and
|
||||
// section-marker-parsing both accept it) but by design has zero
|
||||
// consuming JSON entries.
|
||||
const unusedAtoms = WHEN_VOCABULARY.filter((atom) => atom !== 'always' && !usedAtoms.has(atom));
|
||||
|
||||
// Deliberately UNWEAKENED per 50-test-matrix.md row A3's own instruction:
|
||||
// "if any atom legitimately has no consumer today, do NOT weaken this
|
||||
// test — report it to me instead, it is a real finding." No exclusion
|
||||
// list beyond the single named `always` exemption above is applied here
|
||||
// — if this assertion is red, that redness IS the finding, not a defect
|
||||
// in the test.
|
||||
assert.deepEqual(unusedAtoms, [], `dead vocabulary: these WHEN_VOCABULARY atoms have no consuming section anywhere in ${SHIPPED_MANIFEST_PATH}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Object.prototype-shaped when= values fail closed (REASON.UNKNOWN_WHEN)', () => {
|
||||
const HOSTILE_WHEN_VALUES = Object.freeze([
|
||||
'constructor',
|
||||
|
||||
151
tests/section-marker-inversion-guard.test.cjs
Normal file
151
tests/section-marker-inversion-guard.test.cjs
Normal file
@@ -0,0 +1,151 @@
|
||||
'use strict';
|
||||
|
||||
// allow-test-rule: source-text-is-the-product see #2994 — this file asserts that
|
||||
// specific prose/resolver LINES remain physically outside a `<!-- gsd:section
|
||||
// -->` marker pair in the HOST workflow .md files. The deployed contract IS
|
||||
// the exact text and its position relative to the marker boundary (a runtime
|
||||
// that reads only the gated fragment must still see the flag-absent
|
||||
// fallback), so asserting on rendered text is the only meaningful check here
|
||||
// — a typed/structural assertion on `parseWorkflowSections` output could not
|
||||
// distinguish "the fallback text survived, in the right gap" from "the
|
||||
// fallback text was deleted entirely along with the surrounding gap".
|
||||
|
||||
/**
|
||||
* Inversion-guard tests — #2994 (epic #1671 Phase 6.3) matrix §F, the
|
||||
* highest-risk edit in the PR (`.gsd/phase/chore-2994-fragment-model-workflows/
|
||||
* 50-test-matrix.md`): gating `discuss-phase-assumptions.md`'s `auto_advance`
|
||||
* step WHOLE would delete the flag-absent fallback ("End here — confirm_creation
|
||||
* already ran; do not route back to it."), removing text needed EXACTLY when
|
||||
* `--auto` is absent — the inverse of what a `when=` gate is supposed to do.
|
||||
* The design's split is at `:651/652`: only `auto-advance-dispatch` itself is
|
||||
* gated (`state:auto-advance-active`); the resolvers above it and the
|
||||
* flag-absent fallback below it stay outside the marker pair, in the host
|
||||
* file, unconditionally composed regardless of `section_manifest`.
|
||||
*
|
||||
* The same class — "an always-relevant note living immediately adjacent to a
|
||||
* gated section must not itself be swallowed by the marker" — applies to
|
||||
* `verify-work.md`'s MVP false-branch note (row "Same class applies").
|
||||
*
|
||||
* Parses each host file with the REAL `parseWorkflowSections` (never a
|
||||
* second ad-hoc marker scan) to get the marker's exact byte boundaries, then
|
||||
* asserts the fallback/resolver text is NOT inside the gated section's body
|
||||
* and IS present in the surrounding (always-composed) gap text.
|
||||
*/
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const { parseWorkflowSections } = require('../gsd-core/bin/lib/workflow-fragments.cjs');
|
||||
|
||||
const WORKFLOWS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows');
|
||||
|
||||
function readWorkflow(name) {
|
||||
const filePath = path.join(WORKFLOWS_DIR, `${name}.md`);
|
||||
return { filePath, content: fs.readFileSync(filePath, 'utf8') };
|
||||
}
|
||||
|
||||
/** The gated section's own body, by id — must equal exactly one parsed section. */
|
||||
function bodyOf(sections, id) {
|
||||
const match = sections.filter((s) => s.id === id);
|
||||
assert.equal(match.length, 1, `expected exactly one parsed section with id "${id}"`);
|
||||
return match[0].body;
|
||||
}
|
||||
|
||||
/** Every gap-section body concatenated (i.e., everything OUTSIDE any explicit marker), preserving the "never inside a gate" question. */
|
||||
function outsideGatedText(sections) {
|
||||
return sections.filter((s) => !s.explicit).map((s) => s.body).join('');
|
||||
}
|
||||
|
||||
// ─── F1/F2/F3: discuss-phase-assumptions.md's auto-advance-dispatch split ──
|
||||
|
||||
describe('discuss-phase-assumptions.md: the flag-absent fallback survives exclusion (matrix §F, highest-risk edit)', () => {
|
||||
const { content } = readWorkflow('discuss-phase-assumptions');
|
||||
const sections = parseWorkflowSections(content, 'gsd-core/workflows/discuss-phase-assumptions.md');
|
||||
|
||||
const GATED_ID = 'auto-advance-dispatch';
|
||||
const FALLBACK_TEXT = 'End here — `confirm_creation` already ran; do not route back to it.';
|
||||
const RESOLVER_MARKERS = [
|
||||
'Parse `--auto` flag from $ARGUMENTS',
|
||||
'gsd_run query config-set workflow._auto_chain_active',
|
||||
'AUTO_MODE=$(gsd_run query check auto-mode --pick active',
|
||||
];
|
||||
|
||||
test('the gated section exists and is when="state:auto-advance-active" (sanity)', () => {
|
||||
const gated = sections.find((s) => s.id === GATED_ID);
|
||||
assert.ok(gated, `expected a "${GATED_ID}" section to exist`);
|
||||
assert.equal(gated.when, 'state:auto-advance-active');
|
||||
});
|
||||
|
||||
test('the flag-absent "End here" fallback is present in the composed HOST output (row F1 — the inversion)', () => {
|
||||
assert.ok(content.includes(FALLBACK_TEXT), 'the fallback text must exist verbatim in the host file at all');
|
||||
});
|
||||
|
||||
test('the flag-absent fallback is NOT inside the gated section\'s own body (row F1/F3)', () => {
|
||||
const gatedBody = bodyOf(sections, GATED_ID);
|
||||
assert.ok(
|
||||
!gatedBody.includes(FALLBACK_TEXT),
|
||||
'the fallback must live OUTSIDE the gated marker — gating it away would delete the text needed exactly when --auto is absent',
|
||||
);
|
||||
});
|
||||
|
||||
test('the flag-absent fallback IS present in the unconditionally-composed gap text (row F2 — dispatch body included path also composes the surrounding text unconditionally)', () => {
|
||||
const gapText = outsideGatedText(sections);
|
||||
assert.ok(gapText.includes(FALLBACK_TEXT), 'the fallback must be part of an always-composed gap section, not lost between gaps');
|
||||
});
|
||||
|
||||
test('every resolver line (--auto parse, config-set, AUTO_MODE read) lies OUTSIDE the gated marker (row F3)', () => {
|
||||
const gatedBody = bodyOf(sections, GATED_ID);
|
||||
for (const marker of RESOLVER_MARKERS) {
|
||||
assert.ok(!gatedBody.includes(marker), `resolver text "${marker}" must not live inside the gated "${GATED_ID}" section`);
|
||||
}
|
||||
const gapText = outsideGatedText(sections);
|
||||
for (const marker of RESOLVER_MARKERS) {
|
||||
assert.ok(gapText.includes(marker), `resolver text "${marker}" must be present in the unconditionally-composed surrounding text`);
|
||||
}
|
||||
});
|
||||
|
||||
test('composing the document with every section INCLUDED still contains the fallback (row F2 sanity — inclusion never deletes it either)', () => {
|
||||
// The stub instructs conditional reading of steps/auto-advance-dispatch.md,
|
||||
// but the fallback sentence itself is literal HOST text either way — this
|
||||
// asserts the host's raw byte content carries it once, regardless of
|
||||
// section_manifest, which composeWorkflow (verbatim strategy, #2930)
|
||||
// preserves unconditionally.
|
||||
const occurrences = content.split(FALLBACK_TEXT).length - 1;
|
||||
assert.equal(occurrences, 1, 'the fallback text must appear exactly once in the host file');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Same class: verify-work.md's MVP false-branch note ────────────────────
|
||||
|
||||
describe('verify-work.md: the MVP false-branch note survives exclusion of mvp-uat-framing (same class as §F)', () => {
|
||||
const { content } = readWorkflow('verify-work');
|
||||
const sections = parseWorkflowSections(content, 'gsd-core/workflows/verify-work.md');
|
||||
|
||||
const GATED_ID = 'mvp-uat-framing';
|
||||
const FALSE_BRANCH_NOTE = 'When `MVP_MODE=false` (mode is null, absent, or the phase has no `**Mode:**` line in ROADMAP.md), fall back to the standard UAT generation path — no behavioral change.';
|
||||
|
||||
test('the gated section exists and is when="state:phase-mvp-mode" (sanity)', () => {
|
||||
const gated = sections.find((s) => s.id === GATED_ID);
|
||||
assert.ok(gated, `expected a "${GATED_ID}" section to exist`);
|
||||
assert.equal(gated.when, 'state:phase-mvp-mode');
|
||||
});
|
||||
|
||||
test('the MVP=false fallback note is present in the host file at all', () => {
|
||||
assert.ok(content.includes(FALSE_BRANCH_NOTE));
|
||||
});
|
||||
|
||||
test('the MVP=false fallback note is NOT inside the gated mvp-uat-framing section body', () => {
|
||||
const gatedBody = bodyOf(sections, GATED_ID);
|
||||
assert.ok(
|
||||
!gatedBody.includes(FALSE_BRANCH_NOTE),
|
||||
'gating mvp-uat-framing away (MVP_MODE=false) must not delete the note that documents exactly that fallback',
|
||||
);
|
||||
});
|
||||
|
||||
test('the MVP=false fallback note IS present in the unconditionally-composed gap text', () => {
|
||||
const gapText = outsideGatedText(sections);
|
||||
assert.ok(gapText.includes(FALSE_BRANCH_NOTE));
|
||||
});
|
||||
});
|
||||
@@ -26,6 +26,7 @@ const { test, describe } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { readWorkflowCombined } = require('./helpers.cjs');
|
||||
|
||||
const WORKFLOWS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows');
|
||||
const LIVENESS_PHRASE = 'runs in a subagent';
|
||||
@@ -84,11 +85,24 @@ describe('spawn-liveness-banner', () => {
|
||||
});
|
||||
|
||||
test('every workflow that dispatches a subagent contains the liveness phrase somewhere', () => {
|
||||
const mdFiles = findMdFiles(WORKFLOWS_DIR);
|
||||
// #2994: scoped to HOST workflow files only (top-level gsd-core/workflows/*.md),
|
||||
// each read via readWorkflowCombined (host + its workflows/<wf>/steps/*.md
|
||||
// fragments). The fragment model can move a subagent dispatch site into a step
|
||||
// file while the host still carries the liveness phrase elsewhere for its other
|
||||
// dispatches (e.g. docs-update.md). A raw recursive `findMdFiles` walk treats
|
||||
// that step fragment as an independent "workflow" and reports a false positive
|
||||
// — it is not a standalone workflow, it is part of its host's contract. The
|
||||
// asserted property (every workflow that dispatches a subagent documents the
|
||||
// liveness phrase somewhere in that workflow) is unchanged; only the file
|
||||
// boundary the check honors is corrected.
|
||||
const hostFiles = fs
|
||||
.readdirSync(WORKFLOWS_DIR, { withFileTypes: true })
|
||||
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
||||
.map((entry) => path.join(WORKFLOWS_DIR, entry.name));
|
||||
const presenceViolations = [];
|
||||
|
||||
for (const filePath of mdFiles) {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
for (const filePath of hostFiles) {
|
||||
const content = readWorkflowCombined(filePath);
|
||||
const rel = path.relative(WORKFLOWS_DIR, filePath);
|
||||
|
||||
if (content.includes('subagent_type') && !content.includes(LIVENESS_PHRASE)) {
|
||||
|
||||
@@ -16,7 +16,7 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
const { runGsdTools, createTempProject, cleanup, readWorkflowCombined } = require('./helpers.cjs');
|
||||
|
||||
// ─── config key registration ─────────────────────────────────────────────────
|
||||
|
||||
@@ -170,7 +170,12 @@ describe('#1359: workflows collect background subagents via Read(outputFile), no
|
||||
});
|
||||
|
||||
describe('docs-update.md', () => {
|
||||
const content = readWorkflow('docs-update.md');
|
||||
// #2994: dispatch_monorepo_packages was extracted to
|
||||
// gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md behind a
|
||||
// <!-- gsd:section --> stub, so the bare host file no longer contains that
|
||||
// <step> block. readWorkflowCombined follows the host + its step fragments so
|
||||
// the property below still evaluates against the step's real content.
|
||||
const content = readWorkflowCombined(path.join(WORKFLOWS_DIR, 'docs-update.md'));
|
||||
|
||||
test('contains no deprecated TaskOutput tool references', () => {
|
||||
assert.ok(
|
||||
|
||||
@@ -10,9 +10,31 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const WORKFLOW = path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work.md');
|
||||
const VERIFY_WORK_STEPS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work', 'steps');
|
||||
|
||||
/**
|
||||
* verify-work.md was fragmented (#2994) into gsd-core/workflows/verify-work/steps/*.md.
|
||||
* The MVP-mode UAT framing content (verify-mvp-mode.md reference, user-flow-first
|
||||
* ordering, deferred-technical-checks clause) now lives in
|
||||
* verify-work/steps/mvp-uat-framing.md, only read at all when
|
||||
* state:phase-mvp-mode is true. Read host + every step file combined so these
|
||||
* guards keep seeing the full picture regardless of which file the content
|
||||
* physically lives in.
|
||||
*/
|
||||
function readVerifyWorkCombined() {
|
||||
let combined = fs.readFileSync(WORKFLOW, 'utf8');
|
||||
if (fs.existsSync(VERIFY_WORK_STEPS_DIR)) {
|
||||
for (const entry of fs.readdirSync(VERIFY_WORK_STEPS_DIR).sort()) {
|
||||
if (entry.endsWith('.md')) {
|
||||
combined += '\n' + fs.readFileSync(path.join(VERIFY_WORK_STEPS_DIR, entry), 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
describe('verify-work — MVP mode UAT framing', () => {
|
||||
const content = fs.readFileSync(WORKFLOW, 'utf-8');
|
||||
const content = readVerifyWorkCombined();
|
||||
|
||||
test('Step 1 resolves MVP_MODE from phase mode field', () => {
|
||||
assert.match(content, /MVP_MODE/, 'workflow must declare MVP_MODE');
|
||||
|
||||
@@ -177,25 +177,43 @@ describe('bug #1716: resume_from_file routes to complete_session when no [pendin
|
||||
|
||||
describe('bug #3381: verify-work forwards workstream context', () => {
|
||||
test('workflow forwards ${GSD_WS} to workstream-sensitive SDK queries', () => {
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work.md'),
|
||||
'utf8',
|
||||
);
|
||||
// #2994 fragmentization moved the roadmap.get-phase user-story-format-guard
|
||||
// bash block out of verify-work.md into
|
||||
// gsd-core/workflows/verify-work/steps/mvp-uat-framing.md behind a section
|
||||
// marker (`state:phase-mvp-mode`). Read host + every step file combined so
|
||||
// this GSD_WS-forwarding guard keeps seeing the moved query.
|
||||
const VERIFY_WORK_MD = path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work.md');
|
||||
const VERIFY_WORK_STEPS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-work', 'steps');
|
||||
let workflow = fs.readFileSync(VERIFY_WORK_MD, 'utf8');
|
||||
if (fs.existsSync(VERIFY_WORK_STEPS_DIR)) {
|
||||
for (const entry of fs.readdirSync(VERIFY_WORK_STEPS_DIR).sort()) {
|
||||
if (entry.endsWith('.md')) {
|
||||
workflow += '\n' + fs.readFileSync(path.join(VERIFY_WORK_STEPS_DIR, entry), 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The --ws capture character class was deliberately narrowed from
|
||||
// `[^[:space:]]+` to `[A-Za-z0-9._-]+` (workstream slugs are
|
||||
// alphanumeric/dot/underscore/hyphen; the old class captured any
|
||||
// non-space run, including shell metacharacters). Forwarding itself
|
||||
// (GSD_WS reaching every workstream-sensitive query below) is
|
||||
// unaffected by the narrower class, so only the literal pattern here
|
||||
// is updated — the asserted forwarding property is unchanged.
|
||||
assert.match(workflow, /GSD_WS=""/, 'verify-work must initialize GSD_WS');
|
||||
assert.match(
|
||||
workflow,
|
||||
/grep -qE -- '--ws\[\[:space:\]\]\+\[\^\[:space:\]\]\+'/,
|
||||
/grep -qE -- '--ws\[\[:space:\]\]\+\[A-Za-z0-9\._-\]\+'/,
|
||||
'verify-work must detect --ws in $ARGUMENTS',
|
||||
);
|
||||
assert.match(
|
||||
workflow,
|
||||
/grep -oE -- '--ws\[\[:space:\]\]\+\[\^\[:space:\]\]\+'/,
|
||||
/grep -oE -- '--ws\[\[:space:\]\]\+\[A-Za-z0-9\._-\]\+'/,
|
||||
'verify-work must extract the --ws flag pair from $ARGUMENTS',
|
||||
);
|
||||
assert.match(
|
||||
workflow,
|
||||
/PHASE_ARG=\$\(echo "\$ARGUMENTS" \| sed -E 's\/--ws\[\[:space:\]\]\+\[\^\[:space:\]\]\+\/\/g' \| xargs\)/,
|
||||
/PHASE_ARG=\$\(echo "\$ARGUMENTS" \| sed -E 's\/--ws\[\[:space:\]\]\+\[A-Za-z0-9\._-\]\+\/\/g' \| xargs\)/,
|
||||
'verify-work must derive PHASE_ARG after removing --ws',
|
||||
);
|
||||
// After #3797 architectural fix, callsites use gsd_run
|
||||
|
||||
@@ -465,10 +465,33 @@ test('nonWorkflowMarkdownWithMarkerShapedLineIsNotComposed', () => {
|
||||
|
||||
test('leavesUnmarkedWorkflowEmissionByteIdentical', () => {
|
||||
const workflowsDir = path.join(REPO_ROOT, 'gsd-core', 'workflows');
|
||||
// execute-phase.md (#2932 Phase 5) and plan-phase.md (#2993 Phase 6.2) are
|
||||
// the two files this repo has fragmentized with gsd:section markers — both
|
||||
// excluded here since composeWorkflow is deliberately NOT a no-op for them.
|
||||
const MARKED_WORKFLOWS = new Set(['execute-phase.md', 'plan-phase.md']);
|
||||
// execute-phase.md (#2932 Phase 5), plan-phase.md (#2993 Phase 6.2), and
|
||||
// the thirteen workflows #2994 (epic #1671 Phase 6.3) fragmentizes onto the
|
||||
// marker grammar are the files this repo has fragmentized with gsd:section
|
||||
// markers — all excluded here since composeWorkflow is deliberately NOT a
|
||||
// no-op for them. This set is DELIBERATELY hardcoded rather than derived
|
||||
// from "does the file contain a marker": deriving it would make the guard
|
||||
// tautological — a marker that LEAKED into an unrelated file via a bad
|
||||
// extraction would just get silently excluded instead of failing the
|
||||
// independence check this test exists to enforce. Update this list by hand
|
||||
// whenever a workflow is legitimately marked.
|
||||
const MARKED_WORKFLOWS = new Set([
|
||||
'autonomous.md',
|
||||
'code-review.md',
|
||||
'complete-milestone.md',
|
||||
'discuss-phase-assumptions.md',
|
||||
'docs-update.md',
|
||||
'execute-phase.md',
|
||||
'new-milestone.md',
|
||||
'new-project.md',
|
||||
'plan-phase.md',
|
||||
'progress.md',
|
||||
'quick.md',
|
||||
'review.md',
|
||||
'transition.md',
|
||||
'update.md',
|
||||
'verify-work.md',
|
||||
]);
|
||||
const workflowFiles = fs
|
||||
.readdirSync(workflowsDir, { withFileTypes: true })
|
||||
.filter((d) => d.isFile() && d.name.endsWith('.md'))
|
||||
|
||||
@@ -610,11 +610,23 @@ describe('frozen when= vocabulary', () => {
|
||||
// catch a value being silently renamed). See the dispatch report for
|
||||
// this deliberate deviation from the test matrix's literal wording.
|
||||
//
|
||||
// #2993 (epic #1671 Phase 6.2, matrix row A3) widens this lock 14 -> 19:
|
||||
// #2993 (epic #1671 Phase 6.2, matrix row A3) widened this lock 14 -> 19:
|
||||
// flag:--ingest, flag:--prd, flag:--research-phase, flag:--reviews,
|
||||
// state:chunked-mode. This is the row the lock exists to force — a
|
||||
// deliberate, coordinated update, never a silent drift (Greenspun's
|
||||
// Tenth Rule / ADR-1671:69).
|
||||
// state:chunked-mode. #2994 (epic #1671 Phase 6.3) widened it 19 -> 20
|
||||
// (state:ui-phase-active, verify-work.md), then a further #2994 amendment
|
||||
// widened it 20 -> 23 (flag:--fix, state:fallow-enabled,
|
||||
// state:git-create-tag, fragmentizing code-review.md and
|
||||
// complete-milestone.md), then further #2994 amendments widened it to 30
|
||||
// (autonomous.md, review.md, discuss-phase-assumptions.md, docs-update.md,
|
||||
// update.md, transition.md, new-milestone.md — see
|
||||
// docs/reference/workflow-fragments.md's own widening history). A final
|
||||
// #2994 dead-vocabulary cleanup then narrowed it 30 -> 29: `flag:--full`
|
||||
// was removed (never consumed by any `when=` marker — `quick.md` folds
|
||||
// `--full` into `--discuss`/`--research`/`--validate` before evaluation),
|
||||
// and `state:needs-codebase-map` gained its first real consumer
|
||||
// (`new-project.md`'s `codebase-map-offer` section). This is the row the
|
||||
// lock exists to force — a deliberate, coordinated update, never a
|
||||
// silent drift (Greenspun's Tenth Rule / ADR-1671:69).
|
||||
assert.equal(Object.isFrozen(WHEN_VOCABULARY), true);
|
||||
assert.deepEqual(
|
||||
[...WHEN_VOCABULARY].sort(),
|
||||
@@ -622,8 +634,8 @@ describe('frozen when= vocabulary', () => {
|
||||
'always',
|
||||
'flag:--auto',
|
||||
'flag:--discuss',
|
||||
'flag:--fix',
|
||||
'flag:--forensic',
|
||||
'flag:--full',
|
||||
'flag:--ingest',
|
||||
'flag:--prd',
|
||||
'flag:--research',
|
||||
@@ -632,17 +644,55 @@ describe('frozen when= vocabulary', () => {
|
||||
'flag:--reviews',
|
||||
'flag:--validate',
|
||||
'flag:--wave',
|
||||
'state:auto-advance-active',
|
||||
'state:chunked-mode',
|
||||
'state:fallow-enabled',
|
||||
'state:flat-mode',
|
||||
'state:gap-closure-phase',
|
||||
'state:git-create-tag',
|
||||
'state:has-prior-phases',
|
||||
'state:is-monorepo',
|
||||
'state:needs-codebase-map',
|
||||
'state:next-channel',
|
||||
'state:phase-mvp-mode',
|
||||
'state:plan-strategy-converge',
|
||||
'state:reviewer-instances-configured',
|
||||
'state:ui-phase-active',
|
||||
'state:workstream-active',
|
||||
'state:worktrees-enabled',
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── A further #2994 widening (epic #1671 Phase 6.3): code-review.md /
|
||||
// complete-milestone.md (3 atoms) ────────────────────────────────────────
|
||||
|
||||
describe('widened when= vocabulary (#2994 code-review/complete-milestone)', () => {
|
||||
const NET_NEW_ATOMS_2994B = Object.freeze([
|
||||
'flag:--fix',
|
||||
'state:fallow-enabled',
|
||||
'state:git-create-tag',
|
||||
]);
|
||||
|
||||
test('everyNetNewAtomIsInWhenVocabulary', () => {
|
||||
for (const atom of NET_NEW_ATOMS_2994B) {
|
||||
assert.ok(WHEN_VOCABULARY.includes(atom), `expected "${atom}" in WHEN_VOCABULARY`);
|
||||
}
|
||||
});
|
||||
|
||||
test('acceptsEveryWidenedAtom', () => {
|
||||
for (const when of NET_NEW_ATOMS_2994B) {
|
||||
const source = `<!-- gsd:section id="x" when="${when}" -->\nbody\n<!-- /gsd:section -->`;
|
||||
const sections = parseWorkflowSections(source);
|
||||
const explicitSections = sections.filter((s) => s.explicit);
|
||||
assert.equal(explicitSections.length, 1, `expected acceptance for when="${when}"`);
|
||||
assert.equal(explicitSections[0].when, when);
|
||||
assert.equal(composeWorkflow(source), 'body\n');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ─── #2993 (epic #1671 Phase 6.2): widened when= vocabulary (19 atoms) ─────
|
||||
// 50-test-matrix.md rows A1/A6.
|
||||
|
||||
@@ -708,11 +758,19 @@ describe('widened when= vocabulary (#2992)', () => {
|
||||
// (Object.keys-style derivation of the diff would be tokenization of the
|
||||
// vocabulary itself, so this list is a deliberate hand-written literal,
|
||||
// mirroring the discipline WHEN_PREDICATES already applies).
|
||||
//
|
||||
// `flag:--full` was ONE of the original 10 (#2992) but a later #2994
|
||||
// dead-vocabulary cleanup removed it from WHEN_VOCABULARY entirely — it
|
||||
// never gained a consuming `when=` marker (`quick.md` folds `--full` into
|
||||
// `--discuss`/`--research`/`--validate` before evaluation, so no section
|
||||
// ever gates on the raw flag). Dropped here too so this list stays a
|
||||
// faithful subset of the LIVE frozen export (the parser now throws
|
||||
// REASON.UNKNOWN_WHEN for `when="flag:--full"`, which `acceptsEveryWidenedAtom`
|
||||
// below would otherwise incorrectly assert acceptance for).
|
||||
const NET_NEW_ATOMS = Object.freeze([
|
||||
'flag:--auto',
|
||||
'flag:--discuss',
|
||||
'flag:--forensic',
|
||||
'flag:--full',
|
||||
'flag:--research',
|
||||
'flag:--reset-phase-numbers',
|
||||
'flag:--validate',
|
||||
|
||||
@@ -331,7 +331,15 @@ describe('bug #2924: worktree HEAD attachment + destructive recovery', () => {
|
||||
});
|
||||
|
||||
describe('quick.md pre-dispatch plan commit no longer hard-codes --no-verify', () => {
|
||||
const content = fs.readFileSync(QUICK_PATH, 'utf-8');
|
||||
// #2994 fragmentization moved the pre-dispatch plan commit block out of
|
||||
// quick.md into gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md
|
||||
// behind a section marker. Read host + step file combined so the fenced
|
||||
// code block search below still finds it.
|
||||
const content = fs.readFileSync(QUICK_PATH, 'utf-8') +
|
||||
'\n' + fs.readFileSync(
|
||||
path.join(REPO_ROOT, 'gsd-core', 'workflows', 'quick', 'steps', 'worktree-pre-dispatch-commit.md'),
|
||||
'utf-8'
|
||||
);
|
||||
const codeBlocks = extractFencedCodeBlocks(content);
|
||||
// Find the bash block containing the pre-dispatch plan commit
|
||||
const target = codeBlocks.find(({ body }) =>
|
||||
|
||||
Reference in New Issue
Block a user