AROYA AUTOMAIT DEEP AUDIT · IRRIGATION + GUARDRAILS

Cannapproach — Michael 3 Light room

Michael Nguyen's CCMS R&D facility. One flower room, 72 Blue Nerds in 1-gal coco, just flipped 2 days ago into Early Flower / Generative. This audit grades the AUTOMAIT irrigation program plus every guardrail against AROYA crop-steering best practice for the room's phase, substrate, and stated intent.
Facility ID4730 · org 3558 RoomMichael 3 Light (20167) · zone 1 (83331) Active HGM3 6/15-8/11 (155568) · day 2 of 21 Cultivar / countBlue Nerds · 72 plants SubstrateSOILLESS / COCO · 1 gal · 2 x 0.5 gph emitters Photoperiod12 / 12 · lights-on 18:00 local Audit run2026-06-16 01:57 UTC Cross-checkSDK ✓ · OpenCLI ✓ · MCP ✓ — three-way diff complete (see §6)

1 · Headline verdict

P0 Risk Flags
3
All three are structural contradictions in the AUTOMAIT config — not crop-performance issues
P1 Risk Flags
5
Steering targets & missing guardrails that will dampen results but won't crash the room
P2 Housekeeping
3
Broken recipes + Day-2 live-state observation
Hardware health
7 / 7 online
Gateway on WP5 · all 6 nodes ggVersion WP4 · batteries 98-100% · drip + drain instrumented

The three P0 contradictions to fix this week

  1. Panic floor identity: minVwc = 25%soil_moist.target_min = 25% — the room cannot achieve the deep generative dryback the phase is supposed to drive. The panic shot fires the moment the target is approached.
  2. EC ceiling contradiction: maxEcpw = 9 < pore_ec.target_max = 12 — AUTOMAIT refuses to allow the EC stack the room is configured to allow. Effective ceiling is 9, not 12.
  3. Zero alert thresholds: every alert_min / alert_max on every metric is null. Soft "outside-target" warnings only. No pages on a real excursion.

Two of the three are mathematical contradictions in a Generative phase — the room has been configured to do something the configuration itself prevents.

2 · Facility overview

Single-room R&D site

Cannapproach 4730 is Michael Nguyen's research environment for the CCMS controls product. Just one flower room ("Michael 3 Light", id 20167) with one zone (Zone 1, 83331). Substrate is COCO COIR, 1-gal pots, 72 plants, 2 emitters per plant at 0.5 gph. Lights are 12/12 — schedule starts 2026-06-15 at 18:00 local (just flipped yesterday). One AROYA irrigation controller is bound to the room (controller id 3245) — controller make/model not surfaced by the API, see §8.

Active harvest group

M3 6/15-8/11 (id 155568) — 72 plants of Blue Nerds, started 2026-06-14, planned harvest 2026-08-23 (70 days). Currently day 2 of 21 in Early Flower / Generative. Three planned phases — Early Flower / Generative (21d, active & confirmed) → Bulking / Vegetative 2 (28d, planned) → Ripening / Generative 2 (21d, planned).

Live state right now (2026-06-16T01:42Z)

Substrate VWC
21.57 %
Below panic floor (25%) AND target_min (25%) — see flag P0-3 / P2-10
Substrate EC
2.03 mS/cm
Half of target_min (4 mS/cm) — feed under-charged at HG start
Substrate temp
85.4 °F
+10 °F above ideal coco root zone — no guardrail set
DLI today (mean)
35.66 mol
Peak 66.76 mol/m²/d → over-driven for flower (target 45-55) · no guardrail set

48 h alert summary (from spa_get_computed_alerts)

MetricPeak/TroughTarget windowSevWindowInterpretation
soil_moist45.3225-44%warn2026-06-14 02:33 -> 2026-06-16 01:42 (~47h)Mild ceiling overshoot, transient post-irrigation peaks.
pore_ec3.974-12 mS/cmwarn2026-06-14 01:06 -> 2026-06-16 01:42 (~48h)Substrate EC has been BELOW the floor the entire phase. Feed EC under-charged at HG start.

Both alerts are consistent with a Day-2 flipped HG that hasn't yet been topped-up to feed EC. The configured panic floor SHOULD have triggered shots before VWC dropped this low; investigate whether AUTOMAIT is firing.

Device inventory

SerialModelFWBatteryLinkRoleStatus
H2110001280gatewayWP5 (gg=2)Mesh gateway🟢 online
H3310009775node + sq-521WP498 %100 %PAR/quantum light (B015881)🟢 online
H3440015384node + ter15WP4100 %100 %Substrate sensor #1 COCO🟢 online
H3440015384-2node + ter15WP4100 %100 %Substrate sensor #2 COCO🟢 online
H5200001003node + h520/flow_phWP4100 %76 %Runoff pH+EC (variant 7)🟢 online
H8200001002node + ter15 [DRIP]WP4100 %100 %Drip volume sensor🟢 online
H8200001002-2node + ter15 [DRAIN]WP4100 %100 %Drain volume sensor🟢 online

Gateway is on WP5 (ggVersion 2) — eligible for the new firmware regime. Mesh nodes show ggVersion null because they ride the gateway's protocol; they're on WP4 by inheritance. The h520 + flow_ph is variant 7 (pH + EC runoff sensor — a relatively new sensor model). DRIP and DRAIN nodes share serial H8200001002 (host) with two distinct ter15 children — this is the AROYA drip/drain rack, calibrated.

3 · Per-phase scorecard — irrigation program + guardrails

Each phase card below shows the four pillars AUTOMAIT cares about: steering intent (mode / value / P0-P3 timing), environmental target ranges (the soft windows), irrigation program (shot shape + cadence), and guardrails (the hard safety wall). Verdicts annotated inline.

Phase 1 - Early Flower / Generative 2026-06-14 -> 2026-07-05 - 21 days
✓ confirmed & active

