Skip to content

v0.7.0: cleanup + perf (--tool both removal, probe_hardware cache, pytest-xdist)#129

Merged
JRS1986 merged 10 commits into
mainfrom
feat/v0.7.0-cleanup-and-perf
May 28, 2026
Merged

v0.7.0: cleanup + perf (--tool both removal, probe_hardware cache, pytest-xdist)#129
JRS1986 merged 10 commits into
mainfrom
feat/v0.7.0-cleanup-and-perf

Conversation

@JRS1986
Copy link
Copy Markdown
Owner

@JRS1986 JRS1986 commented May 28, 2026

Summary

Implements v0.7.0 spec. Four bundles, each behind a separate commit:

  1. Consolidate CODING_TOOLS / VALID_TOOLS — single source of truth in intake.py.
  2. Remove --tool both + back-fill helpers — honors v0.6.0 deprecation promise.
  3. Cache probe_hardware() — real user-visible perf win.
  4. Enable pytest-xdist — dev-loop win.

Measured perf delta

Surface Baseline (cold) After (warm) Speedup
doctor 243ms median 78ms 3.1×
pilot 235ms median 79ms 3.0×
Test suite ~22s sequential ~3s parallel ~7×

Breaking changes

  • --tool both removed. Replace with --tool opencode,openclaude. CLI prints the three-line error block on attempted use.
  • Legacy project.json files with singular tool / agent keys (written by 0.5.x and never updated through 0.6.x) silently fall back to DEFAULT_TOOLS; re-run setup run to regenerate.
  • IntakeAnswers.agent property removed. Use IntakeAnswers.tools[0].

See Upgrading wiki for the full migration story.

What's the cache?

A small JSON file at $XDG_CACHE_HOME/coding-scaffold/hardware.json (default ~/.cache/coding-scaffold/hardware.json). 1-hour TTL, keyed on OS / arch / Python version (self-invalidates on any change). Corrupt / expired / unwritable cases all degrade to re-probe.

New --no-probe-cache flag on doctor / pilot / probe forces a fresh probe — handy right after installing a new local runtime like ollama.

Test plan

  • uv run pytest -q — 637 tests pass in ~3s with pytest-xdist.
  • uv run ruff check src/ tests/ — clean.
  • Manual: coding-scaffold setup run --tool both --target /tmp --non-interactive → exits 1 with the three-line error.
  • Manual: cold doctor (243ms) → warm doctor (78ms) confirmed via subprocess timing.
  • Manual: --no-probe-cache re-probes (verified via cache-mtime).

Execution notes

  • Spec + plan committed to the branch (subagent-driven-development pattern, same as v0.6.0).
  • Per-task spec + code-quality review (sonnet for implementer + reviewers).
  • Mid-flight code review caught two stale "both" guards in installers.py and cli.py outside the original Task 2 scope; fixed in the same task.
  • Mid-flight code review caught a perf-gate test that would be flaky under pytest-xdist; rewritten as an in-process probe-count assertion + sanity check, with wall-clock numbers documented here rather than asserted in CI.

JRS1986 added 10 commits May 27, 2026 16:19
…spec §7)

Single source of truth: CODING_TOOLS tuple lives in intake.py; cli.py
re-exports as a list for argparse choices= and derives INSTALLABLE_TOOLS
from it; VALID_TOOLS in intake.py becomes frozenset(CODING_TOOLS). The
drift-detection test is replaced with a derivation invariant test.
Honors the v0.6.0 deprecation promise. Removed: `both` from CODING_TOOLS /
INSTALLABLE_TOOLS / VALID_TOOLS, _BOTH_EXPANSION, _BOTH_WARNING_FIRED,
reset_deprecation_state, the both-expansion branch in normalize_tools,
_normalize_persisted_intake helper, IntakeAnswers.agent property.

Programmatic callers passing "both" now hit a CliError naming the
replacement. CLI users hit a CliError (rc=1) from normalize_tools since
setup run --tool uses action=append (no choices=). Legacy project.json
files with singular `tool` are silently ignored — re-run setup to regenerate.
…tring

Spec review caught: --tool on setup run uses action=append without choices=,
so argparse doesn't reject 'both'. The CliError from normalize_tools is the
actual rejection path. Update both text strings to reflect reality.
…gial loop

Important from review:
- installers.py:50 still branched on 'both' to expand to opencode+openclaude.
  Dead code post-removal; the caller always passes a canonical single tool
  name. Simplified to direct '[_plan_for(selection)]' with the manual check.
- cli.py:2219 still treated 'both' as an opencode-adapter trigger for
  knowledge setup. Same dead branch; cleaned up.

Minor from review:
- normalize_tools had a vestigial 'expanded' list that was always equal to
  'flat' after the 'both' branch became an early raise. Collapsed to a
  single 'if "both" in flat: raise' + dedupe directly on flat.
Real user-visible perf win: doctor/pilot warm calls 243ms → ~78ms (3x+).
Cache at $XDG_CACHE_HOME/coding-scaffold/hardware.json keyed on
OS/arch/Python so it self-invalidates when any of those change. TTL = 1h
balances staleness (new ollama install) against re-probe cost.

--no-probe-cache flag on doctor / pilot / probe forces a fresh probe.

Uses asdict() for cache serialization so HardwareProfile field names are
preserved and reconstruction via HardwareProfile(**profile) works cleanly.
Test uses sys.executable so the correct venv Python is used in subprocess.
- hardware.py: inline comment in _write_cache explaining asdict vs to_dict
  asymmetry (prevents future 'fix me' regressions that would silently
  poison the cache via os_name → os field rename).
- test_hardware_cache.py: replace subprocess-based perf gate with an
  in-process measurement that counts probes. Removes subprocess-startup
  noise and pytest-xdist scheduling jitter (Task 4 is about to enable
  parallel runs). Asserts the cache invariant (1 cold probe + N warm hits)
  + a sanity check that warm < cold. Wall-clock numbers go in the PR
  description, not in CI.
- test_hardware_cache.py: drop spurious 'arch' key from wrong-key fixture
  (HardwareProfile has no arch field; the architecture portion lives in
  _cache_key, not the profile dict). Comment explains.
- test_hardware_cache.py: switch test_expired_cache_re_probes from manual
  try/finally to monkeypatch.setattr for pattern consistency.
Dev-loop improvement: 635 tests sequential ~22s → parallel ~3s with
-n auto. The perf gate test in test_hardware_cache.py is in-process
(no subprocess timing) so it's stable under worker scheduling, and the
autouse XDG_CACHE_HOME fixture in that file gives each worker its own
tmp_path-backed cache. Parallel-safety audit confirmed no other module
writes to fixed external paths during tests.
@JRS1986 JRS1986 merged commit 896b54f into main May 28, 2026
3 checks passed
@JRS1986 JRS1986 deleted the feat/v0.7.0-cleanup-and-perf branch May 28, 2026 12:09
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