Skip to content

docs: working context for the RTL8733B backend - #395

Merged
josephnef merged 2 commits into
masterfrom
rtl8733b-working-context
Aug 13, 2026
Merged

docs: working context for the RTL8733B backend#395
josephnef merged 2 commits into
masterfrom
rtl8733b-working-context

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

Summary

The RTL8733B merge (#388) added a fifth hardware backend but left the auto-loaded guidance describing four. The result is a cross-cutting file that contradicts the tree it describes, and — more damaging for an agent reading it — several blanket "every generation" claims that are now false on the new part. This closes both, and adds the src/rtl8733b/CLAUDE.md that every other HAL subtree has.

Docs only; no code touched.

Root CLAUDE.md

Structural, previously stale:

  • "Four chip generations" → five hardware backends, with an RTL8733B entry.
  • src/{...}/ nested-file list, the per-backend HAL list, and DEVOURER_8733B in the per-chip options.
  • The device-class list, which was missing RtlKestrelDevice as well as Rtl8733bDevice.
  • Naming traps: RTL8733BU is USB and supported, RTL8733BS is the SDIO sibling with no transport here — the same shape of trap as the existing 8821AU and 8822B/C entries.

Claims the new backend makes false, now scoped to the four Jaguar/Kestrel generations: FastRetune, TSF/beacons, the three runtime TX-power knobs, rx.path per-chain telemetry, and CCA disable.

Rather than repeat "except RTL8733B" five times, the underlying rule is stated once at the factory description: optional device methods are virtual with not-ported defaults, not pure virtual, so a backend that hasn't ported a feature inherits false/0/a full-path fallback rather than a fake. SetCcaMode is called out as the deliberate exception — it is pure virtual precisely so no backend can silently no-op it.

Two facts earned during the port that are genuinely cross-cutting, not 8733B trivia:

  • An aggregate larger than one URB gets split by xHCI, descriptor tail and body landing in separate completions. This sat in the MTK bullet as a rule ("never let an aggregate exceed the URB size"); the RTL8733B is now the worked example, including the static_assert that ties the device cap and the URB floor together so neither can be raised alone.
  • Nothing may read a register per frame on the send path. One thermal read — 3 RF writes + a 15 µs settle + an RF read — measured 2.51 ms of a 2.71 ms per-frame budget on USB high speed. Labelled as one bench and one part, with the note that a USB3 host would divide it; the shape is the transferable part, not the number.

New src/rtl8733b/CLAUDE.md

Follows the existing subtree files: HAL layout, dispatch, chip facts, then what is not ported. The parts worth having written down are the ones that cost time to learn — the 40-byte descriptor and its inverted checksum polarity (the opposite of some sibling parts), the 12 KiB aggregate invariant, the TSSI table-switch cost and the settling behaviour that makes a fast rate-switching run misreport power, EFUSE address-space exhaustion being success rather than corruption, and why the power-sequence teardown flag is armed before the attempt.

On accuracy

I fact-checked every technical claim in both files against the source before committing, and it caught two of my own errors worth naming:

  • I had written that three admission predicates are shared by both the SetTxMode and radiotap paths "so the two cannot drift". legacy_request_supported_8733b is in fact only reachable via SetTxMode; the radiotap RATE branch is constrained downstream by valid_tx_desc_config's range check instead. The file now documents the asymmetry rather than an invariant that does not hold — adequate today only because the radiotap RATE field cannot express SGI/LDPC/STBC.
  • I had repeated the in-source comment's claim that the TSSI transition rolls back exactly on failure. It does not: enable_tssi_tracking restores its own snapshot, but the transition as a whole leaves tracking off and the caller tears the session down. That is a safe design and now described as what it is. The source comment at select_tssi_rate_table still says "exact rollback" — worth a look, since it is the code's own description that is misleading.

All four bench figures are marked as coming from the single validation unit with no in-repo oracle, per the standing rule about not quoting a measurement as though it generalizes.

Follow-up to #388. Deferred hardware work is tracked in #390-#394.

The RTL8733B merge added a fifth hardware backend but left the auto-loaded
guidance describing four, so the cross-cutting file now contradicts the tree
it describes and several blanket "every generation" claims are false on the
new part.

Root CLAUDE.md: five backends with an RTL8733B entry, the subtree list, the
DEVOURER_8733B option, the device-class list (RtlKestrelDevice was missing
too), and the naming trap for the BS/BU split. Scope the claims the new
backend breaks — FastRetune, TSF/beacons, the runtime TX-power knobs, rx.path
and CCA disable are the four Jaguar/Kestrel generations only. Optional device
methods are virtual with not-ported defaults rather than pure virtual, which
is the general reason a backend can be missing a feature without saying so;
state that once at the factory description instead of per feature.

Two cross-cutting facts earned during the port: an aggregate that exceeds one
URB gets split by xHCI with the descriptor tail and body in separate
completions (the RTL8733B is the worked example, and its cap and URB floor are
tied by a static_assert so neither can move alone), and nothing may read a
register per frame on the send path — one thermal read measured 93% of the
per-frame budget on USB high speed.

src/rtl8733b/CLAUDE.md: the subtree file every other HAL has. Descriptor
geometry and checksum polarity, the aggregate invariant, the TSSI table-switch
cost and its settling behaviour, EFUSE exhaustion semantics, the power-sequence
teardown ordering, and the admission contract — including which predicates the
radiotap path does not share, so the next reader does not assume the legacy
paths are kept in step by construction.

The bench figures are labelled as single-unit with no in-repo oracle, because
the whole backend rests on one module.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Document RTL8733B backend context and update root guidance

📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Update root CLAUDE.md to reflect five backends, including RTL8733B, and correct scoping claims
• Document feature fallbacks and exceptions (not-ported virtual defaults vs pure-virtual SetCcaMode)
• Add src/rtl8733b/CLAUDE.md capturing HAL layout, invariants, and unported areas
Diagram

graph TD
  A(["Claude Code / agent"]) --> B["CLAUDE.md (root)"] --> C{{"IRtlDevice defaults & contracts"}} --> F["HAL backends"]
  B --> D["src/rtl8733b/CLAUDE.md"] --> F
  subgraph Legend
    direction LR
    _actor(["Actor"]) ~~~ _doc["Documentation"] ~~~ _contract{{"Contract / rule"}} ~~~ _comp["Component"]
  end
Loading
High-Level Assessment

The chosen approach—fixing the root cross-cutting guidance and adding a per-backend CLAUDE.md for RTL8733B—matches the repo’s existing documentation architecture and avoids duplicating backend-specific caveats throughout the root file. Considered but not pursued: generating the backend list automatically from the tree, which would reduce drift but adds tooling complexity and still wouldn’t capture nuanced feature-scoping and behavioral exceptions.

Files changed (2) +231 / -39

Documentation (2) +231 / -39
CLAUDE.mdUpdate cross-cutting guidance for RTL8733B and rescope generation-wide claims +83/-39

Update cross-cutting guidance for RTL8733B and rescope generation-wide claims

• Updates the repository-wide CLAUDE.md to reflect five hardware backends (adds RTL8733B), expands naming-trap guidance (8733BU vs 8733BS), and adds the missing device-class entries. Rescopes several previously blanket "every generation" statements to Jaguar/Kestrel only, and documents the general rule that optional device methods use not-ported defaults (with SetCcaMode called out as intentionally pure virtual). Adds two new cross-cutting performance/USB-path caveats: xHCI URB splitting risks and avoiding per-frame register reads on the send path.

CLAUDE.md

CLAUDE.mdAdd RTL8733B backend working context and invariants +148/-0

Add RTL8733B backend working context and invariants

• Introduces the per-subtree CLAUDE.md for RTL8733B, describing HAL layout, dispatch/identity safety rules, descriptor geometry and checksum behavior, aggregation/URB invariants, TSSI table-switch costs and settling behavior, EFUSE parsing semantics, and power sequencing rationale. Clearly enumerates what is not ported (TSF/beacons, ACK/A-MPDU, FastRetune, runtime TX power levers, rx.path telemetry, CCA disable) and how those map to IRtlDevice defaults vs SetCcaMode’s exception, plus validation/measurement provenance constraints.

src/rtl8733b/CLAUDE.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 13, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. CLAUDE.md duplicates header comments ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
src/rtl8733b/CLAUDE.md re-documents the RTL8733B TX admission contract that is already documented
in header doc-comments, increasing drift risk. Per the checklist, CLAUDE files should link to the
authoritative headers instead of restating their semantics.
Code

src/rtl8733b/CLAUDE.md[R110-113]

+- Refused: SGI (a descriptor with the short-GI bit set submitted successfully,
+  but an independent RTL8812AU witness decoded the probes as **long GI** — the
+  descriptor and the air disagree, and the reason is not yet understood), LDPC
+  and STBC (only forced-global-BCC operation has passed witnessed injection;
Evidence
PR Compliance ID 13 requires CLAUDE.md files to avoid duplicating semantics that are already
documented in header doc-comments. The new src/rtl8733b/CLAUDE.md restates the same
admission/refusal rationale that is already documented directly in
src/rtl8733b/TxDescriptor8733b.h, rather than linking to it as the authoritative source.

CLAUDE.md: Do Not Duplicate Existing Header Doc-Comments in CLAUDE.md Files: CLAUDE.md: Do Not Duplicate Existing Header Doc-Comments in CLAUDE.md Files: CLAUDE.md: Do Not Duplicate Existing Header Doc-Comments in CLAUDE.md Files: CLAUDE.md: Do Not Duplicate Existing Header Doc-Comments in CLAUDE.md Files
src/rtl8733b/CLAUDE.md[87-115]
src/rtl8733b/TxDescriptor8733b.h[35-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`src/rtl8733b/CLAUDE.md` duplicates API/semantic documentation that already exists as header doc-comments (notably in `TxDescriptor8733b.h`). This violates the single-source-of-truth documentation rule and creates a maintenance hazard where the CLAUDE text and the header can diverge.
## Issue Context
The compliance checklist requires CLAUDE.md files to avoid copying/paraphrasing header doc-comments and to link to the header(s) instead.
## Fix Focus Areas
- src/rtl8733b/CLAUDE.md[87-115]
- src/rtl8733b/TxDescriptor8733b.h[35-46]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. disable_cca silently ignored ✓ Resolved 📎 Requirement gap ≡ Correctness
Description
The RTL8733B bring-up path does not apply _cfg.tuning.disable_cca nor emit a bring-up warning, so
the knob can be set but vanishes silently. This violates the requirement to avoid silently dropping
disable_cca behavior on RTL8733B.
Code

src/rtl8733b/CLAUDE.md[R127-129]

+`DeviceConfig::tuning::disable_cca` is currently dropped at bring-up here
+rather than refused, which is the one place a request still vanishes without a
+word.
Evidence
PR Compliance ID 5 requires that _cfg.tuning.disable_cca is not silently dropped at bring-up and
instead is implemented or produces an explicit warning. The newly added RTL8733B CLAUDE.md
explicitly states the option is currently dropped without notice, and the RTL8733B init paths shown
do not reference/apply the knob, while SetCcaMode(true) is a loud refusal separate from bring-up.

RTL8733B CCA control: Resolve bring-up config asymmetry for disable_cca and ensure explicit warn/behavior
src/rtl8733b/CLAUDE.md[127-129]
src/rtl8733b/Rtl8733bDevice.cpp[78-126]
src/rtl8733b/Rtl8733bDevice.cpp[563-584]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
RTL8733B currently drops `DeviceConfig::tuning::disable_cca` during bring-up without applying it and without an explicit warning, creating inconsistent behavior versus the runtime `SetCcaMode(true)` refusal path.
## Issue Context
Compliance requires that bring-up does not silently ignore `disable_cca`: either implement it with verification/readback, or warn explicitly that it is unsupported/unvalidated and will not be applied.
## Fix Focus Areas
- src/rtl8733b/Rtl8733bDevice.cpp[78-130]
- src/rtl8733b/Rtl8733bDevice.cpp[563-584]
- src/rtl8733b/CLAUDE.md[116-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unbacked ~5 dB RF claim ✓ Resolved 📎 Requirement gap ≡ Correctness
Description
The new RTL8733B documentation states an on-air power delta (~5 dB) despite also stating no SDR
was available, which reads as an RF-domain performance measurement without the required SDR
methodology. This should be removed or clearly deferred to SDR-based characterization work.
Code

src/rtl8733b/CLAUDE.md[R63-66]

+- **The loop needs settling time.** Alternating CCK and OFDM at ~9 ms/frame
+  leaves CCK airing ~5 dB above its settled level; the same stream paced to
+  86 ms/frame lands on the settled value. Any power measurement taken during a
+  fast rate-switching run is measuring the tracking loop, not the transmitter.
Evidence
PR Compliance ID 6 requires RTL8733B documentation to avoid RF-domain measurement claims prior to
SDR characterization. The new text asserts a specific dB power difference while also stating that no
SDR was available, which does not meet the prerequisite for RF-domain quantified claims.

RTL8733B SDR characterization prerequisite: Do not claim RF-domain performance without SDR measurements
src/rtl8733b/CLAUDE.md[63-66]
src/rtl8733b/CLAUDE.md[135-137]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`src/rtl8733b/CLAUDE.md` includes an RF-domain numeric claim (`~5 dB`) while also stating that no SDR was available. The compliance rule requires avoiding RF-domain performance claims before SDR-based characterization exists.
## Issue Context
The repository can still describe qualitative behavior (e.g., “significant transient overshoot / settling required”) without asserting dB numbers, or it can defer the numeric value to `docs/rtl8733b.md` after SDR scripts/methodology are committed.
## Fix Focus Areas
- src/rtl8733b/CLAUDE.md[63-66]
- src/rtl8733b/CLAUDE.md[133-137]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/rtl8733b/CLAUDE.md Outdated
Comment thread src/rtl8733b/CLAUDE.md Outdated
Comment thread src/rtl8733b/CLAUDE.md Outdated
…e header

Review follow-ups.

InitWrite warns when tuning.disable_cca is set. SetCcaMode(true) already
refuses loudly, so the config path was the one door where the same request
vanished silently — an operator would believe carrier-sense was off and read
the resulting deferral as a transmitter fault. Warn rather than throw: the
knob is on by default for the streamtx downlink, and refusing to bring TX up
over an unported optimisation is the worse trade.

The subtree CLAUDE.md restated the admission contract that TxDescriptor8733b.h
already doc-comments, against the standing rule about not duplicating headers.
It now points at the header and keeps only what the header cannot say: that
the two legacy paths are not held in step by a shared predicate, and that the
CCK band gate closes end-to-end.

Drop the ~5 dB TSSI overshoot figure. No SDR has been on this part, so an
RF-domain magnitude is not ours to quote; the settling behaviour is stated
qualitatively with the measurement deferred. The timing figures that remain
are register-sequence and USB-transfer costs, and say so.
@josephnef
josephnef merged commit 64d77b5 into master Aug 13, 2026
27 checks passed
@josephnef
josephnef deleted the rtl8733b-working-context branch August 13, 2026 06:37
josephnef pushed a commit that referenced this pull request Aug 14, 2026
…e-table knob (#396)

The two post-merge findings, rebased onto master and answering the
review points on both. Fixes #389.

## The send path no longer touches a register

This backend was the only one doing register I/O inside `send_packet` —
it re-selected the CCK/OFDM thermal-compensation curve on every
rate-class crossing at 84 ms / 136 USB round trips (#389).
`configure_tx_power` now picks the curve once per channel set and leaves
it, which is what the vendor does: `_halrf_tssi_set_tmeter_tbl_8733b` is
reachable only from full TSSI setup, keyed on `phydm_get_tx_rate` at
that instant, never re-selected at runtime.

Measured on the DUT — alternating CCK/OFDM, 200 frames: **19.69 s → 2.82
s, 200 table switches → 0**, TSSI still enabled. `send_packet` now has
no conditional register-I/O path at all.

The TSSI loop itself stays on wherever the EFUSE is TSSI-offset PG,
because there it *is* the TX-power control. An early cut made TSSI
opt-in with a flat-index fallback; witnessed, that could not carry HT at
all — **MCS7, 300/300 submitted, 0 captured, twice**.

## No runtime table switch, and the measurement that closes it

The first revisions carried `DEVOURER_TSSI_RATE_TABLE` as an opt-in for
per-crossing switching, on the argument that the hot thermal-delta
regime is where the two curves are *designed* to differ. Both reviewers
landed on "probably delete it". A heat soak turned that from a judgement
call into a measurement, so **the knob is deleted** — it could never
have done anything on this part.

**The two curves are bit-identical until thermal delta +18.**
Reconstructing the plan against the vendor 64-entry layout: the swing
ramp starts at index 18 (CCK swing 0 for 0..17, then 3,3,5…; the OFDM
plan is all-zero), and every word either side of the baseline is zero in
both tables. Below +18 the CCK table and the OFDM table are the same
bits.

**The part plateaus at +8.** Five-minute max-duty MCS7 soak
(`DEVOURER_TX_GAP_US=0`, ~5000 fps submission), thermal polled every 2
s:

```
raw 33 -> 40   delta +1 -> +8
trajectory: 33/1, 37/5, 38/6, 39/7, 39/7, 39/7, 40/8, 40/8, 40/8, 40/8, 40/8
```

It stopped climbing after about two minutes and held +8 for the
remaining three — asymptotic, not still-rising-when-I-stopped. Less than
half the delta needed for a single table entry to differ. A runtime
switch would therefore spend 84 ms and 136 USB register round trips,
inside `send_packet`, to install a table bit-identical to the one
already loaded.

Deleted with it: `select_tssi_rate_table`, the `DeviceConfig` field, the
env translation, and `_tx_fatal` — whose only producer was that
function's failure path, so keeping it would have left a
permanently-null member guarding a dead branch. Re-verified on air after
the deletion: MCS7 279/300, 1 Mbps CCK 300/300 — unchanged from 277/300
and 300/300 before it.

**+8 is a property of this unit, not of the silicon.** Bare module, open
air, room ambient, and submission-rate duty rather than measured
radiated duty. A sealed BL-M8733BU2 at high ambient could plausibly
reach +18 where this one cannot. The **+18 threshold** is the durable
half — it comes from the vendor table contents, not the unit. So the
code and docs state the reasoning rather than the conclusion, and both
point at #389 for the validated in-place implementation (13.8 ms,
tracking left enabled) as the thing to revisit if a board ever does get
hot enough; #390's heat-soak work now has a specific number to test
against.

## `disable_cca`

Took the reviewer's call — kept my wording naming both spellings,
dropped theirs. One placement change on top: it sits in
`bring_up_to_phy` rather than `InitWrite`, so an RX-only session that
set the knob is told too, and so it fires exactly once per bring-up
rather than twice now that both existed. Verified on hardware: fires
once, bring-up completes, TX proceeds.

## Docs

`src/rtl8733b/CLAUDE.md` from #395 described the 84 ms as an
unconditional per-frame cost and stated the table cannot be changed
while tracking is enabled — both now wrong. Rewritten, pointing at #389.

Follow-up review pass also removed the drift this PR would otherwise
have introduced: both CLAUDE.md sites still placed the `disable_cca`
warning at `InitWrite`, and `docs/rtl8733b.md` still narrated two runs
in terms of per-frame TSSI table switching — a path this tree deletes,
so those runs are not reproducible as described. The rate-coverage and
thermal evidence stays; the mechanism framing is gone.

## The witness qualification you suggested

Cheap and worth it. Sweeping the RTL8812AU across the HT ladder, 300
frames each:

| rate | delivered | witness RSSI |
|---|---|---|
| MCS0 | 270 / 300 | 57.8 |
| MCS1 | 300 / 300 | 65.0 |
| MCS3 | 300 / 300 | 65.3 |
| MCS5 | 300 / 300 | 65.2 |
| MCS6 | 296 / 300 | 65.1 |
| MCS7 | 277 / 300 | 60.3 |

Flat at 100% through MCS5, so the witness is not measuring itself — a
receiver at its cliff falls off progressively at the top rather than
dipping at both ends. Both low readings also carried 5-7 units less RSSI
than the flat middle, which places the variation in per-run link
conditions.

## Checks

53/53, RTL8733B-only 49/49, RTL8733B-only ASan+UBSan 49/49. Hardware
verified on the same one-unit DUT: send-path switch count, the heat
soak, the single `disable_cca` warning, and the ladder above.

Still no SDR on this part, so nothing here asserts an RF-domain
magnitude.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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