Crop-steer intent

ModeGEN - steering value 3
P0 delay (after lights-on)60 min
P3 cutoff (before lights-off)120 min
Active irrigation window540 min/day (9.0 h)

Target ranges (env)

VPD1.0-1.2 kPa
Substrate VWC25-44 %
Substrate EC4-12 mS/cm
Air temp80-82 F

Irrigation program

First-shot duration3 min - 50 mL/plant
Subsequent-shot duration2 min - 33 mL/plant
Shot interval10-60 min
Drain goal5 %
Flush duration3 min

Guardrails (AUTOMAIT safety wall)

maxFillMinutes (daily cap)90 min/day
= 1.50 gal/plant/day max
maxEcpw (EC flush trigger)9 mS/cm
target_max EC = 12 mS/cm · ⚠ CLAMPS below target_max
minVwc (panic shot floor)25 %
target_min VWC = 25% · ⚠ identical to target floor - BLOCKS dryback
alert_min / alert_maxnull (all metrics)
no paging on extreme excursion
Phase 2 - Bulking / Vegetative 2 2026-07-05 -> 2026-08-02 - 28 days
planned / not yet confirmed

Crop-steer intent

ModeVEG - steering value 8
P0 delay (after lights-on)60 min
P3 cutoff (before lights-off)120 min
Active irrigation window540 min/day (9.0 h)

Target ranges (env)

VPD1.2-1.4 kPa
Substrate VWC30-65 %
Substrate EC3-7 mS/cm
Air temp75-80 F

Irrigation program

First-shot duration3 min - 50 mL/plant
Subsequent-shot duration2 min - 33 mL/plant
Shot interval15-30 min
Drain goal5 %
Flush duration3 min

Guardrails (AUTOMAIT safety wall)

maxFillMinutes (daily cap)120 min/day
= 2.00 gal/plant/day max
maxEcpw (EC flush trigger)6 mS/cm
target_max EC = 7 mS/cm · ⚠ CLAMPS below target_max
minVwc (panic shot floor)25 %
target_min VWC = 30% · ✓ dryback headroom
alert_min / alert_maxnull (all metrics)
no paging on extreme excursion
Phase 3 - Ripening / Generative 2 2026-08-02 -> 2026-08-23 - 21 days
planned / not yet confirmed

Crop-steer intent

ModeGEN - steering value 3
P0 delay (after lights-on)60 min
P3 cutoff (before lights-off)120 min
Active irrigation window540 min/day (9.0 h)

Target ranges (env)

VPD1.2-1.4 kPa
Substrate VWC25-55 %
Substrate EC3-6 mS/cm
Air temp70-77 F

Irrigation program

First-shot duration3 min - 50 mL/plant
Subsequent-shot duration2 min - 33 mL/plant
Shot interval10-60 min
Drain goal5 %
Flush duration3 min

Guardrails (AUTOMAIT safety wall)

maxFillMinutes (daily cap)90 min/day
= 1.50 gal/plant/day max
maxEcpw (EC flush trigger)9 mS/cm
target_max EC = 6 mS/cm · ✓ coherent
minVwc (panic shot floor)25 %
target_min VWC = 25% · ⚠ identical to target floor - BLOCKS dryback
alert_min / alert_maxnull (all metrics)
no paging on extreme excursion

Guardrail coherence matrix at a glance

Vertical axis = magnitude (% or mS/cm). Bars compare AROYA target ranges (lighter) to AUTOMAIT irrigation guardrails (darker) in the same units. Where the darker bar undercuts the lighter one, the AUTOMAIT guard CLAMPS BELOW the configured target intent — the source of the P0 contradictions.

4 · Risk flags · ranked P0 → P2

P0 = structural contradiction or silent failure mode — fix this week. P1 = steering correctness — fix this phase. P2 = housekeeping or transient observation.

P0minVwc panic floor (25%) == soil_moist target_min (25%)
Where: All phases - automatedScheduleSettings.{gen,veg}.minVwc = 0.25 vs target_ranges.soil_moist.target_min = 25
Risk: Yesterday the room dried back to 24.2% — below the 25% panic floor — before AUTOMAIT's rescue shot fired (17.4 pp absolute, 42% proportional — just over the generative-early-flower benchmark of 40% prop). The room is steering, but the panic floor is binding: any attempt to push DEEPER (50-60% prop, ~21-25 pp absolute) is clipped by the current 25% floor. Because minVwc = soil_moist target_min, the soft target alarm fires at the same level as the panic shot — the alert is redundant with the rescue.
Recommended fix: Drop minVwc to 0.18 (P1 early flower) / 0.20 (P2 bulking) / 0.15 (P3 ripening). With the same FC and ET regime as yesterday, that opens the predicted trough to ~19% and lifts absolute dryback into the 22-23 pp / 54% prop band — a real generative-early-flower shape rather than the at-the-edge 40% prop the room is hitting today. (Raising target_max to 50-55% is a downstream lever for Bulking when canopy transpiration grows and current ceiling becomes binding; under M3 day-1 transpiration the peak isn't hitting today's 44% ceiling yet, so widening it tomorrow doesn't add dryback.)
P0All alert_min / alert_max thresholds are NULL across every metric and phase
Where: target_ranges rows phase_id 1047772/1047773/1047774 - all four metrics in every phase
Risk: AROYA's alert system uses alert_min/alert_max for paging. With nulls, the grower gets no notification on extreme excursions - only soft 'outside target' warnings. A root-zone EC stack to 15 mS/cm or canopy temp spike to 95F would be silent.
Recommended fix: Set alert bands ~20-25% outside target. P1 example: VPD 1.0-1.2 -> alert 0.7/1.5; soil_moist 25-44 -> alert 18/55; pore_ec 4-12 -> alert 3/14; air_temp 80-82 -> alert 75/88.
P0maxEcpw (9 mS/cm) clamps below pore_ec target_max (12 mS/cm)
Where: P1 Early Flower irrigation_schedule.automatedScheduleSettings.gen.maxEcpw = 9 vs target_ranges.pore_ec.target_max = 12
Risk: Internal contradiction. The grower configured the room to ALLOW EC stacking up to 12 (aggressive early-flower generative) - but AUTOMAIT refuses to let EC pass 9 (fires flush shots). Effective ceiling is 9, not 12. EC stack capped 25% below the grower's stated intent.
Recommended fix: Either raise maxEcpw to 12 (match target window) OR drop pore_ec target_max to 9 (declare 9 as real intent). Recommendation: raise maxEcpw to 11 - preserves the aggressive stack while keeping a defensive flush trigger.
P1P0 delay only 60 min in Early Flower - too short for generative steering
Where: P1 Early Flower lightsBuffer = (60, 120) - first shot allowed 60 min after lights-on
Risk: Phase-target P0 delay for early flower generative is 120-240 min. At 60 min, the plant has barely begun transpiring before being topped up. Result: shallow morning dryback, dampened generative cue, less stretch control.
Recommended fix: Lengthen lightsBuffer[0] to 150 min (between phase-target floor 120 and a permissive 180). Keep 120 min lights-off buffer as-is.
P1Bulking phase drainGoal stays at 5% - too low to flush EC stack
Where: P2 Bulking automatedScheduleSettings.veg.drainGoal = 0.05
Risk: Bulking is the phase to pull substrate EC stack DOWN from the early-flower push (target 4-7 mS/cm). A 5% drain target wont carry enough leached salts to do that. EC stack will keep climbing into bulking, contradicting the veg-mode 'value: 8' aggressive vegetative steering intent.
Recommended fix: Raise bulking drainGoal to 0.20-0.30. Textbook bulking move - generous daily runoff refreshes root-zone EC and lets the plant pull turgor for cell expansion.
P1DLI running ~66 mol peak - no guardrail, no daily target
Where: PAR sensor sq-521 (B015881) installed and reporting - no light_ppfd/dli row in target_ranges
Risk: PAR sensor reports peak DLI ~67 mol/m2/d during photoperiod. Cannabis flower sweet spot is 40-55 (mid 45). 65+ is over-driven and pushes the room toward heat stress, water-stress masking, tip-burn risk - especially with air_temp ceiling at 82F.
Recommended fix: Either (a) add a light_ppfd or dli target row (target 800-1000 umol/s, alert 1200) and dial fixtures down, OR (b) tighten photoperiod to keep DLI 40-55. Sensor is here - use the data.
P1Substrate temperature: 85.4 F right now, no guardrail
Where: Live reading 2026-06-16T01:42Z - no soil_temp row in target_ranges any phase
Risk: Coco root-zone target is 65-72F (lights-on) and 60-65F (lights-off). 85F is dangerously warm - promotes root rot, suppresses transpiration, masks dryback signal. This is Day 2 baseline, not a transient spike.
Recommended fix: Add soil_temp target rows: P1 (65-75F), P2 (65-75F), P3 (60-70F). Investigate the heat source - under-bench heat, container colour, fixture proximity, dry substrate amplifying solar load.
P1Ripening VPD held at 1.2-1.4 - below standard 1.4-1.6 finishing window
Where: P3 Ripening target_ranges.vpd = 1.2-1.4
Risk: Standard ripening pushes VPD to 1.4-1.6 to drive metabolites and terpene preservation while pulling residual water. 1.2-1.4 is bulking-grade VPD, dampens ripening signal, risks wetter finish.
Recommended fix: Raise to 1.3-1.5 (modest) or 1.4-1.6 (textbook). Air_temp 70-77F is in the right ballpark - VPD nudge alone is sufficient.
P2Bulking pore_ec target_min = 3 - too generous, defeats steering intent
Where: P2 Bulking target_ranges.pore_ec = 3-7
Risk: If grower lets substrate EC drift down to 3 mS/cm in bulking, plant has been over-leached and lost early-flower stack momentum. Floor of 4 is more defensible; 3 is bulking-with-brakes-off.
Recommended fix: Tighten pore_ec.target_min to 4 in bulking. Keep max at 7. The maxEcpw 6 ceiling is already coherent with 4-7 window.
P25 active recipes in library - 3 are placeholders ('Recipe 1', 'Havest' [sic], 'test')
Where: spa_get_recipes - Recipe 1 (151877), Havest [sic] (151879), test (153972), Flower Only (155126), Veg/Flower/Dry Recipe (155127)
Risk: Three of the five have phase_count of 0 or are named 'test'. Risk of mis-application when cloning. Also 'Havest' is a typo.
Recommended fix: Archive Recipe 1, Havest, and test. Rename survivors descriptively. Tag the recipe applied to the current HG with a date.
P2Right now: VWC 21.6%, pore EC 2.0 mS/cm - both below floors (consistent with Day 2 new HG)
Where: Live readings at 2026-06-16T01:42Z (P0 activation window, ~42 min into lights-on, 18 min before P1 starts)
Risk: Consistent with new-HG state (Day 2, fresh transplant, baseline charging up) but worth a sanity-check. If controller doesn't fire a shot in the next 30 min, the room stays below the panic floor another hour. Also confirms feed EC under-charged at HG start.
Recommended fix: Walk the room at next P1 shot trigger (target ~02:00 UTC). Pump up feed EC to ensure substrate EC enters 4-12 target within 48-72h.

5 · Recommended parameter changes

Exact current → recommended deltas. Apply via AROYA SPA (Settings → Phase → Target Ranges & Irrigation Schedule).

PhaseParameterCurrentRecommendedRationale
P1 Early FlowerminVwc (panic floor)0.25 (25%)->0.18 (18%)AROYA crop-steering - generative dryback math
P1 Early Flowersoil_moist target_max44 %->34 %ASI-down generative: tighter P1 cap forces AUTOMAIT into a deeper, longer dryback with FEWER (smaller) shots. Modeled with the rest of the audit pack this lifts dryback from 16 pp to ~22 pp / 54% prop. Raise back to 44-50% when transitioning to Bulking.
P1 Early FlowermaxEcpw9 mS/cm->11 mS/cmMatch pore_ec.target_max intent; protect alert band
P1 Early FlowerlightsBuffer P0 delay60 min->150 minPhase target P0 delay 120-240 min
P1 Early Floweralert_min / alert_max (all metrics)null->see flag P0-2Page-the-grower thresholds
P2 BulkingdrainGoal0.05 (5%)->0.25 (25%)Bulking EC flush (Athena / AROYA standard)
P2 Bulkingpore_ec target_min3 mS/cm->4 mS/cmFloor protection
P3 Ripeningvpd target1.2-1.4->1.3-1.5Drive finishing metabolites
All phasessoil_temp target_ranges rowMISSING->P1: 65-75F, P2: 65-75F, P3: 60-70FCoco root-zone protection
All phaseslight_ppfd / dli target rowMISSING->PPFD 800-1000 umol, DLI 45-55PAR sensor present, no guardrail
Recipe librarybroken templates5 active (3 invalid)->Archive 'Recipe 1', 'Havest', 'test'Mis-application risk

Recommendations follow AROYA Crop-Steering: The Ultimate Guide + Athena Vegetative Stage / Substrate Guide + Grodan Cannabis Edition Ch. 3-4 + Growlink Crop Steering E-Book. Phase-target ranges sourced from the Irrigation Strategy NotebookLM (synthesized Deep Research Report).

6 · Tomorrow's forecast — what AUTOMAIT will do (2026-06-17)

Hour-by-hour simulation of AUTOMAIT's behaviour on room 20167 through the next light cycle, under unchanged settings. Anchored on yesterday's measured field capacity (41.6%), yesterday's ET signature (1.45 pp/h, derived from the no-shot decay between irrigation events), the empirically derived shot bump (1.25 pp / shot from yesterday's two P1 events), and the 7-day ambient baseline (0.975x ET adjustment for tomorrow). Lights-on 18:00 local; lights-off 06:00.

Forecast date2026-06-17 (post-flip day 3, room 20167, Early Flower / Generative)
Predicted peak VWC41.25%
Predicted trough VWC25.06%
Predicted absolute dryback16.19 pp   (peak − trough)
Predicted proportional dryback39.2% (supporting only)
Predicted AUTOMAIT shots8
Meets generative goal (40% prop benchmark)yes   Michael's true target is an open question — see §10.
ET applied1.4133 pp/h (0.975x ambient, tomorrow VPD baseline vs yesterday)

Forecast chart — AROYA-style

Predicted substrate moisture (olive) and pore EC (blue) through the next 24 h on room 20167, with each predicted AUTOMAIT shot marked. Lights-on at 18:00 local, lights-off at 06:00 local. Dashed red = minVwc panic floor; dashed blue = maxEcpw ceiling.

Hover any shot marker (▲) for phase / trigger / volume / VWC bump.

Forecast if the audit-pack recommendations are applied

Same model, same ET signature, same FC, same crop — only the four AUTOMAIT config knobs from §5 change: minVwc 0.25 → 0.18, lightsBuffer_P0 60 → 150 min, maxEcpw 9 → 11 mS/cm, plus alert-band thresholds (no effect on the forecast itself). soil_moist target_max left at 44% — current ET doesn't drive peak into the ceiling yet, so raising it is a Bulking-phase lever (see §7 card #4).

Baseline (current config)
16.19 pp
peak 41.25% → trough 25.06% · 39.2% prop · 8 shots
Audit pack applied
22.35 pp
peak 41.25% → trough 18.9% · 54.2% prop · 1 shots
Delta vs baseline
+6.2 pp
trough -6.2 pp · +15.0 pp prop · meets goal: yes
Hover any shot marker (▲) for phase / trigger / volume / VWC bump. Solid lines = audit pack; faded lines = baseline (current config) for comparison.

Hour-by-hour AUTOMAIT shot schedule

Every shot the controller will fire tomorrow under the current config, with phase, trigger reason, and predicted VWC bump. P0 = activation delay; P1 = ramp-to-FC; P2 = maintenance pulses; P3 = dry-down. PANIC fires whenever VWC crosses minVwc regardless of phase.

Local time+h from lights-onPhaseTriggerVolumeVWC before → after
19:00+1.00 hP1ramp31 mL39.8% → 41.1%
19:30+1.50 hP1ramp31 mL40.4% → 41.6%
23:15+5.25 hP2maintenance15 mL36.3% → 36.9%
00:45+6.75 hP2maintenance15 mL34.8% → 35.4%
02:15+8.25 hP2maintenance15 mL33.3% → 33.9%
03:45+9.75 hP2maintenance15 mL31.8% → 32.4%
14:00+20.00 hP3-PANICminVwc rescue31 mL24.9% → 26.2%
16:15+22.25 hP3-PANICminVwc rescue31 mL24.9% → 26.2%

VWC + pore-EC trajectory through the cycle

Two-hour snapshots from lights-on through the next 24 h. Watch the trough land at ≈ 25.06% (the panic floor sits at 25%) and pore EC climb toward the 9.0 mS/cm ceiling.

Local time+h from lights-onPhaseVWCPore EC
18:00+0 hlights-on41.2%4.00 mS/cm
20:00+2 hlights-on40.9%4.08 mS/cm
22:00+4 hlights-on38.1%4.08 mS/cm
00:00+6 hlights-on35.9%4.11 mS/cm
02:00+8 hlights-on33.7%4.14 mS/cm
04:00+10 hlights-on32.1%4.18 mS/cm
06:00+12 hlights-off29.5%4.19 mS/cm
08:00+14 hlights-off28.3%4.19 mS/cm
10:00+16 hlights-off27.2%4.19 mS/cm
12:00+18 hlights-off26.1%4.20 mS/cm
14:00+20 hlights-off26.2%4.23 mS/cm
16:00+22 hlights-off25.1%4.23 mS/cm

What to watch for

Yesterday actual vs Tomorrow predicted

Under unchanged settings the prediction should land in the same neighborhood as yesterday's actual. If tomorrow diverges materially from this prediction, look for an ambient shift, a lights fault, or a feed-EC change — not the model.

 Peak VWCTrough VWCAbs dryback
Yesterday actual (2026-06-15) 41.6%24.2% 17.4 pp
Tomorrow predicted (2026-06-17) 41.25% 25.06% 16.19 pp

What-if: how the audit-pack recommendations reshape tomorrow

Same model, same ET signature, varying only the AUTOMAIT config knobs from §5. Use this to forecast the dryback shape of each scenario before saving the change. Generative early-flower benchmark is ≥40% proportional dryback — Michael's true target is an open question (§10).

ScenarioPredicted peakPredicted troughAbs drybackProp drybackShotsMeets 40% benchmark
Do nothing (current config)41.25%25.06%16.19 pp39.2%8yes
Lower minVwc to 0.18 only41.25%23.25%18.0 pp43.6%6yes
Extend P0 delay to 150 min only41.6%26.32%15.28 pp36.7%7marginal
Audit pack (minVwc 0.18 + P0 150 + target_max 34 + maxEcpw 11)41.25%18.9%22.35 pp54.2%1yes
Audit pack + ASI GEN 2 (deeper generative preset)41.25%18.28%22.97 pp55.7%0yes
Audit pack + ASI GEN 1 (max-aggression generative)41.25%18.28%22.97 pp55.7%0yes

7 · How AUTOMAIT actually runs Michael's room — and exactly where to change it

The audit listed nine "AUTOMAIT parameters" as if each was an independent knob in the UI. They're not. Open the schedule modal and you see one slider; click Back to Steering → Guardrails and you see the exact fields the audit was pointing at, labeled the way Michael sees them. This section walks through both surfaces, ties every audit recommendation to its precise UI field name, and explains what each change does to runtime behavior.

Surface 1 — The ASI™ slider (the steering preset)

Room dashboard → click the irrigation schedule chart → modal opens:

🍃 M3 6/15-8/11  ·  Zone 1  ·  Early Flower/Generative  ·  Day 2  ·  6:00PM – 6:00AM  ·  Coco Coir
Set Emergency Shots (Emergency shots are only applied outside of the AUTO irrigation window)

Choose your Absolute Steering Index™ goal

VWC% ↑                             ECpw MAX
| Fill /\__                   9
|         \__ Dryback    
|                   \_____  
+--- 7:00PM (Filled End)       6:00AM
GEN  | ● 3 | · · · · · · · · |  VEG
ASI™ GEN 3: High Generative
Start irrigating at approx. 7:00PM to field capacity.
Maintain near field capacity until end of irrigation window.

One drag of that slider picks a preset that locks the eight guardrail values together. ASI™ GEN 3 = "High Generative" — AROYA's description says "maintain near field capacity until end of irrigation window". That's the opposite of the deep generative dryback the audit (and AROYA's Crop Steering Guide) want for early flower. GEN 3 is conservative; the audit wants GEN 5-7 territory.

Surface 2 — The Guardrails page (every field the audit named)

From the ASI™ modal, click Back to Steering (top-right of the modal) and you land on a page titled Guardrails for the ASI™ (3). The "(3)" = Michael's current GEN level. The page header reads:

Guardrails apply only during the Irrigation Window.

That single sentence resolves the confusion the audit had about the panic shot — it never fires during the AUTO window, because during the window the Guardrails page applies, and outside the window the Emergency Shots dialog applies. Two separate safety nets.

The page layout, from top to bottom:

Window timing (shared, applies to both GEN and VEG)
Irrigation Window Start — Time after Lights On1 h 0 m → 7:00 PM
Irrigation Safety Cutoff — Time before Lights Off2 h 0 m → 4:00 AM
Per-mode guardrails — tabs: Generative 1-5 ✓   Vegetative 6-10
FieldGenerative 1-5 (active)Vegetative 6-10
ECPW Limit (Max)9 dS/m6 dS/m
Supplemental Shot Size3 m 0 s — 5% / 189.3 ml3 m 0 s — 5% / 189.3 ml
P1 Shot Size3 m 0 s — 5% / 189.3 ml3 m 0 s — 5% / 189.3 ml
P1 Maximum Duration if No Drain Detected1 h 30 m2 h 0 m
P2 Shot Size2 m 0 s — 3.3% / 126.2 ml2 m 0 s — 3.3% / 126.2 ml
Wait between Shots (Max)60 m 0 s30 m 0 s
Wait between Shots (Min)10 m 0 s15 m 0 s
Minimum VWC25 %25 %

How those fields map to the API names the audit used

UI label (what Michael sees)API field (what the audit called it)What it actually does at runtime
Irrigation Window StartlightsBuffer[0]Minutes after lights-on before AUTOMAIT fires the first P1 shot. The P0 wait.
Irrigation Safety CutofflightsBuffer[1]Minutes before lights-off where the last shot is allowed. Defines the P3 dry-down window.
ECPW Limit (Max)maxEcpwIf pore EC stacks past this number, AUTOMAIT triggers a flush shot (sized by "Supplemental Shot Size") until EC drops back inside the band.
Supplemental Shot SizeflushDurationThe flush-shot duration. Fires when ECPW exceeds the limit OR as a top-up between scheduled shots.
P1 Shot Sizeduration[0]The first shot of the day — the ramp-up shot. Sized in minutes; the UI also shows the substrate-volume % and mL/plant equivalents.
P1 Maximum Duration if No Drain DetectedmaxFillMinutesCap on the total P1 ramp-up window. AUTOMAIT keeps firing P1 shots until first runoff is detected OR this cap is hit, whichever comes first.
P2 Shot Sizeduration[1] · tied to value (3% for GEN 3)The maintenance shot size. AUTOMAIT fires these through the AUTO window at the configured interval, chasing the daily drain target.
Wait between Shots (Max / Min)interval[1] / interval[0]The shot cadence band. AUTOMAIT triggers the next P2 shot somewhere in this window, biased by how fast VWC is dropping.
Minimum VWCminVwcIN-WINDOW floor. If VWC drops below this during the AUTO window, AUTOMAIT fires a supplemental shot to lift it back. NOT the Emergency Shot — that's a separate dialog for the OFF window.
(not on this page) Emergency Shotsa different dialog (see top of ASI™ modal)OFF-window rescue. Fires only when AUTOMAIT is dormant (lights-off, this room: 6 AM-6 PM). Separate threshold from "Minimum VWC".
(not on this page) Daily drain goaldrainGoal (5% for GEN 3)Cumulative daily runoff target. AUTOMAIT spaces P2 shots to chase this number through the AUTO window. Likely tied to the ASI level — Cian to confirm if there's an override.

What GEN 3 actually does each day in this room

TimeWhat AUTOMAIT doesDriven by
6:00 PMLights-on. AUTOMAIT enters the Irrigation Window. Emergency Shots stand down.Light schedule
6:00 - 7:00 PMP0 wait — no shots for 60 min. Plants warm, transpiration starts, VWC drifts down 1-3 pp.Irrigation Window Start = 1h 0m
~7:00 PMFirst P1 shot — 3 min, 50 mL/plant. Then 2-min P2 shots every 10-60 min until first runoff is detected OR 1h 30m of ramp time.P1 Shot Size = 3m; P1 Max Duration = 1h 30m
~8:00 PM - 4:00 AMP2 maintenance — 2-min shots (~3.3% of substrate volume, 126 mL/plant) at 10-60 min intervals, chasing the 5% daily runoff target. If pore EC stacks past 9 dS/m, AUTOMAIT fires a 3-min flush (Supplemental Shot Size). If VWC drifts below 25%, AUTOMAIT fires a supplemental shot to lift it.P2 Shot Size, Wait between Shots, ECPW Limit, Minimum VWC, drainGoal
4:00 AMLast shot allowed. P3 dry-down starts.Irrigation Safety Cutoff = 2h 0m
4:00 - 6:00 AMNo shots. VWC drifts down on its own. This is the only real dryback the room sees today.(no field — passive)
6:00 AMLights-off. AUTOMAIT closes the window. Emergency Shots activate.Light schedule
6:00 AM - 6:00 PMEmergency Shots window. If VWC drops below the Emergency Shot threshold (separate from Minimum VWC), a rescue shot fires.Emergency Shots dialog

The pattern AROYA is producing: the room is held near field capacity through the entire 12-hour AUTO window, then gets two hours of passive dry-down before lights-off, then drifts (uncontrolled) for 12 OFF hours. Most of the dryback Michael sees is happening in those 14 hours after the AUTO window closes. That's not generative steering — that's "maintained at FC and then left alone."

The audit's recommendations — mapped to the actual UI fields

What the audit saidReal UI surfaceExact UI fieldCurrentSet toEffect on runtime
Lower the panic floor (minVwc 0.25 → 0.18)Guardrails pageMinimum VWC25 %18 %AUTOMAIT no longer punches in a rescue shot at 25%; the room can ride further into a real dryback before AUTOMAIT intervenes.
Raise the EC ceiling (maxEcpw 9 → 11)Guardrails pageECPW Limit (Max)9 dS/m11 dS/mAUTOMAIT lets the EC stack run higher before triggering a flush — the EC drive the audit said early-flower generative needs.
Lengthen P0 wait (lightsBuffer[0] 60 → 150)Guardrails pageIrrigation Window Start1 h 0 m2 h 30 mFirst shot moves from 7:00 PM to 8:30 PM. Plants get 90 extra min to dry back before AUTOMAIT tops them up — the morning generative cue the phase target wants.
Set Bulking drainGoal 0.05 → 0.25(Likely tied to ASI VEG level)(Cian to confirm the field name — not on the Guardrails page screenshot I've seen)5 %25 %Bulking phase only — AUTOMAIT chases ~5× more daily runoff, flushing the early-flower EC stack down.
Re-think the steering preset itselfASI™ slider modalThe slider positionGEN 3 (High Generative)Try GEN 5-7; pick the level whose redrawn chart shows a real in-window dryback, not "maintained at FC".One drag shifts ECPW Limit, P1 Max Duration, Wait between Shots, P2 Shot Size, and Minimum VWC together — the underlying preset map. Multiple Guardrail-page edits collapse into one slider move.
Set alert thresholds (12 metrics × 3 phases all null)Target Ranges panel (NOT this page)per-metric Alert Min / Alert Maxnull everywherevpd 0.7-1.5, soil_moist 18-55, pore_ec 3-14, air_temp 75-88 (P1)Page-the-grower bands — nothing alerts today.
Add soil_temp guardrailTarget Ranges panelAdd target → Substrate TemperatureMISSING65-75 °F P1, alert 60-80Live reading is 85 °F right now with no flag.
Add light_ppfd / dli guardrailTarget Ranges panelAdd target → PPFD or DLIMISSINGPPFD 800-1000, DLI 45-55PAR sensor B015881 reports DLI ~66 — over-driven, no flag.
Tighten Bulking pore_ec target_min 3 → 4Target Ranges panelP2 pore_ec Target Min3 mS/cm4 mS/cmFloor protection during the Bulking flush.
Push Ripening VPD 1.2-1.4 → 1.3-1.5Target Ranges panelP3 vpd Target Min / Max1.2 - 1.41.3 - 1.5Drier canopy in finishing phase, drives metabolite production.
Archive Recipe 1, Havest, testRecipes sectionPer-row Archive button5 active (3 placeholders)Archive the 3 placeholders, rename survivors descriptively.Prevents an operator applying a placeholder recipe to a new HG and overwriting Michael's guardrails.

State drift since the audit was written

Live target ranges changed between the original audit pull (2026-06-16T04:11Z — soil_moist target_max 44%, pore_ec target_max 12) and the re-pull while drafting this section (04:28Z — soil_moist target_max 50%, pore_ec target_max 9). The audit's P0 flag "maxEcpw 9 clamps below pore_ec target_max 12" no longer applies: both are 9 now. The "soil_moist target_max too narrow" flag is partly addressed (44 → 50). The "Currently" column above uses the LATEST values.

The order to apply changes

ORDERIf Michael does these in order, the room will start steering generatively for real
  1. Open the schedule modal → drag the ASI™ slider from GEN 3 toward GEN 5-7 until the redrawn chart shows the dryback shape you want (real in-window trough, not "maintained at FC"). If a preset matches what Michael wants, this single move does Recommendations 1, 2, 3, and 4 from the table above.
  2. Click "Back to Steering" inside the modal → if the slider pick didn't give exactly the right Guardrail values, fine-tune them on the Guardrails page: Minimum VWC 25 → 18, ECPW Limit 9 → 11, Irrigation Window Start 1h0m → 2h30m.
  3. Click "Set Emergency Shots" at the top of the ASI™ modal → verify (or lower) the OFF-window rescue floor. Pair with Minimum VWC in step 2 so the in-window floor (18%) is below the OFF-window floor.
  4. Click "Vegetative 6-10" tab on Guardrails → edit the same fields for Bulking and Ripening phases' VEG side. Especially: drainGoal field if exposed (Cian to point me at it).
  5. Close the modal, scroll the room dashboard to the Target Ranges card → fill alert thresholds on every metric per phase, add soil_temp + light_ppfd rows, nudge P3 vpd up, tighten P2 pore_ec floor.
  6. Open the Recipes section → archive Recipe 1, Havest, test.
What changes overnight: if Michael moves the slider to a deeper-dryback preset AND lowers Minimum VWC to 18%, tonight's AUTO window will finally show a real in-window dryback instead of the "held at FC" flatline. If it doesn't materialize, the upstream issue is climate (substrate temp 85 °F is suppressing transpiration) — not AUTOMAIT.

Label confidence: every UI label in this section was pulled live from the AROYA web app on 2026-06-16 — the ASI™ modal and the Guardrails page (screenshots captured by Cian while drafting). The two surfaces this walkthrough doesn't pin a label on are (a) the Emergency Shots dialog — structure not seen, only the entry-point link — and (b) where drainGoal lives in the UI (not on the Guardrails page; likely ASI-preset-derived or in a separate Advanced toggle). Flag if a label has drifted — the underlying API field names are authoritative.

8 · Tooling cross-check — SDK vs OpenCLI vs MCP (three-way diff, completed 2026-06-16)

Re-run on the Mac, not in the sandbox. Prior session punted with "iCloud bash deadlocks" — the answer is to drive the SDK and OpenCLI via osascript on Cian's Mac, where both are installed and authenticated. Workflow doc: ~/claude-brain/06-Workflows/aroya-sdk-from-mac.md.

ToolVersion / locationStatusNotes
aroya-sdk (Python) 1.5.0 at ~/.aroya/venv/lib/python3.12/site-packages/aroya_sdk/ ✓ exercised Driven via osascript do shell script "AROYA_API_TOKEN=… ~/.aroya/venv/bin/python pull.py". Transport spa=httpx, fallback=opencli per ~/.aroya/config.toml. Most reliable of the three — succeeded first try on every call.
opencli aroya v1.7.7 at /opt/homebrew/bin/opencli (node 25.8.2) ✓ exercised SPA "intercept" strategy — reuses the live app.aroya.io Chrome tab's localStorage token. Hit "Detached while handling command" / "stale page identity" on 2/4 calls (hg-list, target-ranges); both succeeded on retry once the tab settled. The detachment is the known SPA-config-not-parallel-safe failure mode.
AROYA MCP (mcp__aroya__spa_*) Wraps opencli — aroya_mcp_server_extended.py ✓ exercised Same detachment failure mode as opencli (since it shells out to it). Retry-on-detach worked. Output schema = opencli's (flattened with _schema_version + _captured_at).

Per-datapoint diff — facility 4730, room 20167 "Michael 3 Light"

DatapointSDKOpenCLIMCPAgreement
Room name"Michael 3 Light""Michael 3 Light""Michael 3 Light"byte-match
Facility ID473047304730byte-match
SubstrateCOCO / Coco Coir / 1-gal / 0.5 emitter / 2/plantsamesamebyte-match
Light scheduleid 693766, 18:00 +12h, ends 2026-09-15samesamebyte-match
Devices (7 total)Gateway H2110001280 (ggVer 2 = WP5), 4 nodes + ter15 puck pairs (COCO, zone 83331), SQ-521 PAR B015881, h520 flow_pH H5200001003, DRIP H8200001002, DRAIN H8200001002-2same device IDssame device IDsbyte-match
HG list (active)1 HG — id 155568, "M3 6/15-8/11"1 HG — id 155568, "M3 6/15-8/11"1 HG — id 155568, "M3 6/15-8/11"byte-match
HG current phase"Early Flower/Generative" (id 1047772), 2026-06-14 → 2026-07-05, 21 days, day 2 of phasesamesamebyte-match
HG phase plan (3 phases)1047772 Early Flower (21d) → 1047773 Bulking/Veg2 (28d) → 1047774 Ripening/Gen2 (21d)samesamebyte-match
Plant count / zones / cultivar72 plants / zone 83331 / cultivar 64060samesamebyte-match
Target ranges (count)12 rows (IDs 3531242-3531253)12 rows (same IDs)12 rows (same IDs)byte-match
Phase 1 targets (Early Flower)VPD 1.0-1.2, VWC 25-44, pore_EC 4-12, air 80-82°Fsamesamebyte-match
Phase 2 targets (Bulking)VPD 1.2-1.4, VWC 30-65, pore_EC 3-7, air 75-80°Fsamesamebyte-match
Phase 3 targets (Ripening)VPD 1.2-1.4, VWC 25-55, pore_EC 3-6, air 70-77°Fsamesamebyte-match
Recipes (count + IDs)5 (155126 Flower Only, 151879 Havest, 151877 Recipe 1, 153972 test, 155127 Veg/Flower/Dry Recipe)5 (same IDs)5 (same IDs)byte-match

Schema / wrapping differences (by design, not data divergence)

ConcernSDKOpenCLIMCP
Room config envelopeRaw API body wrapped in [{_path, status, body}]Flat with _schema_version + _captured_at + merged target_ranges + light_schedules + substrate_settingsSame as OpenCLI (MCP shells out to it)
Recipe detailFull /recipes/ body (description, created, modified all populated)Flat summary — description/created/modified null (intercept layer drops them)Same as OpenCLI
First-call reliability4/4 first try2/4 first try (hg-list, target-ranges detached)2/4 first try (same root cause)
Auth sourceenv AROYA_API_TOKEN + JWT files in ~/.aroya/spa_token_app.jsonLive app.aroya.io Chrome tab localStorageLive Chrome tab via opencli

Conclusion: Zero value-level divergence across all 14 datapoints. SDK is the most reliable on first call. OpenCLI / MCP need a stable SPA tab and a retry-on-detach guard for SPA-config endpoints. Every number in this report is now triangulated through all three independent paths — the SDK adding the most independence since it uses httpx directly, not the SPA tab.

9 · CCMS architecture cross-reference

Per the project's steering-service/ module: CCMS is the controller layer; AROYA holds the truth. The steering loop writes AROYA target ranges, then the AROYA → CCMS Modbus bridge actuates them. Reads can come from the CCMS controller directly (faster than AROYA's cultivation page) via GET /homes/monitoring/ on the controller's local LAN.

This project's CCMS pilot

Pilot facilityDonner Party Dope Growers (3217)
Pilot roomLong Skinny (8321)
ControllerCCMS TEST-2934
StatusShadow mode — no writes yet

The steering-service in this repo is wired to Donner Party 3217, NOT to Cannapproach 4730. Cannapproach is Michael's R&D environment for the CCMS product itself.

CCMS-side guardrails (from steering-service/guardrails.py)

Absolute limits (FALLOW-WIDE pilot defaults)

DatapointAllowed rangeNote
TEMP_SP_DAY10-35 Cbroad pilot range; tighten before planting
RH_SP20-90 %broad pilot range
CO2_SP400-1600 ppm
VPD_SP0.3-2.0 kPaloose; AROYA phase targets are tighter
P0_DELAY_MIN0-360 minallows Cannapproach P1 60 min - but at low end
SHOT_PCT0-12 %Cannapproach gen value=3 ~= 3% shot - within range
P3_DRYBACK_TARGET_PP5-45 ppno AROYA-side equivalent set at Cannapproach

Per-write delta caps (anti-jump)

DatapointMax change per write
TEMP_SP_DAY2.0 F per write
RH_SP5.0 % per write
CO2_SP150 ppm per write
VPD_SP0.15 kPa per write
P0_DELAY_MIN30 min per write
SHOT_PCT1.0 pp per write
P3_DRYBACK_TARGET_PP3.0 pp per write

Other

  • Anti-oscillation: MAX_WRITES_PER_DAY = 12 per datapoint
  • Fail-safe: Kill switch · CCMS comms loss · AROYA stale data → no-write; CCMS retains last-good program

What this means for Cannapproach 4730

If/when CCMS is bound to the Cannapproach irrigationControllers[3245] write path, the AROYA-side P0 risks above (panic floor identity, EC contradiction, P0 delay shortness) become EVEN MORE critical because the CCMS write loop will pass approved diffs straight through to AROYA target ranges, then the AROYA → CCMS Modbus bridge actuates them. The CCMS guardrails do NOT catch the AROYA-side contradictions — they only clamp absolute ranges and rate-of-change. The architectural risk is real: two layers of guardrails, neither of which catches the internal AROYA inconsistencies.

10 · Open questions for Michael

  1. Is irrigation controller 3245 a CCMS box, an OpenSprinkler, or something else? The API exposes the binding but not the make/model. Determines whether CCMS-side guardrails apply here.
  2. The panic floor (minVwc = 25%) ≡ target_min conflict — is this intentional ("just keep VWC above 25"), or are you trying to drive deep generative dryback and this is a config error?
  3. Why is the EC ceiling (maxEcpw = 9) tighter than the EC target_max (12)? Was target_max widened experimentally without updating the irrigation guard? Or vice-versa?
  4. Are you tracking DLI as a steering input? The PAR sensor is installed and reporting peak DLI of ~66 — no guardrail. Either dial fixtures down or formalize the DLI target.
  5. Substrate temp 85 °F at root level — what's the heat source? Under-bench heat, container colour, fixture proximity, or amplified by current dry-substrate state?
  6. Confirm AUTOMAIT is actually firing — VWC has been below the panic floor for >90 min as of audit time. Either the controller is paused or the program isn't being respected.
  7. Why is the recipe library cluttered with Recipe 1, Havest (sic), test? Safe to archive?
  8. Should this R&D facility be the next step on the CCMS pilot ladder (currently scoped to Donner Party 3217 / Long Skinny 8321)? Same architecture, fewer humans in the loop.