Skip to content

feat: @orangecheck/me-client v0.2.0 — IntegratorPriceConfig + computeFees#5

Merged
Xaxis merged 2 commits into
mainfrom
feat/me-client-0.2.0
Apr 30, 2026
Merged

feat: @orangecheck/me-client v0.2.0 — IntegratorPriceConfig + computeFees#5
Xaxis merged 2 commits into
mainfrom
feat/me-client-0.2.0

Conversation

@Xaxis
Copy link
Copy Markdown
Contributor

@Xaxis Xaxis commented Apr 30, 2026

Mirrors the systemic refactor in oc-me-web. Adds canonical integrator-configurable pricing types and computeFees() helper. Already published to npm; this commit makes the version bump auditable.

🤖 Generated with Claude Code

Xaxis and others added 2 commits April 30, 2026 11:06
The Packages workflow's build matrix was missing me-client, so PR #3
(me-client v0.1.0) merged green without ever building or testing the
new package — and never auto-published to npm. v0.1.0 was published
manually via NPM_TOKEN to unblock /integrate code samples.

This commit closes that gap so future me-client versions go through
the same gate every other package does:

  - packages.yml: add me-client to the build matrix.
  - release.yml: add me-client-v* to the tag-trigger list, plus a
    matching docstring entry.

After merge, future releases ship with: yarn version → git tag
me-client-v0.X.0 → git push --tags. Packages CI runs build+test on
every push, release.yml publishes on tag push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Fees

Mirror the systemic refactor in oc-me-web. The package now exports the
canonical integrator-configurable pricing types:

  - IntegratorPriceConfig — what every integrator declares
  - IntegratorEventConfig — per-subtype { enabled, site_pays, user_share_pct }
  - SiteFeeShape — { kind: 'fixed_sats' | 'percent_of_amount', ... }
  - ComputedFees — the four-way split: gross / platform / user / site_rebate

Plus the platform constants OC inherits to all integrators:

  - PLATFORM_FEE_POLICY = { pct: 0.2, min_floor_sats: 1, ratified }
  - MIN_INTEGRATOR_PRICE_SATS = 5
  - computeFees(cfg, payment_amount?) helper for client-side preview

Type bundle grew 3.79 KB → 4.81 KB.

Already published manually; this commit makes the version bump
auditable in git history. Future versions auto-publish on
me-client-v0.X.0 tags now that PR #4 added me-client to the release
workflow's tag list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Xaxis Xaxis merged commit 5142575 into main Apr 30, 2026
22 checks passed
@Xaxis Xaxis deleted the feat/me-client-0.2.0 branch April 30, 2026 18:28
Xaxis added a commit that referenced this pull request May 6, 2026
First release of @orangecheck/pledge-core — the load-bearing TypeScript
reference implementation of the OC Pledge protocol. Closes the 6th-verb
gap (every other family member already shipped a -core; pledge had none,
which is why the ochk.io homepage status pill was downgraded to "preview"
ahead of this commit).

Implements:

  - canonicalPledgeMessage / canonicalOutcomeMessage /
    canonicalAbandonmentMessage — byte-exact builders matching SPEC §3.1,
    §4.1, §5.1. Domain separators: "oc-pledge/v1" / "oc-pledge-outcome/v1"
    / "oc-pledge-abandonment/v1". LF-separated, no trailing LF.
  - computePledgeId / computeOutcomeId / computeAbandonmentId — sha256
    over the canonical bytes, lowercase hex, the content-addressed id.
  - createPledge / createOutcome / createAbandonment — build, validate,
    sign. Caller supplies BIP-322 signer adapter (Bip322Signer interface).
  - verifyPledge / verifyOutcome / verifyAbandonment — version + shape +
    canonical-message reconstruction + id check + BIP-322 verify (when
    a verifier is supplied). skipSignatureVerification path for
    test-vector fixtures with placeholder sigs.
  - classifyState — pure-function §4.4 state machine over (pledge,
    outcome | null, abandonment | null, now, chain?, contradictoryOutcomes?).
    Handles block-typed resolves_at, abandonment-trumps-everything (no
    honorable exit), bilateral contradiction → disputed.
  - verifyBond — §8 algorithm with caller-injected AttestationLookup.
    No bundled Bitcoin RPC by design — same shape as
    @orangecheck/stamp-core's verifyOtsAnchor adapter.
  - validateResolutionQuery — regex-level grammar gates for the seven
    §3.4 mechanisms; refuses self_proof per §3.4.8.
  - canonicalize / canonicalizePledgeEnvelope (etc) — RFC 8785 JSON
    canonicalization shared across all three envelope kinds. Same
    encoder as stamp-core (sorted keys, no insignificant whitespace,
    \uXXXX-escaped control chars, undefined keys dropped).
  - PledgeError class carrying SPEC §10 error codes (E_PLEDGE_*,
    E_OUTCOME_*, E_ABANDONMENT_*, E_BOND_*, E_RESOLUTION_*,
    E_DELEGATION_*).
  - generateNonce — 32-char-hex helper using globalThis.crypto.

