Skip to content

fix(board): align the rev2 board profile with the frozen hardware design - #19

Merged
cryptotomte merged 7 commits into
mainfrom
fix/rev2-pin-map
Aug 12, 2026
Merged

fix(board): align the rev2 board profile with the frozen hardware design#19
cryptotomte merged 7 commits into
mainfrom
fix/rev2-pin-map

Conversation

@cryptotomte

Copy link
Copy Markdown
Owner

Summary

Spec-kit feature 012 (specs/012-rev2-pin-map/). The rev2 schematic froze 2026-08-12; this brings the firmware board profile into line with it:

  • Removes the phantom buttons. rev2 defined BTN_MANUAL/BTN_CONFIG (IO5/IO18) — neither exists on the board, and IO18 is EXP_SCK, the expansion header's SPI clock, which app_main polled at every boot to decide provisioning entry. Expansion-bus activity could drop the node into provisioning mode. Buttons are now capability-flagged (BOARD_HAS_BTN_*: rev1 = 1 unchanged, rev2 = 0 with the pin macros deleted — unguarded references fail the build, same pattern as the reservoir pump).
  • Adds the three missing frozen signals behind capability flags: VBAT_SENSE (IO34, ADC1, input-only), PWR_PG (IO35, input-only, externally pulled up), SENS_PWR_EN (IO25, output; rail is OFF by hardware default — sequencing is PR-14 scope).
  • Retires the stale annotations: 11 TODO(SYNC1) markers and the "provisionally mirrors rev 1" header replaced with citations of the frozen SYNC 1 map; solar INA226 comment corrected (populated, decision 2026-06-20 / gate cleared 2026-08-10).
  • Hardening from review: contract TUs now pin every frozen macro VALUE on both boards (the durable FR-002 guard); collision checks extended to the three new pins (mutation-proven: SENS_PWR_EN on the pump gate now fails the build); all eight capability flags definedness-checked ahead of the checks they gate; rev2-only expansion-set reservation (IO18/19/23/4/27); latent IO25 cross-check; maintenance sentinel.

Safety

Constitution principle I verified by review: pumps_force_off() and its call site are byte-identical — the diff touches nothing in the pump boot-safety path. The credentials-absent provisioning path is unchanged on both boards; on rev2 it is now the sole provisioning trigger (the board has no config button — accepted at CP2, a BOOT-button trigger is a possible PR-14+ feature).

Verification

  • Host suite: 316 tests, 0 failures (contract violations are build failures — both TUs compile the real header per target).
  • Both board targets build green in the pinned espressif/idf:v6.0.1 container; CONFIG_BOARD_* verified in sdkconfig.
  • rev1 no-op evidence: full macro-surface dump (clang++ -dM) before/after shows rev1 gained ONLY the five new BOARD_HAS_* flags — zero values changed; the rev1 image is byte-size identical to the pre-feature baseline. Byte-identity (sha256) cannot be demonstrated because CONFIG_APP_REPRODUCIBLE_BUILD is off (ESP-IDF embeds build date/time in the app descriptor); the durable FR-002 guard is the frozen-value static_asserts added to both contract TUs.
  • Guard efficacy mutation-tested (18 cases across review + fix verification): wrong pin values, removed flags, expansion collisions and the unreachable IO25 cross-check all fail the build with their own diagnostics.

Merge order

Depends on #18 (merged): board.h cites hardware/rev2/design-notes/02-mcu.md §2.2, introduced there.

Review trail

Full workflow in specs/012-rev2-pin-map/ (spec → plan → tasks → analyze). Three review agents (code/tests/comments) + fixer + verification re-review (APPROVE); checkpoint docs CP2/CP3 signed off by Paul 2026-08-12. No HIL required — compile-time facts for a board that does not exist yet plus a provably unchanged rev1; bench verification of the new signals lands with PR-14 bring-up.

🤖 Generated with Claude Code

cryptotomte and others added 7 commits August 12, 2026 14:49
…ware

Spec, plan, research, data model, contract and tasks for closing the
gap between the frozen rev2 schematic (2026-08-12) and the firmware
board profile. Spec was rewritten same-day after a codebase survey
showed the reservoir-pump divergence was already fixed in feature 006;
the real remaining scope is the phantom buttons (BTN_CONFIG polled on
EXP_SCK/IO18 at boot), three missing power signals, and stale SYNC1
markers. Analyze pass: 100% coverage, no critical findings; quickstart
build commands corrected to CI's canonical forms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rev2 profile defined BTN_MANUAL=5 and BTN_CONFIG=18, and the boot path
configured IO18 as an input and read it to decide whether to force WiFi
provisioning. The frozen rev2 board has neither button (only BOOT/RESET and
the status LED), and IO18 is EXP_SCK on the expansion header J7 — so on real
hardware expansion-bus traffic could be misread as a held config button, and
core firmware claimed a pin the design reserves.

