Releases: ksuk/merlon
Release list
v0.0.2
How this release was produced. The
CI Requiredand
Security Requiredgates 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 theGovernance Requiredstatus; 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
How this release was produced. The
CI Requiredand
Security Requiredgates 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 theGovernance Requiredstatus; 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.
-
POST /api/v1/customers/{id}/scorenow requires thecdd: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. -
factors[].scorechanged meaning (ADR-0019). It previously held the
same number ascontribution, so summing it double-counted the factor
weighting.scoreis now the factor's own normalised value (0-10) and
contributionis its weighted share of the total.
Migration: a client that summedfactors[].scoreto reconstruct the
total must readfactors[].contributioninstead. The record-levelscore
is unchanged.GET /customers/{id}/score-explanationnow reports
reconciledandreconciliation_deltaso the arithmetic can be verified
rather than assumed. -
POST /api/v1/batch/runs/{id}/rerunreturns 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 withPOST /api/v1/batch/targets/{id}/confirmusing its
token, then start the run withPOST /api/v1/batch/runs.
Two further changes are 2xx-compatible but worth noting:
POST /api/v1/batch/runsreturns 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 atstatus=running.
PollGET /api/v1/batch/runs/{id}for the outcome.investigation.edd.completion_statusgainsoverdueandcompleted
(ADR-0021). Both are refinements of states previously reported asopenor
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_v2scenario schema with per-customer-type and per-risk-tier
thresholds, evaluation modes, and absolute thresholds, with dual support for
the earliertm_scenario_v1format (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.jsoncarries agovernanceblock, the image carries
matchingio.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 Requiredcheck: 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
mainand 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 readbypass_actorsreceives 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.shis the
single definition of the canonical baseline, shared by the drift workflow,
configure-github-ruleset.sh, andmake verify-ruleset-baseline, which runs
on every pull request so a degraded baseline cannot be committed unnoticed.
bypass_actorscarries three explicit states —verified-empty,
verified-nonempty, andunverifiable— because reading it needs write
access to the ruleset and no such credential is stored in Actions. The weekly
run holdsunverifiable, 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 RequiredandSecurity Requiredconcluded
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-onlyworks unmodified), declares a/healthz/liveliveness
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-onlyGET /api/v1/policiesand
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/completedstates, 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...