Skip to content

feat(getff): the getff distribution package — npx getff init from an assembled tarball (U10 S1+S2) - #1613

Merged
artyhoo merged 6 commits into
stagingfrom
claude/u10-getff-dist-package
Sep 5, 2026
Merged

feat(getff): the getff distribution package — npx getff init from an assembled tarball (U10 S1+S2)#1613
artyhoo merged 6 commits into
stagingfrom
claude/u10-getff-dist-package

Conversation

@artyhoo

@artyhoo artyhoo commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

U10 stages S1+S2 of npm-publish-getff-init/kickoff.md: the getff distribution package that makes npx getff@latest init (spec D6) real, and the consumer-matrix cell that proves it. packages/getff/ is a new workspace package (unscoped name per Decision 1) whose tarball lays its contents out exactly like the repository root, so install.sh's 107 PKG_ROOT/… reads land unchanged (freeze record §2 §0.5). The payload is assembled, never committedscripts/build-getff-dist.sh copies the git-tracked payload at prepack and writes MANIFEST.sha256; --check is the drift gate. tests/consumer-matrix/getff-dist-cell.sh is the U10 gate («npx getff init → the first planted violation fails»), wired into ci-success.needs. Publish itself (S3) stays the operator's act and is NOT in this PR.

Changes

  • packages/getff/package.jsongetff 0.1.0, bin: getff, files = the ten payload roots + bin/ + MANIFEST.sha256, private: false stated, prepack = check + assemble, engines.node >= 22, no dependencies.
  • packages/getff/bin/getff — bash; resolves its own symlinked location; initexec bash "$ROOT/setup" "$@"; --version; usage + exit 2 on anything else. No network fetch (the clone-shim was rejected in the freeze record).
  • packages/getff/README.md, LICENSE (copy of root LICENSE.md), .gitignore (payload roots, explicit), .npmignore (so npm-packlist never reads the sibling .gitignore).
  • packages/getff/MANIFEST.sha256 — 1053 lines, the committed drift artefact (six scripts/ lines: exactly the files install.sh and setup.d read from PKG_ROOT).
  • scripts/build-getff-dist.shgit ls-files-sourced assembly (tracked files only, T-U10-B) of the ten roots, with scripts/ cut to the six installer-read files (the assembler itself is NOT shipped), manifest, --check (manifest diff + files-coverage check), bash 3.2-compatible, shellcheck-clean.
  • tests/consumer-matrix/getff-dist-cell.sh — steps (1)-(5) + opt-in (6) paired-RED arms (GETFF_DIST_CELL_RED_ARMS=1; GETFF_DIST_CELL_RED_ONLY=1 + GETFF_DIST_CELL_RED_ENTRIES=<entry> runs one arm alone); see Test plan.
  • .github/workflows/audit-self.yml — job consumer-matrix-getff-dist-cell + ci-success.needs entry with the #warning-nobody-reads rationale.
  • Makefileconsumer-matrix-getff-dist target; consumer-matrix runs it.
  • package.json (root) — build:getff-dist, build:getff-dist:check; package-lock.json — the workspace link entries only (node_modules/getff + packages/getff).
  • docs/meta-factory/prior-art-evaluations.md — entry research(aif-handoff-bridge): Sub-wave B — Variant B filesystem-watcher #267 (Verdict ADOPT: npm files+prepack adopted as the assembly seam, bundleDependencies rejected in the rationale; 3 context7 phrasings cited).
  • .claude/orchestrator-prompts/npm-publish-getff-init/kickoff.md — §3 amended after the round-1 audit flagged two KICKOFF-AMBIGUOUS items: packages/lint-config dropped from the tarball shape (zero PKG_ROOT reads), the scripts/ subset spelled out, the planted-violation reference pointed at tests/consumer-matrix/pnpm-monorepo-cell.sh:200-202 (no sourceable helper exists under tests/install-sh/).
  • docs/meta-factory/getff-name-architecture-freeze.md — «BUILT 2026-09-05» status note above the «still open» items, saying how each was decided.

Prior-art consult

Prior-art: prior-art-evaluations.md#267 (verdict ADOPT — npm files + prepack adopted as the assembly seam; bundleDependencies rejected in the rationale, it bundles node_modules trees, not the PKG_ROOT layout install.sh reads; in-repo precedents build-synth-bundle.sh --check + npm-tarball-cell.sh copied)

Test plan

  • bash scripts/build-getff-dist.sh && bash scripts/build-getff-dist.sh --check✓ … in sync (1053 files); files covers every payload root (at the audited HEAD, clean checkout — the round-1 manifest had been generated before the assembler was git added and was RED; fixed in 641e6f5282).
  • Drift arm RED: append a comment to setup.d/lib.sh--check exit 1: DRIFT … committed setup.d/lib.sh / fresh setup.d/lib.sh; git restore → GREEN.
  • Files arm RED: drop scripts/ from files--check exit 1: files does not list these payload roots: scripts; restore → GREEN.
  • FRAMEWORK_ROOT=<worktree> bash tests/consumer-matrix/getff-dist-cell.sh → GREEN (output pasted below). First run RED on manifest coverage: npm-packlist drops nested .gitignore files (6 fixture files under packages/core/) — recorded as npm's own exclusion alongside node_modules/ trees and lock files, none read by install.sh.
  • git add -n packages/getff → 7 files (metadata only; the assembled payload is ignored).
  • grep -c '^[0-9a-f]* scripts/' packages/getff/MANIFEST.sha256 → 6; grep -c build-getff-dist → 0 (the assembler does not ship itself).
  • npx vitest run principles/36-ci-needs-completeness.test.ts → 7 passed; js-yaml parse of the workflow confirms the job and the needs entry.
  • shellcheck --exclude=SC2034,SC2016,SC2317 on both new scripts → clean; bash -n clean.
  • markdownlint-cli2 on the touched docs → 0 errors. Formatting: only the shipped surface is prettier-enforced (scripts/format-shipped.sh pathspecs); docs/meta-factory/* and the workflow are not prettier-clean at HEAD and were deliberately NOT reformatted wholesale (diff = the inserted lines only).
  • Paired-RED files arms — ten single-entry runs (GETFF_DIST_CELL_RED_ONLY=1 GETFF_DIST_CELL_RED_ENTRIES=<entry>), each packing with that entry removed and running getff init from the crippled tarball: 10/10 RED. Table in Review findings below.
  • CI round 1 on 641e6f5282 — two REDs, both real, both fixed without touching this PR's deliverables:
    • consumer-matrix-getff-dist-cell RED at step (5): install.sh completed, then setup's Companions step died — setup.d/engine.sh:70 «⚠ superpowers install failed — run manually» followed by exit 1 on the bare runner (no claude CLI). Root cause is a pre-existing bug in the shipped engine: companion_step ended with [ "$kind" = "mcp" ] && printf …, returning 1 for every non-mcp companion on BOTH the ✓ and ⚠ branches, so setup -y under set -e died on any fresh machine (masked on operator machines by the «already present — skipping» early return). This is the cell doing its job — the first consumer-facing defect it caught. Fixed as its own atomic PR fix(setup): a companion must never kill setup -y — companion_step returns 0 on both branches #1614 (899f49dd6b, +3 regression tests proven RED on the old code), then merge-forwarded here (66cf3b8508).
    • install-sh battery (shard A) RED in run-local-ci-sweep-coverage.test.sh: the new cell is a CI command the local sweep never runs → allowlisted as UNREACHABLE with rationale (9061a6d007), same class as the three sibling cells.
    • The merge-forward changed setup.d/engine.sh inside the payload → the drift gate went RED on exactly that line (DRIFT … committed setup.d/engine.sh / fresh setup.d/engine.sh) → manifest regenerated in the same push (1d4cad7756, one hash line). Watch-list W-1's «merge-forward without a manifest hunk» tell, live-fired and honoured.
  • CI round 2 on 1d4cad7756: the new job passes step (5) on the bare runner and lands in ci-success.

Cell output (run 6, local, macOS, Node 24 / npm 11, HEAD 641e6f5282)

── (1) drift gate — committed MANIFEST.sha256 == fresh assembly; `files` covers every payload root
✓ packages/getff/MANIFEST.sha256 in sync with the repo root (1053 files); `files` covers every payload root

── (2)+(3) npm pack packages/getff → tarball → npm i <tarball> into a fresh fixture
  tarball: <tmp>/fixture.tgz
npm notice package size: 2.4 MB
npm notice unpacked size: 8.6 MB
npm notice total files: 1052
  installed to: <tmp>/fixture/node_modules/getff

── (4) the bin + manifest coverage
  ✓ getff --version → 0.1.0
  ✓ getff frobnicate → exit 2 + usage
  ✓ manifest coverage: 1045/1045 shippable manifest files present (node_modules/ trees, lock files and nested .gitignore excluded by npm, by design)

── (5) THE U10 GATE — getff init -y ts-server, then the first planted violation must FAIL
  ✓ eslint over src/routes/order.ts → non-zero with 'no-unsafe-zod-parse':
        3:52  error  Use `.safeParse()` instead of `.parse()` in HTTP boundaries — `.parse()` throws and bypasses structured error handling (R2)  rules-as-tests/no-unsafe-zod-parse
      ✖ 1 problem (1 error, 0 warnings)
  ✓ false-positive arm: no R2 message on src/config.ts (eslint rc=0)

✅ consumer-matrix getff-dist cell: GREEN (1052 files in tarball, version 0.1.0)
   getff init -y ts-server from the installed tarball → the planted R2 violation FAILED under eslint.

Provenance

Stage PR: kickoff .claude/orchestrator-prompts/npm-publish-getff-init/kickoff.md §3 S1+S2 (merged #1611 3d78158859) · base origin/staging @ 899f49dd6b after merge-forward (was b843d754a7) · substrate: in-session, host-side (operator route decision 2026-09-05; the aif instance holds no Claude profile) · model: Claude Fable 5.1 for build + a fresh cold seat for the fidelity audit · fidelity Round 1 REVISE (two MAJORs: stale manifest, whole scripts/ shipped) → fixed in 641e6f5282 → Round 2 GO (narrow delta, fresh cold seat) → head moved by merge-forward #1614 + manifest regen + sweep allowlist → Round 3 (narrow delta, git-conflict-merge-forward.md §9 case b).

Review findings

Cold fidelity audits (agents/fidelity-auditor.md, dialogue-blind seats given only the kickoff §3 S1+S2 / §4 / §6 and the diff).

Round 1 — REVISE on 62c2dccbd0 (two MAJORs, both with failure scenarios):

  • MAJOR — packages/getff/MANIFEST.sha256 omitted scripts/build-getff-dist.sh (generated before the assembler was git added); --check exited 1 on a clean checkout, so the CI cell and prepack would both have been RED at the audited SHA. Fixed in 641e6f5282: manifest regenerated after staging.
    Failure-scenario: CI job consumer-matrix-getff-dist-cell fails at step (1) and prepack refuses to pack → ci-success RED; any «gate green» claim measured on the pre-git add working tree, not the audited SHA.
  • MAJOR — scripts/build-getff-dist.sh shipped the whole scripts/ tree (61 files incl. *.test.sh, triage-kernel-v2-bench/, the assembler itself) vs kickoff «scripts/ shipped subset». Fixed: PAYLOAD spells the six files install.sh/setup.d read from PKG_ROOT/scripts/ (install.sh:1015-1016, :1024-1025, :1113-1118; setup.d/50-hooks.sh:68; setup.d/10-skills.sh:176; setup.d/85-worktree-scripts.sh:50-58); MANIFEST now carries 6 scripts/ lines and no build-getff-dist.sh.
    Failure-scenario: every PR touching a factory-only script (ci-success-gate.sh, measure-*.sh, render-*.mjs, *.test.sh) flips MANIFEST.sha256 and REDs the getff cell on a change no consumer installs, pushing maintainers toward reflexive regeneration; the self-shipping assembler is the mechanism that produced the RED gate above.
  • MINOR — no literal private: false → added (packages/getff/package.json:4).
  • MINOR, notes lane (recorded, no round): prepack runs --check && before build (stricter than the kickoff's build-only); bin/getff -h|--help|help|"" exits 0 with usage (kickoff said exit 2 for anything else — help is kept as the one friendly exit); paired-RED arms are opt-in and skip bin/ + MANIFEST.sha256 (both load-bearing for the main cell path instead, see the table); Makefile / root package.json targets, .npmignore, and the «BUILT» note are extra-but-harmless.
  • KICKOFF-AMBIGUOUS ×2 → kickoff §3 amended in 641e6f5282 (see Changes).

Round 2 — GO on 641e6f5282 (narrow delta, fresh cold seat): missing none · extra none · diverged none at MAJOR. Two notes-lane items, both recorded here rather than fixed:

  • The subject of commit 641e6f5282 («… + the assembler itself») reads as if scripts/build-getff-dist.sh were shipped; it is NOT in PAYLOAD or MANIFEST (that was the point of the fix). The subject cannot be reworded on a pushed branch (no force-push); this line is the correction.
  • The round-1 manifest was also stale on 5 files changed by the merge from staging (718bc30e78, fix(pipeline): repoint stale preset markers — aif → project defaults, economy → GLM-5.3 SDK #1608), not only on the omitted assembler line. Merge-forwards are the path that edits payload files with no manifest hunk; CI step (1) and prepack catch it fail-closed, so every merge-forward of this PR that touches a payload file needs a scripts/build-getff-dist.sh regen in the same push.

Round 3 — GO on 1d4cad7756 (narrow delta after the head moved: merge-forward 66cf3b8508 whose second parent is origin/staging = #1614, one allowlist line 9061a6d007, one manifest hash line 1d4cad7756; git-conflict-merge-forward.md §9 case b). Missing none · extra none at MAJOR · diverged none. No S1/S2 artefact changed in the delta. Notes lane: the allowlist line in scripts/run-local-ci-sweep-coverage.test.sh:109 is not named by the kickoff but is the minimal accommodation of an existing repo gate to the kickoff-mandated CI job, proven required by paired-RED — not scope creep; the two *.test.sh hits in the manifest are under packages/core (shipped whole by design), pre-existing since round 2, not a W-2 reintroduction; round 2's evidence line build-getff-dist.sh:38 pointed at the PAYLOAD comment header, the assignment is :42 (cosmetic).

Paired-RED files arms (ten single-entry runs, HEAD 641e6f5282)

Each arm copies the assembled package, deletes ONE files entry from package.json, packs with --ignore-scripts, installs the crippled tarball into a fresh fixture and runs getff init -y ts-server. The gate is «the consumer path FAILS»; the evidence column is the first failing line from init-fixture.log.

files entry arm evidence (first failing line, temp paths elided)
install.sh RED rc=10 — bash: <fixture>/node_modules/getff/install.sh: No such file or directory
setup RED rc=10 — getff: shipped setup not found at <fixture>/node_modules/getff/setup — the package is incomplete
setup.d/ RED rc=10 — same guard: setup refuses to run without its setup.d/ (message names the shipped setup path)
agents/ RED rc=10 — Aborting install: shipped artefacts failed Authoritative-for header verification.
skills/ RED rc=10 — Aborting install: shipped artefacts failed Authoritative-for header verification.
templates/ RED rc=10 — cp: <fixture>/node_modules/getff/templates/ts-server/eslint.config.mjs: No such file or directory
.claude/ RED rc=10 — cp: <fixture>/node_modules/getff/.claude/skills/template-audit: No such file or directory
.prettierrc.json RED rc=10 — cp: <fixture>/node_modules/getff/.prettierrc.json: No such file or directory
packages/ RED rc=10 — Aborting install: shipped artefacts failed Authoritative-for header verification.
scripts/ RED rc=10 — cp: <fixture>/node_modules/getff/scripts/check-ask-files.sh: No such file or directory

bin/ and MANIFEST.sha256 are not arms (they are not payload roots — --check's files-coverage arm covers the ten roots only). Both are load-bearing for the main cell path instead: dropping bin/ fails step (4) test -x node_modules/.bin/getff (tests/consumer-matrix/getff-dist-cell.sh:102), dropping MANIFEST.sha256 fails the step (4) must-exist list and the manifest-coverage read from the installed package (:113, :130). The arms are opt-in locally, not run by CI (each takes 1-2 minutes; CI runs the main path only).

Watch-list

id criterion why defect site reintroduction tell
W-1 kickoff §4 row 2 / host-verify:30 — build-getff-dist.sh --check exits 0 at the audited SHA the manifest is the only committed drift artefact; a stale one makes both CI and prepack fail-closed on an untouched consumer surface packages/getff/MANIFEST.sha256 (no scripts/build-getff-dist.sh line) DRIFT: on a clean checkout; a commit that adds/edits any payload file without a MANIFEST.sha256 hunk in the same commit
W-2 kickoff §2 Shape «scripts/ shipped subset» — PAYLOAD spells the installer-read files factory-only scripts in the payload couple unrelated PRs to the drift gate and ship operator tooling to consumers scripts/build-getff-dist.sh:37 (bare scripts) any *.test.sh, triage-kernel-v2-bench/, measure-*, or build-getff-dist.sh line back in MANIFEST.sha256; grep -c ' scripts/' ≫ 6
W-3 kickoff §3 S2 (6) / §4 row 4 — the per-entry paired-RED table is recorded in the PR body CI never runs the arms, so the R1 «established by paired-RED, not reasoning» evidence exists only where the run was pasted none — preventive PR body lacks a 10-row files entry / arm / evidence table, or a files entry added later with no RED / UNVALIDATED-by-this-cell row
W-4 kickoff §1 «nothing else changes for clone / curl consumers» the package is additive by contract; the 215-reference install.sh blast radius is the disqualifier the freeze recorded none — preventive any hunk under install.sh, setup, setup.d/ in a later round of this PR
W-5 kickoff §3 S1 — bin/getff never fetches over the network the clone-at-runtime shim was rejected in the freeze (unpinned, offline-hostile) none — preventive curl, git clone, npx, or a registry URL appearing in packages/getff/bin/getff

Round 1: W-1 REINTRODUCED (packages/getff/MANIFEST.sha256) · W-2 REINTRODUCED (scripts/build-getff-dist.sh:37) · W-3 N/A · W-4 CLEAN · W-5 CLEAN
Round 2: W-1 CLEAN (--check EXIT=0, 1053 files) · W-2 CLEAN (scripts/build-getff-dist.sh:38, 6 scripts/ lines in MANIFEST) · W-3 N/A (no PR body yet) · W-4 CLEAN (3-dot diff on install.sh/setup/setup.d empty) · W-5 CLEAN (bin/getff:56 exec bash "$ROOT/setup", no fetch)
Round 3: W-1 CLEAN (--check EXIT=0, 1053 files; MANIFEST.sha256:1034 engine.sh hash == shasum at HEAD — the merge-forward regen landed in the same push) · W-2 CLEAN (6 scripts/ lines, no build-getff-dist line; the two *.test.sh hits are packages/core, pre-existing) · W-3 CLEAN (PR #1613 body ## Review findings carries the 10-row files/arm/evidence table = the 10 payload roots of files[]; bin/+MANIFEST.sha256 dispositioned as main-path load-bearing, citations getff-dist-cell.sh:102/:113/:130 verified) · W-4 CLEAN (3-dot diff origin/staging...1d4cad7756 -- install.sh setup setup.d empty; engine.sh hunk is staging's #1614 arriving via merge 66cf3b8, 2nd parent == origin/staging) · W-5 CLEAN (bin/getff unchanged in delta; grep hits are :4 usage comment npx getff init and :41 docs URL text; :56 exec bash "$ROOT/setup" "$@")

Fidelity verdict

FIDELITY: GO
Basis: .claude/orchestrator-prompts/npm-publish-getff-init/kickoff.md#§3 (S1+S2), #§4, #§6
Round: 3
Audited-SHA: 1d4cad7
Evidence: packages/getff/MANIFEST.sha256:1034 — the setup.d/engine.sh hash equals shasum -a 256 setup.d/engine.sh at HEAD; bash scripts/build-getff-dist.sh --check → «✓ packages/getff/MANIFEST.sha256 in sync with the repo root (1053 files); files covers every payload root», EXIT=0; git diff origin/staging...1d4cad7756 --name-only -- install.sh setup setup.d → empty; grep -c ' scripts/' packages/getff/MANIFEST.sha256 → 6; scripts/run-local-ci-sweep-coverage.test.sh:109 — the getff-dist-cell UNREACHABLE row, paired-RED (pre-commit version of the test at HEAD → EXIT=1 naming bash tests/consumer-matrix/getff-dist-cell.sh; HEAD version → PASS=9 FAIL=0). Narrow delta round after the round-2 GO on 641e6f5 (itself after the round-1 REVISE on 62c2dcc); this block replaces both.

Parked questions

  • Publish order relative to BS3: the spec says BS3 first; kept as the operator's floor (kickoff §6). Not decided here.
  • The @getff/core publish + version coupling: deferred to U9 with the rename (freeze §1); the beta publishes getff only.

§1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files)

§1.7 Forward-check applied

Disciplines checked: ci-tool-pinning.md — the new job pins actions/checkout and actions/setup-node by SHA (.github/workflows/audit-self.yml:1919, :1922) and installs no unpinned tool; no-paid-llm-in-ci.md — the cell is bash + npm + eslint, zero API calls (tests/consumer-matrix/getff-dist-cell.sh:1); build-first-reuse-default.md + CLAUDE.md build-vs-reuse gate — SSOT consult + context7 ≥3 phrasings before the capability commit, recorded as entry #267 (docs/meta-factory/prior-art-evaluations.md:340) and the Prior-art: trailer; attention-is-not-a-mechanism.md §1 — the gate is a deterministic CI cell in ci-success.needs (.github/workflows/audit-self.yml:2000), not a warning; principle 36 (packages/core/principles/36-ci-needs-completeness.test.ts:69) passes with the new job; destination-environment-verification.md §4 — the cell's gate discriminates (drift arm and files arm each proven RED then GREEN, scripts/build-getff-dist.sh:91, :73).

§1.7 Backward-check applied

Class of the change = «a shipped artefact assembled from other tracked files with a committed drift artefact». Surfaces swept: scripts/build-synth-bundle.sh:85 (the precedent — same --check shape, unchanged); tests/consumer-matrix/npm-tarball-cell.sh:16 (the R1 method the new cell copies — unchanged, still asserts packages/core on its own); Makefile:34 (the consumer-matrix aggregate now runs three cells); .github/workflows/audit-self.yml:1962 (ci-success.needs mirror — the new job added, principle 36 green); docs/meta-factory/getff-name-architecture-freeze.md:76 («still open» list — annotated as decided, not silently left stale); tests/install-sh/snapshot.sh baselines — the consumer install payload is untouched by this PR (the package is additive; SNAPSHOT_MODE=compare is unaffected because nothing under the shipped surface changed); INSTALL-FOR-AI.md (599/600 lines) — deliberately untouched, the entry-point sentence already exists at README.md:10.

Test added 3 commits September 5, 2026 04:39
… an assembled tarball (U10 S1+S2)

packages/getff/ is a new workspace package published under the unscoped name `getff`
(Decision 1, 2026-09-03): bin/getff (`init` → the shipped `setup`; --version; usage on
anything else), package metadata, README, LICENSE, and a `files` allowlist naming the ten
payload roots install.sh reads from PKG_ROOT. The payload is ASSEMBLED, never committed:
scripts/build-getff-dist.sh copies the git-tracked payload into packages/getff/ (also at
`prepack`) and writes MANIFEST.sha256; `--check` re-assembles into a temp dir and fails on
any hash drift or on a payload root missing from `files` (freeze record §2 §0.5 shape —
install.sh does not move; its 107 PKG_ROOT reads land unchanged).

tests/consumer-matrix/getff-dist-cell.sh is the U10 gate: drift check → npm pack → npm i
<tarball> into a fresh consumer → getff --version / unknown-command / manifest coverage →
`getff init -y ts-server` → a planted OrderSchema.parse(req.body) under src/routes/ FAILS
eslint with the R2 message, and a static-literal parse outside the boundary does not.
Wired into audit-self.yml and ci-success.needs (principle 36). Opt-in paired-RED arms
(GETFF_DIST_CELL_RED_ARMS=1) pack with one `files` entry removed per arm.

Measured locally: 1108 manifest files, 1107 in the tarball (2.6 MB packed / 9.8 MB
unpacked), the six nested fixture .gitignore files being npm's own exclusion; drift arm
RED on an edited setup.d/lib.sh, files arm RED on a dropped `scripts/` entry, both GREEN
after restore. Root lockfile gains the workspace link only.

Prior-art: prior-art-evaluations.md#267 (npm `files` + `prepack` ADOPTED as the assembly seam; `bundleDependencies` REJECTED — it bundles node_modules trees, not the PKG_ROOT layout install.sh reads; in-repo precedents build-synth-bundle.sh --check + npm-tarball-cell.sh copied).
…r itself (fidelity round 2)

Cold fidelity audit round 1 → REVISE, two MAJORs + one MINOR, all fixed here:

- MAJOR: MANIFEST.sha256 lacked scripts/build-getff-dist.sh — the manifest was generated
  before the assembler was `git add`ed, so the self-shipping file was invisible to
  `git ls-files`. Regenerated after staging: the assembler is no longer in the payload at
  all (see next item), and the manifest now covers exactly what the tarball ships.
- MAJOR: the whole `scripts/` tree (116 files, operator tooling) was shipped. PAYLOAD now
  names the six scripts the shipped setup.d/install.sh actually read from PKG_ROOT
  (check-ask-files, run-local-ci-sweep, create-worktree, worktree-node-modules,
  link-coordination, getff-work); PAYLOAD_TOP keeps `scripts` as the `files` root.
- MINOR: `"private": false` stated explicitly in packages/getff/package.json.

Cell: `GETFF_DIST_CELL_RED_ONLY=1` + `GETFF_DIST_CELL_RED_ENTRIES` run one paired-RED arm
per invocation (the serial ten-arm run exceeds a single 10-minute agent call; CI still
runs the main path only). Kickoff §3 amended to match: `lint-config` dropped from the
package shape (never a PKG_ROOT read), scripts subset listed, plant reference fixed.

Measured: 1053 manifest files, 1052 in the tarball (2.4 MB / 8.6 MB unpacked), cell GREEN
with the planted R2 violation failing; ten single-entry arms RED (table in the PR body).

Prior-art: skipped — fidelity round-2 fixes to the round-1 capability commit, no new capability
…al CI sweep

The sweep-coverage metatest (install-sh battery shard A on #1613) named
`bash tests/consumer-matrix/getff-dist-cell.sh` as a CI command the local sweep never runs.
Same class as the three sibling cells already allowlisted: npm pack + npm i into a tmp consumer
plus a real `getff init -y` — network, minutes, non-hermetic. Allowlist entry with rationale;
no gate_table row (the sweep predicts CI, it does not run installers). Not a shipped file, so
MANIFEST.sha256 is untouched.

Prior-art: skipped — test allowlist entry, no new capability
artyhoo added a commit that referenced this pull request Sep 5, 2026
…eturns 0 on both branches (#1614)

`setup` runs under `set -euo pipefail` and calls `companion_step` for every manifest row. In
setup.d/engine.sh the ✓ and ⚠ branches both ended with `[ "$kind" = "mcp" ] && printf …`, so
for every NON-mcp companion (superpowers, ast-grep — kind=cc-plugin/cli) the function's exit
status was that of the failed `[ … ]` test: 1. Under -e the caller died right there:

  - fresh machine, claude CLI present → «✓ superpowers installed» then `setup` exits 1;
  - claude CLI absent (CI runners, Cursor-only machines) → «⚠ superpowers install failed —
    run manually: …» then `setup` exits 1 — despite the message promising to continue.

Machines where superpowers was already installed took the early `return 0` («already present
— skipping») and never saw it, which is why the one-click path looked fine locally. The
getff-dist consumer-matrix cell (PR #1613) ran `getff init -y ts-server` on a bare CI runner
and caught it: install.sh had completed, then the Companions step killed the run.

Fix: the mcp-only log lines become `if … fi` blocks (status never leaks) and companion_step
ends with an explicit `return 0` — a companion is optional by contract. Regression tests in
tests/install-sh/engine.test.sh run companion_step under `set -e` for a cc-plugin whose
install succeeds and one whose install fails; both RED on the previous engine.sh (verified),
GREEN now; the ⚠ run-manually line is still asserted. Snapshot fingerprints unchanged
(engine.sh runs from the package and is never copied into the consumer tree).

Prior-art: skipped — bug fix in an existing shipped script, no new capability

Co-authored-by: Test <test@example.com>
Test added 2 commits September 5, 2026 05:25
…/engine.sh from #1614)

Merge-forward of origin/staging brought the engine.sh fix (#1614) into the payload; the drift
gate went RED on exactly that one line (`DRIFT … committed setup.d/engine.sh / fresh
setup.d/engine.sh`) — the round-2 audit's note that merge-forwards need a regen in the same
push, live-fired. 1053 files, one hash changed.

Prior-art: skipped — generated drift artefact regen, no new capability
@artyhoo
artyhoo merged commit 4e9c524 into staging Sep 5, 2026
55 of 56 checks passed
@artyhoo
artyhoo deleted the claude/u10-getff-dist-package branch September 5, 2026 02:36
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