Sign in

    joinwitness

    Preflight equality joins with exact cardinality, constructive witnesses, coverage contracts and pair-set change analysis.

    join
    cardinality
    counterexample
    data-quality
    etl
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    5 days ago
    Downloads
    16

    No dependencies

    #JoinWitness

    执行关联前,看清哪些键会重复计数、丢失记录,以及反例在哪里。

    MoonBit 原创的有界等值关联预检库:精确输出规模、基数与覆盖率契约、可复现的三行反例、完整输入的缺失匹配核验,以及候选键的真实行对集合变化。

    CI

    关联预检工作台

    #为什么只比较行数不够

    订单和客户表都按 customer 关联,但不同租户可以拥有相同的 customer ID。示例中 4 笔订单关联后会变成 7 行,其中一个订单可以匹配到两位客户。JoinWitness 导出 1 笔订单 + 2 位客户 的完整三行反例:去掉其中任意一行,这个特定的基数违规就不再成立。

    候选复合键加入 tenant 后输出为 4 行,保留 4 个行对、去掉 3 个行对。是否确实符合业务含义仍由使用者判断。

    另一个示例中,更换关联键前后都输出 2 行,但 保留 0、丢失 2、新增 2。总数完全一样,实际关联对象已经全部换掉。仅做 count 回归会漏掉这个变化。

    #已实现

    • inner / left / right / full 等值关联;1..8 个可异名映射的组合键。
    • 文本、整数、布尔值、NULL 严格区分;显式普通 SQL NULL 或组件式 null-safe 匹配。
    • 通过键桶乘积计算精确匹配数量和外连接输出,提前判断预算,无需构造庞大的输出积。
    • matched-group 基数契约、左右覆盖率、输出上限,互相独立检查。
    • 违规来源行 ID、最小的三行多重匹配反例,以及针对完整对表核查的缺失匹配证据。
    • 反例独立导出、再次检查,防止重复 ID、错误键与伪造范围被当作有效证据。
    • 两套键的匹配行对交集与 lost/gained,既报告规模,也报告身份变化和新丢失覆盖。
    • 全部契约通过后,按预算构造可追溯的完整来源行对;不输出失败事务的部分结果。
    • 严格 JSON 协议、Node CLI、可运行 MoonBit 示例和交互式浏览器工作台。

    #运行

    要求 MoonBit 编译器 0.10.16 或更新兼容版本、Node 22+。没有第三方 npm 依赖。

    git clone https://github.com/JQ-ai-nb/JoinWitness.git cd JoinWitness moon check --target all --deny-warn moon test --target all --deny-warn moon build --target all --deny-warn moon fmt --check moon info moon run cmd/demo node scripts/build.mjs node --test tests/cli.test.mjs node scripts/serve.mjs

    浏览器打开 http://127.0.0.1:4175。Native 编译还需要平台 C 工具链;Windows CI 使用 MSVC。

    node bin/joinwitness.mjs check examples/tenant-collision.json node bin/joinwitness.mjs case examples/tenant-collision.json 0 node bin/joinwitness.mjs materialize examples/tenant-collision.json --candidate node scripts/benchmark.mjs

    退出码 0:预检通过或成功导出;1:预检发现契约问题;2:无效输入、被拒绝的构造请求或 IO 错误。示例第一条 check 预期退出 1,这是检测到问题。候选键只在显式 --candidate 时用于构造结果。

    Git 身份日志回归需要真实 Git 克隆;无 .git 的源码归档运行时会跳过这一项,其他 CLI/ESM 检查照常运行。

    可选独立 SQL 对照:python tests/sqlite_oracle.py(SQLite 3.39+)。可选浏览器检查:安装 Python Playwright/Chromium,保持预览服务运行,执行 python tests/browser.py。

    #在 MoonBit 中调用

    模块命名空间为 JQ-ai-nb/joinwitness。Mooncakes 发布状态见 RELEASE.md;确认发布前请使用源码。

    库接口提供 plan、inventory、audit、compare、verify_witness、counterexample、materialize;JSON 文本入口包括 inspect_json、materialize_json、export_case_json。公开签名见 pkg.generated.mbti,可执行 API 文档 随测试验证。

    #质量、规模与边界

    35 项 MoonBit 测试覆盖独立双重循环 oracle、组合键、NULL、基数、反例删除最小性、伪造证据、覆盖率、候选行对交集与资源限制。12 项 Node 集成测试验证真实 CLI/ESM;真实 SQLite 对照 320 组完整行对集合;Chromium 检查候选切换、反例下载、来源定位、注入文本和手机布局。CI 在 Linux/macOS/Windows 检查 wasm、wasm-gc、js、native。

    Windows / i7-14650HX / Node 24 合成基准:两表各 10000 行的单键关联,精确预检 1 亿匹配对但不构造它们,中位约 30.76ms;两表各 5000 行的复合键比较中位约 42.56ms。包含解析、证据、比较和完整 JSON 输出,见 基准范围。不将合成样例外推为生产吞吐承诺。

    这是有界内存工具,不解析任意 SQL、不连接数据库,也不验证真实业务键的语义。最多每表 10000 行、64 列、8 个关联键,文本单元长度 512、每表文本总量 2 Mi UTF-16 单元,JSON 输入 8 Mi 单元;最多构造 20000 个来源行对。证据返回上限 128 条,但问题总数完整统计。字符串精确、区分大小写;没有数据库排序规则、类型强转、范围关联或浮点近似匹配。

    三行反例仅用于构造式多重匹配违规;“没有匹配对象”必须结合完整对表核验,不能由一个空白小片段证明。证据复核不是加密来源认证,宿主负责可信输入、IO、持久化与隐私。

    #维护者与申报

    蒋琦 / JQ-ai-nb。仓库作者和提交者统一为蒋琦,使用账户专属 GitHub noreply 邮箱;python scripts/check_identity.py 检查整个保留历史,CI 同样检查。

    项目与 orbitcron、robopolicy、AgentCanary、TideWeave 的业务实现独立。JOIN、基数与反例是已有概念;独立贡献是具备明确边界的预检、证据复核与行对差分工具,而非发明关系运算。原创代码 MIT;AI 辅助开发已披露,维护者须理解和验证成果。标准库分发说明见 THIRD_PARTY_NOTICES.md。

    十月正式申报书要求一页以内 Markdown,并注明“不要使用 AI 编写”。项目事实文档只能参考,正式申报书须由蒋琦本人理解后独立撰写;技术交付不等于完成报名或官方验收。见 申报说明。

    JoinError

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

    JoinError::equal

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

    JoinError::not_equal

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

    Audit

    pub(all) struct Audit {
    schema_version : Int
    plan : Plan
    inventory : Inventory
    left_multiplicity_groups : Int
    right_multiplicity_groups : Int
    issue_count : Int
    safe : Bool
    witnesses : Array[Witness]
    witnesses_omitted : Int
    } derive(ToJson)

    Audit::to_json

    fn Audit::to_json(Audit) -> Json

    Cell

    pub(all) enum Cell {
    NullCell
    Text(String)
    Integer(Int)
    Flag(Bool)
    } derive(Eq)

    Deliberately exact cells. No implicit string/number/bool coercion.
    impl ToJson for Cell

    Cell::equal

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

    Cell::not_equal

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

    Cell::to_json

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

    Comparison

    pub(all) struct Comparison {
    schema_version : Int
    baseline : Audit
    candidate : Audit
    retained_pairs : Int64
    lost_pairs : Int64
    gained_pairs : Int64
    newly_unmatched_left : Array[String]
    newly_unmatched_right : Array[String]
    recovered_left : Array[String]
    recovered_right : Array[String]
    } derive(ToJson)

    Comparison::to_json

    fn Comparison::to_json(Comparison) -> Json

    Group

    pub(all) struct Group {
    key : Array[Cell]
    left_ids : Array[String]
    right_ids : Array[String]
    pairs : Int64
    } derive(Eq, ToJson)

    Buckets include unmatched non-null keys. Null-ineligible rows are separate.

    Group::equal

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

    Group::not_equal

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

    Group::to_json

    fn Group::to_json(Group) -> Json

    Inventory

    pub(all) struct Inventory {
    left_rows : Int
    right_rows : Int
    matched_left : Int
    matched_right : Int
    matched_pairs : Int64
    output_rows : Int64
    unmatched_left : Array[String]
    unmatched_right : Array[String]
    excluded_null_left : Array[String]
    excluded_null_right : Array[String]
    groups : Array[Group]
    } derive(Eq, ToJson)

    Inventory::equal

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

    Inventory::not_equal

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

    Inventory::to_json

    fn Inventory::to_json(Inventory) -> Json

    KeyPair

    pub(all) struct KeyPair {
    left : String
    right : String
    } derive(Eq, ToJson)

    KeyPair::equal

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

    KeyPair::not_equal

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

    KeyPair::to_json

    fn KeyPair::to_json(KeyPair) -> Json

    Pair

    pub(all) struct Pair {
    left_id : String?
    right_id : String?
    } derive(Eq, ToJson)

    Source-row identity pair. None denotes an outer-join null extension.

    Pair::equal

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

    Pair::not_equal

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

    Pair::to_json

    fn Pair::to_json(Pair) -> Json

    Plan

    pub(all) struct Plan {
    kind : String
    keys : Array[KeyPair]
    nulls : String
    cardinality : String
    require_left : Bool
    require_right : Bool
    max_output : Int
    } derive(Eq, ToJson)

    Contracts concern matched keys; coverage is checked separately.

    Plan::equal

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

    Plan::not_equal

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

    Plan::to_json

    fn Plan::to_json(Plan) -> Json

    Row

    pub(all) struct Row {
    id : String
    values : Array[Cell]
    } derive(Eq, ToJson)

    Row::equal

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

    Row::not_equal

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

    Row::to_json

    fn Row::to_json(Row) -> Json

    Table

    pub(all) struct Table {
    name : String
    columns : Array[String]
    rows : Array[Row]
    } derive(Eq, ToJson)

    Columns are an ordered schema; every row has exactly that width.

    Table::equal

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

    Table::not_equal

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

    Table::to_json

    fn Table::to_json(Table) -> Json

    Witness

    pub(all) struct Witness {
    code : String
    scope : String
    key : Array[Cell]
    left_ids : Array[String]
    right_ids : Array[String]
    explanation : String
    } derive(Eq, ToJson)

    Multiplicity witnesses use three rows; absence witnesses require full input.

    Witness::equal

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

    Witness::not_equal

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

    Witness::to_json

    fn Witness::to_json(Witness) -> Json

    audit

    fn audit(left : Table, right : Table, p : Plan) -> Audit raise JoinError

    Preflight every contract, while returning at most 128 explicit witnesses.

    compare

    fn compare(left : Table, right : Table, baseline : Plan, candidate : Plan) -> Comparison raise JoinError

    Exact pair-set changes. Reduced output does not prove a business-correct key.

    counterexample

    fn counterexample(left : Table, right : Table, p : Plan, w : Witness) -> (Table, Table) raise JoinError

    Export a complete three-row reproducer; absence cannot use this mechanism.

    encode_key

    fn encode_key(key : Array[Cell]) -> String

    export_case_json

    fn export_case_json(source : String, index : Int) -> String raise JoinError

    Export a standalone, auditable three-row reproduction request.

    inspect_json

    fn inspect_json(source : String) -> String raise JoinError

    Optional candidate is compared; optional witness is checked, never ignored.

    inventory

    fn inventory(left : Table, right : Table, p : Plan) -> Inventory raise JoinError

    Count exact row multiplicities without constructing any result pairs.

    materialize

    fn materialize(left : Table, right : Table, p : Plan) -> Array[Pair] raise JoinError

    All preflight contracts must pass before any output pair array is built.

    materialize_json

    fn materialize_json(source : String, use_candidate? : Bool) -> String raise JoinError

    This endpoint executes plan, or candidate only when explicitly selected.

    plan

    fn plan(keys : Array[KeyPair], kind? : String, nulls? : String, cardinality? : String, require_left? : Bool, require_right? : Bool, max_output? : Int) -> Plan raise JoinError

    row_key

    fn row_key(t : Table, row_id : String, p : Plan, is_left : Bool) -> Array[Cell]? raise JoinError

    Explain the exact eligibility/key of one source row under a validated plan.

    validate_table

    fn validate_table(t : Table) -> Unit raise JoinError

    verify_witness

    fn verify_witness(left : Table, right : Table, p : Plan, w : Witness) -> Bool raise JoinError

    Recheck claimed evidence against the supplied complete source tables. Explanation prose is not authenticated; only code/scope/keys/row IDs are facts.