# Resistance & suspension trainers: research notes

Date: 2026-10-25. Scope: portable elastic resistance bands (loop bands with no
handles, tube bands with handles, fabric loop bands, figure-8 bands, mini/therapy
bands) and suspension trainers (TRX-style webbing straps anchored to a fixed
point, used against bodyweight). The taxonomy leaf bundles two mechanisms
experts treat as entirely different tools — one stores elastic energy in rubber,
fabric-covered rubber or TPE; the other has no elastic element at all and uses
body angle against an anchor. One register, one top split (`trainer_type`)
divides them; the rest of the facets and the other two splits apply inside the
band branch only, which the brief allows ("let the splits do the dividing").
Not in scope, left to siblings in `catalog.json` under `supplies > active`:
ankle/wrist cuff weights and free weights (`weights`), stretching straps sold
as a single non-elastic strap for static stretching (`yoga_equipment`), pull-up
bars and dip stations (`gym_benches`), and foam rollers (`foam_rollers`). Where
a mini loop band is marketed for glute "activation" alongside hip circles, it
still belongs here because it is the same elastic product as the rest of the
loop-band family; a non-elastic fabric loop sold purely as a yoga stretching
strap would not, but I found no retail listing that blurs that line in practice.

Quote labels: **verbatim** = the exact sentence appears in quotation marks in
text I fetched myself (curl, with script/style tags stripped by a script, then
read as plain text) or in an NCBI eutils plaintext abstract. **fetched excerpt**
= I fetched the page myself (curl, text visible to me) and I am paraphrasing or
lightly condensing what I read, with the key figures kept exact. **search
excerpt** = from a search-engine results snippet only, page itself not read by
me. No search-excerpt-only number went into category.json.

WebSearch reported its session budget exhausted on the first four queries I
tried (TheraBand colors, band types, TRX anchor specs, latex vs TPE) before I
could use it at all, so every source below was reached by direct curl with a
browser user agent, the WebFetch tool on pages curl could not reach, or the
NCBI eutils API for PubMed abstracts (curl to pubmed.ncbi.nlm.nih.gov itself
returned a cookie-consent wall with no body text; eutils' `efetch` endpoint
returns plain text with no such wall). DuckDuckGo Lite and Bing both returned
only a bot/anomaly challenge or unrelated autosuggest rows for site-restricted
queries, so I could not use either as a search substitute — see "Script and
source problems" below. Retail listings blocked every fetch I tried
(Amazon is not attempted per house convention; roguefitness.com returned
HTTP 403 to curl on both URL guesses I tried) so no facet is marked "listing"
on the strength of a retail page I actually saw; "listing" below means the
field appears as text on a brand's own direct-to-consumer product page, which
is the closest available stand-in per the brief's instruction to mark
`researched` when retail presence can't be confirmed.

## Seed

Seed run (recorded verbatim from the script):

- Example: bedsheets `weave` — "the expert split is often not the number
  everyone advertises. Thread count is the generic trap here. Weave is what
  changes how the sheet feels and sleeps."
- Persona: "An industrial designer, who thinks in materials, joins and what
  the manufacturer saved money on."

1. The resistance-bands equivalent of weave-not-thread-count is
   resistance *level* versus resistance *value*. Every band in a set is printed
   with a color or a word (Light, Heavy, Tan, Black) the way thread count is
   printed on a sheet tag, but — like thread count above ~400 — the number only
   means something within one brand's own ladder. Wikipedia's resistance-band
   article says plainly that "band colour codes vary between brands," and the
   Garage Gym Reviews roundup shows four brands putting wildly different pound
   ranges on bands that look alike (Living.Fit 6–250 lb, Rogue 9–225 lb, Titan
   25–170 lb, Bells of Steel 4–95 lb). Survived the data check: this became the
   `resistance_level` vs `resistance_value` pair of facets and the explicit
   judgement that the color name is not comparable across brands.
