Skip to content

chore(discipline): upgrade to v0.29.0 - #230

Merged
orieg merged 1 commit into
mainfrom
chore/discipline-v0.29.0
Nov 1, 2026
Merged

orieg merged 1 commit into
mainfrom
chore/discipline-v0.29.0

Conversation

@orieg

@orieg orieg commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Upgrade php-judy's discipline integration from v0.18.0 to v0.29.0.

  • Re-pin all 6 orieg/discipline action usages to the v0.29.0 release commit.
  • Regenerate agent hooks with discipline hook install --observe --upgrade for Claude Code, Copilot, agy, and OpenCode.
  • Bump the Claude Code cloud bootstrap version to v0.29.0.

allow-agent-instructions: .agents/hooks.json regenerated by discipline hook install --agent agy --upgrade to v0.29.0 hook format
allow-agent-instructions: .claude/hooks/discipline-bootstrap.sh regenerated by discipline hook install --agent claude-code --upgrade to v0.29.0 (version v0.18.0 -> v0.29.0)
allow-agent-instructions: .claude/settings.json regenerated by discipline hook install --agent claude-code --upgrade to v0.29.0 hook format
allow-agent-instructions: .github/hooks/discipline.json regenerated by discipline hook install --agent copilot --upgrade to v0.29.0 hook format
allow-agent-instructions: .opencode/plugins/discipline.js regenerated by discipline hook install --agent opencode --upgrade to v0.29.0
allow-swallow: .opencode/plugins/discipline.js observe-mode plugin contract: every empty catch is deliberate

Re-pin all orieg/discipline action usages and regenerate agent hooks
with discipline 0.29.0 (observe mode).

allow-agent-instructions: .agents/hooks.json regenerated by discipline hook install --agent agy --upgrade to v0.29.0 hook format
allow-agent-instructions: .claude/hooks/discipline-bootstrap.sh regenerated by discipline hook install --agent claude-code --upgrade to v0.29.0 (version v0.18.0 -> v0.29.0)
allow-agent-instructions: .claude/settings.json regenerated by discipline hook install --agent claude-code --upgrade to v0.29.0 hook format
allow-agent-instructions: .github/hooks/discipline.json regenerated by discipline hook install --agent copilot --upgrade to v0.29.0 hook format
allow-agent-instructions: .opencode/plugins/discipline.js regenerated by discipline hook install --agent opencode --upgrade to v0.29.0
allow-swallow: .opencode/plugins/discipline.js observe-mode plugin contract: every empty catch is deliberate
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

discipline: passed

Base main (origin/main) (merge base 388c75bc68) · 28 gate(s) passed · 2199 item(s) examined · 0 warning(s) · 7 override(s)

review routing: deterministic: directives 12, authority files 7; 1 of 7 files inventoried (unstable until 1.0: names and shape may change in any release; an inventory, not a verdict)

Findings lifted by an override:

  • error-swallowing on .opencode/plugins/discipline.js: .opencode/plugins/discipline.js observe-mode plugin contract: every empty catch is deliberate
  • error-swallowing on .opencode/plugins/discipline.js: .opencode/plugins/discipline.js observe-mode plugin contract: every empty catch is deliberate
  • instruction-smuggling on .agents/hooks.json: .agents/hooks.json regenerated by discipline hook install --agent agy --upgrade to v0.29.0 hook format
  • instruction-smuggling on .claude/hooks/discipline-bootstrap.sh: .claude/hooks/discipline-bootstrap.sh regenerated by discipline hook install --agent claude-code --upgrade to v0.29.0 (version v0.18.0 -> v0.29.0)
  • instruction-smuggling on .claude/settings.json: .claude/settings.json regenerated by discipline hook install --agent claude-code --upgrade to v0.29.0 hook format
  • instruction-smuggling on .github/hooks/discipline.json: .github/hooks/discipline.json regenerated by discipline hook install --agent copilot --upgrade to v0.29.0 hook format
  • instruction-smuggling on .opencode/plugins/discipline.js: .opencode/plugins/discipline.js regenerated by discipline hook install --agent opencode --upgrade to v0.29.0

discipline explain <gate> prints what a gate checks and how a finding is lifted. This comment is updated on every run; the check's status is the verdict.

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

Test Results

PHP Platform Arch TS Tests Pass Fail Skip Duration
✅ 8.4 Linux x64 - 258 258 0 0 9.8s
✅ Total 258 258 0 0

Benchmark Results

