binpacker 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ module Binpacker
2
+ module Skills
3
+ ROOT: String
4
+
5
+ def self.list: () -> Array[Hash[Symbol, String]]
6
+ def self.exist?: (untyped) -> bool
7
+ def self.path: (untyped) -> String?
8
+ def self.body: (untyped) -> String
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Binpacker
2
+ def key: () -> [untyped, String]
3
+ class TestDiscovery
4
+ def initialize: (untyped) -> void
5
+ def enumerate: () -> Array[Binpacker::Test]
6
+ end
7
+ class RSpecDiscovery < TestDiscovery
8
+ def enumerate: () -> Array[Binpacker::Test]
9
+ end
10
+ class MinitestDiscovery < TestDiscovery
11
+ def enumerate: () -> Array[Binpacker::Test]
12
+ end
13
+ class Test
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Binpacker
2
+ class TestRunner
3
+ def self.runner_name: () -> bot
4
+ def self.for: (untyped) -> (singleton(Binpacker::MinitestRunner) | singleton(Binpacker::RSpecRunner))
5
+ end
6
+ class RSpecRunner
7
+ def self.runner_name: () -> "rspec"
8
+ def self.discovery_command: (untyped) -> Array[untyped]
9
+ end
10
+ class MinitestRunner
11
+ def self.runner_name: () -> "minitest"
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Binpacker
2
+ class Timing
3
+ def initialize: (untyped) -> void
4
+ DEFAULT_WEIGHT: Float
5
+ MAX_SAMPLES_PER_TEST: Integer
6
+ def calibrated?: () -> bool
7
+ def load_with_fallback: (untyped) -> Hash[untyped, Float]
8
+ def load_raw: () -> (Hash[[String, untyped], untyped] | {})
9
+ def load_per_file: () -> (Hash[String, untyped] | {})
10
+ def normalize_path: (untyped) -> String
11
+ def measured?: (file: untyped, name: untyped) -> bool
12
+ def compact!: () -> nil
13
+ def append_all: (untyped) -> nil
14
+ class Entry
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module Binpacker
2
+ class Worker
3
+ def initialize: (untyped, untyped, ?passthrough: untyped, ?quiet: untyped) -> void
4
+ def start: () -> Binpacker::Worker
5
+ def send_test: (untyped) -> nil
6
+ def batch_done: () -> nil
7
+ def wait_for_batch: () -> (nil | { timings: [], exit_code: 0 | 1, examples: untyped, passed: untyped } | { timings: [], exit_code: untyped, examples: untyped, passed: untyped })
8
+ def collect_results: () -> :finished
9
+ def timings: () -> Array[untyped]
10
+ def status: () -> (:crashed | :created | :error | :finished | :ready | :running)
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Binpacker
2
+ class WorkerQueue
3
+ def initialize: (untyped, ?untyped) -> void
4
+ def empty?: () -> (false | true)
5
+ def pop: () -> untyped
6
+ def total_weight: (Hash[untyped, Float]) -> Float
7
+ end
8
+ end
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: binpacker-improve
3
+ description: Tune an already-configured binpacker project from real CI data — fetch recent run reports, analyze the gap between predicted and actual durations, and propose binpacker.yml adjustments. Use when binpacker is set up and running in CI and the user wants to reduce makespan, fix worker imbalance, or refresh stale timing data. Propose-only — never apply changes without confirmation.
4
+ ---
5
+
6
+ # Binpacker Improve
7
+
8
+ A recurring, **propose-only** workflow. It reads real CI data and proposes config changes; it never edits `binpacker.yml`, commits, or pushes without explicit user confirmation.
9
+
10
+ Run `binpacker describe` first. If it recommends `binpacker-setup`, the project isn't configured yet — use that skill instead.
11
+
12
+ ## 1. Gather CI data
13
+
14
+ Fetch recent run reports (see `docs/design/run-report-format.md` for the schema) from CI artifacts:
15
+
16
+ ```sh
17
+ gh run list --workflow <ci-workflow> --limit 10
18
+ gh run download <run-id> --name <report-artifact>
19
+ ```
20
+
21
+ Collect several recent reports so you can see trends, not just one run. Each report holds `predicted_makespan`, `actual_makespan`, per-worker predicted/actual durations, `balance`, and the worst-drift Tests.
22
+
23
+ ## 2. Analyze
24
+
25
+ Look for patterns across the reports:
26
+
27
+ - **Persistent worker skew** — the same worker is consistently slowest → the partition or worker count is off.
28
+ - **Predicted vs actual gap** — `actual_makespan` far above `predicted_makespan` → timing data is stale; the scheduler is planning against wrong Weights.
29
+ - **Recurring high-drift files** — the same files top the `drift` list every run → their timing data is stale or they are outliers.
30
+ - **Cache-miss frequency** — if CI logs show frequent timing-cache misses (e.g. after dependency bumps), the runtime cache isn't helping cold starts.
31
+
32
+ ## 3. Propose
33
+
34
+ Present a concrete `binpacker.yml` diff and/or commands, with the evidence behind each change. Typical levers:
35
+
36
+ - **`workers`** — raise/lower the `ci` worker count when actual makespan shows consistent under- or over-utilisation.
37
+ - **`scheduler.algorithm`** — `lpt` ↔ `multifit`. Prefer `multifit` for tighter balance; only suggest `lpt` if `multifit` isn't helping.
38
+ - **`scheduler.steal_enabled`** — enable when static balance is poor but runtime stealing would recover it.
39
+ - **Re-calibrate** — when drift is high or timing is stale, recommend `binpacker calibrate --incremental` to refresh the drifting Tests.
40
+ - **Commit a baseline** — when the cache misses often (dependency-bump churn) or timings have stabilised, recommend committing `binpacker.timings` as a durable baseline (cold-start floor). See `docs/adr/0005-two-tier-timing-persistence.md`.
41
+
42
+ ## 4. Confirm and apply
43
+
44
+ - Show the diff. Explain the expected effect (e.g. "should cut max deviation from 6% toward <3%").
45
+ - Apply only what the user approves. Committing a baseline or editing config both require confirmation.
46
+ - If the user wants, open a PR with `gh`; otherwise leave the working tree changes for them to review.
47
+
48
+ ## Done when
49
+
50
+ - The user has seen the predicted-vs-actual analysis with evidence.
51
+ - A concrete, confirmed set of changes (or an explicit "no change needed") has been reached.
52
+ - Any commit / PR was made only with confirmation.
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: binpacker-setup
3
+ description: Bring a project from zero to a working parallel test run with binpacker — detect the framework, generate config, calibrate timing data, validate a parallel run, and wire CI. Use when binpacker is installed but not yet set up (no binpacker.yml, or no timing data), or when the user asks to set up / configure / adopt binpacker.
4
+ ---
5
+
6
+ # Binpacker Setup
7
+
8
+ A one-time workflow that takes a project from zero to a working parallel test run. Run `binpacker describe` first — if it recommends `binpacker-improve`, the project is already set up and you want that skill instead.
9
+
10
+ Assess state as you go and **ask the user at each decision point** rather than assuming. Do not run destructive or outward-facing steps (committing, opening a PR) without explicit confirmation.
11
+
12
+ ## 1. Detect
13
+
14
+ - Confirm binpacker is installed: `binpacker --version`.
15
+ - Run `binpacker describe` to read current state (config present? timing data? framework? CI wired?).
16
+ - Determine the test framework (rspec / minitest) and the test glob. If `binpacker describe` reports one, trust it; otherwise inspect the repo.
17
+
18
+ ## 2. Config
19
+
20
+ If `binpacker.yml` is absent, create it with `binpacker init` (it auto-detects the framework and writes `default` + `ci` profiles). Then review the generated file with the user and adjust:
21
+
22
+ - `workers` — `auto` locally; a fixed number (e.g. `4`) for the `ci` profile matching the CI runner.
23
+ - `test_pattern` / `test_exclude` — match the project's real layout.
24
+ - `scheduler.algorithm` — `multifit` (default) unless there's a reason to use `lpt`.
25
+ - `scheduler.steal_enabled` — `true` to let idle workers steal at runtime.
26
+ - `report_file` (on the `ci` profile) — e.g. `binpacker-report.json`, so CI always emits a run report.
27
+
28
+ ## 3. Calibrate
29
+
30
+ Seed timing data so the scheduler has real Weights:
31
+
32
+ ```sh
33
+ binpacker calibrate
34
+ ```
35
+
36
+ If some timing data already exists, measure only the gaps:
37
+
38
+ ```sh
39
+ binpacker calibrate --incremental
40
+ ```
41
+
42
+ ## 4. Validate
43
+
44
+ Run the suite in parallel and confirm it is green and balanced:
45
+
46
+ ```sh
47
+ binpacker run
48
+ ```
49
+
50
+ Check the summary's `Balance: max deviation`. A large deviation on the first run is expected before timing data accumulates; note it and move on.
51
+
52
+ ## 5. Wire CI
53
+
54
+ Add (or extend) a CI workflow so the suite runs under binpacker. The workflow should:
55
+
56
+ - Install binpacker (via the project's dependency manager or `gem install binpacker`).
57
+ - Restore and save `binpacker.timings` with `actions/cache` (key includes OS + a hash of the test files). This is the runtime timing layer.
58
+ - Run `binpacker run --profile ci` (which emits the run report via `report_file`).
59
+ - Upload the run report with `actions/upload-artifact` so `binpacker-improve` can read it later.
60
+
61
+ Propose the workflow YAML and let the user review it before writing.
62
+
63
+ ## 6. Handoff
64
+
65
+ Only after the user confirms:
66
+
67
+ - Create a branch, commit `binpacker.yml`, the CI workflow, and (if the user wants a committed baseline) `binpacker.timings`.
68
+ - Open a PR with `gh`, summarising what was set up.
69
+ - After CI runs, point the user at `binpacker-improve` to tune from real CI data.
70
+
71
+ ## Done when
72
+
73
+ - `binpacker run` passes locally across workers.
74
+ - `binpacker.yml` reflects the project's framework, layout, and CI worker count.
75
+ - CI runs `binpacker run` and uploads a run report.
76
+ - The user has confirmed any commit / PR.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: binpacker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - megurine
@@ -9,8 +9,9 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
- description: A test runner wrapper that manages worker processes and distributes tests
13
- among them using LPT scheduling with optional work-stealing.
12
+ description: A test runner wrapper that models test distribution as an identical-machines
13
+ scheduling problem and assigns tests to worker processes using LPT scheduling, with
14
+ optional work-stealing.
14
15
  executables:
15
16
  - binpacker
16
17
  extensions: []
@@ -25,13 +26,32 @@ files:
25
26
  - lib/binpacker/config.rb
26
27
  - lib/binpacker/orchestrator.rb
27
28
  - lib/binpacker/progress.rb
29
+ - lib/binpacker/project_state.rb
30
+ - lib/binpacker/report.rb
28
31
  - lib/binpacker/scheduler.rb
32
+ - lib/binpacker/skills.rb
29
33
  - lib/binpacker/test_discovery.rb
30
34
  - lib/binpacker/test_runner.rb
31
35
  - lib/binpacker/timing.rb
32
36
  - lib/binpacker/version.rb
33
37
  - lib/binpacker/worker.rb
34
38
  - lib/binpacker/worker_queue.rb
39
+ - sig/binpacker/calibration.rbs
40
+ - sig/binpacker/cli.rbs
41
+ - sig/binpacker/config.rbs
42
+ - sig/binpacker/orchestrator.rbs
43
+ - sig/binpacker/progress.rbs
44
+ - sig/binpacker/project_state.rbs
45
+ - sig/binpacker/report.rbs
46
+ - sig/binpacker/scheduler.rbs
47
+ - sig/binpacker/skills.rbs
48
+ - sig/binpacker/test_discovery.rbs
49
+ - sig/binpacker/test_runner.rbs
50
+ - sig/binpacker/timing.rbs
51
+ - sig/binpacker/worker.rbs
52
+ - sig/binpacker/worker_queue.rbs
53
+ - skills/binpacker-improve/SKILL.md
54
+ - skills/binpacker-setup/SKILL.md
35
55
  homepage: https://github.com/rigortype/binpacker
36
56
  licenses:
37
57
  - MPL-2.0
@@ -54,6 +74,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
74
  requirements: []
55
75
  rubygems_version: 4.0.10
56
76
  specification_version: 4
57
- summary: Minimize CI test-suite makespan by solving an identical-machines scheduling
58
- problem
77
+ summary: Reduce CI test-suite makespan via identical-machines scheduling
59
78
  test_files: []