Conformance:

  - Cross-implementation conformance harness in src/test-vectors.test.ts
    loads every committed vector in oc-pledge-protocol/test-vectors/
    (28 vectors as of this commit) and asserts:
      · canonical_message reconstructs byte-identical
      · canonical_message_bytes_len matches
      · pledge_id / outcome_id / abandonment_id == sha256(canonical_bytes)
      · declared envelope passes verifyX(skipSignatureVerification:true)
      · bond-verification fixtures produce the named expected.code
      · state-transition fixtures produce the named expected.state
      · bilateral consistency / contradiction → kept / disputed
      · malformed-input v28 (empty nonce) raises E_PLEDGE_MALFORMED
  - All 28 vectors green. Vector locator checks (a) OC_PLEDGE_VECTORS_DIR
    env, (b) sibling oc-pledge-protocol checkout, (c) user-home fallback.

Two SPEC nuances surfaced and handled (both pinned by vectors):

  - V08 (agent-delegated) has sig.pubkey = swearer.address (the
    principal), not agent_address. SPEC §3.6 says sig.pubkey MUST equal
    agent_address; SPEC §7.3 step 6 says "verify sig.value under
    agent_address" treating sig.pubkey as informational. The vector
    follows §7.3. Resolution: relax shape check, use agent_address as
    the BIP-322 verification key when via_delegation is present.
  - V16 (counterparty_signs + outcome=expired_unresolved) has
    resolved_by="deterministic" + sig=null. Discriminator is resolved_by,
    not mechanism — outcomeRequiresSignature() now keys off resolved_by.
    "expired_unresolved" is a deterministic classification any verifier
    can make once the deadline passes without a counterparty signature.

CI:

  - .github/workflows/packages.yml gains pledge-core in the build matrix
    + the protocol-vectors checkout step that mirrors vote-core /
    agent-core (clones oc-pledge-protocol → exposes via
    OC_PLEDGE_VECTORS_DIR).

Tests: 105 passing across 7 files (canonical, pledge, outcome,
abandonment paths, bond, state, resolution, plus the 28-vector harness).

Stack: TypeScript ES2020, tsup CJS+ESM dual build, vitest, @noble/hashes
for sha256. No bundled Bitcoin RPC, no Nostr client, no BIP-322 lib —
all I/O lives in caller-supplied adapters so the SDK runs everywhere.