500,000 elements, 7 iterations (median), Judy 2.8.0

Run Status

Platform PHP 8.4
Linux ✅

Memory (Linux, PHP 8.4)

Peak RSS of a child process building one structure, n = 500,000, minus an empty-process floor. Judy's memory advantage is type- and scale-dependent — see BENCHMARK.md for the curve across sizes on a dedicated host.

Type Judy PHP array Judy vs PHP array
Bitset 484.0 KB 9.1 MB 19.2x smaller
Int to Int 4.5 MB 8.9 MB 2.0x smaller
Int to Mixed 42.6 MB 38.3 MB 1.11x larger
Int to Packed 17.2 MB 38.4 MB 2.2x smaller
String to Int 10.5 MB 38.0 MB 3.6x smaller
String to Mixed 48.5 MB 69.1 MB 1.4x smaller
String to Int (Hash) 31.7 MB 38.0 MB 1.2x smaller
String to Mixed (Hash) 69.9 MB 69.0 MB about the same
String to Int (Adaptive) 31.6 MB 38.0 MB 1.2x smaller
String to Mixed (Adaptive) 69.8 MB 69.1 MB about the same

API Speedups (Linux, PHP 8.4)

Speedup = PHP time / Judy time. Bold = Judy faster.

Operation Judy PHP Speedup
putAll() 16.8 ms 22.1 ms 1.3x
fromArray() 17.0 ms 22.1 ms 1.3x
toArray() 30.2 ms 40.2 ms 1.3x
getAll() 2.0 ms 2.3 ms 1.1x
keys() 12.5 ms 21.7 ms 1.7x
values() 11.4 ms 21.5 ms 1.9x
sumValues() 5.9 ms 16.4 ms 2.8x
populationCount() 0.00 ms 18.8 ms O(1) vs O(n)
deleteRange() 30.5 ms 42.7 ms 1.4x
equals() 8.1 ms 36.6 ms 4.5x
union() Bitset 26.5 ms 11.2 ms 0.4x
intersect() Bitset 10.5 ms 10.7 ms ~1.0x
diff() Bitset 10.7 ms 4.5 ms 0.4x
xor() Bitset 21.2 ms 23.6 ms 1.1x
mergeWith() Int→Int 39.4 ms 53.7 ms 1.4x
mergeWith() Str→Int 184.3 ms 196.9 ms 1.1x
forEach() Int→Int 19.8 ms 18.2 ms 0.9x
filter() Int→Int 32.6 ms 31.5 ms ~1.0x
map() Int→Int 36.3 ms 36.7 ms ~1.0x
forEach() Str→Int 46.1 ms 44.1 ms ~1.0x
filter() Str→Int 84.1 ms 82.9 ms ~1.0x
map() Str→Int 118.7 ms 118.6 ms ~1.0x

O(1) vs O(n) marks a row whose ratio is decided by the complexity classes rather than measured: populationCount() reads libJudy's cached population, the PHP arm counts every element. It scales with n and says nothing about this change. judy-bench.php declines the same comparison for size($lo, $hi) for the same reason.

Core Types (Linux, PHP 8.4)

Speedup = PHP time / Judy time. Bold = Judy faster.

Type Op Judy PHP array Speedup
Bitset Write 15.2 ms 8.3 ms 0.5x
Bitset Read 9.0 ms 3.0 ms 0.3x
Bitset Iter 16.4 ms 2.6 ms 0.2x
Bitset Free 0.01 ms 0.56 ms 103x
Int to Int Write 21.8 ms 8.4 ms 0.4x
Int to Int Read 9.6 ms 3.0 ms 0.3x
Int to Int Iter 16.0 ms 2.4 ms 0.1x
Int to Int Free 0.51 ms 0.57 ms 1.1x
Int to Mixed Write 26.9 ms 11.1 ms 0.4x
Int to Mixed Read 9.9 ms 4.5 ms 0.5x
Int to Mixed Iter 16.4 ms 2.9 ms 0.2x
Int to Mixed Free 12.8 ms 5.9 ms 0.5x
String to Int Write 68.9 ms 26.0 ms 0.4x
String to Int Read 28.0 ms 6.1 ms 0.2x
String to Int Iter 42.5 ms 3.5 ms 0.1x
String to Int Free 15.5 ms 1.9 ms 0.1x
String to Int (Adaptive) Write 126.7 ms 27.0 ms 0.2x
String to Int (Adaptive) Read 19.1 ms 6.2 ms 0.3x
String to Int (Adaptive) Iter 52.6 ms 3.5 ms 0.1x
String to Int (Adaptive) Free 42.5 ms 2.3 ms 0.1x
All types detail

