Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "perun",
"description": "Perun: a suite of skills for building with AI agents. Deep code review, token and cost tools (spend reports, auto-compact with handoff, model-tier guidance), gated agentic delivery (merge train, lanes, destructive-command guard, auto-update), an idea critic, and product, growth, positioning, business-ops and output-safety specialists.",
"skills": "./.claude/skills",
"version": "1.629.0",
"version": "1.630.0",
"author": {
"name": "deep-code-review contributors"
},
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/agentic-delivery/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: >-
license: MIT
metadata:
author: deep-code-review contributors
version: "1.629.0"
version: "1.630.0"
---

# Agentic delivery
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/agentic-delivery/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.629.0
1.630.0
2 changes: 1 addition & 1 deletion .claude/skills/deep-code-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: >-
license: MIT
metadata:
author: deep-code-review contributors
version: "1.629.0"
version: "1.630.0"
---

# Deep Code Review
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/deep-code-review/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.629.0
1.630.0
2 changes: 1 addition & 1 deletion .claude/skills/idea-critic/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: >-
license: MIT
metadata:
author: deep-code-review contributors
version: "1.629.0"
version: "1.630.0"
---

# Veles: the evil twin (idea-critic)
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/idea-critic/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.629.0
1.630.0
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "perun",
"version": "1.629.0",
"version": "1.630.0",
"description": "Perun: a skill suite for AI-agent teams: deep code review, token and cost tools, gated delivery, an idea critic and product specialists.",
"skills": "./.claude/skills",
"interface": {
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
All notable changes to this repository are documented here. Format loosely
follows Keep a Changelog; versioning follows Semantic Versioning.

## [1.630.0] — 2026-10-31

### Changed
- The CI `perpr` job now runs four legs instead of three (`shard: [1, 2, 3, 4]`, `SHARD=i/4`), and its legs are balanced by recorded test time instead of by sorted position. `scripts/ci-tests-shard.sh` reads `scripts/ci-durations.tsv` (whole seconds per `scripts/ci-tests.d/*.sh` registration: the seconds between consecutive `== <registration>` lines of the `perpr` job logs of public CI run 41148962559 (2026-10-31), rounded, at least 1), takes the serial registrations longest first (ties by name, C locale) and gives each to the least-loaded leg (ties to the lowest index). A registration with no row counts as the table's median, so adding a test never needs a table edit and two PRs never conflict on the table. `*.bg.sh` registrations keep the sorted round-robin, because they run beside the serial ones, so only serial seconds are balanced. The contract is unchanged: the `i/N` slices are disjoint and cover every registration for any N, a malformed `SHARD` exits 2, an empty slice exits 1, the listing is sorted and does not depend on the locale. On the committed table, which counts every test at least 1 s (so these are predictions from the table, not CI measurements), the old helper with three legs on the tree before this change gives legs of 283, 489 and 682 s of serial tests, and the new split over four legs gives 364, 364, 364 and 363 s.
- The `Per-PR tests` step also prints one `bg elapsed: <test> <seconds> s` line per background test (its wall time from the background start, `?` when it left no end time), because the `== <registration>` lines show only how long the step waited for it, not how long it ran.
- Test: `scripts/test-perpr-shard-balance.sh` (registered as `scripts/ci-tests.d/perpr-shard-balance.sh`) checks the committed table's format, that the slices are disjoint and complete for N = 1 to 5, that the slowest of the legs `ci.yml` runs (the N its `perpr` legs pass in `SHARD=i/N`, read from `ci.yml`) is predicted within 1.1x of the mean (it fails on the old split), and, on a fixture, the exact longest-first assignment, the median default for a malformed or missing row, and the round-robin of background tests. `scripts/test-perpr-shard.sh` no longer asserts that the slices hold nearly equal numbers of registrations, which only the old split guaranteed, and now checks that each leg logs its `bg elapsed:` line. `CONTRIBUTING.md` describes the new split, says when to refresh the table (the slowest leg's `Per-PR tests` step more than 20% over the fastest on a PR run) and gives the awk command that rebuilds its rows from the job logs of the legs; the test runs that command on synthetic logs.

### Added
- Bundled semgrep rule `perun.js.body-cap-after-buffer` (INFO, in `templates/semgrep-taint/js.yml`): a request body read whole with `await req.formData()`, `.json()`, `.text()` or `.arrayBuffer()` on a receiver named like `req` or `request` (`req`, `request`, `c.req`, `event.request`) and followed later in the same block by a `.size`, `.length` or `.byteLength` comparison against a cap on the result (directly, or on an entry read from it with `.get(...)`), or preceded only by a `content-length` comparison. The body is already in memory when the cap runs, and a declared length does not bound a chunked body. A comparison with the literal `0` is an emptiness check, a read on `res`, `response` or `file` is not a request body, and a counted `getReader()` read is a bounded read: none of them is reported. Test, fixture and mock paths are skipped.
- Bundled semgrep rule `perun.js.limiter-key-forwarded-header` (INFO): an `x-forwarded-for` or `x-real-ip` read (`headers.get(...)`, `headers.header(...)` or `headers[...]`) inside a function named like `clientKey`, `limiterKey`, `rateKey`, `deriveKey` or `getIp`. The message asks the reviewer to check the trusted-hop count, whether a missing header maps every caller onto one shared key, and whether it fails open. Test, fixture and mock paths are skipped.
- `scripts/test_semgrep_taint_ext.py`, registered in `scripts/ci-tests.d/semgrep-taint-ext.sh`, checks these rules with annotated fixtures: a `// ruleid:` comment marks the next line as a required finding, an `// ok:` comment marks it as one that must stay clean, and every unannotated line must stay clean. The live part needs semgrep and prints SKIP without it; it also scans a copy of each fixture under a test path and expects no finding, and loads a copy of the rules with an invalid severity and expects semgrep to reject it, so the schema check of the rule file does not depend on the network. The offline part always runs: severity, languages and message keywords, the skipped paths compared with a sibling rule's list, a `ponytail:` ceiling line in the file header for each rule, the whole pattern skeleton of each rule (every shape and the tags that join them) compared with the rule text, and replays of the rules' own regexes on positive and negative values.
- Known ceilings, also recorded as `ponytail:` lines in the `js.yml` header. `perun.js.limiter-key-forwarded-header` follows the function name, so it misses a differently named function (`getClientIp`, for one) and reports any function whose name matches. `perun.js.body-cap-after-buffer` matches the receiver by name, so it misses a request bound to another name (`r`) or read through a call (`req.clone().json()`). It recognises only `>` comparisons with the result on the left, does not tie a body bound by destructuring or read inline to a later check, does not match a `?.` or `!` on the result or on its `.get(...)` entry (`body?.length`, `body!.length`, `form.get("file")!.size`), does not count a deeper field path such as `body.items.length` or a read and a check in different blocks, and cannot see a cap enforced in middleware or a framework option.

## [1.629.0] — 2026-10-31

