Expand description
stratify_branch — substrate operator for classifier-routing.
Substrate counterpart of TS extra/composition/stratify.ts (D199,
Unit 5 Q9.2 of SESSION-rust-port-layer-boundary.md). The TS
stratify(name, source, rules, opts) -> Graph factory composes N
instances of this branch operator (one per rule) inside a single
Graph; the Graph wrapper itself stays binding-side (presentation
under D193). The classifier-routing logic — two-input subscribe,
reactive-rules cache, two-dep DIRTY gating, per-fire dispatch — is
the Rust substrate.
§Semantics (mirrors TS _addBranch in stratify.ts)
- Subscribes to BOTH
sourceandrules. Rules first, then source — so push-on-subscribe of rules’ cached DATA arrives before any source DATA the branch processes (R2.2.7). - Two-dep DIRTY gating (TS parity). On either dep’s DIRTY, the
handler buffers and waits. When BOTH deps have settled in the
same wave (no pending DIRTY on either), the cached source value
is classified under the cached rules. This eliminates the
stale-rules race when both deps update inside a single
core.batch(). rulesDATA: replaces the cached rules handle. Retains the new handle; releases the previously cached one. No downstream emit (“future items only” — rules updates affect FUTURE source items classified under them, not the current one).sourceDATA: buffered (with retain) until both deps settle. On resolve, invokesbinding.invoke_stratify_classifier_fn(classifier_fn_id, rules_handle, value_handle). Iftrue, the buffered handle’s retain transfers to the emit queue. Iffalse, the handle is released. If no rules handle has arrived (sentinel state), the buffered source DATA is dropped — matches TS “rule not found → false”.sourceCOMPLETE / ERROR / TEARDOWN: forwarded unchanged. F1 fix (QA 2026-05-14) — TEARDOWN forwarding restored to match TSif (depIndex === 0) actions.down([msg])for tier 5 + 6.rulesCOMPLETE / ERROR / TEARDOWN / INVALIDATE: silently absorbed. The branch keeps its last-seen rules cache and continues; rules’ terminals don’t propagate downstream of the branch (TS parity). F5 fix (QA 2026-05-14) — rules INVALIDATE intentionally does NOT clearlatest_rules; matches TS, where rules’ INVALIDATE message is silently absorbed andlatestRuleskeeps its previous value.- On producer deactivation: the Drop impl on
StratifyStatereleases both the cached rules handle and any buffered source value viaWeak<dyn BindingBoundary>(leaf-op safe). - N2 fix (QA 2026-05-14) — under Phase H+ STRICT scheduling,
subscribe_to(rules, ...)may returnDeferred, in which case the post-subscribe sync push doesn’t populatelatest_rulesbefore the source’s first DATA arrives. The build closure defensively readscore.cache_of(rules)and pre-seeds the cache when the sync push didn’t. Matches the TS factory-timelatestRules = rulesNode.cacheseeding.
Functions§
- stratify_
branch - Single classifier-routing branch. Each rule in a TS
stratify(...) -> Graphbecomes one instance of this operator.