Core Types (Linux, PHP 8.4) — All

Speedup = PHP time / Judy time. Bold = Judy faster.

Type Op Judy PHP array Speedup
Bitset Write 15.2 ms 8.3 ms 0.5x
Bitset Read 9.0 ms 3.0 ms 0.3x
Bitset Iter 16.4 ms 2.6 ms 0.2x
Bitset Free 0.01 ms 0.56 ms 103x
Int to Int Write 21.8 ms 8.4 ms 0.4x
Int to Int Read 9.6 ms 3.0 ms 0.3x
Int to Int Iter 16.0 ms 2.4 ms 0.1x
Int to Int Free 0.51 ms 0.57 ms 1.1x
Int to Mixed Write 26.9 ms 11.1 ms 0.4x
Int to Mixed Read 9.9 ms 4.5 ms 0.5x
Int to Mixed Iter 16.4 ms 2.9 ms 0.2x
Int to Mixed Free 12.8 ms 5.9 ms 0.5x
Int to Packed Write 37.0 ms 13.3 ms 0.4x
Int to Packed Read 22.4 ms 4.9 ms 0.2x
Int to Packed Iter 29.6 ms 3.1 ms 0.1x
Int to Packed Free 7.2 ms 5.9 ms 0.8x
String to Int Write 68.9 ms 26.0 ms 0.4x
String to Int Read 28.0 ms 6.1 ms 0.2x
String to Int Iter 42.5 ms 3.5 ms 0.1x
String to Int Free 15.5 ms 1.9 ms 0.1x
String to Mixed Write 88.4 ms 30.1 ms 0.3x
String to Mixed Read 30.4 ms 8.6 ms 0.3x
String to Mixed Iter 55.6 ms 5.7 ms 0.1x
String to Mixed Free 51.2 ms 8.7 ms 0.2x
String to Int (Hash) Write 121.8 ms 26.1 ms 0.2x
String to Int (Hash) Read 19.7 ms 6.1 ms 0.3x
String to Int (Hash) Iter 52.7 ms 3.5 ms 0.1x
String to Int (Hash) Free 42.1 ms 2.1 ms 0.1x
String to Mixed (Hash) Write 186.2 ms 31.5 ms 0.2x
String to Mixed (Hash) Read 21.9 ms 8.4 ms 0.4x
String to Mixed (Hash) Iter 77.1 ms 5.3 ms 0.1x
String to Mixed (Hash) Free 104.3 ms 9.4 ms 0.1x
String to Int (Adaptive) Write 126.7 ms 27.0 ms 0.2x
String to Int (Adaptive) Read 19.1 ms 6.2 ms 0.3x
String to Int (Adaptive) Iter 52.6 ms 3.5 ms 0.1x
String to Int (Adaptive) Free 42.5 ms 2.3 ms 0.1x
String to Mixed (Adaptive) Write 197.4 ms 32.2 ms 0.2x
String to Mixed (Adaptive) Read 21.9 ms 8.9 ms 0.4x
String to Mixed (Adaptive) Iter 87.6 ms 5.8 ms 0.1x
String to Mixed (Adaptive) Free 111.8 ms 8.3 ms 0.1x

Release Comparison (2.8.0 → 2.8.0)

Interleaved A/B comparison against v2.8.0 (pie install) on the same CI runner: 5 benchmark groups × 5 rounds × 2 arms, 300,000 elements, median of 3 per child. Each row is the median of the paired current/baseline ratios with a 95% percentile-bootstrap CI; it is flagged only when the whole drift-adjusted CI clears ±10%. Advisory — benchmarks never gate a merge.

Run-wide median delta -0.02% (PHP-array control -0.25%); runner common-mode -0.25% divided out of every row.

Summary: 0 regressions, 95 unchanged, 5 not evaluated (unstable)

