Implement Design A: monitor subsystem compute engine - #25
Open
mpound wants to merge 19 commits into
Open
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds slama.monitor.compute, the declarative recipe engine chosen in
docs/monitorsystem_writer_design.md: computations.json wires named,
registered Python functions to resolved SMAX input points, the engine
ticks in topological order (so aggregate-of-aggregate outputs see
this-tick values, not stale ones), and writes each result back to SMAX
as an ordinary point plus a "validity" metadata entry (validity is
computed, not natively stored by SMAX/Redis).
Structured like slama.fault (FaultSystem/FaultConfig/FaultNode): same
tick()/run_forever()/stop()/reload_config() shape, __each__ template
expansion, and load-time validation that fails fast on unknown
functions, undeclared outputs, or dependency cycles.
Built-in functions: worst_validity (severity-ranked, since Validity's
enum int order does not match severity order), count_true, count_valid,
min/max/mean/median_value, and sequence_validity (a stuck-timeout
trajectory check for state-machine string points, using a per-node
persistent ctx.state dict and ctx.params, per design doc §3.5/§6.1).
One real end-to-end example is wired: monitorsystem:array:antennas_online,
counting antenna:{1..8}:is_online. sequence_validity is unit-tested but
not wired into computations.json (no real tuning-state point exists in
smax.json yet).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All three shared one blind spot: every test fed plain Python values while production feeds smax.smax_data_types.Smax* instances. - MonitorPoint._state_machine_validity(): a real smax_pull() result is a SmaxStr, which (being an @DataClass with default eq=True) has __hash__ set to None, so a dict lookup on self.value directly raised TypeError. Coerce to str first. - ComputeConfig._resolve_pattern(): a colon segment containing '-' that isn't a numeric range (e.g. smax.json's literal "4K-plate", "a1-a2" segments) made _parse_index_set raise. Catch that locally and fall back to treating the segment as a literal, rather than loosening _parse_index_set's own contract (shared with slama.fault's __each__ expansion, where a malformed range is more likely a config typo). - engine._wrap(): passed the float wall-clock straight through as `timestamp`, but SmaxVarBase.timestamp is datetime | None and MonitorPoint.time does Time(self._smax_result.timestamp) -- astropy rejects a bare float. Convert to an aware datetime. Also narrowed the bare `except Exception` around the resulting mp.time read in _resolve_one(), which would otherwise convert this exact class of bug into a silent, permanent INVALID_NO_DATA. Also: warn (rather than silently ignore) when a computation sets the reserved-but-unconsulted per-entry interval_s; and worst_validity now writes a severity-ranked score instead of int(Validity), since the whole reason _SEVERITY_ORDER exists is that the enum's own ordinal isn't severity-ordered -- writing it as a value would have scrambled any later numeric/threshold comparison on that point. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
output now accepts a dict of role-name -> canonical-name for entries whose function naturally computes several related points in one pass (e.g. min/max), avoiding a double call and keeping the function reusable under __each__ expansion. Also hardens tick() with per-node error isolation: any exception, including a multi-output key mismatch, now only invalidates that node instead of aborting the whole tick. Folds the design into docs/monitorsystem_writer_design.md §8. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers every function and method in engine.py and computeconfig.py that lacked one or had only a one-line summary, including private helpers -- Parameters/Returns/Raises added throughout. No behavior change. computenode.py already had full docstrings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nction for computing sun angle
- coordinates/core.py: sun_distance() referenced angular_separation without importing it (NameError on call); switched hasattr(x, "unit") checks to isinstance(x, u.Quantity) since a real SMAX value (SmaxFloat etc.) carries its own unrelated .unit metadata attribute, always making hasattr() true and skipping the degree conversion. Same fix applied to sun_distance_from_coord. Length check now uses np.size() so scalar (single-antenna) calls work, not just arrays. - functions.py: replaced the 32-input/8-output sun_distance_degrees (which had an output-shape mismatch against the engine's contract, an off-by-one slice, and passed ResolvedInput objects instead of raw values) with a single-antenna, dict-input version paired with a __each__-expanded entry per antenna instead. - computations.json / smax.json: sun_distance entries/points declared per-antenna via __each__, with warn_low=45, err_low=40 degrees per Marc. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
slama.monitor.computepackage: a declarative recipe engine (Design A, chosen over the plugin-class Design B perdocs/monitorsystem_writer_design.md) that reads SMAX monitor points, applies registered Python functions to them, and writes derived values + computed validity back to SMAX under a newmonitorsystem:table — mirroring theSmaxRedisClient/Validitymetadata pattern already used byslama.fault.computeconfig.py: parsesconf/computations.json, resolves input patterns (exact names,{i}ranges via the existing_parse_index_set, and glob wildcards) against the realMonitorSystemtree, and topologically sorts entries so a downstream aggregate-of-an-aggregate sees this tick's upstream result, not a stale one.functions.py: built-in registry (worst_validity,count_true,count_valid,min/max/mean/median_value,sequence_validity), including an explicit severity-ranking table sinceValidity'sIntEnumordinal is declaration order, not severity (INVALID_NO_DATAhas a lower ordinal thanVALID_GOOD).engine.py:ComputeEngine.tick()/run_forever(), with engine-enforced staleness/missing-input policy (skipvspropagate) and per-node persistent state (ComputeContext.state) so a stateless function design can still express stuck-timeout/trajectory checks likesequence_validity.monitorsystem:array:antennas_online(count_trueoverantenna:1-8:is_online), declared under a newmonitorsystemsubtree inconf/smax.json.smax.smax_data_types.Smax*instances): unhashableSmaxStrin state-machine validity lookup,_parse_index_setraising on real hyphenated segment names like4K-plate, and_wrap()passing a bare float whereSmaxVarBase.timestampneeds adatetime.Test plan
uv run pytest src/slama/monitor/ -q— 145 passeduv run ruff check src/slama/monitor/— clean (aside from pre-existing, unrelated warnings verified viagit stashagainstmain)localhost:6380): seededantenna:1-8:is_online, ranpython -m slama.monitor.compute conf/computations.json --once, confirmedmonitorsystem:array:antennas_online= 6 and validity metadata =VALID_WARNING_LOW(correct:warn_low=6, value=6)monitorsystem:*output points with an initial value before first run —MonitorSystem.read_all()(shared withFaultSystem) eagerly pulls every declared point including outputs, so an unwritten output point crashes the first tick🤖 Generated with Claude Code