Skip to content

feat(beta-delivery-ux): S2 — pipeline presets + status + workspace one-command, with the refresh-drift gate closed - #1327

Merged
artyhoo merged 1 commit into
stagingfrom
harvest/s2-final
Aug 9, 2026
Merged

feat(beta-delivery-ux): S2 — pipeline presets + status + workspace one-command, with the refresh-drift gate closed#1327
artyhoo merged 1 commit into
stagingfrom
harvest/s2-final

Conversation

@artyhoo

@artyhoo artyhoo commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Ships S2 (pipeline launch presets + /pipeline status + workspace one-command, spec A4/A5/A9) and closes the three items that left it HALTED at the §2.4 two-REVISE cap.

1 — do_refresh() omitted the four worktree scripts (the RED gate on this branch)

setup.d/85-worktree-scripts.sh:50 copy_safes create-worktree.sh, worktree-node-modules.sh, link-coordination.sh and getff-work.sh on the --full env+ path, with no refresh arm. A brownfield env+ consumer therefore received none of Park-6's «full functional set» on --refresh — the #869 class this gate exists to catch. Verified against the merge-base rather than assumed: 7d44221af3 = 6/6 PASS, branch = 5/6.

The list has to be duplicated — the delivery site is a setup.d module sourced only during install, so do_refresh cannot read its array — and the set-difference check cannot see a per-script divergence: both sides collapse to the token scripts/, so adding a 5th script to the delivery array while forgetting the refresh loop would stay GREEN. Added a parity check that compares the two lists directly, plus its non-vacuity negative.

Falsified for real, not asserted — a 5th name added to the delivery array only:

✗ worktree-scripts parity: delivery/refresh lists DIVERGE —
  delivered=[brand-new-thing.sh create-worktree.sh getff-work.sh link-coordination.sh worktree-node-modules.sh]
  refreshed=[create-worktree.sh getff-work.sh link-coordination.sh worktree-node-modules.sh]
PASS=7 FAIL=1        → restored: PASS=8 FAIL=0

2 — render-status.sh:104 did not compile, and the fallback hid it

The and the mergeable= label sat inside the \(…) interpolations, which is a jq syntax error; the 2>/dev/null || echo fallback on the next line swallowed it, so §3's «open PRs + mergeable state» rendered the fallback line on every single run. Live proof:

old → jq: error: syntax error, unexpected INVALID_CHARACTER (exit 3)
new →   - #42 Test [feat → main, mergeable=MERGEABLE]        (exit 0)

3 — it.fails() is no longer a delivery mechanism

NON-DEGRADED-PR-SECTION shipped as it.fails() with the defect written up as an operator TODO in the impl-note §8.2 — a known-broken path presented as a passing suite. That is exactly the #warning-nobody-reads shape attention-is-not-a-mechanism.md §1 rejects. With the template fixed the marker is gone and the guard is live: re-introducing the defect → 1 failed | 5 passed; restored → 6 passed.

4 — SKILL.md §3 Step 3b, the last open MAJOR

Spec A4 (lines 269-271) TTY preset row, additive and TTY-gated; --preset / AIF_PIPELINE_PRESET stays primary per kickoff §2 binding constraint 1, and menu-only UX stays REJECTED. The block lives in .claude/skills/pipeline/references/output-format.md:493 (§8) rather than inline, because inlining pushed SKILL.md to 602 lines and tripped the 600-line markdown gate; SKILL.md:309 keeps a one-line pointer. Principle 18 still 6/6.

On the «permission-blocked» claim

Items 2 and 4 were reported across both rework rounds as «PERMISSION-BLOCKED — .claude/skills/pipeline/ not writable». The cold auditor read that as contradicted by a diff that creates files under exactly that path. Both readings are wrong, in different directions.

The auditor's contradiction does not hold: the two rework commits (dfc955842b, 6564566d67) touch .claude/skills/pipeline/ zero times, while the three initial commits wrote nine files under it. The claim was about the rework rounds, and the commit record is consistent with it.

But the stated mechanism does not exist on any surface reachable from here: the repo deny list carries no .claude/skills entry (.claude/settings.json), the container's global settings have permissions: null, all seven PostToolUse Edit hooks exit 0 on both paths, and the container filesystem is writable as root. So the claim is not falsified and not corroborated — and the practical consequence is the one that matters: both edits were made here without incident.

Verification