Benchmark Baseline Current Delta 95% CI Status
adv.filter.int_to_int 20.7 ms 20.4 ms -0.9% [-2.7%, +0.1%] ~same
adv.filter.string_to_int 49.1 ms 49.4 ms +0.7% [-1.1%, +1.5%] ~same
adv.forEach.int_to_int 12.3 ms 12.8 ms +5.6% [-0.5%, +6.2%] ~same
adv.forEach.string_to_int 27.0 ms 27.2 ms +2.4% [-0.8%, +2.5%] ~same
adv.map.int_to_int 22.0 ms 21.9 ms -1.4% [-2.5%, +2.2%] ~same
adv.map.string_to_int 67.8 ms 68.2 ms +0.8% [-0.5%, +1.5%] ~same
adv.optiter.foreach.string_to_int_adaptive.default 54.5 ms 51.1 ms -7.7% [-13.6%, +13.8%] ~same
adv.optiter.foreach.string_to_int_adaptive.optimized 36.0 ms 36.8 ms +1.5% [-9.0%, +11.3%] ~same
adv.optiter.foreach.string_to_int_hash.default 42.2 ms 45.2 ms -3.5% [-6.1%, +25.8%] ~same
adv.optiter.foreach.string_to_int_hash.optimized 26.2 ms 26.6 ms +2.5% [-3.6%, +5.0%] ~same
adv.optiter.overwrite.string_to_int_adaptive.default 51.0 ms 50.8 ms +1.1% [-16.1%, +7.1%] ~same
adv.optiter.ratio.foreach.string_to_int_adaptive 65.7 ms 66.1 ms -0.7% [-1.9%, +17.8%] ~same
adv.optiter.ratio.foreach.string_to_int_hash 60.2 ms 58.2 ms +1.1% [-16.3%, +6.8%] ~same
adv.optiter.ratio.increment.string_to_int_hash 110.6 ms 107.5 ms -3.1% [-10.4%, +17.7%] ~same
adv.optiter.ratio.overwrite.string_to_int_adaptive 92.0 ms 91.5 ms +0.4% [-13.8%, +8.5%] ~same
adv.optiter.ratio.overwrite.string_to_int_hash 106.1 ms 113.0 ms +1.9% [-13.6%, +19.8%] ~same
adv.optiter.ratio.toArray.string_to_int_adaptive 70.3 ms 70.8 ms +0.9% [-2.9%, +24.5%] ~same
adv.optiter.ratio.toArray.string_to_int_hash 59.7 ms 54.7 ms -0.5% [-13.6%, -0.1%] ~same
adv.optiter.ratio.values.string_to_int_adaptive 61.3 ms 56.9 ms -7.0% [-16.1%, +17.2%] ~same
adv.optiter.ratio.values.string_to_int_hash 52.3 ms 51.4 ms +1.3% [-7.5%, +14.6%] ~same
adv.optiter.toArray.string_to_int_adaptive.default 68.4 ms 65.0 ms -2.9% [-20.3%, +6.0%] ~same
adv.optiter.toArray.string_to_int_adaptive.optimized 46.6 ms 46.1 ms -1.0% [-4.9%, +2.6%] ~same
adv.optiter.toArray.string_to_int_hash.default 54.1 ms 59.7 ms -0.3% [-1.5%, +16.1%] ~same
adv.optiter.toArray.string_to_int_hash.optimized 32.6 ms 32.6 ms -0.9% [-1.9%, +0.2%] ~same
adv.optiter.values.string_to_int_adaptive.default 52.7 ms 54.6 ms +3.9% [-13.0%, +22.4%] ~same
adv.optiter.values.string_to_int_adaptive.optimized 31.8 ms 31.0 ms +1.8% [-8.3%, +8.8%] ~same
adv.optiter.values.string_to_int_hash.default 41.1 ms 41.5 ms -0.9% [-13.5%, +10.1%] ~same
adv.optiter.values.string_to_int_hash.optimized 21.2 ms 21.5 ms +0.2% [-4.3%, +4.4%] ~same
api.deleteRange.int_to_int 17.9 ms 18.0 ms +1.6% [-1.7%, +4.4%] ~same
api.equals.int_to_int 4.9 ms 4.9 ms +0.3% [-8.4%, +5.6%] ~same
api.fromArray.int_to_int 12.0 ms 12.2 ms -1.4% [-2.5%, +2.4%] ~same
api.getAll.int_to_int 0.43 ms 0.41 ms -2.8% [-4.6%, -1.1%] ~same
api.increment.int_to_int 12.3 ms 12.1 ms 0.0% [-2.2%, +3.3%] ~same
api.keys.int_to_int 7.1 ms 7.2 ms +0.9% [-4.5%, +3.0%] ~same
api.mergeWith.int_to_int 23.6 ms 23.3 ms -1.8% [-5.4%, +3.5%] ~same
api.mergeWith.string_to_int 107.8 ms 107.2 ms -0.3% [-1.1%, +0.5%] ~same
api.populationCount.int_to_int 0.00 ms 0.00 ms +0.2% [+0.2%, +0.2%] ~same
api.putAll.int_to_int 12.2 ms 12.5 ms +2.3% [-1.8%, +5.1%] ~same
api.range.keys.int_to_int 0.46 ms 0.44 ms -1.2% [-3.4%, +4.4%] ~same
api.range.size.string_to_int 1.7 ms 1.7 ms -1.2% [-2.5%, +1.5%] ~same
api.range.size1000.int_to_int 0.67 ms 0.67 ms +0.2% [-0.8%, +0.6%] ~same
api.setop.diff.bitset 6.2 ms 6.3 ms +3.3% [-3.1%, +6.6%] ~same
api.setop.diff.int_to_int 7.4 ms 7.9 ms +6.7% [-9.6%, +11.7%] ~same
api.setop.diff.string_to_int 47.4 ms 48.1 ms +1.8% [-1.2%, +5.8%] ~same
api.setop.intersect.bitset 6.3 ms 6.4 ms +3.3% [-1.5%, +5.7%] ~same
api.setop.intersect.int_to_int 7.3 ms 7.8 ms +5.8% [-6.5%, +15.1%] ~same
api.setop.intersect.string_to_int 52.6 ms 54.1 ms +3.0% [-5.4%, +4.5%] ~same
api.setop.union.bitset 15.9 ms 15.9 ms +0.8% [-15.1%, +4.7%] ~same
api.setop.union.int_to_int 20.7 ms 20.5 ms -0.8% [-2.6%, +3.3%] ~same
api.setop.union.string_to_int 116.9 ms 120.2 ms +3.1% [-0.5%, +4.9%] ~same
api.setop.xor.bitset 12.8 ms 12.8 ms +2.5% [-3.9%, +8.2%] ~same
api.setop.xor.int_to_int 14.9 ms 15.9 ms +5.4% [-9.7%, +16.0%] ~same
api.sumValues.int_to_int 3.3 ms 3.2 ms -5.3% [-17.9%, +4.5%] ~same
api.toArray.int_to_int 23.9 ms 23.3 ms -1.4% [-6.4%, +0.6%] ~same
api.values.int_to_int 7.6 ms 7.5 ms +0.9% [-7.5%, +2.0%] ~same
core.bitset.free 0.00 ms 0.00 ms +4.8% [-8.3%, +67.1%] ~same
core.bitset.iter 9.7 ms 9.9 ms +2.1% [-3.0%, +4.8%] ~same
core.bitset.read 5.3 ms 5.3 ms +0.1% [-1.2%, +4.6%] ~same
core.bitset.write 8.7 ms 8.9 ms +1.6% [-3.0%, +8.7%] ~same
core.int_to_int.free 0.51 ms 0.50 ms +4.1% [-11.9%, +14.6%] ~same
core.int_to_int.iter 9.9 ms 9.8 ms -0.6% [-5.5%, +1.8%] ~same
core.int_to_int.read 4.9 ms 5.1 ms +7.1% [-12.8%, +14.4%] ~same
core.int_to_int.write 13.3 ms 13.4 ms +0.6% [-2.4%, +4.1%] ~same
core.int_to_mixed.free 7.7 ms 7.6 ms +0.8% [-7.6%, +3.9%] ~same
core.int_to_mixed.iter 10.1 ms 10.0 ms -0.1% [-2.9%, +2.7%] ~same
core.int_to_mixed.read 6.1 ms 6.2 ms +0.2% [-0.5%, +2.9%] ~same
core.int_to_mixed.write 16.5 ms 16.6 ms +0.2% [-4.7%, +2.6%] ~same
core.int_to_packed.free 4.3 ms 4.4 ms +0.4% [-1.7%, +4.3%] ~same
core.int_to_packed.iter 17.8 ms 18.0 ms +1.5% [-2.5%, +2.9%] ~same
core.int_to_packed.read 13.6 ms 13.6 ms 0.0% [-11.3%, +6.2%] ~same
core.int_to_packed.write 22.1 ms 22.4 ms +2.0% [-2.0%, +3.7%] ~same
core.string_to_int.free 8.3 ms 8.3 ms -0.8% [-2.9%, +0.7%] ~same
core.string_to_int.iter 24.1 ms 23.9 ms +0.2% [-2.3%, +0.4%] ~same
core.string_to_int.read 15.7 ms 15.8 ms -0.1% [-3.5%, +2.2%] ~same
core.string_to_int.write 40.3 ms 40.0 ms -0.6% [-2.3%, +1.4%] ~same
core.string_to_int_adaptive.free 23.1 ms 22.5 ms -1.9% [-9.1%, +4.2%] ~same
core.string_to_int_adaptive.iter 30.2 ms 29.9 ms -0.6% [-2.2%, +2.7%] ~same
core.string_to_int_adaptive.read 11.5 ms 11.5 ms -0.7% [-6.1%, +1.5%] ~same
core.string_to_int_adaptive.write 70.8 ms 70.5 ms -0.4% [-1.8%, +8.4%] ~same
core.string_to_int_hash.free 21.8 ms 21.9 ms -4.2% [-12.2%, +9.2%] ~same
core.string_to_int_hash.iter 30.3 ms 30.1 ms -1.3% [-1.9%, +2.0%] ~same
core.string_to_int_hash.read 11.8 ms 11.7 ms +1.1% [-1.9%, +2.3%] ~same
core.string_to_int_hash.write 70.5 ms 69.3 ms -1.7% [-3.1%, +2.8%] ~same
core.string_to_mixed.free 28.2 ms 27.5 ms -3.4% [-10.6%, +4.7%] ~same
core.string_to_mixed.iter 28.9 ms 28.5 ms -1.9% [-5.3%, -0.0%] ~same
core.string_to_mixed.read 17.4 ms 17.1 ms -1.9% [-3.3%, +2.5%] ~same
core.string_to_mixed.write 50.8 ms 50.5 ms +0.8% [-5.7%, +1.8%] ~same
core.string_to_mixed_adaptive.free 58.9 ms 59.7 ms +2.8% [-13.7%, +4.2%] ~same
core.string_to_mixed_adaptive.iter 41.5 ms 41.7 ms +0.8% [-3.6%, +2.1%] ~same
core.string_to_mixed_adaptive.read 13.1 ms 13.3 ms +1.0% [-1.3%, +5.9%] ~same
core.string_to_mixed_adaptive.write 107.5 ms 107.8 ms +0.1% [-0.5%, +20.6%] ~same
core.string_to_mixed_hash.free 57.7 ms 54.7 ms -1.1% [-6.0%, +5.6%] ~same
core.string_to_mixed_hash.iter 43.6 ms 43.0 ms -1.1% [-2.5%, +2.8%] ~same
core.string_to_mixed_hash.read 13.5 ms 13.2 ms -0.8% [-5.2%, +1.2%] ~same
core.string_to_mixed_hash.write 102.5 ms 99.5 ms -2.7% [-4.4%, +2.8%] ~same
5 benchmarks not evaluated (within-arm scatter exceeded the effect being claimed)
Benchmark Baseline Current Delta 95% CI Status
adv.optiter.increment.string_to_int_hash.default 34.9 ms 32.3 ms -0.9% [-21.8%, +13.4%] — unstable
adv.optiter.increment.string_to_int_hash.optimized 35.9 ms 32.6 ms -8.2% [-11.2%, +1.3%] — unstable
adv.optiter.overwrite.string_to_int_adaptive.optimized 46.1 ms 46.3 ms +1.1% [-27.8%, +10.4%] — unstable
adv.optiter.overwrite.string_to_int_hash.default 32.6 ms 30.6 ms -6.4% [-9.9%, +23.6%] — unstable
adv.optiter.overwrite.string_to_int_hash.optimized 34.0 ms 34.6 ms +1.4% [-8.2%, +7.7%] — unstable