2. The industrial designer, thinking in materials, joins and what the
   manufacturer saved money on, would notice first that a "tube band with
   handles" and a "loop band" are the same rubber tube, molded or cut
   differently, and that the handle is the part most likely to fail (Garage Gym
   Reviews' tester: "I've had handles snap off old bands while using them with
   clients"). They'd also notice that TRX's one real engineering flex — the
   locking carabiner — is "exclusive to Pro4 models," i.e. cheaper suspension
   trainers use a plain clip that can walk open under load. Survived: this
   became the `band_type` split (loop vs. tube-with-handles) and the
   `locking_carabiner` facet. Dropped: a planned facet for handle grip material
   (foam vs. rigid plastic) — no brand page states what the handle is made of,
   only reviewer opinion on comfort, so it would have been `researched` at high
   cost for low narrowing; left out rather than padding the register.

## Sources and what each supports

- **theraband.com / performancehealth.com (spec_sheet)** —
  `https://www.theraband.com/products/latex-resistance-bands` and
  `https://www.performancehealth.com/theraband-professional-latex-resistance-bands`.
  Both fetched directly with curl (200 OK), script/style stripped, read as
  plain text. **Verbatim**, from the Performance Health page: "the exercise
  resistance bands come in levels that range from Super Light (2.4 lbs) to
  Elite (14.2 lbs)"; "an initial 2-foot (60 cm) length of green band that is
  stretched to 4 feet (120 cm, double its resting length) is at 100%
  elongation. Therefore, the resistance of the band is 4.6 pounds at that
  elongation"; "Each progressive step represents a consistent pull-force
  increase of 25% in the clinical range (Tan through Black) and 40% in the
  advanced range (Silver and Gold)"; "Developed by Juan Carlos Colado, PHD,
  University of Valencia, Valencia, Spain." Supports: the mechanism (resistance
  is a function of % elongation from resting length, not a fixed number), the
  7-level progressive naming scheme, and the specific Super Light/Elite/green
  figures. These three numbers (2.4, 14.2, 4.6 lb) have only this one source —
  I could not reach a second independent page that restates them, so I did
  **not** put them in `category.json`'s `range` fields; they stay here as a
  single-sourced data point and inform only the qualitative mechanism text and
  one low-confidence judgement.
- **en.wikipedia.org/wiki/Resistance_band (primer)** — fetched via WebFetch.
  **Fetched excerpt**: identifies six band types (therapy/no-handle, compact
  with plastic handles, flat loop, figure-8, ring, lateral/ankle-cuff); bands
  "were originally made from surgical tubing"; "the bands are color-coded to
  show different levels of resistance" but "Code colors vary between brands."
  Supports: the `band_type` value list and the cross-brand-incomparability
  judgement (paired with Garage Gym Reviews below as the second source).
- **en.wikipedia.org/wiki/Suspension_training (primer)** — fetched via
  WebFetch. **Fetched excerpt**: suspension training is "an approach to
  strength training that uses a system of ropes and webbing... to allow users
  to work against their own body weight"; TRX was created by Randy Hetrick, a
  former Navy SEAL, in the 1990s and marketed from 2005; "sports scientists
  have expressed concern that weaker individuals may not have the core
  stability or joint integrity to use the system safely and effectively."
  Supports: the suspension-trainer mechanism family and a low-stakes judgement
  about who the product doesn't suit.