bash tests/install-sh/refresh-covers-full-delivery.test.sh   → PASS=8 FAIL=0
npx vitest run packages/core/hooks/render-status.test.ts
        packages/core/principles/18-meta-orchestrator-output-format.test.ts → 12 passed
bash tests/install-sh/glm-onebutton.test.sh (post-merge, S4 on staging)     → PASS=33 FAIL=0

All on the host. The refresh gate was re-run after merging staging (which brought S4's install.sh changes) and still reports 8/8, so no sibling delivery site regressed.

§1.7 Forward-check applied

Complies with attention-is-not-a-mechanism.md:29 — the it.fails() removal at packages/core/hooks/render-status.test.ts:105 converts a check whose failure mode was «nobody looked» into one that fails, and the new parity arm at tests/install-sh/refresh-covers-full-delivery.test.sh:1 is a deterministic gate at the earliest reachable channel (pre-push) carrying its own non-vacuity negative. Complies with no-paid-llm-in-ci.md:1 (awk/grep/jq only, zero API-billed calls). Complies with doc-authority-hierarchy.md:1 — the new §8 lands in a file that already carries a Class + Authoritative-for header, and the §3 pointer keeps SKILL.md under the 600-line ceiling rather than growing the hot doc. Complies with language-discipline.md:1 (machinery in English).

§1.7 Backward-check applied

Class of this change = a --full copy_safe delivery site with no matching do_refresh arm. Enumerated beyond this diff: setup.d/45-python.sh:1SWEPT-CLEAN, it owns its own GETFF_TOOLCHAIN_REFRESH path and Check 4 of this same gate already asserts that parity; setup.d/40-configs.sh:1SWEPT-CLEAN, its deliveries are either refreshed or in the EXCLUDED list, which Check 2 proves is not stale; setup.d/aif-handoff-guided-install.sh:1SWEPT-CLEAN, it is invoked from install.sh:1139 and is not a copy_safe delivery at all, so the class does not reach it. Second class = a shipped helper whose failure is masked by a 2>/dev/null || fallback: swept .claude/skills/pipeline/helpers/list-presets.sh:1 and .claude/skills/pipeline/helpers/resolve-preset.sh:1SWEPT-CLEAN, both carry paired-negative coverage (packages/core/hooks/list-presets.test.ts:1, packages/core/hooks/parse-preset.test.ts:1) that exercises the real jq path rather than only the fallback.

Prior-art: prior-art-evaluations.md#87 (Worktree-creation CLI landscape, verdict BUILD — scripts/getff-work.sh and setup.d/85-worktree-scripts.sh do NOT rebuild worktree creation; they compose the already-BUILT scripts/create-worktree.sh from that row and merely ship it to env+ consumers, which is the delivery half #87's BUILD verdict presumes).
Prior-art: prior-art-evaluations.md#110 (cross-worktree gitignored-SSOT symlink sync, verdict ADAPT — link-coordination.sh is the artefact that row owns; this PR adds it to the shipped set and to do_refresh, changing no behaviour of the script itself).
Prior-art: clig.dev flag-first, verdict REFERENCE, no new SSOT row — upstream problem class = non-interactive CLI UX; ours = preset activation must work for agents and CI, not only an interactive TTY. Match is identical, so the flag/env path stays primary and the §3 Step 3b TTY row is strictly additive.

Fidelity verdict

FIDELITY: skipped — no cold fidelity auditor was run in this session, so a GO would be unearned; this is a dispatcher-side repair of the S2 halt, self-reviewed on the host, with every claim carrying a command output or an in-repo file:line and two falsification runs (parity gate, render-status guard) standing as the non-vacuity evidence

…e-command (A4/A5/A9)

Ships S2 and closes the three items that left it HALTED at the dispatcher §2.4 two-REVISE cap.
Collapsed to one commit onto current staging: the branch history carried a pre-§1.7-era commit
(cc7af50) that the trailer backstop rejects, and force-push is unavailable to agents.

Delivered (A4/A5/A9): four data-driven launch presets (aif/night/economy/sdd) with a `list` verb;
`/pipeline status`; the workspace one-command `getff-work.sh`; and setup.d/85-worktree-scripts.sh
as the single ship-point for the worktree script cluster (R7 — the §1j block in 10-skills.sh that
shipped only create-worktree.sh is removed; a partial ship from two sites drifts independently).

Three repairs on top of that:

1. do_refresh() omitted the four worktree scripts — the RED gate on this branch. 85-worktree-
   scripts.sh:50 copy_safe's them on the --full env+ path with no refresh arm, so a brownfield
   env+ consumer got NONE of Park-6's "full functional set" on --refresh. Verified against the
   merge-base rather than assumed: 7d44221 = 6/6, branch = 5/6. Adds the loop.

   The list must be duplicated (the delivery site is a setup.d module sourced only during install),
   and the set-difference check cannot see a per-script divergence — both sides collapse to the
   token "scripts/". Added a direct list-parity check plus its non-vacuity negative. Falsified for
   real: a 5th name in the delivery array only → "delivery/refresh lists DIVERGE", PASS=7 FAIL=1;
   restored → PASS=8 FAIL=0.

2. render-status.sh:104 jq template did not compile. The arrow and the "mergeable=" label sat
   inside the interpolations — a jq syntax error — and the `2>/dev/null || echo` fallback swallowed
   it, so §3's "open PRs + mergeable state" rendered the fallback on every run.
     old → jq: error: syntax error, unexpected INVALID_CHARACTER (exit 3)
     new →   - #42 Test [feat -> main, mergeable=MERGEABLE]        (exit 0)

3. NON-DEGRADED-PR-SECTION flipped from it.fails() to it(). A known-broken path shipped as a
   passing suite plus an operator TODO is the #warning-nobody-reads shape
   attention-is-not-a-mechanism.md §1 rejects. Guard is now live: re-introducing the defect →
   1 failed | 5 passed; restored → 6 passed.

Plus SKILL.md §3 Step 3b (spec A4 lines 269-271, the last open MAJOR): TTY-gated and additive, the
flag/env path stays primary. The block lives in references/output-format.md §8 because inlining it
tripped the 600-line markdown gate; SKILL.md keeps a pointer. Principle 18 still 6/6.

§1.7: forward-check applied — the it.fails() removal at packages/core/hooks/render-status.test.ts:105
brings the branch into line with attention-is-not-a-mechanism.md:29, which rejects a check whose
failure mode is "nobody looked"; the new parity arm at
tests/install-sh/refresh-covers-full-delivery.test.sh:1 is a deterministic gate at the earliest
reachable channel (pre-push) carrying its own non-vacuity negative; zero API-billed calls, per
no-paid-llm-in-ci.md:1; the new §8 lands in a file already carrying a Class + Authoritative-for
header, per doc-authority-hierarchy.md:1. backward-check sweep — class of this change = "a --full
copy_safe delivery site with no matching do_refresh arm". Enumerated beyond this diff:
setup.d/45-python.sh:1 — SWEPT-CLEAN, it owns its own GETFF_TOOLCHAIN_REFRESH path and Check 4 of
the same gate asserts that parity; setup.d/40-configs.sh:1 — SWEPT-CLEAN, its deliveries are either
refreshed or in the EXCLUDED list, which Check 2 proves is not stale;
setup.d/aif-handoff-guided-install.sh:1 — SWEPT-CLEAN, invoked from install.sh:1139 and not a
copy_safe delivery at all. Second class = "a shipped helper whose failure is masked by a
2>/dev/null fallback": .claude/skills/pipeline/helpers/list-presets.sh:1 and
.claude/skills/pipeline/helpers/resolve-preset.sh:1 — SWEPT-CLEAN, both carry paired-negative
coverage exercising the real jq path.

Prior-art: prior-art-evaluations.md#87 (worktree-creation CLI landscape, verdict BUILD — getff-work.sh and 85-worktree-scripts.sh do NOT rebuild worktree creation; they compose the already-BUILT scripts/create-worktree.sh from that row and ship it to env+ consumers, the delivery half #87's BUILD verdict presumes).
Prior-art: prior-art-evaluations.md#110 (cross-worktree gitignored-SSOT symlink sync, verdict ADAPT — link-coordination.sh is the artefact that row owns; this adds it to the shipped set and to do_refresh, changing no behaviour of the script).
@artyhoo
artyhoo merged commit 3ae7edf into staging Aug 9, 2026
42 checks passed
@artyhoo
artyhoo deleted the harvest/s2-final branch August 9, 2026 08:10
artyhoo added a commit that referenced this pull request Aug 9, 2026
…re-review measured false (#1332)

The re-review of #1329 returned REVISE: B2 CLOSED, zero regressions, but B1 only
partially closed — the replacement sentence had itself gone false.

#1329 wrote «`--refresh` never deepens an install, so `--refresh --profile env` on a
`core` project is a no-op that still exits 0». That was true against its base
(8d092f1) and false by the time it merged: #1327 landed ~20 minutes earlier and
added a worktree-scripts refresh arm at install.sh:1001-1005 with NO profile check,
while its delivery site documents `PROFILE=core → skip`
(setup.d/85-worktree-scripts.sh:19-22).

Re-measured against staging on a core consumer: `--refresh --profile env` → exit 0,
tier-home NO, arch NO, but create-worktree.sh, worktree-node-modules.sh,
link-coordination.sh and getff-work.sh all ARRIVE. Not a no-op.

The claim is now stated so it holds whichever way the underlying defect is resolved:
`--refresh` re-delivers fixes to what you already have and does NOT reliably deepen
an install — no «never», no «no-op». The ungated arm is surfaced in INSTALL-FOR-AI.md
as what a consumer actually observes, and attributed to beta-delivery-ux rather than
fixed here (different umbrella; gating it is that umbrella's call).

Also corrected, all measured rather than copied:
- «core artefacts stay byte-identical» → every pre-existing core file IS byte-identical
  except .prettierignore, whose managed block gains the newly-shipped paths (verified by
  md5 manifest across a core→env deepening).
- Stale line citations from the merge-forward: the F7 gate is install.sh:678, not
  669-671 (that range is the core skills loop); the tier-home presence gate moved to
  install.sh:1090-1093.

Verified: first-steps-parity 9/9 · principle 09 37/37 · SSOT parses · run-audit.sh
«non-PORTABLE findings (none)» · baselines regenerated (11 added / 11 removed, all the
one AI-USAGE-GUIDE.md path) · SNAPSHOT_MODE=compare 15/15.

Prior-art: skipped — corrects a factual claim in shipped docs, no new capability.

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 9, 2026
…ms routed here after authoring (#1337)

kickoff-s3.md was authored 2026-08-08 16:35, before the meta-launch routed three
items into this stage. The state file records the routing; the dispatch input did
not, so a fresh S3 tab handed only this kickoff would have lost all three.

Adds §2 D5 with each item re-measured against origin/staging 4f68ed5 rather
than inherited as prose:

- i  presets row (meta-launch M4) — AI-USAGE-GUIDE.md:272 still says «not shipped»
     while #1327 shipped 4 preset JSONs + 2 helpers; the row's own trigger fired.
     Note the line moved from the :269/:270 recorded in the state file.
- ii living-docs-auditor.md:110,173 asserts an /aif-verify gate that
     skills/getff/SKILL.md:128 denies — maintainer-owned, so D3 proposal only,
     reusing the replacement text S1 drafted in PR #1311's body.
- iii aif-version is read 0 times by deps-hash-check.sh (control deps-hash = 15)
     across 4 tracked files — an operator fork, explicitly parked, not resolved.

Also states why item i does not collide with §3's consumer-payload carve-out
(AI-USAGE-GUIDE.md *is* what S1 landed), and names a hazard neither sibling
kickoff covered: the 11 install baselines fingerprint both AI-USAGE-GUIDE.md and
six shipped skills SKILL.md paths, so S2 and S3 can collide on the generated
baseline surface that §5's source-file ownership split does not reach.

Acceptance item 8 makes all three non-droppable.

Prior-art: skipped — dispatch-input doc edit only, no new capability (markdown kickoff, no dependency, no module)

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 10, 2026
…1361)

All six stages are merged to staging: S1 #1173, S2 #1327, S3 #1272,
S4 #1341/#1350/#1351, S5 #1285, R1 #1358 (a88da6d, 2026-08-10). The
last-stage condition the meta-launch state.md named is now satisfied, so
the umbrella-closure convention fires.

Writing done.md is what makes `priority-score.sh` Layer C3 score the
umbrella `status=DONE basis=done-md` and stop offering it for dispatch —
verified after the write, both the umbrella and its meta-launch dir now
report `done_pr=1358 basis=done-md`. Holding it back until now was the
deliberate call recorded in state.md: writing it before R1 merged would
have short-circuited C1/C2 and stopped R1 from being dispatched at all.

The record carries what a future reader would otherwise re-derive: the
per-stage ledger, the U9/U10 gates from the R1 freeze record (the @Getff
scope-ownership probe, the missing `bin: getff`, the finding that
promoting eslint to runtime deps is necessary but not sufficient), the
ci-success `needs:` completeness gap R1's backward sweep surfaced and
deliberately did not fix per the PR-strategy rule, S4's two
operator-accepted risks, S5's P5 vendor-scope fork, and the seven
`done`-unharvested aif task ids.

Prior-art: skipped — closure record only; done.md is a documentation
artefact per the CLAUDE.md capability-commit doc carve-out, adds no
dependency, no module and no new capability.

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 17, 2026
…ll slugs (#1312, #1334) (#1412)

## Summary

`do_refresh` had drifted from the install arm in **both** directions, and the two directions are the two issues this PR closes. #1312: three skill slugs shipped on install but reached no refresh loop — `arch` (in none at all), `claude-glm-executor-handoff` (factory install loop only), and `rule-tests`, which the refresh header **announced** and then skipped because its payload lives under `.claude/skills/`, not `skills/`. #1334: the worktree-scripts arm carried no profile check at all, so any `--refresh` on a `core` project delivered four `env+` artefacts — the inverse defect, and one that makes «what does `core` contain» unanswerable from `--profile` alone.

Both are the same seam, so both get the same resolution: **every depth-gated refresh arm now uses the delivery site's own profile predicate OR presence-on-disk** (presence = prior opt-in, the brownfield upgrade path), and the per-tier slug lists collapse into one shared constant each so the two arms cannot drift again.

## Changes

- **`setup.d/lib.sh:58-60`** — `GETFF_SKILLS_CORE` / `_ENV` / `_FACTORY`: the slug lists as an SSOT read by both arms. Issue #1312's own suggested direction #1; the three drifts it measured were three copies of one list, not three bugs.
- **`setup.d/10-skills.sh:113/127/133`** — the install arm reads the constants; its `▶ Contour surface` / `▶ AIF operator suite` announcements render from them too.
- **`install.sh:684-701`** — the refresh arm reads the same constants, in three loops with three gates: core unconditional, env+ (`env|factory|WITH_AIF_SUITE` OR presence), factory (`factory|WITH_AIF_SUITE` OR presence). `arch`, `pipeline` and `claude-glm-executor-handoff` are refreshed for the first time; `rule-tests` moves here from the plain-copy loop, where its source path could never resolve.
- **`install.sh:643`** — the plain-copy header renders from `_PLAIN_SKILLS`, so it can no longer announce a slug the loop does not carry (#1312's honest-signals half).
- **`install.sh:1030`** — the worktree-scripts arm gains the gate it never had (#1334). Presence probe is `scripts/create-worktree.sh`: the cluster's load-bearing entry point, present in every version of it, and the four ship together by construction — so a consumer who opted in before `getff-work.sh` joined the cluster still receives it.
- **`install.sh:1128`** — tier-home moves from presence-ONLY to the same uniform gate. Without it, `--refresh --profile env` would deepen some arms and not others: the «each arm decides for itself» state `INSTALL-FOR-AI.md` previously had to describe in a paragraph. Named in #1334's own arm table as part of this decision.
- **`tests/install-sh/consumer-upgrade-path.test.sh:447-612`** — TESTs 8-11, the behavioural gates: core refresh delivers no deeper artefact (#1334), a bare `--refresh` keeps an already-opted-in factory payload fresh (#1312), the `▶ Skills` header cannot announce what the run does not touch, and `--refresh --profile env` DOES deliver — which is the paired-negative for TEST 8's absence claim (same paths, same tree, present as soon as the profile says so).
- **`tests/install-sh/refresh-covers-full-delivery.test.sh:296-345`** — extends the existing parity gate (added by #1327 for the same worktree cluster) rather than adding a parallel one: both arms must READ every tier constant, and neither may carry a literal-slug `for _skill in` loop (a fourth copy). Two paired-negative arms.
- **`INSTALL-FOR-AI.md:152/160-166/444`** — re-measured. The old text documented both defects as consumer-observable behaviour; leaving it would have made the shipped doc lie in the opposite direction.

## Prior-art consult

- [x] Not a capability commit per [CLAUDE.md «What is a capability commit?»](../CLAUDE.md) — no new dependency, no new file (all four touched files existed), nothing under `packages/`. Commit carries the escape-hatch trailer with rationale.
- [x] No new capability area surfaced: the fix reuses the gate shape already in this function (`install.sh:621` agents arm, F7 skills arm) and the parity-test precedent from #1327.
- [x] n/a — no SSOT entry matched or needed.
- [x] n/a — no new capability area, so no context7 pass claimed.

## Test plan

- [x] `bash tests/install-sh/consumer-upgrade-path.test.sh` — RED baseline before the fix: `PASS=37 FAIL=7` (the four worktree scripts leaking onto a core refresh ×2 arms; `arch`, `rule-tests`, `claude-glm-executor-handoff` stale after a bare refresh; the announced-then-skipped `rule-tests`; `arch`/`pipeline`/`tier-home` missing under `--refresh --profile env`). After: **`PASS=44 FAIL=0`**.
- [x] `bash tests/install-sh/refresh-covers-full-delivery.test.sh` — before: `PASS=9 FAIL=2`; after: **`PASS=13 FAIL=0`** (both new checks plus their negatives).
- [x] `SNAPSHOT_MODE=compare bash tests/install-sh/snapshot.sh` — exit 0, baselines unchanged (the install arm ships the same bytes; only its source of names moved).
- [x] Full `tests/install-sh/*.test.sh` battery — see the run summary in the review findings section.
- [x] `shellcheck --exclude=SC2034,SC2016,SC2317 setup.d/*.sh install.sh` — exit 0 (CI's exact invocation, `.github/workflows/audit-self.yml:804`).
- [x] Manual smoke: `--profile core` install → bare `--refresh` → `--refresh --profile core` → `--refresh --profile env`, asserting the depth boundary at each step (this is TESTs 8/11 run end-to-end against real installs, not a mocked harness).

## Provenance

n/a — issue-driven fix, not a stage PR. Base: `staging` @ `049b35e851`. In-session (no aif substrate).

## Review findings

n/a — see Test plan for the RED→GREEN evidence.

## Fidelity verdict

FIDELITY: skipped — issue-driven bug fix with no kickoff or spec stage behind it; the acceptance contract is the two issue bodies (#1312, #1334) plus the paired-negative gates listed in the Test plan.

## Parked questions

n/a

### §1.7 Forward-check applied

Checked against the disciplines this diff touches. [`dual-implementation-discipline.md §7`](../.claude/rules/dual-implementation-discipline.md) (single source of truth): the two hand-maintained slug lists collapse to `setup.d/lib.sh:58-60`, read by `setup.d/10-skills.sh:113` and `install.sh:684` — the duplication that drifted three times is gone rather than re-asserted. [`attention-is-not-a-mechanism.md §1`](../.claude/rules/attention-is-not-a-mechanism.md): every claim in this PR lands on a deterministic channel — the depth boundary on `tests/install-sh/consumer-upgrade-path.test.sh:447`, the announce↔deliver honesty on `:554`, the SSOT-consumption invariant on `tests/install-sh/refresh-covers-full-delivery.test.sh:296`; none of them is «a reviewer will read the diff». [`no-paid-llm-in-ci.md`](../.claude/rules/no-paid-llm-in-ci.md): the new gates are bash + real installs, zero API calls. [`effort-worthiness.md §1`](../.claude/rules/effort-worthiness.md): `build-and-verify` contour — a reversible installer change verified live against real consumer trees, no research-grade round. [`evidence-regeneration.md`](../.claude/rules/evidence-regeneration.md): `INSTALL-FOR-AI.md:160` was a dated measurement of the old behaviour, so it was re-measured (2026-08-17) instead of silently inherited.

### §1.7 Backward-check applied

Swept every profile-gated install layer for its refresh counterpart, not just the two the issues named: `setup.d/20-agents.sh:39` (suite agents) → gated arm exists at `install.sh:621`; `setup.d/20-agents.sh:70` (skill-context) → gated arm exists at `install.sh:1146`; `setup.d/30-templates.sh:108` (tier-home) → was presence-only, unified here; `setup.d/85-worktree-scripts.sh:34` (worktree cluster) → the #1334 defect, fixed here; **`setup.d/55-runtime-bridge-vendor.sh:65` (factory vendor payload) → has NO refresh arm at all** — a pre-existing #1312-class gap, outside both issues' scope, so it is recorded in `INSTALL-FOR-AI.md:166` as install-only rather than silently fixed in this PR. Also swept for stale claims about the changed behaviour: `grep -rln "create-worktree\|getff-work.sh" tests/` → only the file updated here; `grep -rn 'for _skill in' setup.d install.sh` → no literal-slug loop survives (now asserted); `INSTALL-FOR-AI.md:152/160-166/444` were the only prose stating the old semantics, and #1329's weakened claim (repaired in #1332) still holds under the new behaviour.

Closes #1312
Closes #1334
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant