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.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.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.
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.
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).
| Metric | Peak/Trough | Target window | Sev | Window | Interpretation |
|---|---|---|---|---|---|
| soil_moist | 45.32 | 25-44% | warn | 2026-06-14 02:33 -> 2026-06-16 01:42 (~47h) | Mild ceiling overshoot, transient post-irrigation peaks. |
| pore_ec | 3.97 | 4-12 mS/cm | warn | 2026-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.
| Serial | Model | FW | Battery | Link | Role | Status |
|---|---|---|---|---|---|---|
H2110001280 | gateway | WP5 (gg=2) | — | — | Mesh gateway | 🟢 online |
H3310009775 | node + sq-521 | WP4 | 98 % | 100 % | PAR/quantum light (B015881) | 🟢 online |
H3440015384 | node + ter15 | WP4 | 100 % | 100 % | Substrate sensor #1 COCO | 🟢 online |
H3440015384-2 | node + ter15 | WP4 | 100 % | 100 % | Substrate sensor #2 COCO | 🟢 online |
H5200001003 | node + h520/flow_ph | WP4 | 100 % | 76 % | Runoff pH+EC (variant 7) | 🟢 online |
H8200001002 | node + ter15 [DRIP] | WP4 | 100 % | 100 % | Drip volume sensor | 🟢 online |
H8200001002-2 | node + ter15 [DRAIN] | WP4 | 100 % | 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.
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.
| Mode | GEN - steering value 3 |
| P0 delay (after lights-on) | 60 min |
| P3 cutoff (before lights-off) | 120 min |
| Active irrigation window | 540 min/day (9.0 h) |
| VPD | 1.0-1.2 kPa |
| Substrate VWC | 25-44 % |
| Substrate EC | 4-12 mS/cm |
| Air temp | 80-82 F |
| First-shot duration | 3 min - 50 mL/plant |
| Subsequent-shot duration | 2 min - 33 mL/plant |
| Shot interval | 10-60 min |
| Drain goal | 5 % |
| Flush duration | 3 min |
| 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_max | null (all metrics) no paging on extreme excursion |
| Mode | VEG - steering value 8 |
| P0 delay (after lights-on) | 60 min |
| P3 cutoff (before lights-off) | 120 min |
| Active irrigation window | 540 min/day (9.0 h) |
| VPD | 1.2-1.4 kPa |
| Substrate VWC | 30-65 % |
| Substrate EC | 3-7 mS/cm |
| Air temp | 75-80 F |
| First-shot duration | 3 min - 50 mL/plant |
| Subsequent-shot duration | 2 min - 33 mL/plant |
| Shot interval | 15-30 min |
| Drain goal | 5 % |
| Flush duration | 3 min |
| 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_max | null (all metrics) no paging on extreme excursion |
| Mode | GEN - steering value 3 |
| P0 delay (after lights-on) | 60 min |
| P3 cutoff (before lights-off) | 120 min |
| Active irrigation window | 540 min/day (9.0 h) |
| VPD | 1.2-1.4 kPa |
| Substrate VWC | 25-55 % |
| Substrate EC | 3-6 mS/cm |
| Air temp | 70-77 F |
| First-shot duration | 3 min - 50 mL/plant |
| Subsequent-shot duration | 2 min - 33 mL/plant |
| Shot interval | 10-60 min |
| Drain goal | 5 % |
| Flush duration | 3 min |
| 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_max | null (all metrics) no paging on extreme excursion |
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.
P0 = structural contradiction or silent failure mode — fix this week. P1 = steering correctness — fix this phase. P2 = housekeeping or transient observation.
All phases - automatedScheduleSettings.{gen,veg}.minVwc = 0.25 vs target_ranges.soil_moist.target_min = 25minVwc = soil_moist target_min, the soft target alarm fires at the same level as the panic shot — the alert is redundant with the rescue.target_ranges rows phase_id 1047772/1047773/1047774 - all four metrics in every phaseP1 Early Flower irrigation_schedule.automatedScheduleSettings.gen.maxEcpw = 9 vs target_ranges.pore_ec.target_max = 12P1 Early Flower lightsBuffer = (60, 120) - first shot allowed 60 min after lights-onP2 Bulking automatedScheduleSettings.veg.drainGoal = 0.05PAR sensor sq-521 (B015881) installed and reporting - no light_ppfd/dli row in target_rangesLive reading 2026-06-16T01:42Z - no soil_temp row in target_ranges any phaseP3 Ripening target_ranges.vpd = 1.2-1.4P2 Bulking target_ranges.pore_ec = 3-7spa_get_recipes - Recipe 1 (151877), Havest [sic] (151879), test (153972), Flower Only (155126), Veg/Flower/Dry Recipe (155127)Live readings at 2026-06-16T01:42Z (P0 activation window, ~42 min into lights-on, 18 min before P1 starts)Exact current → recommended deltas. Apply via AROYA SPA (Settings → Phase → Target Ranges & Irrigation Schedule).
| Phase | Parameter | Current | Recommended | Rationale | |
|---|---|---|---|---|---|
| P1 Early Flower | minVwc (panic floor) | 0.25 (25%) | -> | 0.18 (18%) | AROYA crop-steering - generative dryback math |
| P1 Early Flower | soil_moist target_max | 44 % | -> | 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 Flower | maxEcpw | 9 mS/cm | -> | 11 mS/cm | Match pore_ec.target_max intent; protect alert band |
| P1 Early Flower | lightsBuffer P0 delay | 60 min | -> | 150 min | Phase target P0 delay 120-240 min |
| P1 Early Flower | alert_min / alert_max (all metrics) | null | -> | see flag P0-2 | Page-the-grower thresholds |
| P2 Bulking | drainGoal | 0.05 (5%) | -> | 0.25 (25%) | Bulking EC flush (Athena / AROYA standard) |
| P2 Bulking | pore_ec target_min | 3 mS/cm | -> | 4 mS/cm | Floor protection |
| P3 Ripening | vpd target | 1.2-1.4 | -> | 1.3-1.5 | Drive finishing metabolites |
| All phases | soil_temp target_ranges row | MISSING | -> | P1: 65-75F, P2: 65-75F, P3: 60-70F | Coco root-zone protection |
| All phases | light_ppfd / dli target row | MISSING | -> | PPFD 800-1000 umol, DLI 45-55 | PAR sensor present, no guardrail |
| Recipe library | broken templates | 5 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).
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 date | 2026-06-17 (post-flip day 3, room 20167, Early Flower / Generative) |
| Predicted peak VWC | 41.25% |
| Predicted trough VWC | 25.06% |
| Predicted absolute dryback | 16.19 pp (peak − trough) |
| Predicted proportional dryback | 39.2% (supporting only) |
| Predicted AUTOMAIT shots | 8 |
| Meets generative goal (40% prop benchmark) | yes Michael's true target is an open question — see §10. |
| ET applied | 1.4133 pp/h (0.975x ambient, tomorrow VPD baseline vs yesterday) |
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.
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).
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-on | Phase | Trigger | Volume | VWC before → after |
|---|---|---|---|---|---|
| 19:00 | +1.00 h | P1 | ramp | 31 mL | 39.8% → 41.1% |
| 19:30 | +1.50 h | P1 | ramp | 31 mL | 40.4% → 41.6% |
| 23:15 | +5.25 h | P2 | maintenance | 15 mL | 36.3% → 36.9% |
| 00:45 | +6.75 h | P2 | maintenance | 15 mL | 34.8% → 35.4% |
| 02:15 | +8.25 h | P2 | maintenance | 15 mL | 33.3% → 33.9% |
| 03:45 | +9.75 h | P2 | maintenance | 15 mL | 31.8% → 32.4% |
| 14:00 | +20.00 h | P3-PANIC | minVwc rescue | 31 mL | 24.9% → 26.2% |
| 16:15 | +22.25 h | P3-PANIC | minVwc rescue | 31 mL | 24.9% → 26.2% |
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-on | Phase | VWC | Pore EC |
|---|---|---|---|---|
| 18:00 | +0 h | lights-on | 41.2% | 4.00 mS/cm |
| 20:00 | +2 h | lights-on | 40.9% | 4.08 mS/cm |
| 22:00 | +4 h | lights-on | 38.1% | 4.08 mS/cm |
| 00:00 | +6 h | lights-on | 35.9% | 4.11 mS/cm |
| 02:00 | +8 h | lights-on | 33.7% | 4.14 mS/cm |
| 04:00 | +10 h | lights-on | 32.1% | 4.18 mS/cm |
| 06:00 | +12 h | lights-off | 29.5% | 4.19 mS/cm |
| 08:00 | +14 h | lights-off | 28.3% | 4.19 mS/cm |
| 10:00 | +16 h | lights-off | 27.2% | 4.19 mS/cm |
| 12:00 | +18 h | lights-off | 26.1% | 4.20 mS/cm |
| 14:00 | +20 h | lights-off | 26.2% | 4.23 mS/cm |
| 16:00 | +22 h | lights-off | 25.1% | 4.23 mS/cm |
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 VWC | Trough VWC | Abs 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 |
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).
| Scenario | Predicted peak | Predicted trough | Abs dryback | Prop dryback | Shots | Meets 40% benchmark |
|---|---|---|---|---|---|---|
| Do nothing (current config) | 41.25% | 25.06% | 16.19 pp | 39.2% | 8 | yes |
| Lower minVwc to 0.18 only | 41.25% | 23.25% | 18.0 pp | 43.6% | 6 | yes |
| Extend P0 delay to 150 min only | 41.6% | 26.32% | 15.28 pp | 36.7% | 7 | marginal |
| Audit pack (minVwc 0.18 + P0 150 + target_max 34 + maxEcpw 11) | 41.25% | 18.9% | 22.35 pp | 54.2% | 1 | yes |
| Audit pack + ASI GEN 2 (deeper generative preset) | 41.25% | 18.28% | 22.97 pp | 55.7% | 0 | yes |
| Audit pack + ASI GEN 1 (max-aggression generative) | 41.25% | 18.28% | 22.97 pp | 55.7% | 0 | yes |
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.
Room dashboard → click the irrigation schedule chart → modal opens:
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.
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:
| UI label (what Michael sees) | API field (what the audit called it) | What it actually does at runtime |
|---|---|---|
| Irrigation Window Start | lightsBuffer[0] | Minutes after lights-on before AUTOMAIT fires the first P1 shot. The P0 wait. |
| Irrigation Safety Cutoff | lightsBuffer[1] | Minutes before lights-off where the last shot is allowed. Defines the P3 dry-down window. |
| ECPW Limit (Max) | maxEcpw | If 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 Size | flushDuration | The flush-shot duration. Fires when ECPW exceeds the limit OR as a top-up between scheduled shots. |
| P1 Shot Size | duration[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 Detected | maxFillMinutes | Cap 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 Size | duration[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 VWC | minVwc | IN-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 Shots | a 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 goal | drainGoal (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. |
| Time | What AUTOMAIT does | Driven by |
|---|---|---|
| 6:00 PM | Lights-on. AUTOMAIT enters the Irrigation Window. Emergency Shots stand down. | Light schedule |
| 6:00 - 7:00 PM | P0 wait — no shots for 60 min. Plants warm, transpiration starts, VWC drifts down 1-3 pp. | Irrigation Window Start = 1h 0m |
| ~7:00 PM | First 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 AM | P2 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 AM | Last shot allowed. P3 dry-down starts. | Irrigation Safety Cutoff = 2h 0m |
| 4:00 - 6:00 AM | No shots. VWC drifts down on its own. This is the only real dryback the room sees today. | (no field — passive) |
| 6:00 AM | Lights-off. AUTOMAIT closes the window. Emergency Shots activate. | Light schedule |
| 6:00 AM - 6:00 PM | Emergency 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."
| What the audit said | Real UI surface | Exact UI field | Current | Set to | Effect on runtime |
|---|---|---|---|---|---|
| Lower the panic floor (minVwc 0.25 → 0.18) | Guardrails page | Minimum VWC | 25 % | 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 page | ECPW Limit (Max) | 9 dS/m | 11 dS/m | AUTOMAIT 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 page | Irrigation Window Start | 1 h 0 m | 2 h 30 m | First 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 itself | ASI™ slider modal | The slider position | GEN 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 Max | null everywhere | vpd 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 guardrail | Target Ranges panel | Add target → Substrate Temperature | MISSING | 65-75 °F P1, alert 60-80 | Live reading is 85 °F right now with no flag. |
| Add light_ppfd / dli guardrail | Target Ranges panel | Add target → PPFD or DLI | MISSING | PPFD 800-1000, DLI 45-55 | PAR sensor B015881 reports DLI ~66 — over-driven, no flag. |
| Tighten Bulking pore_ec target_min 3 → 4 | Target Ranges panel | P2 pore_ec Target Min | 3 mS/cm | 4 mS/cm | Floor protection during the Bulking flush. |
| Push Ripening VPD 1.2-1.4 → 1.3-1.5 | Target Ranges panel | P3 vpd Target Min / Max | 1.2 - 1.4 | 1.3 - 1.5 | Drier canopy in finishing phase, drives metabolite production. |
| Archive Recipe 1, Havest, test | Recipes section | Per-row Archive button | 5 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. |
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.
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.
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.
| Tool | Version / location | Status | Notes |
|---|---|---|---|
| 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). |
| Datapoint | SDK | OpenCLI | MCP | Agreement |
|---|---|---|---|---|
| Room name | "Michael 3 Light" | "Michael 3 Light" | "Michael 3 Light" | byte-match |
| Facility ID | 4730 | 4730 | 4730 | byte-match |
| Substrate | COCO / Coco Coir / 1-gal / 0.5 emitter / 2/plant | same | same | byte-match |
| Light schedule | id 693766, 18:00 +12h, ends 2026-09-15 | same | same | byte-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-2 | same device IDs | same device IDs | byte-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 phase | same | same | byte-match |
| HG phase plan (3 phases) | 1047772 Early Flower (21d) → 1047773 Bulking/Veg2 (28d) → 1047774 Ripening/Gen2 (21d) | same | same | byte-match |
| Plant count / zones / cultivar | 72 plants / zone 83331 / cultivar 64060 | same | same | byte-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°F | same | same | byte-match |
| Phase 2 targets (Bulking) | VPD 1.2-1.4, VWC 30-65, pore_EC 3-7, air 75-80°F | same | same | byte-match |
| Phase 3 targets (Ripening) | VPD 1.2-1.4, VWC 25-55, pore_EC 3-6, air 70-77°F | same | same | byte-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 |
| Concern | SDK | OpenCLI | MCP |
|---|---|---|---|
| Room config envelope | Raw API body wrapped in [{_path, status, body}] | Flat with _schema_version + _captured_at + merged target_ranges + light_schedules + substrate_settings | Same as OpenCLI (MCP shells out to it) |
| Recipe detail | Full /recipes/ body (description, created, modified all populated) | Flat summary — description/created/modified null (intercept layer drops them) | Same as OpenCLI |
| First-call reliability | 4/4 first try | 2/4 first try (hg-list, target-ranges detached) | 2/4 first try (same root cause) |
| Auth source | env AROYA_API_TOKEN + JWT files in ~/.aroya/spa_token_app.json | Live app.aroya.io Chrome tab localStorage | Live 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.
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.
| Pilot facility | Donner Party Dope Growers (3217) |
| Pilot room | Long Skinny (8321) |
| Controller | CCMS TEST-2934 |
| Status | Shadow 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.
steering-service/guardrails.py)| Datapoint | Allowed range | Note |
|---|---|---|
TEMP_SP_DAY | 10-35 C | broad pilot range; tighten before planting |
RH_SP | 20-90 % | broad pilot range |
CO2_SP | 400-1600 ppm | |
VPD_SP | 0.3-2.0 kPa | loose; AROYA phase targets are tighter |
P0_DELAY_MIN | 0-360 min | allows Cannapproach P1 60 min - but at low end |
SHOT_PCT | 0-12 % | Cannapproach gen value=3 ~= 3% shot - within range |
P3_DRYBACK_TARGET_PP | 5-45 pp | no AROYA-side equivalent set at Cannapproach |
| Datapoint | Max change per write |
|---|---|
TEMP_SP_DAY | 2.0 F per write |
RH_SP | 5.0 % per write |
CO2_SP | 150 ppm per write |
VPD_SP | 0.15 kPa per write |
P0_DELAY_MIN | 30 min per write |
SHOT_PCT | 1.0 pp per write |
P3_DRYBACK_TARGET_PP | 3.0 pp per write |
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.
Recipe 1, Havest (sic), test? Safe to archive?