- **garagegymreviews.com/best-resistance-bands (specialist_review)** — fetched
  with curl (200 OK, 1 MB page; a naive script/style strip produced an
  almost-empty result because of an unmatched tag, so I rewrote the stripper to
  scan tag-by-tag rather than with one greedy regex — see "Script and source
  problems"). **Verbatim** quotes pulled from the plain text: Living.Fit
  "Resistance Range 6-250 lbs," "Material Premium latex," "Length (In Inches)
  41"", compared against "Average Resistance Band ... Resistance Range 10-175
  lbs"; Rogue Monster Bands offered "in eight different resistance totals from
  9 to 225 pounds"; Titan Fitness Heavy Resistance Bands "Resistance Range
  25-170 lbs," "Thickness 1.125" to 3.375""; REP Fitness Tube Resistance Bands
  "Resistance Range Light, Medium, Heavy," "Thickness 9 mm, 12 mm, 13.5 mm,"
  and the tester's complaint that they're "labeled as Light, Medium, and Heavy,
  but it's unclear what the maximum resistance is... Doesn't tell you the
  resistance tension in pounds"; Iron Bull Strength mini bands "Thickness 2","
  Length (In Inches) 12"," resistance "Extra Light, Light, Medium, Heavy, Extra
  Heavy"; Bells of Steel fabric bands "Resistance Range 4-95 lbs," a
  "Fabric and latex blend," labeled "Skinny, Mini, Slim, Light, Average, and
  Strong" with no lb number on the band itself; "resistance bands are prone to
  snapping with extended use"; a tester "can't use these bands for assisted
  pull-ups since they don't form a strong loop" (about tube/handle bands).
  Supports: the `band_type` split rationale (loop vs. tube trades
  pull-up/anchor versatility for upper-body grip comfort), `resistance_level`
  vs `resistance_value` as separate facets, the `band_thickness` facet (the only
  number given at all for handled tube bands), the fabric-vs-latex trade-off,
  and the snapping/durability judgement (paired with the two ophthalmology
  case reports below).
- **trxtraining.com/products/pro and
  trxtraining.com/pages/suspension-training-collection-page (spec_sheet)** —
  both fetched with curl (200 OK). **Verbatim**: "Use a door, tree, or pole,
  and start moving"; "The locking carabiner—exclusive to Pro4 models—easily
  connects and secures your straps to any anchoring solution"; anchor catalog
  copy — "DOOR ANCHOR ... fits easily over any hinged door. Comes included
  with all Suspension Trainers"; "SUSPENSION ANCHOR ... Loop the TRX Suspension
  Anchor around a tree, basketball pole, fence post, beam"; "TRX XMOUNT ... can
  be secured to walls, ceilings, and beams, and is made with durable steel";
  "The Xtender adds length... or to ceilings over 9-feet tall." Pro4 unit
  weight listed as "1.5 lbs." No page on trxtraining.com states a maximum user
  weight or load rating anywhere I could fetch (I checked the Pro4 product page
  in full); I treat the absence as the finding itself, not as evidence the spec
  doesn't exist elsewhere. Supports: the `anchor_type` facet and its values,
  the `locking_carabiner` facet, and the judgement that published max-user-weight
  figures are not a feature of this market the way they are for, say, gym
  racks.
- **PMID 33165305, "Ocular injuries associated with elastic exercise bands,"
  Ng et al., Retina Cases Brief Rep 2022 (academic)** — fetched as plain text
  via the NCBI eutils `efetch` endpoint (pubmed.ncbi.nlm.nih.gov itself served
  only a cookie-consent wall to curl, with and without a cookie jar).
  **Verbatim** abstract: "Thirteen eyes from 11 patients met the inclusion
  criteria of possessing ocular trauma secondary to recoil from exercise
  bands"; injuries included "traumatic iritis (54%)," "vitreous hemorrhage
  (54%)," three eyes (23%) needing surgery; "The frequency of this event would
  be decreased by the use of sports goggles and careful inspection of equipment
  for wear and over use." Supports the eye-injury judgement directly.
- **PMID 7864743, "Exercise band-induced hyphema," Ducharme & To, Arch
  Ophthalmol 1995 (academic)** — fetched the same way; eutils returned only the
  title/journal/year (no abstract text was indexed for this short case report),
  which I'm using only to support that the hazard has been documented in the
  literature since at least 1995, not for any numeric claim. This is the second
  source for "this is a real, recurring, decades-old injury pattern," paired
  with the 2022 case series above.

## Data points used for derived metrics

`cost_per_lb_of_resistance` (price ÷ top resistance_value in the set) is the
only derived metric. It depends on `resistance_value` and the listing price
(already in the system, not a facet here). I did not compute an example number
into the JSON — the formula is stated, not a specific result — because the
only prices I have (Living.Fit $128.94 for 6–250 lb, Titan $104.99 for 25–170
lb, from the Garage Gym Reviews page above) come from one fetched source and
the brief's two-source bar applies to JSON numbers; the formula itself needs
no citation beyond "this is arithmetic over two listing fields."

## Against the existing add-on schema

`resistance_band.jsonc` currently has exactly three fields: `band_material`
(enum), and under `sizing`, `resistance_level` (enum) and `resistance_value`
({value, unit}). Read against what I found:

| This register's facet | Existing field | Kind proposed | Gap / note |
|---|---|---|---|
| `trainer_type` | — (none) | categorical, vertical anchor | **Missing entirely.** The add-on is named `resistance_band.jsonc` and every field in it assumes an elastic band. The taxonomy leaf also includes suspension trainers (TRX-style), which have no band, no material in the `band_material` enum sense, and no resistance level or value. A suspension trainer mapped through this add-on today has nowhere to put its one defining fact. |
| `band_type` | — (none) | categorical, vertical anchor | **Missing.** Loop-vs-tube-vs-fabric-vs-figure-8 decides which exercises the product supports (pull-up assist and ankle work need a closed loop; presses and rows want a handle) more than material or resistance level do, per the Garage Gym Reviews versatility scoring. Not derivable from the two existing fields. |
| `resistance_level` | `sizing.resistance_level` enum `[extra_light, light, medium, heavy, extra_heavy, variable, unspecified]` | ordinal, hard filter within one listing | Keep, but it is **not a cross-listing filter** the way the enum's flat value list implies — see judgement below. The enum also doesn't cover brands that print only a bare number with no name at all (Titan: "25-170 lbs" stamped directly, no tier word) or Iron Bull's "extra-extra-heavy" top tier in some of its sets; `variable` and `unspecified` already give an escape hatch, which is adequate, but a ranker reading this field as comparable across rows would be wrong to do so. |
| `resistance_value` | `sizing.resistance_value {value, unit: kg\|lb}` | numeric, **category quality currency** per AGENTS.md rule 4 | This is the field that actually is comparable across brands (same unit, same physical quantity), which makes it the better candidate for "quality currency" under rule 4 — except it is the field most often **missing**: REP Fitness's own tube bands print no lb number at all, only "Light/Medium/Heavy," and the Garage Gym Reviews tester calls this out as a real complaint. Backfill cost here should be `medium`-to-`high`, not `low`, and the pipeline should not expect it dense. |
| `band_material` | `band_material` enum `[latex, natural_rubber, tpe, fabric, latex_free, unspecified]` | categorical, vertical anchor | Keep. One judgement: `tpe` and `latex_free` overlap conceptually (TPE is a latex-free elastomer), but listings I saw name their non-latex material inconsistently ("biomedical-grade rubber," "latex-free") without saying TPE specifically, so collapsing the enum wouldn't gain accuracy — I'd leave both values rather than merge them on the evidence I have. |
| `contains_latex` | — (derivable) | boolean, hard filter | Not a new field — it's `band_material in {latex, natural_rubber}` — but worth stating explicitly as the filter a latex-allergic buyer actually uses, since the enum alone requires the consuming code to know which values mean "latex." |
| `band_thickness` | — (none) | numeric, candidate quality currency for handled bands specifically | **New.** The one case where a brand (REP) prints no resistance figure in pounds at all, it prints thickness in mm instead. For tube/handle bands this is sometimes the *only* quantitative spec on the page. |
| `anchor_type` | — (none) | categorical, hard filter (suspension trainers only) | **Missing**, same root cause as `trainer_type` — the add-on has no concept of a suspension trainer, so it has no field for what anchor hardware the product ships with (door anchor vs. wraparound vs. permanent wall mount), even though TRX's own page treats this as the main thing that differs between its SKUs. |
| `locking_carabiner` | — (none) | boolean, minor filter | New, low priority. Small but real per TRX's own marketing copy; cheap suspension trainers often use a plain gate clip instead. |
| max user weight | `active-standard.jsonc` → `sizing.max_user_weight` (generic, already exists) | — | Not a new field. Worth flagging that for suspension trainers this is the one load-bearing number an expert would want and I could not find it published on TRX's own product page for the Pro4 — expect this field to be sparse for this category and `researched` rather than `listing` even for the market leader. |
| band/strap length | `supplies-standard.jsonc` → `sizing.dimensions.length` (generic, already exists) | — | Not a new field. Mini loops run about 12 in, big loop bands about 41 in, tube bands longer still (Garage Gym Reviews lengths above) — this is exactly the kind of per-variant number rule 2 says belongs in `sizing`, already provided for. |

Noise: nothing in the current three-field add-on reads as noise; it's too
short to have accumulated any. No field is proposed for removal.

## Branches

- Split 1 `trainer_type`, `when: ["suspension trainer"]` → `then_ask:
  [anchor_type, locking_carabiner]`, `makes_irrelevant: [band_type,
  resistance_tier, resistance_level, resistance_value, band_material,
  contains_latex, band_thickness]`. Traced to: a suspension trainer has no
  elastic band (Wikipedia suspension-training definition: "ropes and webbing,"
  no mention of elastic resistance), so none of the band-only facets apply —
  stated directly in notes above and in the mechanism's two-family split.
- Split 1, `when: ["stretchy band"]` → `then_ask: [band_type, resistance_tier]`,
  `makes_irrelevant: [anchor_type, locking_carabiner]`. Traced to: anchor
  hardware and carabiners are TRX-page facts about suspension trainers only
  (see sources above); a band has neither.
- Split 2 `band_type` has no branch on the "loop with no handles" leg. I
  considered one (to say handle grip material becomes irrelevant) but dropped
  it — that facet never made it into the register in the first place (see
  Seed §2), so there is nothing to make irrelevant on that leg, and the
  register follows the brief's rule to write a branch only where the answer
  really changes the path.
- Split 2, `when: ["tube with grip handles"]` → `then_ask: [band_thickness]`,
  chain: REP Fitness's tube bands print thickness in mm and no resistance
  figure in lb (Garage Gym Reviews, verbatim above) → when a band is a tube
  with handles, thickness is often the *only* quantitative spec available, so
  it's worth asking/showing specifically on this branch even though it's a
  lower-priority annotation generally. Traced to the exact sentence quoted
  above ("Doesn't tell you the resistance tension in pounds").
- Split 3 `resistance_tier`, `when: ["serious strength or pull-up assist"]` →
  `then_ask: [resistance_value]`, `makes_irrelevant: []`. Chain: heavy/power
  loop bands are the ones brands print a pound figure on (Titan "stamped with
  their specific resistance range," Rogue "eight different resistance totals")
  — both stated verbatim above — so asking for the actual lb value is useful
  specifically once a buyer says they want the heavy-power tier; at the light
  end, buyers answer with a tier name (Iron Bull's "extra-light" etc.), not a
  number, since mini bands commonly carry no lb figure at all.
- I considered a branch from `resistance_tier` to `band_material` (heavier
  bands favor natural latex for recoil durability) but found no source that
  states a rule connecting tier to material — Living.Fit's 250 lb top band and
  Iron Bull's mini bands are both "100%"/"premium" latex, so material doesn't
  track tier in the data I have. Dropped.

## Trimmed detail

- The Performance Health page's full "Trusted Progression" explanation,
  including the named academic (Juan Carlos Colado, PhD, University of
  Valencia) and the 25%/40% step-up rule, is condensed to one sentence in
  `mechanism.plain` to fit the 150-word cap; the full quote is above under
  Sources.
- Garage Gym Reviews' full per-product scoring (durability/materials/
  versatility/value/customer-experience, each out of 5, for six different
  products) is far more granular than anything that fits in
  `why_experts_care` (80-word cap); I kept only the comparative facts
  (ranges, lengths, thicknesses, the pull-up-assist versatility complaint)
  that map onto specific facets, not the star ratings themselves.
- TRX's anchor catalog describes five distinct accessories (Xmount, door
  anchor, suspension anchor, Xtender, Invizi-Mount); `anchor_type`'s value
  list keeps the three a buyer actually chooses between at purchase
  (door/wraparound/permanent-mount) and treats the Xtender as an accessory
  for the wraparound/mount values rather than a fourth value, since it's an
  extension piece, not an anchoring method on its own.

## Script and source problems

- WebSearch reported its 200-call session budget already exhausted before I
  issued a single query in this run (first four attempts all returned the same
  "session has used its web search budget" message). I could not get it
  re-enabled and worked entirely from direct fetches per the brief's fallback
  instruction.
- `WebFetch` 404'd on every URL I guessed for theraband.com, performancehealth.com
  and trxtraining.com (it appears to resolve a slightly different path or hit a
  bot wall that curl with a browser user-agent does not), so I switched to curl
  for every brand and retailer page below and used `WebFetch` only for
  Wikipedia, which it handled fine.
- DuckDuckGo Lite (`html.duckduckgo.com/html/`) returned an anomaly/bot-check
  page with no results on the one query I tried. Bing returned a results page
  for a `site:` query, but for a site-restricted query it silently ignored the
  `site:` operator and returned unrelated autosuggest/definition rows (e.g.
  "Car suspension - Wikipedia" for `site:garagegymreviews.com suspension
  trainer`) rather than an error, which is worth flagging: a results page that
  looks well-formed but has silently dropped the site filter is a trap for
  this kind of research unless every row's domain is checked against the
  intended site, which I did (none matched, so I discarded the page).
- `cpsc.gov`'s recall search and `roguefitness.com`'s product pages both
  returned HTTP 403 to curl with a browser user agent; I did not find a working
  route to either and have not cited either site. I could not find a published
  maximum-user-weight figure for any suspension trainer in the sources I could
  reach; I'm treating that absence as a finding (see the register's judgement
  on it) rather than continuing to search for a number that may not be
  published anywhere reachable.
- My first attempt to strip `<script>`/`<style>` tags from the Garage Gym
  Reviews page with a single non-greedy regex (`<script.*?</script>`, `re.S`)
  produced almost no text (the page has 71 `<script` opens and 69 `</script>`
  closes — an imbalance, likely from a script tag's own content containing the
  literal string `</script>` inside a JS string). I rewrote the stripper as a
  tag-by-tag scan (find `<script`, find the next `</script>`, repeat) rather
  than a single regex; this is a note for my own research process, not a bug
  in the skill's own scripts, which I did not modify.
- `validate.py`, `render.py` and `viewer.py` ran clean on the first try with no
  modification needed; no problem to report there.

## Corrections (2026-10-26)

- `band_length.range.typical` dropped the unsupported "longer for tube bands" clause — the cited source's only tube band (REP Fitness) has length marked "Not disclosed," so nothing in `garagegymreviews_bands` backs that clause.
- `resistance_value.evidence` dropped `theraband_performance_health` — that page's own flat bands top out at 14.2 lb, which contradicts rather than supports the "roughly 250 lb" figure; it stays cited on the mechanism's elongation claim instead.
- `mechanism.plain` rescoped "often double the resting length" to name TheraBand specifically, since only one brand's page states its own rating stretch.
- Added `band_length` to `trainer_type`'s suspension-trainer branch `makes_irrelevant` — it is a band-only facet by its own definition, same as the seven facets already listed there.
- Widened `band_type`'s split question and `cold_start_question` from a loop-vs-tube binary to name all four of the facet's values, since the old wording silently dropped fabric loop and figure-8 as answerable options.
- Reclassified `anchor_type` and `locking_carabiner` from `source: listing` to `researched` — notes.md's own admission is that no facet here was confirmed on an actual third-party retail listing, only on TRX's DTC pages, and `locking_carabiner`'s medium backfill cost and uncertain-absence hint were already researched-facet language.
- `judgements[3]` (no ASTM/EN standard) note rewritten to state plainly why no `evidence` is listed — ASTM's search is JS-rendered and CPSC blocked the fetch, so neither gave a citable negative-result page — rather than leaving the empty array unexplained.
- Rejected: did not pursue a second source for `resistance_value`'s 250 lb figure or for a tube-band length figure (check.md offered dropping the bad citation as an equally valid alternative); did not add new branches for `band_type`'s "fabric loop"/"figure-8" values, since widening the question was the other option check.md itself offered and no source states a distinct next-ask for either value; left `trainer_type` and `band_material` as `source: listing` since the checker's own read found those two "probably safe in practice" unlike the other two.