Memory Comparison

Memory: 0 regressions, 10 unchanged

Type Baseline Current Delta Status
Bitset 160 B 160 B 0.0% ~same
Int to Int 160 B 160 B 0.0% ~same
Int to Mixed 4.6 MB 4.6 MB 0.0% ~same
Int to Packed 8.0 MB 8.0 MB 0.0% ~same
String to Int 64.2 KB 64.2 KB 0.0% ~same
String to Int (Adaptive) 64.2 KB 64.2 KB 0.0% ~same
String to Int (Hash) 64.2 KB 64.2 KB 0.0% ~same
String to Mixed 4.6 MB 4.6 MB 0.0% ~same
String to Mixed (Adaptive) 4.6 MB 4.6 MB 0.0% ~same
String to Mixed (Hash) 4.6 MB 4.6 MB 0.0% ~same
Full benchmark output

Linux — PHP 8.4

══════════════════════════════════════════════════════════════════════════════════════════
  php-judy Benchmark Suite — 500,000 elements, 7 iterations (median)
  PHP 8.4.27 | Judy ext 2.8.0 | Linux x86_64
  Suite: all | Groups: core.int,core.str,api.batch,api.setops,adv.iter,adv.sso
  memory_limit: -1
  Memory: peak RSS of a child process, empty-process floor subtracted, median of 3
