Skip to content

feat(sc-git-worktree, sc-commit-push-pr): stack-aware worktree factory and commit/PR flows (0.13.0) - #107

Open
randlee wants to merge 13 commits into
feature/sc-gh-stackfrom
feature/sc-git-worktree-gh-stack
Open

feat(sc-git-worktree, sc-commit-push-pr): stack-aware worktree factory and commit/PR flows (0.13.0)#107
randlee wants to merge 13 commits into
feature/sc-gh-stackfrom
feature/sc-git-worktree-gh-stack

Conversation

@randlee

@randlee randlee commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Middle layer of the stack: develop <- #101 (sc-gh-stack) <- this <- #84 (refactory).

sc-git-worktree — worktree factory decision model

Create resolves every request to exactly one product (see the package's DESIGN.md):

  • A — flat worktree: the legacy product, byte-identical (verified against git history). A repo that is not stack-active never evaluates anything else — existing prompts are unaffected until a repo actually uses stacks (positive-signal rule).
  • B — new stack: same path as flat + gh stack init (repo policy git.always_stack, stack_root default develop).
  • C — stack layer: no new worktree; the branch is created inside the base's stack worktree via gh stack add (dependency: an unmerged base is by definition a stack layer).

Precedence Intent > Dependency > Policy > default A. Mandatory collaborator prerequisites in stack-active repos (CREATE.STACK_PREREQS_MISSING lists installs). Destructive safety: batch cleanup skips gh-stack-tracked worktrees; scan/cleanup/abort report gh_stack_tracked. Optional gh-stack interop reference defers all stack authority to managing-gh-stacks.

sc-commit-push-pr — fully stack-aware, hard gh-stack dependency

This package is the critical junction where stack-unaware pushes/PRs/merges corrupt stacks:

  • Unconditional toolchain gate (gh + gh-stack extension + sc-gh-stack skill) at every entry, wired into preflight/agent start-hooks.
  • On a stack layer: destination pull/merge skipped (stack linearity), push + PR creation refuse with STACK.USE_GH_STACK routing to managing-gh-stacks by name, accurate committed/pushed reporting.
  • Non-stack flows byte-compatible once prerequisites pass; Azure DevOps flows untouched.

Both packages version-matched at 0.13.0 (synchronized marketplace release; registries regenerated per layer). Tests: 167 (sc-git-worktree) + 26 (sc-commit-push-pr); validate-all 9/9. Opus-reviewed with empirical verification across four rounds.

🤖 Generated with Claude Code

@randlee
randlee force-pushed the feature/sc-git-worktree-gh-stack branch from 30a2df4 to 3f6129b Compare August 30, 2026 23:35
randlee and others added 13 commits August 30, 2026 22:25
…stack

Surgical additions to the tested package, opus-reviewed twice (review ->
fixes -> empirical verification incl. reproducing the destroy scenario
pre/post-fix):

- references/gh-stack-support.md (gated): defers ALL stacked-PR
  authority to the managing-gh-stacks skill (sc-gh-stack) when
  installed; strongly recommends installing it otherwise; 5-row
  non-interactive survival-kit table as fallback, banner-marked as not
  a substitute for the skill
- SKILL.md: one description clause + one gated pointer section. Two
  independent gates: destructive safety is UNCONDITIONAL (stack
  tracking is repository state, not local toolchain); the extension
  gate applies only to stack operations
- Destructive-safety guard (the one unavoidable code change): batch
  cleanup skips any worktree carrying gh-stack tracking
  (.git/worktrees/<wt>/gh-stack), surfaced in gh_stack_skipped —
  verified: pre-fix batch cleanup destroyed a stack worktree whose
  bottom layer looked merged (tracking lost, open PRs above orphaned);
  post-fix it is preserved. scan reports gh_stack_tracked per worktree
  + summary count; single-branch cleanup/abort surface it without
  blocking. check_gh_stack_tracked fails closed incl. OSError on
  prunable worktrees (regression caught in verification)
- Pre-existing doc fixes: abort agent protected-branch clause matched
  to implementation; TRACKING.MISSING casing
- 12 new tests (132 -> 144), all validators green

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The invariant: a worktree must be stacked iff it NEEDS to be — the base
branch decides. Basing on trunk/protected/merged = independent work,
flat create proceeds byte-identically (the many existing /sc-git-worktree
prompts are unaffected). Basing on an unmerged branch = the work depends
on unmerged work = a stack layer by definition: worktree_create.py
refuses flat creation (CREATE.NEEDS_STACK, before any mutation) and
routes — into the tracked stack's own worktree when the base carries
gh-stack tracking (layers share one worktree), else a new
stack/<base-slug> worktree + gh stack init. Explicit flat:true
overrides. Above this hard floor the docs add the activity layer:
stack-oriented work creates stacked even off trunk (orchestrator
judgment, not script-enforced).

Opus-verified empirically (full matrix incl. no-mutation-on-refusal and
routing), with its blocker finding fixed: the guard fails OPEN when
protected-branch config is absent, so config-free repos keep the
historical flat-create path (regression test added). Also fixed in
passing, verified safe: is_branch_merged missed git's '+ ' prefix for
branches checked out in other worktrees — single-branch cleanup of a
genuinely merged branch always refused before; batch cleanup proven
byte-identical pre/post. suggested_worktree_path honors a custom
worktree_base; cleanup agent doc notes single-branch mode is the only
path that can remove a tracked stack worktree.

7 new tests (144 -> 151); validate-all 9/9 PASS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…accreted guards)