### Fixed
Expand Down
14 changes: 7 additions & 7 deletions SHA256SUMS
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ ef9e423362b12d0dd73c8e165faf32e9f53c4d4ac215b57c2e34002a88713838 .claude/skills
9521b057ff3db92d1e60923ebd88170713914f7e235ceb45717eb39419daf811 .claude/skills/agentic-ceo/scripts/weekly_receipt.py
7e2179751e9dd2fb371b3e9fb01fca987d69605af1e8e6e609ff9b0d0abb384b .claude/skills/agentic-delivery/INDEX-scripts.md
47fff02dcb4401d5a9b42b2b3b7f7c123125eece55e7f9adee8cfe488c70a146 .claude/skills/agentic-delivery/INDEX.md
0908eb84e129f09d35b869fc2f4829dae514f493c0e9a35d560be0b0d88fc3b0 .claude/skills/agentic-delivery/SKILL.md
c3928436efc2dcc3d67d251cec0e86098547dd4f135a3e1273bc4725d5499b84 .claude/skills/agentic-delivery/VERSION
6858279bbeebfc7fb7c0df3c058378aa4505dd4b8f035567dc1bfab93bcbebd0 .claude/skills/agentic-delivery/SKILL.md
b78778d02b1ed21cf6001646fbc0fc5b212475318c3c619a05cae2d39aadf46e .claude/skills/agentic-delivery/VERSION
94144c101f82399eb6c18f688321a00e1c195dd0ab334f3a5daa2543b40ff9f5 .claude/skills/agentic-delivery/evals/evals.json
fba7699a2d0836b51b7c838d019b1f0cd20570522a362e8a32b8dacfb911298e .claude/skills/agentic-delivery/evals/triggers.json
39140ac0b40907dc2279bb3234ce1d8ffb4db56e8658c7f89cc370f777df0592 .claude/skills/agentic-delivery/references/cost-quality-guardrails.md
Expand Down Expand Up @@ -206,8 +206,8 @@ d98f3e4380da3496061ba63be7beebe75017ab4ee1734eda9a3e798e19007b0e .claude/skills
18f20db537ab784460ad33cf218f7a01ac0a172fc38413f14c0e19e1ce6821cc .claude/skills/contribution/scripts/share_learning.py
57ab71eae0e846ea4e5e8287da26679a5a010cf576fed89ca37c94e0c900180f .claude/skills/deep-code-review/INDEX-scripts.md
9fcb6a002fb7e3fe28163199783968f80b920744c83280cff211a348215c9c0d .claude/skills/deep-code-review/INDEX.md
a3d823187b8bab01cc9345102057b858d7eaffa9246dfa83521e3636a0dbc152 .claude/skills/deep-code-review/SKILL.md
c3928436efc2dcc3d67d251cec0e86098547dd4f135a3e1273bc4725d5499b84 .claude/skills/deep-code-review/VERSION
38f7641cd69b145af32440d34daf29a52272bef4313da5d9483eb31a9ff7c61b .claude/skills/deep-code-review/SKILL.md
b78778d02b1ed21cf6001646fbc0fc5b212475318c3c619a05cae2d39aadf46e .claude/skills/deep-code-review/VERSION
b97d95bc93cc23a8bc689e2e23db261a138367bcbc69d2f8a0452d5c2c6dfb68 .claude/skills/deep-code-review/evals/evals.json
13dbb52e4bf61b1093302e094151def167371d26e7cf67a026f3beeb09d34378 .claude/skills/deep-code-review/evals/triggers.json
b84e3a2b88dc189f041784e76b97e68ad879915814e00f4b37cd27513746d6f1 .claude/skills/deep-code-review/references/a11y-aria.md
Expand Down Expand Up @@ -416,7 +416,7 @@ f31e66a322ee172e4b9621c3b70717a6e896ee64178f0e8ea77ac2088b6d0cb6 .claude/skills
d84df8bbfb7e87be95446e91151f1badcc85797c07d3cb574be00c66b4f6b7c4 .claude/skills/deep-code-review/templates/perun-review.yml
429b66e715e660931543b71e346f60df85dfa8df70d6caa409f51958f4202acd .claude/skills/deep-code-review/templates/pre-push-verify.sh
a82701e4893739b8451bcfab0fe6df01e130f1659cd9b4c3780f1461c874d698 .claude/skills/deep-code-review/templates/semgrep-taint/gha.yml
b43f67489d710551171428fce62e4f129839361f5da3dda5d62d6d3523ec365c .claude/skills/deep-code-review/templates/semgrep-taint/js.yml
1470877bc6329921c1eebcd763201f9198e47b6f97670a9d42eb8dc281b99cd8 .claude/skills/deep-code-review/templates/semgrep-taint/js.yml
7bdab757847b5a5ce2323e4fb06905e4446919196f5417c25511ac279b4a1e0e .claude/skills/deep-code-review/templates/semgrep-taint/py.yml
29ee3a47eb7973011cdfe1fb4321aac89fc0fe8f98776505df70a6d6a45cbf0f .claude/skills/growth-analytics/INDEX.md
4fe9fb6176818c279ddce11bde1aa97157800190075ba79604c174a5d9a7c59c .claude/skills/growth-analytics/SKILL.md
Expand All @@ -426,8 +426,8 @@ e951eaa63fd0d1870701d69c89c29ef4fe74dbad9b680ab6ef0a4e993fb8bc20 .claude/skills
fd316c63bbf1cc0ea64322d7d923d66692eaf7b545c056367bfecca35146c862 .claude/skills/growth-analytics/references/full-map.md
2f1d7499e9ed7ae59f550b5c00043e465b2a4e885821ad153438e2e33fcccb45 .claude/skills/growth-analytics/scripts/readout_check.py
67e71ec40535ad0b3931c51f3decf323bce809ed4c9586c6d422b7ad5698129f .claude/skills/idea-critic/INDEX.md
47c6a04bcb63ec82fb918ed8f818b98280333077a344e5757279d65a50868072 .claude/skills/idea-critic/SKILL.md
c3928436efc2dcc3d67d251cec0e86098547dd4f135a3e1273bc4725d5499b84 .claude/skills/idea-critic/VERSION
0d1f64cbd5c26d4ffa9fe1717835090fbd696915688e5bc596c656f6e9585b6c .claude/skills/idea-critic/SKILL.md
b78778d02b1ed21cf6001646fbc0fc5b212475318c3c619a05cae2d39aadf46e .claude/skills/idea-critic/VERSION
9f77d5d6d13c99fd16cd8c398795d8be226d74bae5a5bf65369ed94a59fa56b7 .claude/skills/idea-critic/evals/evals.json
0e1c0db300661a1ab1a427a7157c75e2ed67130ab24d5c6cb02ec3ff9e793f58 .claude/skills/idea-critic/evals/heldout.json
d8098c5ced63e8b8608867dd144091049563a0553cf62d27ce05b9d52ac54266 .claude/skills/idea-critic/evals/triggers.json
Expand Down
4 changes: 0 additions & 4 deletions changelog.d/perpr-shard-balance.md

This file was deleted.

5 changes: 0 additions & 5 deletions changelog.d/semgrep-taint-extended-rules.md

This file was deleted.

2 changes: 1 addition & 1 deletion gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "perun",
"version": "1.629.0",
"version": "1.630.0",
"description": "Perun: a skill suite for AI-agent teams: deep code review, token and cost tools, gated delivery, an idea critic and product specialists.",
"contextFileName": "AGENTS.md"
}
Loading