══════════════════════════════════════════════════════════════════════════════════════════

── Core: Integer-Keyed Types ────────────────────────────────────────────────

  Type                         Write(ms)      Read(ms)      Iter(ms)      Free(ms)        Memory
  ────────────────────────  ────────────  ────────────  ────────────  ────────────  ────────────
  BITSET                           15.22          9.04         16.42          0.01      484.0 KB
    PHP array                       8.25          2.98          2.60          0.56        9.1 MB
  INT_TO_INT                       21.83          9.59         15.97          0.51        4.5 MB
    PHP array                       8.36          2.99          2.37          0.57        8.9 MB
  INT_TO_MIXED                     26.86          9.90         16.42         12.76       42.6 MB
    PHP array                      11.12          4.53          2.88          5.91       38.3 MB
  INT_TO_PACKED                    36.99         22.41         29.60          7.23       17.2 MB
    PHP array                      13.26          4.90          3.13          5.91       38.4 MB

── Core: String-Keyed Types ────────────────────────────────────────────────

  Type                         Write(ms)      Read(ms)      Iter(ms)      Free(ms)        Memory
  ────────────────────────  ────────────  ────────────  ────────────  ────────────  ────────────
  STRING_TO_INT                    68.95         28.00         42.55         15.51       10.5 MB
    PHP array                      25.96          6.10          3.47          1.92       38.0 MB
  STRING_TO_MIXED                  88.43         30.42         55.56         51.24       48.5 MB
    PHP array                      30.11          8.61          5.66          8.65       69.1 MB
  STR_TO_INT_HASH                 121.81         19.68         52.65         42.15       31.7 MB
    PHP array                      26.09          6.14          3.46          2.11       38.0 MB
  STR_TO_MIX_HASH                 186.17         21.85         77.13        104.26       69.9 MB
    PHP array                      31.52          8.42          5.30          9.37       69.0 MB
  STR_INT_ADAPTIVE                126.68         19.12         52.62         42.52       31.6 MB
    PHP array                      26.99          6.17          3.50          2.33       38.0 MB
  STR_MIX_ADAPTIVE                197.37         21.86         87.60        111.78       69.8 MB
    PHP array                      32.18          8.87          5.79          8.27       69.1 MB

