Skip to content

fix: make the codex packaging and SDD skill test suites pass reliably off-macOS#1994

Merged
arittr merged 2 commits into
devfrom
fix/test-suite-portability
Jul 19, 2026
Merged

fix: make the codex packaging and SDD skill test suites pass reliably off-macOS#1994
arittr merged 2 commits into
devfrom
fix/test-suite-portability

Conversation

@obra

@obra obra commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Who is submitting this PR? (required)

Field Value
Your model + version Claude Fable 5 (claude-fable-5)
Harness + version Claude Code CLI (Linux), maintainer session
All plugins installed superpowers (this repo, dev), superpowers-lab, superpowers-chrome, superpowers-developing-for-claude-code, episodic-memory, elements-of-style, plugin-dev, agent-sdk-dev, frontend-design, code-simplifier, claude-code-setup, mcp-server-dev, linear, context7, primeradiant-ops, claude-session-driver, github-triage, release-radar, summarize-meetings, jam, landing-page-design, scenario-testing, simmer, speed-run, worldview-synthesis
Human partner who reviewed this diff Jesse Vincent (@obra) — asked for these failures to be fixed after they surfaced in a full test sweep; reviewing the complete diff in this PR

What problem are you trying to solve?

Running the full test matrix on dev (Linux, GNU tar, umask 002, TZ=UTC) during pre-release verification of #1993 turned up two failing suites, both failing on clean dev with no local changes:

  1. tests/codex/test-package-codex-plugin.sh fails hard on any Linux box. tar: unrecognized option '--uid' — the packaging script's deterministic-metadata flags are bsdtar spellings that GNU tar rejects, so the tar.gz archive step dies and three assertions cascade. Two more portability bugs hide behind it: staged file modes only came out 755 because git archive's tar.umask default (0002 → 775) happened to be re-masked by macOS's default process umask (022 → 755) — on a umask-002 Linux box the executable lands as 775 and the mode assertion fails; and the test's timestamp assertion parses bsdtar's -tv column layout expecting epoch 0 rendered as "Dec 31 1969", which is both the wrong column split for GNU tar and the wrong string on any UTC host.
  2. tests/claude-code/test-subagent-driven-development.sh flakes. Observed 3 failures across 4 runs, each different: a spurious timeout (the file's worst case is 9 prompts × 90s = 810s, but the runner kills files at 600s), and two prose-matching misses where the model capitalized the skill's own headings — output containing "Do Not Trust the Report" failed the case-sensitive pattern not trust, and a structured answer failed First:.*spec.*compliance.

What does this PR change?

Codex packaging: detect the tar flavor and use the GNU spellings (--owner=:0 --group=:0 --numeric-owner, byte-identical ustar headers) when tar is GNU; pin -c tar.umask=0022 on the git archive call and extract the stage with -p so modes are canonical 755/644 regardless of builder umask; assert tar mtimes via python3 tarfile (mtime == 0), matching how the test already checks zip timestamps. SDD test: raise the runner's per-file budget to 900s (and fix its help text, which claimed a 300s default that was never true), make the assert helpers match case-insensitively, widen two Test 5 keyword patterns to phrasings observed in real runs, and make assert_order dump the model output on failure the way assert_contains already does.

Is this change appropriate for the core library?

Yes — it fixes the repo's own test infrastructure and release packaging script. No behavior-shaping skill content is touched.

What alternatives did you consider?

  • For the tar flags: a single flag set both tars accept — none exists; GNU and bsdtar have disjoint spellings for owner metadata. Flavor detection with the macOS branch preserved verbatim is the smallest change that can't regress the working platform.
  • For the mode bug: chmod -R normalization of the stage — rejected as a workaround; the root cause was two umasks accidentally canceling, and pinning tar.umask + -p removes both dependencies instead of papering over them.
  • For the SDD flake: retrying failed assertions — rejected, it masks real failures. Restructuring all nine prompts into rigid answer formats — rejected as a larger semantic change to a test the file header says is kept by design; case-insensitive keyword matching plus a correct time budget targets exactly the observed failure modes.

Does this PR contain multiple unrelated changes?

Two fixes, one per commit, deliberately bundled: they are the two failures from the same full-matrix test sweep, and the maintainer asked for them as one PR. Happy to split if preferred on review.

Existing PRs

  • I have reviewed all open AND closed PRs for duplicates or prior art
  • Related PRs: Fix Codex package timestamp normalization across timezones #1901 (closed) — found the real TZ-dependence in this same script and test; its zip-side TZ=UTC fix already landed, and this PR's python-tarfile assertion removes the tar-side TZ dependence it identified. Allow Codex packaging from linked worktrees #1910 (closed) — a different packaging portability bug (worktree guard), deliberately NOT included here; it remains open work. Both were closed for batch-submission reasons, not correctness; this PR credits the underlying reports.

Environment tested

Harness Harness version Model Model version/ID
Claude Code (Linux, GNU tar 1.35, umask 002, TZ=UTC) 2.1.210 Fable claude-fable-5 (drives the SDD test's real sessions)

macOS/bsdtar was not available to re-test; the bsdtar branch keeps the exact flags that passed there before this change, and the GNU branch was verified to write byte-identical ustar owner headers (empty uname/gname, uid/gid 0) by comparing raw header bytes.

New harness support

Not applicable — no new harness.

Evaluation

  • Initial prompt: maintainer asked to fix the two suites that failed during the fix(hooks): dispatch the SessionStart hook via Git Bash on Windows (shell: "bash") #1993 pre-release test sweep.
  • Codex packaging test: failed on clean dev before (exit 2 with tar: unrecognized option '--uid', then the mode assertion at 775 vs 755); passes completely after, with the marketplace-manifest and codex-plugin-sync suites re-run green alongside.
  • SDD skill test: before the change, 3 distinct failures in 4 full runs (timeout; not trust case miss; First:.*spec.*compliance miss). After: 3/3 consecutive full runs pass (each run is 9 real claude -p sessions). The case-insensitivity fix was also validated retroactively against the captured failing outputs — both recorded pattern misses match under grep -i.

Rigor

  • This change was tested adversarially, not just on the happy path (the flake was measured across repeated runs before and after; the packaging fix was verified at the raw tar-header-byte level; failure outputs were captured and re-tested against the new patterns)
  • Not a skills change — no superpowers:writing-skills pressure testing applicable; no behavior-shaping content touched.
  • I did not modify carefully-tuned content

Human review

  • A human has reviewed the COMPLETE proposed diff before submission — Jesse (@obra) requested the work and is the merging reviewer; the diff is 5 files, +36 −15, awaiting his review here.

obra added 2 commits July 16, 2026 03:32
…dtar

The packaging pipeline only worked on a Mac with default umask, for
three stacked reasons:

- The deterministic-metadata tar flags (--uid/--gid/--uname/--gname)
  are bsdtar spellings; GNU tar rejects them, so the tar.gz archive
  step died on Linux. Detect the tar flavor and use --owner=:0
  --group=:0 --numeric-owner on GNU tar, which writes byte-identical
  ustar headers (uid/gid 0, empty uname/gname).
- Staged file modes depended on two umasks canceling out: git archive
  masks entry modes with tar.umask (git default 0002 -> 775), and the
  unflagged tar extraction re-masked with the process umask (022 on
  macOS -> 755, but 002 elsewhere -> 775). Pin tar.umask=0022 on the
  archive call and extract with -p so staged modes are canonical
  755/644 on every machine.
- The test's timestamp assertion parsed bsdtar's -tv column layout and
  expected epoch 0 rendered in a US timezone ("Dec 31 1969"); GNU tar
  uses different columns and UTC hosts render "1970-01-01". Assert
  mtime == 0 via python3 tarfile instead, matching how the test
  already checks zip timestamps.

tests/codex/test-package-codex-plugin.sh now passes on Linux/GNU tar;
the bsdtar branch preserves the exact flags that passed on macOS.
tests/claude-code/test-subagent-driven-development.sh failed
intermittently for two independent reasons:

- Budget mismatch: the file runs 9 prompts with a 90s timeout each
  (810s worst case) inside the runner's 600s per-file ceiling, so slow
  backend days produced spurious timeouts. Raise the runner default to
  900s and fix the help text, which claimed the default was 300.
- Case-sensitive prose matching: the assert helpers grepped free-form
  model output case-sensitively, but models capitalize the skill's own
  headings — observed failures include "Do Not Trust the Report"
  missing pattern "not trust" and a structured answer missing
  "First:.*spec.*compliance". Match case-insensitively in
  assert_contains/assert_not_contains/assert_count/assert_order, widen
  two Test 5 keyword patterns to phrasings observed in real runs, and
  make assert_order dump the output on failure the way assert_contains
  already does, so the next flake is diagnosable.

Observed 3 failures across 4 runs before the change (timeout, two
distinct pattern misses); 3/3 consecutive full runs pass after it.

@arittr arittr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@arittr
arittr merged commit 0634449 into dev Jul 19, 2026
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.

2 participants