- board.h: BOARD_HAS_BTN_MANUAL / BOARD_HAS_BTN_CONFIG on both boards
  (rev1 = 1 with pins 5/18 unchanged, rev2 = 0 with the pin macros
  deliberately undefined — the RS485-DE / reservoir-pump enforcement
  pattern, so unguarded references fail the build).
- board.h sanity: flag<->pin consistency pairs for both button flags, the
  button distinctness check guarded by the flags, and a rev2-ONLY
  expansion-reservation check erroring if any defined pin lands on
  IO18/19/23/4/27 (rev1 legitimately uses 18 and 27 — the reservation is a
  property of the rev2 board, not of the firmware).
- app_main: the config-button read, its poll loop and LED feedback compile
  only under BOARD_HAS_BTN_CONFIG; buttonless boards fall back to the
  credentials-absent provisioning path (feature 007), unchanged. The pump
  boot fail-safe is untouched.
- Contract TUs pin both sides: rev1 buttons present with frozen values
  (FR-002 regression guard), rev2 buttons absent plus expansion
  disjointness for every core pin.

Spec: specs/012-rev2-pin-map (US1, FR-001..004, FR-007)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The frozen rev2 design provides three signals the board profile did not
mention, forcing the next developer back to the schematic (project rule:
pin tables live only in components/board/).

- BOARD_HAS_VBAT_SENSE / BOARD_PIN_VBAT_SENSE 34 — battery divider on an
  input-only ADC1 pin (ADC2 is unusable with WiFi up); readings compress
  above ~2.45 V at the pin, FW-1.
- BOARD_HAS_PWR_PG / BOARD_PIN_PWR_PG 35 — buck power-good, input-only,
  open-drain with an external pull-up; IO34-39 have no internal pulls, FW-6.
- BOARD_HAS_SENS_PWR_EN / BOARD_PIN_SENS_PWR_EN 25 — switched 12 V sensor
  domain. The rail is OFF by HARDWARE default (R61 holds the gate off while
  the GPIO is hi-Z), so this feature deliberately does not drive the pin;
  rail sequencing and the FW-3 settle are PR-14 scope.

All three carry the flag<->pin consistency pattern: rev1 defines the flags
at 0 with the pin macros absent, so an unguarded PR-14 reference fails the
rev1 build. Contract TUs pin both sides, and the new pins join the rev2
expansion-disjointness checks.

Spec: specs/012-rev2-pin-map (US2, FR-005, FR-007)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SYNC 1 has happened (2026-08-12: all sheets drawn, ERC clean, components
ordered) and every rev2 value in the profile matches the frozen contract, so
the 11 TODO(SYNC1) markers and the "GPIO numbers provisionally mirror rev 1"
header were actively misleading — they invite edits to values that are now
fixed by hardware.

- Each rev2 pin group cites hardware/rev2/design-notes/02-mcu.md §2.2
  SYNC 1 map (frozen 2026-08-12) once, at group level.
- I2C address map corrected: 0x41 is the solar INA226, POPULATED on this
  node per the 2026-08-12 decision (it was documented as a DNP footprint);
  driver support is PR-14. BME280 is 0x77 (SDO -> VDDIO, rev1 parity),
  and the note now says BOARD_INA226_ADDR names the pump monitor.
- The rev2 contract TU's copy of the old DNP claim is corrected too.

No macro values change in this commit.

Spec: specs/012-rev2-pin-map (US3, FR-006, SC-004)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ty flags

firmware/CLAUDE.md still told agents that rev2 pins were provisional behind
TODO(SYNC1) markers, and its capability-flag list predated feature 012.

- Board-revision section: rev2 pins are FROZEN and cite the SYNC 1 map;
  rev2 has no buttons and reserves IO18/19/23/4/27 for J7 (a rev2-only
  invariant — rev1 legitimately uses IO18/IO27).
- Capability-flag list extended with the five new flags, and the
  enforcement-pattern sentence now names which pin macros are undefined on
  which board. The rev2-only power/rail signals are noted as declared but
  consumer-less until PR-14.