── API: Batch Operations (INT_TO_INT) ────────────────────────────────────────

  Operation                           Judy(ms)       PHP(ms)     Speedup
  ──────────────────────────────  ────────────  ────────────  ──────────
  putAll()                               16.76         22.07        1.3x
  fromArray()                            16.98         22.07        1.3x
  toArray()                              30.25         40.19        1.3x
  getAll(50100 keys)                      2.01          2.28        1.1x
  increment(500000 ops/1000 keys)         20.09          8.07        0.4x

── API: Native Methods (keys, values, sum, popCount, deleteRange, equals) ────

  Operation                           Judy(ms)       PHP(ms)     Speedup
  ──────────────────────────────  ────────────  ────────────  ──────────
  keys() INT_TO_INT                      12.49         21.67        1.7x
  values() INT_TO_INT                    11.45         21.55        1.9x
  keys($lo,$hi) INT_TO_INT                0.73         19.52       26.9x
    vs slice()->keys()                    2.12             -        2.9x
  size($lo,$hi) INT x1000                 0.81             -        O(1)
  size($lo,$hi) STRING_TO_INT             2.85          3.66        1.3x
  sumValues() INT_TO_INT                  5.93         16.42        2.8x
  populationCount() INT_TO_INT            0.00         18.85   269275.5x
  deleteRange() INT_TO_INT mid50%         30.53         42.69        1.4x
  equals() INT_TO_INT                     8.12         36.64        4.5x

