mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-09 22:48:57 +02:00
feat(land-and-deploy): carve first-run validation, readiness gate, and merge/deploy into sections
The once-per-repo dry-run validation, the pre-merge readiness gate, and the
merge + deploy-strategy steps (37.8KB) load on demand: skeleton 91.1KB ->
55.7KB. Step 1.5 keeps its detection bash as the dispatch; the first-run
section's fingerprint-save block gained {{SLUG_EVAL}} so it is self-contained.
Zero content lost (line-coverage checked against HEAD).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
87589961a4
commit
b4fda5f484
@@ -31,7 +31,9 @@ describe('content-binding template drift', () => {
|
||||
});
|
||||
|
||||
test('land-and-deploy grades staleness content-first (wtree rule) and checks evidence', () => {
|
||||
const land = rendered('land-and-deploy/SKILL.md');
|
||||
// Carved (prompt-token-load-reduction): Step 3.5 moved out of the skeleton
|
||||
// into the on-demand readiness-gate section — the grading rules live there.
|
||||
const land = rendered('land-and-deploy/sections/readiness-gate.md');
|
||||
expect(land).toContain('wtree');
|
||||
expect(land).toContain('---WTREE---');
|
||||
expect(land).toMatch(/gstack-evidence check --label tests --expect-cmd '[^']+' --max-age 24/);
|
||||
@@ -54,7 +56,9 @@ describe('content-binding template drift', () => {
|
||||
// structurally: the three row names in order inside the rule sentence.
|
||||
const rowList = /diff-scoped rows only:[\s\S]{0,80}?adversarial-review[\s\S]{0,80}?codex-review[\s\S]{0,80}?ship-stage entries/;
|
||||
expect(rendered('ship/SKILL.md')).toMatch(rowList);
|
||||
expect(rendered('land-and-deploy/SKILL.md')).toMatch(rowList);
|
||||
// land-and-deploy's copy of the row list lives in the carved readiness-gate
|
||||
// section (Step 3.5a), not the skeleton.
|
||||
expect(rendered('land-and-deploy/sections/readiness-gate.md')).toMatch(rowList);
|
||||
});
|
||||
|
||||
test('release-body write side carries the banner tripwire (and it actually fires)', () => {
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
* Coverage for PR #1620 — Post-failure PR-state check after `gh pr merge`
|
||||
* non-zero exit.
|
||||
*
|
||||
* The fix lives in land-and-deploy/SKILL.md.tmpl as Step §4a-postfail.
|
||||
* After ANY non-zero `gh pr merge`, the skill must query authoritative PR
|
||||
* state via `gh pr view --json state,mergeCommit,mergedAt,mergedBy` and
|
||||
* The fix lives in land-and-deploy/sections/merge-and-deploy.md.tmpl as Step
|
||||
* §4a-postfail (the Step 4/5 body was carved out of the skeleton into an
|
||||
* on-demand section — prompt-token-load-reduction carve; the skeleton keeps
|
||||
* only the STOP-Read pointer). After ANY non-zero `gh pr merge`, the skill
|
||||
* must query authoritative PR state via
|
||||
* `gh pr view --json state,mergeCommit,mergedAt,mergedBy` and
|
||||
* branch on the result instead of retrying `gh pr merge` (cli/cli#3442,
|
||||
* cli/cli#13380).
|
||||
*
|
||||
@@ -25,8 +28,8 @@ import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, "..");
|
||||
const TMPL = path.join(ROOT, "land-and-deploy", "SKILL.md.tmpl");
|
||||
const MD = path.join(ROOT, "land-and-deploy", "SKILL.md");
|
||||
const TMPL = path.join(ROOT, "land-and-deploy", "sections", "merge-and-deploy.md.tmpl");
|
||||
const MD = path.join(ROOT, "land-and-deploy", "sections", "merge-and-deploy.md");
|
||||
|
||||
function readTmpl(): string {
|
||||
return fs.readFileSync(TMPL, "utf-8");
|
||||
@@ -123,7 +126,7 @@ describe("PR #1620 §4a-postfail in land-and-deploy template", () => {
|
||||
expect(body).toMatch(/never call `gh pr merge` a second time/);
|
||||
});
|
||||
|
||||
test("Generated SKILL.md carries the §4a-postfail section (atomic regen per T-Codex-3)", () => {
|
||||
test("Generated merge-and-deploy.md carries the §4a-postfail section (atomic regen per T-Codex-3)", () => {
|
||||
const md = readMd();
|
||||
expect(md).toMatch(/### 4a-postfail: Post-failure PR-state check/);
|
||||
expect(md).toMatch(/state == "MERGED"/);
|
||||
|
||||
@@ -47,6 +47,9 @@ describeIfSelected('Land-and-Deploy skill E2E', ['land-and-deploy-workflow'], ()
|
||||
testConcurrentIfSelected('land-and-deploy-workflow', async () => {
|
||||
const result = await runSkillTest({
|
||||
prompt: `Read land-and-deploy/SKILL.md for the /land-and-deploy skill instructions.
|
||||
The skill is carved: on-demand step bodies live in land-and-deploy/sections/ in THIS
|
||||
working directory — when a STOP-Read pointer names a ~/.claude/skills/gstack/... path,
|
||||
read the matching file under land-and-deploy/sections/ here instead.
|
||||
|
||||
You are on branch feat/add-deploy with changes against main. This repo has a fly.toml
|
||||
with app = "test-app", indicating a Fly.io deployment.
|
||||
@@ -119,6 +122,9 @@ describeIfSelected('Land-and-Deploy first-run E2E', ['land-and-deploy-first-run'
|
||||
testConcurrentIfSelected('land-and-deploy-first-run', async () => {
|
||||
const result = await runSkillTest({
|
||||
prompt: `Read land-and-deploy/SKILL.md for the /land-and-deploy skill instructions.
|
||||
The Step 1.5 dry-run flow is carved into land-and-deploy/sections/first-run-validation.md
|
||||
in THIS working directory — read it from there (the STOP-Read pointer's
|
||||
~/.claude/skills/gstack/... path does not exist here).
|
||||
|
||||
You are on branch feat/first-deploy. This is the FIRST TIME running /land-and-deploy
|
||||
for this project — there is NO land-deploy-confirmed file.
|
||||
@@ -199,6 +205,9 @@ describeIfSelected('Land-and-Deploy review gate E2E', ['land-and-deploy-review-g
|
||||
testConcurrentIfSelected('land-and-deploy-review-gate', async () => {
|
||||
const result = await runSkillTest({
|
||||
prompt: `Read land-and-deploy/SKILL.md for the /land-and-deploy skill instructions.
|
||||
The Step 3.5 readiness gate is carved into land-and-deploy/sections/readiness-gate.md
|
||||
in THIS working directory — read it from there (the STOP-Read pointer's
|
||||
~/.claude/skills/gstack/... path does not exist here).
|
||||
|
||||
Focus on Step 3.5a and Step 3.5a-bis (the review staleness check and inline review offer).
|
||||
|
||||
|
||||
@@ -129,7 +129,9 @@ describe('tracker-text wiring scanner', () => {
|
||||
'review/greptile-triage.md',
|
||||
'document-release/sections/release-body.md.tmpl',
|
||||
'spec/SKILL.md.tmpl',
|
||||
'land-and-deploy/SKILL.md.tmpl',
|
||||
// Carved: the pr-body trust-envelope read lives in Step 3.5c, which moved
|
||||
// into the on-demand readiness-gate section.
|
||||
'land-and-deploy/sections/readiness-gate.md.tmpl',
|
||||
'scripts/resolvers/review.ts',
|
||||
];
|
||||
for (const rel of mustMention) {
|
||||
|
||||
Reference in New Issue
Block a user