Sign in

    tideweave

    Generic embeddable event-time windowing library: windows, watermarks, UDAFs, triggers and state cleanup, plus a correction layer (retraction rebuild, finality guards, before-image validation) for amended facts. Structured events supported.

    event-time
    retraction
    session-window
    streaming
    changelog
    Download zip
    Author
    Version
    0.2.4
    License
    MIT
    Last updated
    5 hours ago
    Downloads
    43

    No dependencies

    #TideWeave

    通用、可嵌入的事件时间窗口处理库:窗口、水位线、UDAF、触发与状态清理,对标 Flink 能力;在此之上提供一般窗口库不具备的事实更正层(撤回重建、终结保护、before-image 校验)。事件支持任意结构化字段,数值度量可按字段配置。

    MoonBit 事件时间窗口与修正日志引擎。迟到事件可以合并会话,撤回桥接事件可以重新拆分会话;每次原子修正输出 before/after 变更,显式水位线保护已终结事实,下游按版本检查漏接与旧值冲突。

    跨平台 CI

    实验室中的迟到事件合并与变更日志

    #一个容易出错的真实问题

    同一设备先上报 at=0 和 at=16 的两条记录,gap=10,因此它们属于两个会话。设备恢复网络后补传 at=8 的记录,两个会话应合并。随后发现该记录有误并撤回,窗口必须再次拆分。只对 SUM 做加减会留下错误的边界、成员与 min/max。

    TideWeave 将每次修正视为原子状态变更:计算候选事实 → 重建受影响 key → 校验终结约束 → 提交版本 → 输出完整变更。事务若失败,窗口、事件索引、去重状态与版本一起保持原状。

    #已实现

    • 滚动、带相位偏移的滑动与会话窗口;半开区间;负窗口起点的数学 floor 对齐。
    • 按事件 ID 插入、替换、撤回,支持跨 key 移动与多项原子事务。
    • 会话迟到合并、撤回拆分,count / Int64 sum / min / max 与完整成员来源。
    • 显式水位线推进与 allowed-lateness 迟到容忍;WatermarkTracker 提供有界乱序水位生成;within_lateness 探针。
    • 可插拔自定义聚合(UDAF):Measure + measure_window,内置 count/sum/min/max/avg。
    • 任意结构化事件:事件可携带 fields 键值属性并随检查点与变更日志完整保留(扁平键值,单事件 ≤32 项,嵌套结构请序列化为字符串);配置 value_field 后,任意整数字段即可作为窗口度量(事件无需再带固定 value)。
    • 可配置触发:Watermark 或 Count(n) 提前发射;结果以 before/after changelog 输出,下游 View 原子校验。
    • 显式状态清理:Forget 封存已终结事实、释放活动容量、拒绝后续修正,且可经 checkpoint 精确回放。
    • open → closing → final;保护已终结窗口及原始事件,拒绝将旧事实重新打开。
    • 成功命令幂等、冲突检测;可重放检查点恢复后继续去重。
    • 稳定顺序的 before/after 日志,以及校验版本连续性、旧值与原子应用的下游 View。
    • 严格 JSON 协议,拒绝重复解码键、未知字段、被浮点舍入掩盖的小数和不适用参数。
    • Node CLI、六个可重现示例、交互式浏览器实验室(六个场景),共用 MoonBit 核心。

    能力与 Apache Flink 事件时间窗口体系的逐条对照见 Flink 能力对照。

    Flink 是分布式集群运行时,解决的是大规模、长期、多租户流的吞吐问题。TideWeave 解决的是另一个问题:已经发生的事实被更正时,如何给出可核对、可回放、可被下游验证的修正。这不是营销话术,而是行为差异:

    场景Flink 的典型做法TideWeave
    撤回桥接事件后的会话边界retract 流交给下游自行消化;窗口边界不会自动重新拆分按连通分量重新拆分会话,输出完整 delete + upsert
    已终结窗口被迟到数据改写依赖 allowed lateness 与下游幂等,边界语义分散final 窗口与其成员事实显式保护,等 SUM 也无法绕过
    下游漏接或拿到旧值需自建版本校验View 原子校验版本连续性、before-image 与行身份
    部署形态JVM 集群、状态后端、checkpoint 存储单进程嵌入式,确定性回放,无外部依赖

    Flink 有的窗口、水位线、UDAF、触发、状态清理我们逐项对标实现;Flink 做起来最痛的"撤回后重建 + 终结保护 + 下游校验"是独立贡献。两者是不同部署层级,不是替代关系。

    #在 MoonBit 中使用

    要求编译器 0.10.16 或更新兼容版本。

    moon add LMK-ai-nb/tideweave@0.2.4

    在消费项目的 moon.pkg 加入:

    import { "LMK-ai-nb/tideweave" @tide }

    在可抛出错误的函数中:

    let cfg = @tide.config(@tide.Session(gap=10), lateness=20, value_field=Some("watts")) // 度量取自 fields.watts
    let engine = @tide.Engine::new(cfg)
    let view = @tide.View::new()
    let outcome = engine.apply(@tide.Transact(id="batch-1", changes=[
    @tide.Put({ id: "left", key: "device-A", at: 0, value: 20, fields: Some([("watts", "20")]) }),
    @tide.Put({ id: "right", key: "device-A", at: 16, value: 35, fields: Some([("watts", "35")]) }),
    ]))
    view.apply(outcome)
    let restored = @tide.restore(engine.checkpoint())
    assert_true(restored.rows() == engine.rows())

    完整公开接口由 moon info 生成,见 pkg.generated.mbti。aggregate 可批处理;Engine 可持续接收容量内的修正;replay_json / resume_json 提供严格文本边界。

    #什么场景才用得到:三个具体场合

    先说清楚这个库不做什么:它不负责"把一条已入库的记录改对",那是 UPDATE 的活。它负责的是另一件事——当"事实被更正"本身是一条流时,窗口结果如何保持一致,以及如何向对账方交代到底改了什么。三个具体场合:

    场合数据库/业务系统的做法为什么不够
    设备网关、边缘控制器、桌面工具、CI 测试夹具没有数据库可改现场只有一个进程,既没有 DB 也没有集群;但迟到合并、撤回拆分、窗口边界一样要算对
    广告计费、退款回冲、订单撤改定时全量重算,或 UPDATE 后另补一张报表更正不是一次性动作:无效流量撤回、退款、补传各自成流,乱序且会重复;照命令日志重放会二次扣减
    对账、审计、风控要求"交代改了什么"行级 after 值,或翻 binlog给不出成员级 before/after,也给不出"这两个会话本该拆开"的拓扑结论;下游没法在应用前拦下旧值

    反过来,下面几种情况不必用这个库,用了反而更麻烦:只要每天出一张报表、允许全量重算的,用数仓;追求集群吞吐与多租户隔离的,用 Flink;需要跨机共享状态与高可用的,本项目是单进程嵌入,不合适。

    同一套窗口、水位与撤回语义,已经跑通三个互不相干的域——设备会话(session-correction)、订单(order-amendment)、广告计费(ad-billing)。差别只在 fields 与 value_field,引擎本身不认领域,只认 (key, at, 结构化字段)。

    用数据库完成同样的事,需要物化视图、触发器、自研撤回流与版本校验,事件时间语义散落在应用层;而且 UPDATE 本身不可重放,要幂等还得另建一层命令去重——这层去重、终结保护与变更日志,正是本库提供的东西。

    #与社区同类项目的关系(主动披露)

    八月初审的多份驳回通知指出"社区已有类似项目、申报未说明扩展关系"。本项目主动披露检索结果与边界,详见 同类项目披露。

    检索到的 MoonBit 同类包各有明确分工:moonwatermarkkit 做水位判定与窗口分配原语(无状态聚合、无撤回);moon-stream-quality 做数据质量规则与迟到策略;moon-distinct-sketch 做近似统计;mooncep 做复杂事件模式检测(其文档明确声明不支持事件修正/撤回)。

    TideWeave 与它们无代码复用、不是任何项目的分支或扩展,独立实现窗口分配、水位推进、聚合、修正与检查点。差异集中在修正层:撤回后重建会话、原子多事件事务、终结保护、before-image 校验。需要"水位判定"或"数据质量规则"时,上述专门包更合适;需要"已记录事实被更正后仍保持一致"时用 TideWeave。

    #两种接入方式:库内嵌,或管道直连

    不需要先写一套集成代码:

    1. 库内嵌:moon add LMK-ai-nb/tideweave,在 MoonBit 程序中直接调用 Engine::apply,见上一节。
    2. 管道直连:stream 子命令读取 NDJSON(首行配置,其后每行一条命令),逐行输出结果,末尾输出 summary 与 checkpoint。任何能产出换行 JSON 的进程都能直接驱动:

    cat examples/session-stream.ndjson | node bin/tideweave.mjs stream node bin/tideweave.mjs stream examples/session-stream.ndjson --checkpoint saved.json

    同一核心同时提供 MoonBit 类型化 API、严格 JSON 协议、CLI 与浏览器实验室;宿主按需选择接入层,不必重写业务逻辑。更多宿主侧示例见 接入指南。

    #运行与验证

    moon version --all moon check --target all --deny-warn moon test --target wasm-gc,wasm,js --deny-warn moon build --target wasm-gc,wasm,js --deny-warn moon fmt --check moon info node scripts/check_identity.mjs moon run cmd/demo node scripts/build.mjs node --test tests/cli.test.mjs node scripts/serve.mjs

    浏览器打开 http://127.0.0.1:4174。Node 要求 22+;没有第三方 npm 依赖。

    这里刻意只列 wasm-gc / wasm / js 三个目标——任何机器都能跑。--target all 会带上 native,需要本机有平台 C 工具链(Windows 为 MSVC Build Tools + Windows SDK),没有时 moon test --target all 会直接报 requires an MSVC compiler/linker driver。native 由 CI 在三个系统上分别验证。

    node bin/tideweave.mjs run examples/order-amendment.json --checkpoint checkpoint.json node bin/tideweave.mjs run examples/session-correction.json node scripts/benchmark.mjs # 恢复:checkpoint 不能直接喂给 resume,要嵌进请求 node -e "const c=require('./checkpoint.json');require('fs').writeFileSync('resume.json',JSON.stringify({schema_version:1,checkpoint:c,commands:[]}))" node bin/tideweave.mjs resume resume.json

    CLI 退出码:0 表示所有命令 accepted/duplicate;1 表示存在 rejected/conflict(演示中有意触发);2 表示输入/IO/运行错误。resume 接收的是请求对象 {schema_version:1,checkpoint:<保存的对象>,commands:[...]},把裸 checkpoint 文件直接传进去会得到 unknown or inapplicable field。完整格式见 FORMAT.md。

    可选浏览器检查:安装 Python Playwright 和 Chromium 后,在预览服务运行时执行 python tests/browser.py。CI 在 Linux 实际运行此检查。

    #质量与边界

    67 个 MoonBit 测试包括独立区间枚举 oracle、独立图连通 oracle、混合 key 状态差分、原子回滚、终结保护、检查点恢复、自定义聚合、水位生成、触发与状态封存。10 个 Node 集成测试覆盖公共协议与真实 CLI;Chromium 检查交互、导出、注入文本与 390px 手机布局。GitHub CI 在 Linux、macOS、Windows 检查 wasm、wasm-gc、js、native 四个目标。

    这是有界、同步、单进程的可嵌入状态机,适用于离线对账、边缘批次及流处理回归测试。最多 5000 活跃事件、10000 成功命令、20000 窗口、2 Mi 规范 journal 单元。状态清理是显式的:Forget 封存已终结事实并释放活动容量,封存事实冻结为可回放的不可变历史,不做静默驱逐。连续无限流需要宿主设计分区/批次生命周期,宿主还负责消息 IO、持久化、授权与外部消费一致性。这里不提供分布式运行时或外部 exactly-once 承诺。

    Windows / Node 24 合成基准:4096 事件、64 key、32 批次,包含解析、状态修正、日志、检查点和完整 JSON 输出,10 次样本中位约 84 ms。环境、范围与复现命令见 BENCHMARK.md,不将其外推为生产吞吐承诺。

    #可核对证据

    每条主张都能定位到可运行的代码或测试,不必只读文字:

    主张证据
    撤回后重建会话(不是数值减法)node scripts/compare_naive.mjs;examples/session-correction.json
    终结窗口与成员事实保护boundary_wbtest.mbt、engine_wbtest.mbt
    自定义聚合(UDAF)aggregate.mbt、aggregate_wbtest.mbt
    水位生成与迟到判定watermark.mbt、watermark_wbtest.mbt
    触发(Watermark / Count)trigger_wbtest.mbt
    状态封存与确定性回放forget_wbtest.mbt;moon run cmd/demo 末行 frozen=2, active=0
    NDJSON 流式驱动examples/session-stream.ndjson、tests/cli.test.mjs
    结构化事件与可配置度量structured_wbtest.mbt;examples/structured-events.json;API.mbt.md(随测试编译)
    同一引擎跨域通用(设备/订单/广告计费)examples/session-correction.json、order-amendment.json、ad-billing.json 三个不相干域共用同一套窗口与撤回语义
    提交身份归属node scripts/check_identity.mjs

    全部测试:moon test --target wasm-gc(70 项)、node --test tests/cli.test.mjs(10 项)。

    #原创性与申报

    维护者:李明坤 / LMK-ai-nb。独立新仓库与新业务实现,不复用 submit-guard、permscope 或 AgentCanary 的核心。事件时间、窗口和 changelog 是已有概念;本项目的独立贡献是修正、会话拆分、事务终结保护、下游旧值校验和重启去重的组合实现,不声称发明流处理。

    开发使用 AI 辅助;维护者须理解实现并承担验证责任。原创代码 MIT,标准库编译分发保留许可与 NOTICE,所有示例为合成数据,见 第三方说明。

    十月报名表要求一页内 Markdown 申报书,且注明“不要使用 AI 编写”。项目事实文档是参考材料,正式申报书须由李明坤理解项目后亲自撰写。技术交付不等于完成官方报名/通过审核。见 申报说明 与 三分钟演示。

    TideError

    pub(all) suberror TideError {
    TideError(String)
    } derive(Eq)

    TideError::equal

    fn TideError::equal(TideError, TideError) -> Bool

    TideError::not_equal

    fn TideError::not_equal(x : TideError, y : TideError) -> Bool

    Command

    pub(all) enum Command {
    Transact(id~ : String, changes~ : Array[Mutation])
    Advance(id~ : String, to~ : Int)
    Forget(id~ : String, to~ : Int)
    } derive(Eq)

    impl ToJson for Command

    Command::equal

    fn Command::equal(Command, Command) -> Bool

    Command::not_equal

    fn Command::not_equal(x : Command, y : Command) -> Bool

    Command::to_json

    fn Command::to_json(self : Command) -> Json

    Config

    pub(all) struct Config {
    window : WindowSpec
    lateness : Int
    max_events : Int
    max_operations : Int
    trigger : Trigger
    value_field : String?
    } derive(Eq)

    impl ToJson for Config

    Config::equal

    fn Config::equal(Config, Config) -> Bool

    Config::not_equal

    fn Config::not_equal(x : Config, y : Config) -> Bool

    Config::to_json

    fn Config::to_json(self : Config) -> Json

    Delta

    pub(all) struct Delta {
    kind : String
    before : Window?
    after : Window?
    } derive(Eq, ToJson)

    Apply all deltas in an outcome atomically. Deletes precede upserts.

    Delta::equal

    fn Delta::equal(Delta, Delta) -> Bool

    Delta::not_equal

    fn Delta::not_equal(x : Delta, y : Delta) -> Bool

    Delta::to_json

    fn Delta::to_json(Delta) -> Json

    Engine

    pub struct Engine {
    cfg : Config
    records : Map[String, Event]
    frozen : Map[String, Event]
    materialized : Array[Window]
    clock : Int
    revision : Int
    committed : Map[String, Command]
    journal : Array[Command]
    journal_units : Int
    }

    Opaque mutable engine. Public queries and outcomes return detached arrays.

    Engine::apply

    fn Engine::apply(self : Engine, command : Command) -> Outcome

    All failures leave state, version, successful IDs and journal unchanged.

    Engine::checkpoint

    fn Engine::checkpoint(self : Engine) -> String

    A portable validated replay checkpoint, not a signed proof of history.

    Engine::correctable

    fn Engine::correctable(self : Engine, id : String) -> Bool

    True when the event is still active and none of its current windows is final. This mirrors the freeze predicate used by Forget. A correction that moves the event to another key or timestamp can still be rejected by finality in the destination windows.

    Engine::events

    fn Engine::events(self : Engine) -> Array[Event]

    Active (still correctable) events, sorted by ID. Sealed finalized facts are excluded: they are frozen and can no longer be inserted, replaced or removed.

    Engine::frozen_count

    fn Engine::frozen_count(self : Engine) -> Int

    Number of frozen (finalized) facts still retained for replay.

    Engine::lateness

    fn Engine::lateness(self : Engine) -> Int

    Engine::new

    fn Engine::new(cfg : Config) -> Engine raise TideError

    Engine::rows

    fn Engine::rows(self : Engine) -> Array[Window]

    Detached, sorted materialized view. Mutating its arrays cannot alter state.

    Engine::run

    fn Engine::run(engine : Engine, commands : Array[Command]) -> Replay raise TideError

    Resume on an existing engine; commands are processed in supplied order.

    Engine::version

    fn Engine::version(self : Engine) -> Int

    Engine::watermark

    fn Engine::watermark(self : Engine) -> Int

    Engine::within_lateness

    fn Engine::within_lateness(self : Engine, at : Int) -> Bool

    True when an event timestamp is not more than allowed_lateness behind the current watermark: at + allowed_lateness >= watermark. This is the Flink-style "late event" heuristic hosts use to decide whether to forward a correction. It is not a correctness guarantee: window finality is the authoritative gate, and a timestamp behind the watermark can still land in a window whose end lies in the future (and thus remain correctable). For an exact answer about a specific fact, use correctable.

    Event

    pub(all) struct Event {
    id : String
    key : String
    at : Int
    value : Int
    fields : Array[(String, String)]?
    } derive(Eq)

    Event ID is global within one engine. Keys and IDs are opaque Unicode. fields carries arbitrary structured attributes as sorted key/value pairs; value is the numeric measure the built-in aggregates consume (either supplied directly, or derived from Config.value_field).
    impl ToJson for Event

    Event::equal

    fn Event::equal(Event, Event) -> Bool

    Event::field

    fn Event::field(self : Event, key : String) -> String?

    Look up one structured field. Fields are stored sorted, so this is a linear scan over at most 32 entries.

    Event::measure

    fn Event::measure(self : Event, value_field : String?) -> Int64 raise TideError

    The numeric measure this event contributes to built-in aggregates: its value, or — when the engine is configured with value_field — the structured field of that name parsed as a plain decimal integer.

    Event::not_equal

    fn Event::not_equal(x : Event, y : Event) -> Bool

    Event::to_json

    fn Event::to_json(self : Event) -> Json

    Measure

    pub(all) struct Measure {
    name : String
    identity : Int64
    step : (Int64, Int64) -> Int64
    finish : (Int64, Int64) -> Int64
    }

    A pluggable scalar aggregate (user-defined aggregate function, UDAF).

    step folds one event measure (its value, or the configured structured field) into the accumulator; finish turns the accumulator and the event count into the emitted measure value. Because measure_window recomputes a window from its full member list on every call, measures stay correct under late arrivals and retractions without a separate subtractive pass — the window members are the source of truth.

    MeasureResult

    pub(all) struct MeasureResult {
    name : String
    value : Int64
    } derive(Eq, ToJson)

    A named, computed measure value.

    MeasureResult::equal

    MeasureResult::not_equal

    fn MeasureResult::not_equal(x : MeasureResult, y : MeasureResult) -> Bool

    MeasureResult::to_json

    MeasureWindow

    pub(all) struct MeasureWindow {
    key : String
    start : Int
    end : Int
    count : Int
    measures : Array[MeasureResult]
    phase : String
    } derive(Eq, ToJson)

    A window summarized by caller-chosen measures instead of the fixed count/sum/min/max profile. Uses the same assignment, session grouping and phase rules as the stateful engine.

    MeasureWindow::equal

    MeasureWindow::not_equal

    fn MeasureWindow::not_equal(x : MeasureWindow, y : MeasureWindow) -> Bool

    MeasureWindow::to_json

    Mutation

    pub(all) enum Mutation {
    Put(Event)
    Remove(String)
    } derive(Eq)

    impl ToJson for Mutation

    Mutation::equal

    fn Mutation::equal(Mutation, Mutation) -> Bool

    Mutation::not_equal

    fn Mutation::not_equal(x : Mutation, y : Mutation) -> Bool

    Mutation::to_json

    fn Mutation::to_json(self : Mutation) -> Json

    Outcome

    pub(all) struct Outcome {
    id : String
    status : String
    version : Int
    watermark : Int
    deltas : Array[Delta]
    message : String
    } derive(Eq, ToJson)

    Outcome::equal

    fn Outcome::equal(Outcome, Outcome) -> Bool

    Outcome::not_equal

    fn Outcome::not_equal(x : Outcome, y : Outcome) -> Bool

    Outcome::to_json

    fn Outcome::to_json(Outcome) -> Json

    Replay

    pub(all) struct Replay {
    schema_version : Int
    config : Config
    steps : Array[Outcome]
    rows : Array[Window]
    events : Array[Event]
    frozen : Int
    watermark : Int
    version : Int
    checkpoint : Json
    } derive(ToJson)

    Replay::to_json

    fn Replay::to_json(Replay) -> Json

    Trigger

    pub(all) enum Trigger {
    Watermark
    Count(threshold~ : Int)
    } derive(Eq)

    When a window is emitted early (marked closing) before the watermark finalizes it. Watermark is the default and keeps the original behavior; Count(n) additionally marks a window closing once it holds n events. Trigger affects emission/phase only — finality still depends on the watermark plus allowed lateness, so early-fired windows stay correctable.
    impl ToJson for Trigger

    Trigger::equal

    fn Trigger::equal(Trigger, Trigger) -> Bool

    Trigger::not_equal

    fn Trigger::not_equal(x : Trigger, y : Trigger) -> Bool

    Trigger::to_json

    fn Trigger::to_json(self : Trigger) -> Json

    View

    pub struct View {
    materialized : Array[Window]
    revision : Int
    clock : Int
    last_delivery : String
    }

    A downstream materialized view that rejects gaps and stale before-images.

    View::apply

    fn View::apply(self : View, outcome : Outcome) -> Unit raise TideError

    Validates transport consistency; authenticity is the host's responsibility.

    View::new

    fn View::new() -> View

    View::rows

    fn View::rows(self : View) -> Array[Window]

    View::version

    fn View::version(self : View) -> Int

    WatermarkTracker

    pub struct WatermarkTracker {
    max_time : Int
    allowed_lateness : Int
    }

    A bounded-out-of-orderness watermark generator, the counterpart of Flink's BoundedOutOfOrdernessWatermarks: the watermark trails the largest observed event timestamp by exactly allowed_lateness. Feed every observed event timestamp into observe, then advance the engine with the returned value.

    WatermarkTracker::max_time

    fn WatermarkTracker::max_time(self : WatermarkTracker) -> Int

    WatermarkTracker::new

    fn WatermarkTracker::new(allowed_lateness? : Int) -> WatermarkTracker raise TideError

    WatermarkTracker::observe

    fn WatermarkTracker::observe(self : WatermarkTracker, at : Int) -> Int raise TideError

    Record an observed event timestamp and return the current watermark.

    WatermarkTracker::value

    fn WatermarkTracker::value(self : WatermarkTracker) -> Int

    The current watermark: max(0, max_time - allowed_lateness).

    Window

    pub(all) struct Window {
    key : String
    start : Int
    end : Int
    count : Int
    sum : Int64
    min : Int
    max : Int
    members : Array[String]
    phase : String
    } derive(Eq, ToJson)

    Finality is materialized so downstream consumers need no hidden clock.

    Window::equal

    fn Window::equal(Window, Window) -> Bool

    Window::not_equal

    fn Window::not_equal(x : Window, y : Window) -> Bool

    Window::to_json

    fn Window::to_json(Window) -> Json

    WindowSpec

    pub(all) enum WindowSpec {
    Tumbling(size~ : Int, offset~ : Int)
    Sliding(size~ : Int, slide~ : Int, offset~ : Int)
    Session(gap~ : Int)
    } derive(Eq)

    Window parameters use caller-defined integer time units.

    WindowSpec::equal

    fn WindowSpec::equal(WindowSpec, WindowSpec) -> Bool

    WindowSpec::not_equal

    fn WindowSpec::not_equal(x : WindowSpec, y : WindowSpec) -> Bool

    WindowSpec::to_json

    fn WindowSpec::to_json(self : WindowSpec) -> Json

    aggregate

    fn aggregate(c : Config, events : Array[Event], watermark? : Int) -> Array[Window] raise TideError

    Batch aggregation API. Validates the same bounds used by the state machine.

    assign_fixed

    fn assign_fixed(spec : WindowSpec, at : Int) -> Array[(Int, Int)] raise TideError

    Return start/end pairs in ascending order, including negative starts.

    average_measure

    fn average_measure() -> Measure

    Arithmetic mean, truncated toward zero (integer arithmetic).

    config

    fn config(window : WindowSpec, lateness? : Int, max_events? : Int, max_operations? : Int, trigger? : Trigger, value_field? : String?) -> Config raise TideError

    count_measure

    fn count_measure() -> Measure

    decode_commands

    fn decode_commands(source : String) -> Array[Command] raise TideError

    decode_config

    fn decode_config(source : String) -> Config raise TideError

    max_measure

    fn max_measure() -> Measure

    measure

    fn measure(name~ : String, identity~ : Int64, step~ : (Int64, Int64) -> Int64, finish~ : (Int64, Int64) -> Int64) -> Measure

    A custom measure: identity seeds the fold, step accumulates one event value, finish derives the result from the accumulator and member count.

    measure_window

    fn measure_window(c : Config, events : Array[Event], measures : Array[Measure], watermark? : Int) -> Array[MeasureWindow] raise TideError

    Compute caller-chosen measures for every window of the supplied events, reusing the engine's window assignment, session grouping and phase rules. Validate the same bounds as the stateful engine.

    min_measure

    fn min_measure() -> Measure

    replay

    fn replay(c : Config, commands : Array[Command]) -> Replay raise TideError

    replay_json

    fn replay_json(source : String) -> String raise TideError

    Validate all input before running; domain rejections are report steps.

    restore

    fn restore(source : String) -> Engine raise TideError

    resume_json

    fn resume_json(source : String) -> String raise TideError

    Resume input has a checkpoint object and an array of new commands.

    stream_json

    fn stream_json(source : String) -> String raise TideError

    Process newline-delimited JSON (NDJSON) in one incremental pass.

    The first non-blank line is a session header: {"schema_version":1,"config":{...}}. Every later non-blank line is one command object, exactly as it would appear in a replay commands array. The result is one outcome line per command followed by a final {"summary":{...}} line, so the engine can be driven by any line-oriented producer without writing MoonBit or re-parsing a whole batch.

    sum_measure

    fn sum_measure() -> Measure

    validate_event

    fn validate_event(e : Event) -> Unit raise TideError