Skip to content

Latest commit

 

History

55 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

libdualnative

libdualnative is a bounded, deterministic Rust and WebAssembly library for two related JSON operations:

  • three-way merge of scalar/object state from a common base; and
  • RFC 8785 canonical JSON with a structured SHA-256 content identity.

It is experimental pre-1.0 software. Merge input is recursively array-free and arrays fail closed with a typed result. The separate CID domain accepts arrays. Conflict results can reproduce raw application values and must be handled as sensitive data.

Five-minute Rust start

From a source checkout:

cargo +1.82.0 test --all-targets
cargo +1.82.0 run --example basic_merge
cargo +1.82.0 run --example array_rejection

The basic example merges independent changes to name and owner:

use libdualnative::v1::{merge_json_v1, MergeOutcomeV1};

let response = merge_json_v1(
    r#"{"name":"draft","owner":"A"}"#,
    r#"{"name":"ready","owner":"A"}"#,
    r#"{"name":"draft","owner":"B"}"#,
);

match response.outcome {
    MergeOutcomeV1::Merged { merged } => {
        println!("{}", serde_json::to_string(merged.value())?);
    }
    other => println!("merge did not succeed: {other:?}"),
}
# Ok::<(), Box<dyn std::error::Error>>(())

The normalized merged value is:

{"name":"ready","owner":"B"}

The public v0.1.0-alpha.1 prerelease can be consumed from its immutable Git tag without relying on a registry:

[dependencies]
libdualnative = { git = "https://github.com/DualNative/libdualnative-v1", tag = "v0.1.0-alpha.1" }
serde_json = "1"

The package is intentionally absent from crates.io. Do not replace the exact tag with a branch dependency when reproducibility matters.

How three-way merge works

The caller supplies:

  • base: the last state shared by both editors;
  • source: one independently edited state; and
  • target: the other independently edited state.

Independent object-member changes merge. Identical changes agree. Divergent changes to the same value, incompatible type changes, and delete-versus-edit produce complete typed conflicts. Missing object members and explicit JSON null are different states.

Merge accepts bounded JSON null, booleans, finite binary64 numbers, strings, and objects at any supported depth. An array at any depth returns typed arrays_not_supported with its input side and RFC 6901 path. It is never delegated to legacy array behavior.

See API_REFERENCE.md for the seven native operations and DTOs.

Content identities

Use compute_cid_json_v1 when the requirement is canonical identity rather than merge:

use libdualnative::v1::compute_cid_json_v1;

let cid = compute_cid_json_v1(r#"{"b":2,"a":1.0}"#)?;
assert_eq!(cid.algorithm, "libdualnative-rfc8785-sha256-v1");
# Ok::<(), Box<dyn std::error::Error>>(())

The full identity includes schema, domain, algorithm, and digest. The digest alone is not the complete identity. CID accepts ordered arrays even though merge does not.

Negative zero is intentionally admitted and normalized to positive zero. Callers requiring RFC 8785 Erratum 7920 parser behavior must reject -0 before calling the library.

GitHub-only WASM package

The WASM package has no root export and exposes only:

  • libdualnative-wasm-v1/node
  • libdualnative-wasm-v1/web

Each entry exposes init_v1, merge_json_v1, and compute_cid_json_v1. Operations accept primitive JSON strings and return complete compact JSON strings.

Download these two assets from the v0.1.0-alpha.1 prerelease, then verify the sidecar before installing locally:

libdualnative-wasm-v1-0.1.0-alpha.1.tgz
libdualnative-wasm-v1-0.1.0-alpha.1.tgz.sha256
Get-FileHash -Algorithm SHA256 .\libdualnative-wasm-v1-0.1.0-alpha.1.tgz
npm install --ignore-scripts .\libdualnative-wasm-v1-0.1.0-alpha.1.tgz

Minimal Node use:

import {
  init_v1,
  merge_json_v1,
} from "libdualnative-wasm-v1/node";

await init_v1();
const response = JSON.parse(merge_json_v1(
  '{"name":"draft","owner":"A"}',
  '{"name":"ready","owner":"A"}',
  '{"name":"draft","owner":"B"}',
));
console.log(response);

Browser consumers import libdualnative-wasm-v1/web and await init_v1 before computation. Default Web initialization fetches the package-relative WASM module; callers may instead supply one accepted Web initialization input. Generated bindings are internal and are not supported import paths.

The package remains marked private=true to block npm registry publication. That flag does not prevent installation from the verified local archive.

Building WASM from source

Generated output remains ignored under target/wasm-v1:

$env:PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = '1'
npm --prefix wasm ci --ignore-scripts
$env:PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = $null
npm --prefix wasm exec playwright -- install chromium firefox
npm --prefix wasm run build
npm --prefix wasm run test:node
npm --prefix wasm run test:node-failure
npm --prefix wasm run test:adversarial
npm --prefix wasm run test:types
npm --prefix wasm run test:inspect
npm --prefix wasm run test:memory
npm --prefix wasm run test:browser

The normative facade boundary is LIBDUALNATIVE_V1_WASM_FACADE_CONTRACT.md.

Fixed resource envelope

Every merge, CID, and JSON Pointer operation uses the non-configurable libdualnative-core-resource-budget-v1. Its ceilings include:

  • 1 MiB per input;
  • depth 64;
  • 65,536 value nodes;
  • 32,768 object members;
  • 1 MiB canonical output;
  • 2 MiB merge response; and
  • 4,096 conflicts.

A limit failure returns no partial merge, CID, or diagnostic result. There is no option, feature, constructor, environment variable, or alternate public API that raises these limits.

The complete rules are in CORE_V1_RESOURCE_BUDGET_AND_RECURSION_CONTRACT.md. Normalized semantics are in CORE_V1_CONTRACT.md, and semantic identities are in V1_IDENTITY_REGISTRY.md.

Deliberate boundaries

libdualnative does not provide:

  • array merge;
  • profiles or receipts;
  • structural diff;
  • persistence or synchronization;
  • migration between engine generations;
  • authorization, HTTP, WordPress, or agent runtime behavior;
  • configurable limits; or
  • a redacted diagnostic surface.

Conflict DTOs contain normalized values from all three inputs. Do not log, transmit, or render them into HTML without application-level redaction and safe rendering.

The API is explicitly versioned under libdualnative::v1. Package SemVer does not override its semantic engine, domain, schema, algorithm, or resource-budget identities.

Release status

The latest release is the experimental GitHub-only v0.1.0-alpha.1 prerelease, whose source commit is d986f1ab9b851dea8dd8d4a99dac6ef92acd8f25. The Rust crate and WASM archive are not published to crates.io or npm. Release assets include SHA-256 sidecars; verify them before use.

Current main may contain documentation, tests, and package-shell maintenance that is not part of that tagged release. Semantic changes require a new reviewed identity and a separately versioned release.

Validation and reproducible builds

Core local checks:

cargo +1.82.0 test --workspace --locked
cargo +1.82.0 test --release --locked --test v1_resource_subprocess
cargo +1.82.0 fmt --all -- --check
cargo +1.92.0 clippy --workspace --all-targets --all-features --locked -- -D warnings

The public CI workflow runs the native suite on Linux and Windows with Rust 1.82 and 1.92, plus Node, Chromium, and Firefox checks for the WASM package.

scripts/release-v1.sh assembles the native crate, WASM archive, and checksum sidecars. The reproducibility entry point creates two clean source directories, builds in the pinned container with networking disabled, and compares every deterministic output byte:

bash ./scripts/prove-reproducible-builds.sh <exact-commit>

Build output is ignored under target/release-v1. These commands only assemble local files; they do not create a tag or release, upload assets, deploy, or publish a registry package.

The source-package adaptation that keeps the complete 84-process small-stack proof reproducible is documented in PROVENANCE.md.

License, contributions, and security

Source is available under the MIT License. Contributions use the same license without a separate CLA or DCO; see CONTRIBUTING.md. Direct dependency licensing is summarized in THIRD_PARTY_NOTICES.md.

Do not report suspected vulnerabilities in a public issue or include live secrets in a report. Follow SECURITY.md.

About

Bounded deterministic JSON three-way merge and RFC 8785 content identities for Rust and WebAssembly. Experimental alpha.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages