Skip to content

Releases: ksuk/merlon

Release list

v0.0.2

Choose a tag to compare

@github-actions github-actions released this 20 Sep 07:38
Immutable release. Only release title and notes can be modified.
7e6146f

How this release was produced. The CI Required and
Security Required gates are verified to have passed on the release
commit before this release is published. Pull requests merged after
ADR-0016
additionally carry a maintainer self-review record, enforced at merge
time by the Governance Required status; that record is on the pull
request, and this release does not re-verify it. This release does
not assert independent approval or separation of duties: the
project has one maintainer, and one person cannot review their own
work independently. The image carries a build provenance attestation,
a CycloneDX SBOM, and an immutable digest regardless.

Fixed

  • Treat the expected two-decimal persistence rounding in CDD score
    explanations as reconciled while continuing to report the measured delta.
  • Return a stable error code when a case cannot close because a linked alert
    remains unresolved, allowing the operator UI to distinguish that condition
    from an optimistic-concurrency conflict.
  • Retry the initial PostgreSQL connection for a bounded, configurable period
    and restart the API after an explicit Compose database restart.

Verification

  • Add deterministic Standard-topology browser acceptance for authentication,
    role enforcement, last-administrator protection, authenticated OpenAPI,
    build identity, and restart persistence.
  • Strengthen the Docker Demo tours to validate exported STR and rule content,
    score reconciliation, OpenAPI, and exact build identity.

v0.0.1

Choose a tag to compare

@github-actions github-actions released this 19 Sep 13:54
Immutable release. Only release title and notes can be modified.
3e5d00e

How this release was produced. The CI Required and
Security Required gates are verified to have passed on the release
commit before this release is published. Pull requests merged after
ADR-0016
additionally carry a maintainer self-review record, enforced at merge
time by the Governance Required status; that record is on the pull
request, and this release does not re-verify it. This release does
not assert independent approval or separation of duties: the
project has one maintainer, and one person cannot review their own
work independently. The image carries a build provenance attestation,
a CycloneDX SBOM, and an immutable digest regardless.

Breaking

Three deliberate contract changes ship in the Wave 3 operator workflows. Each
withdraws an ability or corrects a field whose name did not match its meaning,
so none has an additive alternative.

  1. POST /api/v1/customers/{id}/score now requires the cdd:score
    permission
    (ADR-0019). The CDD score decides EDD requirements, monitoring
    thresholds and rescreening frequency, so producing one is a control action.
    Admin and Analyst hold the permission; Viewer receives 403.
    Migration: move Viewer-role integrations that rescore customers to
    Analyst. Deployments running without authentication are unaffected -- with
    no roles configured there is nothing to check.

  2. factors[].score changed meaning (ADR-0019). It previously held the
    same number as contribution, so summing it double-counted the factor
    weighting. score is now the factor's own normalised value (0-10) and
    contribution is its weighted share of the total.
    Migration: a client that summed factors[].score to reconstruct the
    total must read factors[].contribution instead. The record-level score
    is unchanged. GET /customers/{id}/score-explanation now reports
    reconciled and reconciliation_delta so the arithmetic can be verified
    rather than assumed.

  3. POST /api/v1/batch/runs/{id}/rerun returns an unconfirmed manifest
    (ADR-0018). It previously cloned the target manifest as already-confirmed
    and executed it immediately, which let any population be re-run with no
    second look and no second person -- bypassing the preview-and-confirm
    control that the target mechanism exists to provide.
    Migration: the response body is now
    {target_manifest, operation, parameters, rerun_of, next}. Confirm the
    returned manifest with POST /api/v1/batch/targets/{id}/confirm using its
    token, then start the run with POST /api/v1/batch/runs.

Two further changes are 2xx-compatible but worth noting:

  • POST /api/v1/batch/runs returns 202 Accepted rather than 201. The run
    is started and its row committed; execution continues independently of the
    request, so a client disconnect no longer strands it at status=running.
    Poll GET /api/v1/batch/runs/{id} for the outcome.
  • investigation.edd.completion_status gains overdue and completed
    (ADR-0021). Both are refinements of states previously reported as open or
    escalated.

Added

  • CDD risk scoring with configurable weights, country risk tables, and risk
    tiers, driving TM thresholds, case priority, and screening frequency
    (ADR-0004, Score-Driven Architecture).
  • Transaction monitoring engine with structuring, rapid movement, dormant
    account reactivation, high-frequency small-amount, and high-risk country
    transfer scenarios.
  • tm_scenario_v2 scenario schema with per-customer-type and per-risk-tier
    thresholds, evaluation modes, and absolute thresholds, with dual support for
    the earlier tm_scenario_v1 format (ADR-0006).
  • Sanctions and PEP screening with scheduled list imports that continue
    matching against the last successful list on fetch failure, and flags repeated
    failures for operators (structured log, dashboard flag, staleness metric).
  • Backtesting against candidate rule sets, including affected-customer
    reporting and cancellation.
  • Alert and case management: bulk alert close and case assignment, case notes,
    related-case linking, alert suppression, and STR report generation and
    export.
  • Dual-path authentication with role-based permissions and dual control on
    rule activation and whitelist approval (ADR-0007, ADR-0014).
  • Encryption at rest for direct-PII customer attributes, applied in the
    repository layer so no write path can bypass it, with online key rotation
    (merlon-keyrotate) that re-encrypts in batches without downtime.
  • Append-only audit log with partitioning and a merlon-audit verify
    integrity check (ADR-0010, ADR-0011).
  • Webhook delivery with a dead-letter queue and reprocessing.
  • Cursor-based pagination across list endpoints, with the offset/limit
    contract retained during its deprecation period (ADR-0005).
  • REST API surface with a generated OpenAPI 3.0 document.
  • React UI (Vite, React 19, Tailwind CSS v4, React Router v8).
  • PostgreSQL schema with a checksum-verified, forward-only migration runner.
  • Docker Compose topologies (minimal, standard, development, demo) and a
    synthetic demo dataset generator.
  • Release workflow publishing a multi-architecture image with build
    provenance attestation, a CycloneDX SBOM, and a release evidence manifest.
  • Single release channel vX.Y.Z, with the project's governance posture
    published alongside every release rather than encoded in a tag suffix:
    release-manifest.json carries a governance block, the image carries
    matching io.github.ksuk.merlon.governance.* labels, and the release notes
    carry a disclosure header. All three record that the release does not assert
    independent approval or separation of duties (ADR-0016).
  • Governance Required check: every pull request must carry a self-review
    record posted by its author and bound to its head commit, verified by
    scripts/check-self-review.mjs. A record from anyone else is ignored and
    deleting the record turns the check red again, so the gate cannot be
    satisfied by a passer-by on a public repository. It replaces the approving
    review a single-maintainer repository cannot produce, and is never described
    as one.
  • Ruleset drift detection: the main and release-tag rulesets are committed to
    .github/rulesets/ and compared weekly against the live configuration.
    Rulesets deleted from the live configuration are reported as drift alongside
    modified and unknown ones. The export is validated before any comparison is
    made — a token that cannot read bypass_actors receives it omitted rather
    than refused, so the check now proves it can see the field instead of
    reporting its absence as a difference. scripts/ruleset-baseline.sh is the
    single definition of the canonical baseline, shared by the drift workflow,
    configure-github-ruleset.sh, and make verify-ruleset-baseline, which runs
    on every pull request so a degraded baseline cannot be committed unnoticed.
    bypass_actors carries three explicit states — verified-empty,
    verified-nonempty, and unverifiable — because reading it needs write
    access to the ruleset and no such credential is stored in Actions. The weekly
    run holds unverifiable, names the last administrator-verified value, and
    compares a rendering that omits the field from both sides; verification itself
    is a release-checklist step run by an administrator.
  • Release gate verifying that CI Required and Security Required concluded
    successfully on the release commit before any image is published, so the
    disclosure header the release carries is checked rather than asserted.
  • Container image hardening: runs as non-root uid 10001, needs no writable
    path (--read-only works unmodified), declares a /healthz/live liveness
    healthcheck — readiness is exposed separately at /healthz/ready — and
    carries OCI annotations including the build revision.
  • Troubleshooting guide with a symptom index keyed on the actual error
    strings, and an FAQ covering the design decisions evaluators ask about.
  • Security and assurance documentation for vendor review: a complete
    enumeration of outbound connections, supply-chain controls and their known
    gaps, and accepted risks with their compensating controls.
  • make backup / make restore, which capture the database and the
    encryption key ring as separate artifacts and refuse to produce a
    database-only backup silently.
  • Guards for environment-variable drift (make verify-env-vars) and OpenAPI
    coverage (make verify-openapi-coverage), both required in CI.
  • Bilingual (English/Japanese) documentation site with generated API and rule
    schema reference pages.
  • Versioned, operator-editable policy documents for KYC required fields, the
    EDD stage schedule, CDD rule-set selection, Travel Rule applicability, and
    screening source readiness, with read-only GET /api/v1/policies and
    GET /api/v1/policies/{policy} (ADR-0016). Their digests are pinned onto
    the runs and batches they governed.
  • Server-side Travel Rule assessment recorded on every transaction, including
    those submitted without a counterparty block (ADR-0017). A client assertion
    that disagrees with the policy is preserved and the conflict recorded rather
    than silently corrected, and evidence that is required but absent routes the
    transaction to the PENDING_REVIEW queue instead of rejecting it.
  • Explicit EDD completion (POST /api/v1/customers/{id}/edd/{complete,reopen})
    with an append-only event history, overdue/completed states, and
    overdue_days (ADR-0021). A tier downgrade now closes an EDD window while
    retaining its evidence rather than erasing the stage timestamps.
  • Maker-checker for CDD tier overrides: an override becomes a proposal that a
    second person approves via
    POST /api/v1/customers/{id}/score-overrides/{id}/approve (ADR-0019), plus
    `GET /api/v1/cus...
Read more