Designed rework per DESIGN.md 'Worktree factory decision model': create
resolves every request to exactly one product — A (flat, legacy,
byte-identical to pre-guard behavior, verified against git history),
B (new stack: same path as flat + rerere + gh stack init, requested_base
surfaced when policy overrides the base), C (layer: no new worktree;
checkout + gh stack add inside the base's stack worktree). Precedence
Intent > Dependency > Policy > default A, evaluated lazily under the
positive-signal rule: a repo that is not stack-active (no always_stack,
no gh-stack tracking anywhere) never evaluates any of it — legacy
prompts are auto-upgraded only where stacks demonstrably exist, and
branch-of-branch flat creates keep working in stack-naive repos.
Mandatory collaborator prereq gate (gh + extension + sc-gh-stack skill)
fires only in stack-active repos, before any mutation. Fallback settings
parser strips inline comments; unknown boolean scalars coerce False;
pyyaml declared in requires. Tests rebuilt from the decision matrix:
test_factory_decision.py (24) replacing the two incremental guard
suites; 167 total green; validate-all 9/9.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ndency

This package is the critical junction where stack-unaware pushes, PRs,
and destination-merges corrupt stacks — per design it now depends on the
gh-stack toolchain outright (manifest: gh CLI, gh-stack extension,
sc-gh-stack package). New scripts/stack_guard.py (self-contained, no
cross-package imports): unconditional prerequisite gate at every entry
(PREFLIGHT.STACK_PREREQS_MISSING with exact installs — wired into
preflight so agent start-hooks block before any commit), and state-based
stack-layer detection (.git/worktrees/<wt>/gh-stack). On a layer:
destination pull/merge is SKIPPED (stack linearity; syncing belongs to
gh stack sync), push and PR creation refuse with STACK.USE_GH_STACK
routing to the managing-gh-stacks skill by name, committed/pushed state
reported accurately. Non-stack flows byte-compatible once prereqs pass;
Azure DevOps flows untouched by construction. Agents/SKILL/README
document the codes and the never-work-around rule. 26 new tests.
Version 0.13.0 (synchronized marketplace release; registries regenerate
at the release layer).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both packages carry behavior changes in this stack layer and ship at the
synchronized marketplace release version (matching PR #84's platform
bump and sc-gh-stack's 0.13.0 below); registries regenerated via
set-package-version.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, JSONL-as-trace)

Additive codex path: gpt-*/luna/sol/terra models route through codex
exec --yolo --json; command_execution/agent_message/usage events map
into CollectedData so every existing expectation evaluator works
unchanged; {test_id}-codex-events.jsonl is the trace artifact (codex has
no hooks). CODEX_HOME provisioned inside the isolated HOME (auth via
copy_codex_auth); ZDOTDIR-owned dotfiles keep stub PATH control under
zsh -lc; AGENTS.md generated as codex's skill channel (Skill-tool
equivalent). Claude path byte-identical (regression-tested). 35 new
tests; harness suite 671 -> 706. Companion docs in sc-test-harness
docs/CODEX.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Six cases mapped to DESIGN.md decision-table rows, non-stack AND
stacked: flat-create-stays-flat, branch-of-branch-naive (distribution
guarantee), always-stack-product-b, dependent-base-joins-stack (product
C, no new worktree), prereqs-missing-onboarding, cleanup-skips-tracked-
stack. All scaffolds mechanically verified against the real scripts
(two fixtures initially hit the positive-signal fail-open exactly as
designed — fixed with explicit protected-branches config). Skill tool
allowed in every case. Fixtures generated + FixtureLoader-verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four cases: non-stack-flow-normal (control, byte-compat),
stack-layer-refusal-routing (no push/PR workaround; routes to
managing-gh-stacks by name), prereqs-gate-onboarding (exact install
lines, no improvisation), no-destination-merge-on-layer (poison-file
grader proven to discriminate by simulating the bad-agent merge).
Mechanical finding: url.insteadOf can't fake a GitHub remote for
provider_detect (get-url applies substitution) — bin/git passthrough
wrapper intercepts only 'remote get-url origin'. Fixtures generated +
FixtureLoader-verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
codex exec with a piped/inherited stdin waits to read it as an appended
<stdin> block ('Reading additional input from stdin...') and never
starts the turn — found empirically when backgrounded eval reruns
produced zero events until timeout. Same fix as the local runner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…6 on worktree

Cross-model prove-out iterations (full trail in site/reports/evals):
- Runner unified across worktrees (each copy had half the fixes) +
  stdin=DEVNULL and partial-events capture on the claude path too;
  absolute workspace-bin PATH prepend (stubs win for script-spawned
  processes in other cwds — turned always-stack-product-b green)
- git-wrapper scaffolds: canonicalize PATH entries before self-exclusion
  (relative ./bin WAS the wrapper -> infinite self-exec hang at claude
  startup)
- Partial-events capture found two more hang causes: model-chosen
  background bash tasks stall headless -p sessions (prompts now forbid
  backgrounding), and transient 401 auth throttling under rapid batches
- SKILL script-route rules from graded failures: default sibling layout
  unless told otherwise; sweeps use BATCH cleanup (single-branch removal
  of gh_stack_tracked:true requires explicit approval — stop and ask);
  relay refusal suggested_action verbatim, never soften into workaround
  offers. Agent-tool naming sweep (formerly Task); codex
  collaboration.spawn_agent delegation notes
- Grader calibration: dependent-base checked-out grader removed
  (redundant + brittle; outcome pinned by no-new-worktree-dir +
  stack-add-ran + llm judge)

Scorecard: sc-git-worktree luna 6/6; haiku oscillates on 3 multi-step
flows across runs — recorded as a model-reliability finding (the skill
content is proven by luna's consistency), not a skill defect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ity, residue scrub

The isolated-run debugging arc, each fix transcript-verified:
- pytest_plugin: implement setup.files (FileMapping) execution — loader
  supported it, execution never wired, so file-mapped fixtures (incl.
  all generated eval scaffolds) silently never arrived in the project
- environment: validate ANTHROPIC_API_KEY once per process and scrub
  only provably-dead keys (a stale env key hijacks fresh-HOME sessions
  with 401s; OAuth does not transfer into an isolated HOME by file copy
  — a VALID key is the isolated-auth path); copy_claude_auth for
  credential-file setups
- runner: collected_data.cwd set authoritatively to the project path
  (transcript cwd does not survive HOME-override translation)
- generator: per-case residue scrub before scaffolds (harness project
  persists across cases); escape-processing fix in the frontmatter
  parser (authored regexes like STACK\\.X arrived double-escaped and
  could never match — six graders across suites were inert)
- sc-commit-push-pr eval budgets raised (max_turns 40 / 450s) — the
  pipeline suite legitimately needs more room

Companion fix in sc-test-harness (dbb69de): hook commands pinned to
${CLAUDE_PROJECT_DIR} — hooks run in the shell's cwd, so any agent cd
broke every relative log-hook.py invocation, and PreToolUse blocking
errors froze all tool execution. Harness suite 706 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…arness runs

Full progression: sc-git-worktree haiku iterations + luna 6/6;
sc-commit-push-pr local-runner iterations (environment-blocked era) and
the first isolated harness runs, ending at pure behavioral results:
haiku breaks script-first discipline (direct push on a stack layer,
speculation instead of running the gate) where luna holds it — the
measured model-reliability floor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ok tests; CI greens

The unconditional gh-stack prerequisite gate (this branch's
sc-commit-push-pr change) fires before every scenario in the
pre-existing repo-level suites — tests/test_commit_push.py,
test_create_pr.py, test_hooks.py now satisfy it via an autouse fixture
(gate behavior itself is covered by the package's
test_stack_awareness.py). tests/test_sc_prefix_validation.py pins
sc-git-worktree at 0.13.0 (bumped ahead of the platform release at this
stack layer; refactory's bump above moves _CURRENT_VERSION and
reconciles). Eval scaffolds chmod +x (security-scan). Full repo suite
green; validate-all ALL PASSED.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@randlee
randlee force-pushed the feature/sc-git-worktree-gh-stack branch from ff9a529 to da45e55 Compare August 31, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant