Semantic Grammar and Analysis Coaching
CubeDynamics keeps its public language deliberately small:
pipe(noun) | verb() | verb()
The semantic grammar describes that sentence while it runs. It does not create a second language, reorder verbs, optimize a workflow, or replace plain Python callables. Every stage is called once, from left to right, exactly where the author wrote it.
This makes the pipeline more than a compact spelling of function calls: it is an executable scientific statement whose authored syntax can be inspected. Computational repeatability answers whether the statement can run again; scientific inspectability also asks which observations entered, what object each stage produced, and what evidence supports the path to the result. See Scientific inspectability for the full framing.
scientific noun configured verb configured verb
│ │ │
▼ ▼ ▼
pipe(cube) ─────────► anomaly() ─────────► threshold_state()
│ │ │
└─ field metadata └─ trace step └─ condition metadata
execution is never rewritten
The small state vocabulary
The grammar uses a compact vocabulary to describe what flows through the pipe. This is semantic metadata, not a new set of runtime container classes.
| State | Meaning |
|---|---|
observation |
A value whose more specific role is not yet known |
continuous_field |
Numeric measurements distributed in space and/or time |
categorical_field |
Labels or categories distributed in space and/or time |
condition |
A true/false scientific state, with optional magnitude and threshold |
event |
One or more identified intervals or occurrences |
feature |
A discrete geometry or observation feature |
relationship |
A comparison, association, or synchrony result |
summary |
A reduction that no longer retains all source variation |
network |
Connected features with graph or flow semantics |
SemanticState also records dimensions, shape, units, CRS, temporal and
spatial status, time ordering, remaining time variation, source flavor, and
whether source provenance is present. Inference reads metadata and coordinates;
it does not compute array values.
Verb contracts
The registry in cubedynamics.grammar describes a maintained starter set of
verbs. A VerbSpec names accepted and returned states, required information,
preserved or removed information, ownership category, and runnable examples.
import cubedynamics as cd
event_contract = cd.grammar.get_verb_spec("detect_events")
print(event_contract.accepts) # ('condition',)
print(event_contract.requires) # time, ordered time, time variation
all_contracts = cd.grammar.list_verb_specs()
Unregistered callables still work normally. They appear in the trace by their Python function name, and their result state is inferred from public metadata. Projects therefore do not need a base class or registration step to create a custom verb.
Explain, suggest, and validate
The pipe exposes three optional coaching tools. None changes the value or executes another analysis stage.
analysis = (
pipe(temperature)
| v.anomaly(over="time")
| v.threshold_state(threshold=2.0, direction="above")
)
print(analysis.explain())
analysis.suggest()
print(analysis.validate())
explain()narrates the starting noun, each completed verb, the current state, and relevant order notes. It always states the no-rewrite guarantee.suggest()returns at most six compatible, implemented next verbs with a reason and runnable spelling. Conceptual or future verbs are never presented as runnable suggestions.validate()returns a structuredValidationReportand a readable summary. It checks semantic state, dimensions, ordered time, CRS, units, provenance, and order notes using metadata only.CHECKasks for human confirmation; onlyERRORmakes the report unsuccessful.
The immutable semantic_trace and current semantic_state are public for
notebooks, documentation, and agent tooling:
analysis.semantic_state.as_dict()
analysis.semantic_trace[0].as_dict()
The trace covers only the inspected statement. Preparation before pipe(...)
and work after unwrap() remain outside it, so a semantic trace complements
rather than replaces general workflow provenance.
Useful failures
Known incompatible steps fail before their technical implementation produces a
lower-level error. Messages identify what the verb expects, what the current
object represents, and a common repair. For example, detect_events() accepts
a temporal condition, not raw continuous temperature measurements:
detect_events() groups consecutive true periods into events. The current
object is a continuous field ... so there is not yet a condition to group.
A common pattern is: observations → threshold_state(...) → detect_events().
A retained length-one time dimension after mean(over="time") does not fool
the grammar. The trace records that time variation was removed and recommends
detecting events before the reduction.
Order knowledge
Order rules are explanatory knowledge, never rewrite instructions.
| Category | Meaning |
|---|---|
REQUIRED_ORDER |
The later operation requires a product of the earlier one |
ORDER_CHANGES_MEANING |
Both orders may run but answer different questions |
ORDER_REMOVES_REQUIRED_INFORMATION |
The earlier operation can erase information needed later |
ORDER_EQUIVALENT_OR_NEAR_EQUIVALENT |
The order is equivalent only under stated assumptions |
The curated library includes current paths such as anomaly → threshold,
threshold → events, and mean-over-time → events. It also records spatial and
event concepts such as near/density, intersect/summarize, events/duration, and
upstream/intersect for future project vocabularies. Every rule has an
implemented flag. A conceptual rule is available to documentation and agent
tools but cannot become a .suggest() result until a corresponding public verb
actually exists.
For example, these two spatial sentences are both meaningful, but they do not say the same thing:
| Written order | Plain-language interpretation |
|---|---|
buildings → near(streams) → density() |
Select buildings near streams, then calculate the density of those selected buildings |
buildings → density() → near(streams) |
Calculate building density everywhere, then inspect or annotate density relative to streams |
near() and density() are order-library concepts rather than current
CubeDynamics core verbs. They are documented here to show how a project verb
package can share the same coach. The implemented=False flag prevents either
one from being suggested as runnable core API.
rules = cd.grammar.get_order_rules()
future_rules = [rule for rule in rules if not rule.implemented]
Readable dimension keywords
Core reducers and normalizers accept the grammatical over= spelling:
pipe(cube) | v.mean(over="time")
pipe(cube) | v.anomaly(over="time")
The established dim= spelling remains supported. Supplying conflicting
values for both names raises a direct error instead of guessing.
Statement boundary
The adoption path is deliberately reversible:
xarray object → pipe → semantic operations and inspection → unwrap → xarray object
unwrap() acts as a local boundary marker between the inspected statement and
ordinary Python. It returns the wrapped value; it does not force computation,
certify the analysis, complete the wider workflow, or prevent the value from
entering another pipe.
Architectural boundary
┌──────────────────────────────────────────────────────────────┐
│ Public analysis: pipe(noun) | ordinary configured callables │
└──────────────────────────────┬───────────────────────────────┘
│ observes completed stages
┌──────────────────────────────▼───────────────────────────────┐
│ Semantic layer: state + trace + contracts + order notes │
│ explain() suggest() validate() │
└──────────────────────────────┬───────────────────────────────┘
│ metadata only
┌──────────────────────────────▼───────────────────────────────┐
│ Existing xarray, streaming, event, and rendering runtimes │
└──────────────────────────────────────────────────────────────┘
This boundary keeps the grammar useful to scientists and agents while leaving runtime ownership with the established verb implementations.