- WiFi section: the boot config-button read is compiled out where
  BOARD_HAS_BTN_CONFIG == 0.

Verification notes for this feature (all in the pinned v6.0.1 container):
host suite 316 tests / 0 failures; both board targets build with the right
CONFIG_BOARD_* in sdkconfig and all five artifacts present; the rev1 image
is byte-size identical to the pre-feature baseline (0x103df0), which is the
practical evidence for the rev1 no-op requirement (FR-002). Negative proof
(quickstart §4): an unguarded BOARD_PIN_BTN_CONFIG reference added to the
rev2 contract TU fails the build ("was not declared in this scope") and was
reverted — the enforcement pattern bites.

Spec: specs/012-rev2-pin-map (polish, plan D4)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… gaps, correct citations

Hardening pass over the feature 012 review findings. The rev2 profile itself
was confirmed correct; these changes make its guarantees enforceable and its
provenance accurate. No pin VALUE changes: board.h gains only #if/#error
guards and comments.

- Pin the frozen macro VALUES in both contract TUs (FR-002's durable guard):
  rev1 I2C 21/22, RS485 16/17, DE 25, UART2, pump 26, LED 2; the mirror set
  for rev2. Previously only the values feature 012 touched were asserted, so
  a stray edit to a pre-existing pin passed the host suite.
- Extend the pin-distinctness net to the three new rev2 power/rail pins
  (VBAT_SENSE, PWR_PG, SENS_PWR_EN) against every core function pin and each
  other, under their capability flags. Mutation-proven: SENS_PWR_EN == 26
  (the pump gate) compiled silently before this.
- Require every capability flag to be DEFINED, not merely 0/1 — an undefined
  macro evaluates to 0 in #if with no diagnostic, silently deleting the
  behavior it gates and disabling the flag-guarded checks above.
- Add a maintenance sentinel to the rev2 section: the preprocessor cannot
  enumerate macros, so a new BOARD_PIN_* must be added by hand to the
  expansion-reservation check and to the rev2 contract TU.
- Correct the I2C address-map citation to 07-i2c-env.md §7.3 (§7.4 is open
  items), and the solar INA226 provenance to the 01-power.md §1.5 decision of
  2026-06-20 with the populate gate cleared 2026-08-10 (2026-08-12 is the
  schematic freeze, a different event).
- De-pair the expansion comment: SCK=IO18, MISO=IO19, MOSI=IO23, CS=IO4,
  IRQ=IO27 per 08-expansion.md §8.3 — "SCK/MOSI/MISO on IO18/19/23" read
  pairwise implied MOSI=IO19, which is wrong.

Verification: host suite 316 tests / 0 failures; both board targets build
green with CONFIG_BOARD_REV1_DEVKIT=y and CONFIG_BOARD_REV2=y respectively.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ntinel

Follow-up to 176be1e, from the verification re-review. board.h only; still
zero #define additions or removals.

- Move the capability-flag definedness check to the TOP of the sanity
  section, ahead of every flag-guarded check rather than after them. Those
  checks are gated on the very flags it validates, so an undefined flag could
  previously switch OFF the collision checks it was meant to enable and still
  reach the definedness error only afterwards. Ordering makes that
  structurally impossible. Placed above the reservoir-pump and RS485-DE
  guards too, not just the power/rail block — they have the same dependency.
- Add the latent SENS_PWR_EN vs RS485_DE cross-check, matching the existing
  double-guard pattern. Unreachable on both boards today (no board has both
  signals), but a future board combining them would put both on IO25 and
  collide silently. Verified to fire by synthetically granting rev1 a sensor
  rail on 25.
- Complete the maintenance sentinel: it listed only the two hand-maintained
  lists that predated it and omitted the third one the previous commit
  introduced — the eight-flag definedness check. Now covers new BOARD_HAS_*
  flags as well as new BOARD_PIN_*.
- Sentinel wording: "disjointness/frozen-value asserts" overstated the rev2
  TU, which asserts frozen values and expansion-set membership, not general
  pairwise disjointness. Corrected.

Verification: host suite 316 tests / 0 failures; rev2 target builds green
with CONFIG_BOARD_REV2=y.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cryptotomte
cryptotomte merged commit 814d31c into main Aug 12, 2026
3 checks passed
@cryptotomte
cryptotomte deleted the fix/rev2-pin-map branch August 12, 2026 15:44
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