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 AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ collaborators.
|-------|---------|
| `red-team` | Filed by `/red-team`. Also that skill's mode switch — don't delete it |
| `sev:high` / `sev:med` / `sev:low` | Former P1 / P2 / P3 |
| `area:1`…`area:13` | Red-team focus area, per `dev/red-team/focus-areas.md` |
| `area:1`…`area:15` | Which area **owns the code**, per `dev/red-team/focus-areas.md` — not which round found it; an issue may carry several |
| `task` | Planned work migrated from the retired `to-do.md` |
| `deferred` | Assessed and parked; not scheduled |
| `chore` | Infrastructure / process work |
Expand Down
7 changes: 5 additions & 2 deletions dev/red-team/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# `dev/red-team/` — the red-team rotation's state

Everything the `/red-team` skill reads and writes. The skill itself is user-level and shared
across projects; **this directory is the project-local memory that makes it work.** If a file
across projects (`~/.claude/skills/red-team/`), rewritten 2026-08-05 around GitHub issues —
its dual-mode `findings.md` machinery is retired to `~/.claude/skills-retired/red-team/`, the
only surviving record of file mode. **This directory is the project-local memory that makes
it work.** If a file
here goes stale, the next round pays for it in wasted finder tokens — that is not
hypothetical, it is what the 2026-07-27 rounds measured.

## The files

| File | What it is | Who writes it |
|------|------------|---------------|
| [`focus-areas.md`](focus-areas.md) | The rotation table: 13 numbered areas, the files each owns, its `start_tier`, and its key questions. Built once, edited rarely. **Adding a row** also needs, and nothing currently automates: a matching `area:N` GitHub label (`gh label create area:N --description "Red-team focus area N"`), and recomputing `N` in `log.md`'s rotation-formula comment (see RT12-01). | A round, when it finds the scope row wrong |
| [`focus-areas.md`](focus-areas.md) | The rotation table: 15 numbered areas, the files each owns, its `start_tier`, and its key questions. Built once, edited rarely. **Adding a row** also needs, and nothing currently automates: a matching `area:N` GitHub label (`gh label create area:N --description "Red-team focus area N"`), and recomputing `N` in `log.md`'s rotation-formula comment (see RT12-01). | A round, when it finds the scope row wrong |
| [`log.md`](log.md) | Append-only, **newest first**. One entry per round (`area` / `reviewed_by` / `date` / `tier` / `yield` / `notes`), the **model-version legend** at the top, and `last_focus:` at the very bottom. | Every round |
| **GitHub issues** in [`agent-issues/TreeSearch`](https://github.com/agent-issues/TreeSearch/issues?q=label%3Ared-team) | **OPEN verified findings live here since 2026-08-04**, labelled `red-team` + `sev:high\|med\|low` + `area:N`. Status is GitHub state, so it cannot drift from merge state. Filed *after* verification; trivial issues are fixed inline and noted in `log.md` instead. | A round files; a merged `Fixes #N` closes |
| [`findings-archive.md`](findings-archive.md) | **FROZEN 2026-08-04.** Terminal-state findings from the file era, one compressed line each. **Offline anti-duplication memory, not a trophy case** — the one thing the tracker doesn't provide. | Nobody; it is closed to new rows |
Expand Down
27 changes: 27 additions & 0 deletions dev/red-team/focus-areas.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ top of `log.md`; seams that a version bump has made re-eligible are queued in
| 11 | **Zero-length-branch collapse (MPT set)** | `src/ts_collapsed.cpp/.h`, `src/ts_splits.cpp` (`compute_collapsed_splits`), `src/ts_rcpp.cpp` (`ts_collapse_flags_batch`), `src/ts_tbr.cpp` (enum `add_collapsed` sites), `R/MaximizeParsimony.R` (collapse block) | **opus** | DEFAULT-ON since 2026-06-24, so every `MaximizeParsimony` call exercises it. Does `compute_collapsed_flags_aggressive` flag the *correct* min-length-0 branches under **IW / profile / NA**, not just EW (verified)? Is it really rooting-invariant, or does tip-rooting+`RenumberTips(labs)` alignment break on constraint trees / user start trees / `RenumberTips` permutations (cf. [[na-validation-alignment-gotcha]])? Can the dedup key `write.tree(SortTree(unroot(t)))` over-merge (two distinct collapsed topologies → same key) or under-merge across rootings? `result$scores == best_score` float-equality safe under IW/profile? Degenerate inputs: star tree, single MPT, 3–4 tips, all-resolved (must be exact no-op), fully-unresolved? Does collapse ever produce a tree that violates an active `constraint`? |
| 12 | **Red-team process meta-review** | `dev/red-team/focus-areas.md`, `dev/red-team/log.md`, the `red-team` issue list in `agent-issues/TreeSearch`, `dev/red-team/README.md` | **sonnet** | Are any areas too broad — spanning multiple distinct seams such that a finder concentrating on one file family misses another? Are any too narrow — a single-feature scope that would be better merged into a neighbour? Do any areas overlap (same source files audited under two different area headings)? Has any area gone persistently dry (≥ 3 consecutive rounds with zero confirmed findings) — should it be retired, merged, or downtiered? Are there new code seams (recently merged features, new source files) not covered by any existing area? Are tier assignments calibrated to actual yield recorded in `log.md` — any area that keeps surprising at its current tier and should escalate, or one that has been consistently empty and should drop? Propose concrete restructuring actions (split, merge, retire, add, re-tier) with rationale tied to `log.md` yield history. |
| 13 | **Constrained search correctness** | `src/ts_constraint.h/.cpp`, `src/ts_nni_perturb.cpp`, constraint integration points in `src/ts_driven.cpp` (fuse), `src/ts_parallel.cpp` (parallel-fuse), `src/ts_wagner.cpp`/`src/ts_sector.cpp` (posthoc retry), `src/ts_tbr.cpp` (`regraft_violates_constraint`) | **opus** | Does every `impose_constraint()` caller verify-before-capture, not just trust an improved score (T-213 gap, fixed d9a4f827: `nni_perturb_search` was the one caller that didn't re-check `constraint_node[]` after repair — fuse/parallel-fuse already did)? Any other heuristic-repair or posthoc-retry caller (Wagner build retry, sector) that skips discard-on-failure? Is `impose_one_pass`'s `best_node` reference stale after its own move-out loop's `topology_spr()` calls relocate a node — traced mechanism, produced one `std::bad_alloc` crash under experimental code, did NOT reproduce in 600 stress-test seeds against shipped code; needs a targeted adversarial tree construction, not more random seeds, to confirm either way. Is `map_constraint_nodes`/DFS-timestamp resync correct on every topology-mutation path, including reject paths (cross-check vs area 2's tabu-reject question)? Are nested/overlapping constraint splits handled consistently across TBR clip-gating, Wagner retry, and sector/fuse posthoc paths? |
| 14 | **Statistics & support metrics** | `src/MaddisonSlatkin.cpp`, `src/expected_mi.cpp`, `src/ts_mc_fitch.cpp`, `src/quartet_concordance.cpp`, `R/Concordance.R`, `R/ParsSim.R`, `R/pp_info_extra_step.r`, `R/WideSample.R`, `R/Consistency.R`, `R/TaxonInfluence.R`, `R/ScoreSpectrum.R`, `R/RandomTreeScore.R`, `R/WhenFirstHit.R`, `R/QuartetResolution.R` | **sonnet** | Is the recursive Maddison–Slatkin DP correct at its recursion boundaries, and does its cache key everything the recurrence depends on? Does the factorial-cache log-space arithmetic under/overflow at realistic tip counts, and are log-space sums accumulated stably? When does the exact DP hand off to the Monte Carlo fallback, and is the fallback's estimator unbiased — or silently substituted without the caller being able to tell? Are concordance-factor statistics well-defined on polytomies, on single-taxon splits, and on characters with missing data? Do the R wrappers validate tip-label correspondence, or index by position (cf. the [[na-validation-alignment-gotcha]] class)? |
| 15 | **Legacy pure-R search API** | `R/CustomSearch.R` (`TreeSearch()`), `R/Ratchet.R`, `R/NNI.R`, `R/SPR.R`, `R/TBR.R`, `R/SuccessiveApproximations.R`, `R/tree_rearrangement.R`, `R/morphy-deprecated.R`, `R/Bootstrap.R` | **sonnet** | Is `EdgeListScore()` — the default `TreeScorer` for `TreeSearch()`/`Ratchet()`/`Jackknife()`, and one of the four entry points #16 confirms vulnerable — reachable with the out-of-bounds inputs #16 describes? Do the pure-R rearrangement samplers (`NNI`/`SPR`/`TBR`) generate only valid topologies, and do they cover the neighbourhood they claim? Does `SuccessiveApproximations` reweight consistently with the C++ IW kernel, or has it drifted? Do `Bootstrap`/`Jackknife` resample characters with the weights the user supplied? Does anything here still route through removed MorphyLib paths (`morphy-deprecated.R`)? |

### Maturity / tier rationale (one line each)

Expand Down Expand Up @@ -140,3 +142,28 @@ top of `log.md`; seams that a version bump has made re-eligible are queued in
reading the backlog row that holds the actual ask (item 7 explains this at length). Whoever
takes area 13 next must decide explicitly: harness first, or #18/#19 first — both are live,
and the harness plan predates the two findings.
- **14 Statistics & support metrics — sonnet, UNMEASURED / no inherited maturity.** Added
2026-08-05 from #42's scope-coverage diff: 5,553 lines across 14 files that were owned by no
area and therefore never reviewed at any tier. **The gap has already cost a finding** — the
arm64 `probe_slot()` hang in `src/MaddisonSlatkin.cpp` (fixed, PR #272,
cf. [[maddisonslatkin-arm64-profile-hang]]) was found incidentally, not by rotation. The code
is numerically dense — recursive DP, factorial caches, log-space arithmetic, Monte Carlo
fallbacks — the profile the tier doctrine normally reserves for `opus`, and #42 recommended
`opus` on that basis. **Deliberately starting at `sonnet` anyway** (maintainer decision,
2026-08-05): density is a prediction about where bugs *hide*, not evidence that cheap sweeps
are exhausted, and this area has no measured yield at all. Let a Sonnet pass measure it; the
escalation rules will lift the tier the moment a round comes back dry. Its own test convention
(`test-MaddisonSlatkin.R`, `test-Concordance.R`, `test-ParsSim.R`, `test-Consistency.R`,
`test-ScoreSpectrum.R`, `test-QuartetResolution.R`, `test-TaxonInfluence.R`,
`test-WideSample.R`, `test-pp-*.R`) is a useful first read.
- **15 Legacy pure-R search API — sonnet, UNMEASURED / no inherited maturity.** Added
2026-08-05 from #42's scope-coverage diff: 2,183 lines across 9 files backing the
still-shipped pre-C++-engine search functions, owned by no area. **Higher urgency than its
size suggests:** #16 (`sev:high`) names `EdgeListScore()` as *"the default `TreeScorer` for
`TreeSearch()`/`Ratchet()`/`Jackknife()`"* and one of four confirmed-vulnerable entry points,
so this family is a second, wholly unreviewed exposure surface for an already-confirmed bug —
take that question first. #42 offered "review once as frozen legacy, then deprioritise";
**the maintainer chose a full rotation area instead (2026-08-05): keep revisiting until the
seam stops yielding.** Legacy is not the same as clean, and this code is still shipped and
still the documented entry point for users who have not moved to the C++ engine. Treat "it
isn't growing" as a reason the seam should *exhaust* quickly, not as a reason to stop early.
8 changes: 5 additions & 3 deletions dev/red-team/log.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
Append-only record of every red-team round. **Newest first.** Each invocation of
`/red-team` adds one entry and updates `last_focus:` at the **bottom** of this file. The
next area is `(last_focus mod N) + 1`, where `N` is the current row count in
`focus-areas.md` (13 as of 2026-07-03 — **not** the stale `10` this line said until then,
which made areas 11-13 mathematically unreachable by normal rotation; see RT12-01,
2026-07-03 area-12 round below). Recompute `N` whenever a row is added.
`focus-areas.md` (**15 as of 2026-08-05**, when areas 14 and 15 were added to close #42's
scope-coverage gap — previously 13 as of 2026-07-03, and **not** the stale `10` this line
said until then, which made areas 11-13 mathematically unreachable by normal rotation; see
RT12-01, 2026-07-03 area-12 round below). **Count the rows; do not trust this number.**
Recompute `N` whenever a row is added.

**Entry format** (per round): `area`, `reviewed_by`, `date`, `tier` — **which now records the
model *version* that ran, not just the rung** (`tier: opus (Opus 4.8)`) — `yield` (count of
Expand Down