── API: Set Operations (BITSET, 50% overlap) ────────────────────────────────

  Operation                           Judy(ms)       PHP(ms)     Speedup
  ──────────────────────────────  ────────────  ────────────  ──────────
  union() BITSET                         26.55         11.17        0.4x
  intersect() BITSET                     10.45         10.66        1.0x
  diff() BITSET                          10.68          4.51        0.4x
  xor() BITSET                           21.24         23.60        1.1x
  union() INT_TO_INT                     32.24         67.95        2.1x
  intersect() INT_TO_INT                 12.44         32.00        2.6x
  diff() INT_TO_INT                      12.50         32.35        2.6x
  xor() INT_TO_INT                       25.29         65.03        2.6x
  union() STRING_TO_INT                 201.33        223.39        1.1x
  intersect() STRING_TO_INT              86.11        103.72        1.2x
  diff() STRING_TO_INT                   84.73        101.50        1.2x
  mergeWith() INT_TO_INT                 39.42         53.73        1.4x
  mergeWith() STRING_TO_INT             184.29        196.90        1.1x

── Advanced: C-Level forEach/filter/map ──────────────────────────────────────

  Operation                        C-level(ms)       PHP(ms)     Speedup
  ──────────────────────────────  ────────────  ────────────  ──────────
  forEach() INT_TO_INT                   19.83         18.23        0.9x
  forEach() STRING_TO_INT                46.08         44.12        1.0x
  filter() INT_TO_INT (50% pass)         32.59         31.47        1.0x
  filter() STRING_TO_INT (50% pass)         84.12         82.90        1.0x
  map() INT_TO_INT (*2)                  36.30         36.75        1.0x
  map() STRING_TO_INT (*2)              118.73        118.60        1.0x

── Advanced: optimizeIteration trade (opt-in key-index payload mirror) ──────

  Operation                        default(ms)    optim.(ms)   optim./def.
  ──────────────────────────────  ────────────  ────────────  ────────────
  foreach() HASH kl16                    48.34         26.29         54.4%
  values() HASH kl16                     39.75         21.45         54.0%
  toArray() HASH kl16                    57.49         32.12         55.9%
  overwrite() HASH kl16                  29.58         36.75        124.2%
  increment() HASH kl16                  33.22         35.51        106.9%
    HASH kl16: honoured?          yes
  foreach() ADAPTIVE kl40                53.42         34.76         65.1%
  values() ADAPTIVE kl40                 51.08         31.25         61.2%
  toArray() ADAPTIVE kl40                72.12         46.51         64.5%
  overwrite() ADAPTIVE kl40              47.75         43.37         90.8%
    ADAPTIVE kl40: honoured?      yes
  skipped — increment() ADAPTIVE kl40: Judy::increment() is only supported for INT_TO_INT, STRING_TO_INT and STRING_TO_INT_HASH types

  Ratios are optimized as a percentage of default, measured inside this
  build; below 100 is the traversal win, above 100 the write price. Lower
  is better on every row, so a lost win reads as a rise.

── Advanced: Adaptive SSO — short keys (<8 bytes) via JudyL ─────────────────

  Operation                   STR_TO_INT    STR_INT_HASH   STR_INT_ADPTV    Best ratio
  ──────────────────────  ──────────────  ──────────────  ──────────────  ────────────
  insert (short keys)          60.15 ms       92.85 ms       90.26 ms       1.5x
  read (random access)         17.51 ms       17.16 ms       17.97 ms       1.0x
  foreach (iterate all)        41.32 ms       57.48 ms       61.73 ms       1.4x

── Advanced: Adaptive SSO — long keys (>=8 bytes) fallback to JudyHS ────────

  Operation                   STR_TO_INT    STR_INT_HASH   STR_INT_ADPTV    Best ratio
  ──────────────────────  ──────────────  ──────────────  ──────────────  ────────────
  insert (long keys)           86.56 ms      154.46 ms      158.00 ms       1.8x
  read (random access)         35.30 ms       29.63 ms       33.26 ms       1.2x
  foreach (iterate all)        69.83 ms       77.89 ms       76.50 ms       1.1x

══════════════════════════════════════════════════════════════════════════════════════════
  Benchmark complete — 2026-11-01 05:52:07
  All timings: median of 7 iterations via hrtime(true), 1 warmup run
  Memory: peak RSS of a child process building one structure of 500,000 elements,
          minus an empty-process floor. Measured with getrusage(), not
          memory_get_usage(), for the reason above. Judy's memory advantage is
          scale- and type-dependent — see BENCHMARK.md for the curve.
══════════════════════════════════════════════════════════════════════════════════════════

  JSON results written to: bench.json

@orieg
orieg merged commit ba078c8 into main Nov 1, 2026
21 checks passed
@orieg
orieg deleted the chore/discipline-v0.29.0 branch November 1, 2026 05:58
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