Status: 0.1.0-alpha tracking oc-pledge-protocol v0.1.0-alpha. v1.0.0
will land alongside protocol stabilization (Tasks #5 cross-impl Python +
#6 dogfood real pledges + #7 SECURITY re-walk + #8 bump).
Xaxis added a commit that referenced this pull request May 7, 2026
Mirrors @orangecheck/pledge-core@0.1.0 function-for-function so the
"cross-impl, where it counts" claim on ochk.io now applies to OC Pledge
the same way it applies to OC Attest. All 28 committed test vectors in
oc-pledge-protocol/test-vectors/ reproduce byte-identically across the
two SDKs.

Module layout (orangecheck/pledge/):

  canonical.py    Canonical messages, ids, validators, RFC 8785 envelope
                  canonicalization. Exports:
                    canonical_pledge_message / _outcome_ / _abandonment_
                    compute_pledge_id / _outcome_id / _abandonment_id
                    validate_pledge_input / _outcome_ / _abandonment_
                    pledge_input_from_dict / _outcome_ / _abandonment_
                    canonicalize_envelope, generate_nonce
                  Frozen dataclasses for inputs (PledgeCanonicalInput,
                  OutcomeCanonicalInput, AbandonmentCanonicalInput,
                  ResolvesAtTime / ResolvesAtBlock, PledgeBond /
                  Resolution / Dispute, OutcomeEvidence).

  envelopes.py    create_pledge / verify_pledge with the §3.5
                  hex-id-as-sign-target rule and the §7.3
                  agent-address-as-verify-key override; create/verify
                  for outcome and abandonment envelopes; PledgeError
                  carrying SPEC §10 codes; the Bip322Signer Protocol
                  and VerifyBip322 Callable typing for caller adapters.
                  The §4.3 `expired_unresolved` nuance (test vector v16)
                  is honoured: outcomeRequiresSignature() keys off
                  resolved_by, not mechanism.

  state.py        classify_state — pure-function §4.4 transition table.
                  Pure Python ISO-8601-UTC parsing (regex + civil-from-
                  days arithmetic) avoids datetime quirks across CPython
                  versions and is stable on Python 3.9+.

  bond.py         verify_bond — the §8 algorithm with a sync-callable
                  attestation lookup. Caller pre-resolves an
                  AttestationLookupResult and hands it in; mirrors the
                  TS SDK's verifyBond shape minus the Promise.

  resolution.py   validate_resolution_query — regex-level grammar gates
                  for the seven §3.4 mechanisms. Refuses self_proof per
                  §3.4.8.

Conformance harness (tests/pledge/test_vectors.py):
  * Loads vectors via OC_PLEDGE_VECTORS_DIR env, sibling-clone, or a
    user-home fallback (same locator pattern as vote-core / agent-core).
  * Parameterizes pytest over the 28 committed vectors; fails the named
    vector if any of canonical_message / id / state / bond code / error
    code drifts.
  * As of this commit, all 28 pass:
      v01-v10  pledge envelopes (all 7 mechanisms + agent-delegated +
                edge cases)
      v11-v16  outcome envelopes (kept / broken / disputed /
                expired_unresolved across deterministic and
                counterparty-signed paths)
      v17      abandonment envelope
      v18-v20  bond verification (valid / insufficient sats /
                bond-draining UTXO spend)
      v21-v22  bilateral consistency / contradiction → kept / disputed
      v23-v27  state-machine transitions (pending / resolvable / kept /
                broken-via-abandonment / expired_unresolved)
      v28      empty-nonce rejection → E_PLEDGE_MALFORMED

Test counts (full sdk-py suite):
  * Existing OC Attest tests: 52 passing (unchanged)
  * New pledge conformance: 28 passing
  * Total: 80 passing in 0.22s on Python 3.11

Package shape:
  * pyproject.toml: 0.1.3 → 0.2.0 (minor — additive submodule)
  * orangecheck/__init__.py: re-exports `from . import pledge as pledge`
    so consumers can write `from orangecheck import pledge` or use the
    nested attribute path.
  * No new runtime dependency. Optional `[verify]` extra (bip322 native
    binding) is reused; pledge's BIP-322 hook accepts any verifier
    callable matching `(msg, sig_b64, address) -> bool`, including
    orangecheck.verify_bip322_signature.

This unblocks Task #5 (extend the conformance CI job in
oc-packages/.github/workflows/packages.yml to clone oc-pledge-protocol
and run both SDKs against its 28 vectors). Closes Task #4.
Xaxis added a commit that referenced this pull request May 7, 2026
Extends the oc-packages conformance gate so the homepage's "cross-impl,
where it counts" claim now applies to OC Pledge in CI, not just locally.

Two surgical edits to packages.yml:

1. The basic `python` job now also clones oc-pledge-protocol and exposes
   it via OC_PLEDGE_VECTORS_DIR. Previously the new pledge tests in
   tests/pledge/test_vectors.py would gracefully skip on CI (no vectors
   directory present); now they run as part of every PR's CI gate.
   Move `working-directory: sdk-py` from `defaults` onto the install/
   test step alone so the protocol checkouts can land at the workspace
   root rather than under sdk-py/.

2. The `conformance` job gains parallel pledge-side steps:
     * Clone oc-pledge-protocol/main alongside oc-attest-protocol.
     * Run pledge-core's TS conformance suite against
       /tmp/oc-pledge-protocol/test-vectors.
     * Run sdk-py's pledge conformance suite against the same dir.
   Two SDKs producing byte-identical canonical messages + ids for every
   one of the 28 committed vectors IS the gate. Note that pledge has no
   in-tree vendoring (both SDKs load at test time), so the "vendored
   copy drifted from spec" failure mode is impossible by construction —
   only the symmetric drift "TS produced X, Python produced Y" can fail
   this job, which is exactly the property "cross-impl tested" claims.

Comment block at the top of the conformance job documents the two-family
gate so future maintainers don't strip the pledge half thinking it's
duplicated work.

Closes Task #5.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant