From 566cecd8f9a0c5af92c89562a068a528eabfe628 Mon Sep 17 00:00:00 2001 From: defiQUG Date: Fri, 24 Apr 2026 22:06:26 -0700 Subject: [PATCH] feat: add universal resource activation policy profile flow --- .gitea/workflow-sources/validate-on-pr.yml | 4 + .gitea/workflows/validate-on-pr.yml | 4 + config/jurisdictions/catalog.v1.json | 44 +++++ ...ion.policy-profile-registry.v1.schema.json | 70 ++++++++ .../MANIFEST_AUTOMATION_DESIGN.md | 36 ++++ .../POLICY_PROFILES_REGISTRY.md | 23 +++ .../examples/ledger-snapshot.example.json | 8 + .../omnl-ledger-mapping.v1.example.json | 10 ++ .../omnl-ledger-mapping.v1.schema.json | 48 ++++++ .../manifest-fragments/README.md | 38 ++++ .../manifest.json | 58 ++++--- .../policy-profiles.json | 53 ++++++ .../DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md | 1 + ...RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md | 90 ++++++++++ docs/03-deployment/URA_MANIFEST_WRITER_OPS.md | 63 +++++++ docs/04-configuration/README.md | 12 +- .../GENERIC-COMMON-LAW-STUB/README.md | 9 + .../GENERIC-COMMON-LAW-STUB/banking_v1.md | 36 ++++ .../ID-INDONESIA/README.md | 11 ++ .../ID-INDONESIA/banking_v1.md | 59 +++++++ .../INSTITUTION_ONBOARDING_CHARTER.md | 47 +++++ .../INSTITUTION_ONBOARDING_PLAYBOOK.md | 67 ++++++++ .../compliance-matrices/README.md | 24 +++ .../US-DELAWARE-CORP-STUB/README.md | 9 + .../US-DELAWARE-CORP-STUB/banking_v1.md | 25 +++ .../_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md | 45 +++++ .../jurisdictions/JURISDICTION_CATALOG.md | 22 +++ .../jurisdictions/SLICE1_SCOPE_FREEZE.md | 36 ++++ .../universal-resource-activation/README.md | 8 +- .../SKR_CUSTODY_AUTOMATION_NOTES.md | 27 +++ .../UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md | 4 +- .../UNIVERSAL_RESOURCE_ONTOLOGY.md | 4 +- .../UNIVERSAL_RESOURCE_PILOT_PLAN.md | 4 +- .../UNIVERSAL_RESOURCE_POLICY_PROFILES.md | 12 +- .../UNIVERSAL_RESOURCE_WIRING.md | 39 +++-- ...IFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md | 54 ++++++ .../URA_PILOT_CLOSURE_RUNBOOK.md | 62 +++++++ .../technical-specs/README.md | 23 +++ .../TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md | 52 ++++++ .../TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md | 92 ++++++++++ .../TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md | 99 +++++++++++ .../TS-SETTLEMENT-INDEXER-MANIFEST-V1.md | 95 ++++++++++ .../TS-SKR-CUSTODY-ETL-MANIFEST-V1.md | 71 ++++++++ docs/MASTER_INDEX.md | 2 +- .../DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md | 2 +- .../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md | 14 ++ .../DBIS_RAIL_JURISDICTION_TRACEABILITY.md | 42 +++++ .../DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md | 33 ++++ .../GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md | 9 +- .../runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md | 57 ++++++ package.json | 11 ++ phoenix-deploy-api/.env.example | 7 + phoenix-deploy-api/README.md | 9 +- phoenix-deploy-api/openapi.yaml | 44 +++++ phoenix-deploy-api/server.js | 121 ++++++++++++- scripts/README.md | 2 +- scripts/ura/keccak-resource-ids.mjs | 38 ++++ scripts/ura/lib/validate-ura-manifest.mjs | 134 +++++++++++++++ scripts/ura/manifest-writer/README.md | 36 ++++ .../manifest-writer/build-ledger-fragment.mjs | 71 ++++++++ .../build-settlement-fragment.mjs | 38 ++++ .../ura/manifest-writer/lib/get-by-path.mjs | 25 +++ scripts/ura/merge-manifest-fragments.mjs | 162 ++++++++++++++++++ scripts/ura/policy-profiles-content-hash.mjs | 46 +++++ scripts/ura/validate-manifest-closure.mjs | 81 +++++++++ .../validate/validate-omnl-ledger-mapping.mjs | 51 ++++++ ...validate-universal-resource-activation.mjs | 100 +---------- .../validate/validate-ura-policy-profiles.mjs | 65 +++++++ scripts/validation/validate-config-files.sh | 9 + .../smoke-universal-resource-activation.sh | 49 +++++- smom-dbis-138 | 2 +- 71 files changed, 2705 insertions(+), 153 deletions(-) create mode 100644 config/jurisdictions/catalog.v1.json create mode 100644 config/universal-resource-activation.policy-profile-registry.v1.schema.json create mode 100644 config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md create mode 100644 config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md create mode 100644 config/universal-resource-activation/integration/examples/ledger-snapshot.example.json create mode 100644 config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json create mode 100644 config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json create mode 100644 config/universal-resource-activation/manifest-fragments/README.md create mode 100644 config/universal-resource-activation/policy-profiles.json create mode 100644 docs/03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md create mode 100644 docs/03-deployment/URA_MANIFEST_WRITER_OPS.md create mode 100644 docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/README.md create mode 100644 docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/banking_v1.md create mode 100644 docs/04-configuration/compliance-matrices/ID-INDONESIA/README.md create mode 100644 docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md create mode 100644 docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md create mode 100644 docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md create mode 100644 docs/04-configuration/compliance-matrices/README.md create mode 100644 docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/README.md create mode 100644 docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/banking_v1.md create mode 100644 docs/04-configuration/compliance-matrices/_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md create mode 100644 docs/04-configuration/jurisdictions/JURISDICTION_CATALOG.md create mode 100644 docs/04-configuration/jurisdictions/SLICE1_SCOPE_FREEZE.md create mode 100644 docs/04-configuration/universal-resource-activation/SKR_CUSTODY_AUTOMATION_NOTES.md create mode 100644 docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md create mode 100644 docs/04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md create mode 100644 docs/04-configuration/universal-resource-activation/technical-specs/README.md create mode 100644 docs/04-configuration/universal-resource-activation/technical-specs/TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md create mode 100644 docs/04-configuration/universal-resource-activation/technical-specs/TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md create mode 100644 docs/04-configuration/universal-resource-activation/technical-specs/TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md create mode 100644 docs/04-configuration/universal-resource-activation/technical-specs/TS-SETTLEMENT-INDEXER-MANIFEST-V1.md create mode 100644 docs/04-configuration/universal-resource-activation/technical-specs/TS-SKR-CUSTODY-ETL-MANIFEST-V1.md create mode 100644 docs/dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md create mode 100644 docs/dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md create mode 100644 docs/runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md create mode 100755 scripts/ura/keccak-resource-ids.mjs create mode 100644 scripts/ura/lib/validate-ura-manifest.mjs create mode 100644 scripts/ura/manifest-writer/README.md create mode 100644 scripts/ura/manifest-writer/build-ledger-fragment.mjs create mode 100644 scripts/ura/manifest-writer/build-settlement-fragment.mjs create mode 100644 scripts/ura/manifest-writer/lib/get-by-path.mjs create mode 100644 scripts/ura/merge-manifest-fragments.mjs create mode 100644 scripts/ura/policy-profiles-content-hash.mjs create mode 100644 scripts/ura/validate-manifest-closure.mjs create mode 100644 scripts/validate/validate-omnl-ledger-mapping.mjs create mode 100644 scripts/validate/validate-ura-policy-profiles.mjs diff --git a/.gitea/workflow-sources/validate-on-pr.yml b/.gitea/workflow-sources/validate-on-pr.yml index 05db708e..dac6c96e 100644 --- a/.gitea/workflow-sources/validate-on-pr.yml +++ b/.gitea/workflow-sources/validate-on-pr.yml @@ -21,5 +21,9 @@ jobs: REMOTE="${GITEA_WORKFLOW_REMOTE:-gitea}" fi git fetch --depth=1 "$REMOTE" main master + # Optional: set org/repo variable URA_STRICT_CLOSURE=1 to fail PRs while pilot placeholders + # remain in manifest (see scripts/ura/validate-manifest-closure.mjs). Not enabled by default. - name: run-all-validation (no LAN, no genesis) + env: + URA_STRICT_CLOSURE: ${{ vars.URA_STRICT_CLOSURE }} run: bash scripts/verify/run-all-validation.sh --skip-genesis diff --git a/.gitea/workflows/validate-on-pr.yml b/.gitea/workflows/validate-on-pr.yml index 05db708e..dac6c96e 100644 --- a/.gitea/workflows/validate-on-pr.yml +++ b/.gitea/workflows/validate-on-pr.yml @@ -21,5 +21,9 @@ jobs: REMOTE="${GITEA_WORKFLOW_REMOTE:-gitea}" fi git fetch --depth=1 "$REMOTE" main master + # Optional: set org/repo variable URA_STRICT_CLOSURE=1 to fail PRs while pilot placeholders + # remain in manifest (see scripts/ura/validate-manifest-closure.mjs). Not enabled by default. - name: run-all-validation (no LAN, no genesis) + env: + URA_STRICT_CLOSURE: ${{ vars.URA_STRICT_CLOSURE }} run: bash scripts/verify/run-all-validation.sh --skip-genesis diff --git a/config/jurisdictions/catalog.v1.json b/config/jurisdictions/catalog.v1.json new file mode 100644 index 00000000..7fccde89 --- /dev/null +++ b/config/jurisdictions/catalog.v1.json @@ -0,0 +1,44 @@ +{ + "schemaVersion": "1.0.0", + "updatedAt": "2026-04-25T18:00:00Z", + "description": "Canonical jurisdiction catalog for multi-institution onboarding. Add rows as jurisdictions are formally in-scope. Legal review required before marking status production_ready.", + "jurisdictions": [ + { + "id": "ID", + "label": "Indonesia", + "governingLawNote": "Indonesian law; BI and sector regulators — detail in compliance matrix, not legal advice.", + "regulatorsNote": "Bank Indonesia (BI); OJK where applicable — confirm with counsel.", + "activitiesInScope": ["payments_omnl", "server_funds_treasury", "rtgs_sidecars", "chain138_settlement_evidence"], + "activitiesExcluded": ["generic_securities_issuance_unless_scoped"], + "complianceMatrixPath": "docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md", + "status": "pilot_ready", + "policyProfileIdsReferenced": [ + "institutional_custody_skr_v1", + "server_funds_treasury_v1", + "infra_capacity_ops_v1" + ] + }, + { + "id": "GENERIC-COMMON-LAW-STUB", + "label": "Generic common-law banking stub (template)", + "governingLawNote": "Illustrative only — replace with real jurisdiction before production.", + "regulatorsNote": "Placeholder — no regulator list.", + "activitiesInScope": ["template_process_only"], + "activitiesExcluded": ["all_production_until_replaced"], + "complianceMatrixPath": "docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/banking_v1.md", + "status": "template_only", + "policyProfileIdsReferenced": [] + }, + { + "id": "US-DELAWARE-CORP-STUB", + "label": "US Delaware corporate stub (draft second jurisdiction)", + "governingLawNote": "Illustrative corporate/treasury stub — not legal advice; replace with real federal/state matrix.", + "regulatorsNote": "Placeholder.", + "activitiesInScope": ["draft_matrix_training_only"], + "activitiesExcluded": ["all_production_until_replaced"], + "complianceMatrixPath": "docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/banking_v1.md", + "status": "draft", + "policyProfileIdsReferenced": [] + } + ] +} diff --git a/config/universal-resource-activation.policy-profile-registry.v1.schema.json b/config/universal-resource-activation.policy-profile-registry.v1.schema.json new file mode 100644 index 00000000..d43e082a --- /dev/null +++ b/config/universal-resource-activation.policy-profile-registry.v1.schema.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://d-bis.org/schemas/universal-resource-activation.policy-profile-registry.v1.json", + "title": "PolicyProfileRegistry", + "type": "object", + "required": ["schemaVersion", "profiles"], + "properties": { + "schemaVersion": { "type": "string", "minLength": 1 }, + "updatedAt": { "type": "string" }, + "description": { "type": "string" }, + "profiles": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "policyProfileId", + "version", + "jurisdictions", + "participantClasses", + "resourceFamilies", + "minimumGruGovernanceLevel" + ], + "properties": { + "policyProfileId": { "type": "string", "minLength": 1 }, + "version": { "type": "string", "minLength": 1 }, + "effectiveFrom": { "type": "string" }, + "effectiveTo": { "type": "string" }, + "supersedes": { "type": "string" }, + "jurisdictions": { + "type": "array", + "minItems": 1, + "items": { "type": "string" } + }, + "participantClasses": { + "type": "array", + "minItems": 1, + "items": { "type": "string" } + }, + "resourceFamilies": { + "type": "array", + "minItems": 1, + "items": { "type": "string" } + }, + "tokenizationModesAllowed": { + "type": "array", + "items": { "type": "string" } + }, + "ledgerModel": { "type": "string" }, + "standards": { + "type": "array", + "items": { "type": "string" } + }, + "minimumGruGovernanceLevel": { + "type": "integer", + "minimum": 0, + "maximum": 5 + }, + "complianceMatrixPaths": { + "type": "array", + "items": { "type": "string" } + }, + "notes": { "type": "string" } + }, + "additionalProperties": true + } + } + }, + "additionalProperties": true +} diff --git a/config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md b/config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md new file mode 100644 index 00000000..0037b8aa --- /dev/null +++ b/config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md @@ -0,0 +1,36 @@ +# URA manifest — automation design + +**Last updated:** 2026-04-25 +**Status:** **Implemented in-repo:** fragment merge + strict closure gate + public Phoenix read for `policy-profiles.json` + ledger/settlement fragment CLIs + [`URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md`](../../docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md). Full OMNL ETL and GRU M00 diamond remain **operator/service** work; standalone `PolicyProfileRegistry` ships under `smom-dbis-138/contracts/universal-resource/`. + +## Implemented + +| Piece | Location | +|-------|----------| +| Merge fragments → validated manifest | `scripts/ura/merge-manifest-fragments.mjs` · `pnpm ura:merge-manifest` | +| Shared schema validation | `scripts/ura/lib/validate-ura-manifest.mjs` (used by `pnpm ura:validate` and merge) | +| Production placeholder gate | `scripts/ura/validate-manifest-closure.mjs` · `pnpm ura:validate-closure` (warn) / `pnpm ura:validate-closure:strict` (fail) · optional `URA_STRICT_CLOSURE=1` in `validate-config-files.sh` | +| Fragment drop zone | `manifest-fragments/README.md` | +| Public API: policy profiles | `GET /api/v1/universal-resource-activation/policy-profiles` on phoenix-deploy-api | + +## Goals (remaining / service-bound) + +- Generate fragments from **approved** ops forms, ledger exports, chain receipts (outside this repo or future ETL). +- Fail CI on **production** branches when closure rules violate (use `URA_STRICT_CLOSURE=1` on that pipeline). + +## Pipeline (merge) + +1. **Inputs:** JSON fragments under `manifest-fragments/*.json` (or another `--fragments-dir`). +2. **Merge:** Deterministic sort; `policyProfileRefs` union; resources/evidence by id with shallow merge. +3. **Validate:** Full JSON Schema + cross-checks (`validateUraManifestData`). +4. **Optional:** `--out path` to write; then review and replace `manifest.json` if intended. + +## Non-goals + +- Automatic legal classification of assets (human sign-off on matrices + profiles). +- Writing to chain or OMNL from this repo without separate deployment controls. + +## Related + +- [`UNIVERSAL_RESOURCE_WIRING.md`](../../docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) +- [`scripts/validate/validate-ura-policy-profiles.mjs`](../../scripts/validate/validate-ura-policy-profiles.mjs) diff --git a/config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md b/config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md new file mode 100644 index 00000000..7ae6e730 --- /dev/null +++ b/config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md @@ -0,0 +1,23 @@ +# Policy profiles registry — doc control + +**Last updated:** 2026-04-25 +**Purpose:** Human-readable **change control** for rows in [`policy-profiles.json`](policy-profiles.json). Legal/risk owns interpretation; engineering owns schema conformance (`pnpm ura:validate-profiles`). + +| `policyProfileId` | Version in registry | `effectiveFrom` | Legal / risk sign-off | Notes | +|-------------------|---------------------|-----------------|----------------------|-------| +| `institutional_custody_skr_v1` | 1 | 2026-04-25 | Pending — replace when signed | ID matrix: SKR / custody path | +| `server_funds_treasury_v1` | 1 | 2026-04-25 | Pending — replace when signed | ID matrix: server funds / OMNL | +| `infra_capacity_ops_v1` | 1 | 2026-04-25 | Pending — replace when signed | LAN internal capacity | + +## Procedure + +1. Add or bump `version` and `effectiveFrom` in `policy-profiles.json`; update this table with sign-off reference (ticket, memo id, or “N/A — internal only”). +2. Ensure [`manifest.json`](manifest.json) `policyProfileRefs` lists every profile used by a resource at the correct version. +3. Run `pnpm ura:validate && pnpm ura:validate-profiles`. + +## Related + +- [`UNIVERSAL_RESOURCE_POLICY_PROFILES.md`](../../docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md) +- [`DBIS_RAIL_JURISDICTION_TRACEABILITY.md`](../../docs/dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) +- **Public read:** `GET /api/v1/universal-resource-activation/policy-profiles` on phoenix-deploy-api (same auth rules as manifest; override via `UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH`). +- **On-chain anchor (optional):** `smom-dbis-138/contracts/universal-resource/PolicyProfileRegistry.sol` — publish `contentHash` from `pnpm ura:profile-hash `; see [`GRU_REGISTRY_WIRING_CHECKLIST.md`](../../docs/runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md) §6. diff --git a/config/universal-resource-activation/integration/examples/ledger-snapshot.example.json b/config/universal-resource-activation/integration/examples/ledger-snapshot.example.json new file mode 100644 index 00000000..a8ed8573 --- /dev/null +++ b/config/universal-resource-activation/integration/examples/ledger-snapshot.example.json @@ -0,0 +1,8 @@ +{ + "journalEntryId": "OMNL-JE-2026-00042", + "batchRef": "FINERACT-BATCH-88", + "postedAt": "2026-04-25T12:00:00Z", + "currency": "USD", + "amountMinor": "1000000", + "notes": "Illustrative export shape — replace with real OMNL/Fineract field names from your deployment." +} diff --git a/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json b/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json new file mode 100644 index 00000000..62eb6ce8 --- /dev/null +++ b/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json @@ -0,0 +1,10 @@ +{ + "schemaVersion": "1.0.0", + "description": "Example mapping from Fineract/OMNL export fields to URA evidence package columns. Copy to omnl-ledger-mapping.v1.json when live.", + "evidencePackages": [ + { + "evidencePackageId": "ura:pilot:evidence-register-bootstrap", + "accountingRefField": "journalEntryId" + } + ] +} diff --git a/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json b/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json new file mode 100644 index 00000000..879f3418 --- /dev/null +++ b/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://d-bis.org/schemas/omnl-ledger-mapping.v1.json", + "title": "OMNLLedgerMapping", + "type": "object", + "required": ["schemaVersion", "evidencePackages"], + "properties": { + "schemaVersion": { "type": "string", "const": "1.0.0" }, + "description": { "type": "string" }, + "resourceUpdates": { + "type": "array", + "items": { + "type": "object", + "required": ["resourceId", "quantityField"], + "properties": { + "resourceId": { "type": "string", "minLength": 1 }, + "quantityField": { "type": "string", "description": "Dot path in ledger snapshot for quantity string" } + }, + "additionalProperties": false + } + }, + "evidencePackages": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": ["evidencePackageId"], + "properties": { + "evidencePackageId": { "type": "string", "minLength": 1 }, + "accountingRefField": { + "type": "string", + "description": "Dot path into ledger snapshot JSON for accountingRef string (e.g. journalEntryId or omnl.batchRef)" + }, + "quantityField": { + "type": "string", + "description": "Optional dot path for resource quantity string" + }, + "resourceIdForQuantity": { + "type": "string", + "description": "If quantityField set, which resource row to patch" + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false +} diff --git a/config/universal-resource-activation/manifest-fragments/README.md b/config/universal-resource-activation/manifest-fragments/README.md new file mode 100644 index 00000000..2ee6845e --- /dev/null +++ b/config/universal-resource-activation/manifest-fragments/README.md @@ -0,0 +1,38 @@ +# URA manifest fragments (optional) + +**Purpose:** Drop partial JSON files here to **merge** onto the canonical [`../manifest.json`](../manifest.json) without hand-editing the full file. Used for ops overlays, environment-specific rows, or generated snippets. + +## Fragment shape + +Each `*.json` file (sorted by filename; skip `_prefix.json`) may contain any of: + +| Key | Effect | +|-----|--------| +| `policyProfileRefs` | Union with manifest (same `id` + `version` deduped). | +| `resources` | Add or **shallow-merge** replace by `resourceId`. | +| `evidencePackages` | Add or **shallow-merge** replace by `evidencePackageId`. | + +Top-level manifest fields (`schemaVersion`, `description`, …) come **only** from the `--base` file (default: `manifest.json`). + +## Commands + +```bash +pnpm ura:merge-manifest +# Validate merge and print counts (dry-run; does not write) + +node scripts/ura/merge-manifest-fragments.mjs --out /tmp/merged.json +# Write merged JSON; inspect and copy into manifest.json if correct +``` + +After any manifest edit: `pnpm ura:validate && pnpm ura:validate-profiles`. + +## Production gate + +When pilots are closed, enforce no placeholders: + +```bash +pnpm ura:validate-closure:strict +# Or: URA_STRICT_CLOSURE=1 bash scripts/validation/validate-config-files.sh +``` + +See [`MANIFEST_AUTOMATION_DESIGN.md`](../MANIFEST_AUTOMATION_DESIGN.md) and [`URA_PILOT_CLOSURE_RUNBOOK.md`](../../../docs/04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md). diff --git a/config/universal-resource-activation/manifest.json b/config/universal-resource-activation/manifest.json index c3f69b61..71ecc2b6 100644 --- a/config/universal-resource-activation/manifest.json +++ b/config/universal-resource-activation/manifest.json @@ -1,7 +1,7 @@ { "schemaVersion": "1.0.0", - "updatedAt": "2026-04-24T00:00:00Z", - "description": "Canonical in-repo store for universal resource activation (SKR, server funds, infra). Replace example-* rows in production; keep valid JSON and run scripts/validate/validate-universal-resource-activation.mjs in CI.", + "updatedAt": "2026-04-25T12:00:00Z", + "description": "Canonical in-repo store for universal resource activation (SKR, server funds, infra). Pilot-scoped resourceIds; jurisdiction ID for financial pilots per JURISDICTION_CATALOG and ID-INDONESIA matrix. Replace ura:participant:pilot-*-assign and evidence TBDs per URA_PILOT_CLOSURE_RUNBOOK.md. Run pnpm ura:validate && pnpm ura:validate-profiles in CI.", "policyProfileRefs": [ { "id": "institutional_custody_skr_v1", "version": "1" }, { "id": "server_funds_treasury_v1", "version": "1" }, @@ -9,14 +9,14 @@ ], "resources": [ { - "resourceId": "ura:example:skr-pilot-placeholder", + "resourceId": "ura:pilot-1:skr-custody-record", "schemaVersion": 1, - "displayName": "Example SKR / custody position (pilot template)", - "description": "Replace with a real safekeeping or strategic evidence-backed record. Not production.", + "displayName": "Pilot 1 — SKR / custody record", + "description": "PILOT-1 (Indonesia-scope): bind participant registry id, evidenceRefs, and custody evidence per URA_PILOT_CLOSURE_RUNBOOK.md and ID-INDONESIA compliance matrix.", "family": "SKR_SAFEKEEPING", "subType": "CUSTODY_STATEMENT", - "ownerParticipantId": "0x0000000000000000000000000000000000000000000000000000000000000000", - "jurisdiction": "TBD", + "ownerParticipantId": "ura:participant:pilot-1-assign", + "jurisdiction": "ID", "policyProfileId": "institutional_custody_skr_v1", "tokenizationMode": "NONE", "quantity": "0", @@ -25,17 +25,17 @@ "encumbranceState": "unencumbered", "lifecycleState": "draft", "deployabilityState": "informational_only", - "evidenceRefs": [] + "evidenceRefs": ["ura:evidence:pending-pilot-1-custody-package"] }, { - "resourceId": "ura:example:server-funds-pilot", + "resourceId": "ura:pilot-2:server-funds-treasury-pool", "schemaVersion": 1, - "displayName": "Example server funds pool (pilot template)", - "description": "Logical funding resource; bind to OMNL/Fineract and server-funds-sidecar when SoR is frozen. Not a wallet balance.", + "displayName": "Pilot 2 — Server funds treasury pool", + "description": "PILOT-2 (Indonesia-scope): OMNL + server-funds-sidecar SoR; replace accountingRef in evidence when ledger posts per runbook.", "family": "SERVER_FUNDS", "subType": "TREASURY_POOL", - "ownerParticipantId": "0x0000000000000000000000000000000000000000000000000000000000000000", - "jurisdiction": "TBD", + "ownerParticipantId": "ura:participant:pilot-2-assign", + "jurisdiction": "ID", "policyProfileId": "server_funds_treasury_v1", "tokenizationMode": "NONE", "quantity": "0", @@ -44,16 +44,16 @@ "encumbranceState": "unencumbered", "lifecycleState": "draft", "deployabilityState": "funding_eligible", - "evidenceRefs": [] + "evidenceRefs": ["ura:evidence:pending-pilot-2-ledger-link"] }, { - "resourceId": "ura:example:infra-r630-01-capacity", + "resourceId": "ura:pilot-3:infra-r630-01-api-small", "schemaVersion": 1, - "displayName": "Example R630-01 capacity slice (pilot template)", - "description": "Operational capacity record; not a tradable security. See reports/storage and ALL_VMIDS_ENDPOINTS for live inventory.", + "displayName": "Pilot 3 — Infra capacity (R630-01, api_small)", + "description": "PILOT-3: LAN ops capacity; link deploymentRef in evidence after non-prod deploy per runbook.", "family": "INFRA_CAPACITY", "subType": "BUNDLE", - "ownerParticipantId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "ownerParticipantId": "ura:participant:pilot-3-assign", "jurisdiction": "LAN", "policyProfileId": "infra_capacity_ops_v1", "tokenizationMode": "NONE", @@ -62,22 +62,26 @@ "encumbranceState": "unencumbered", "lifecycleState": "active", "deployabilityState": "infra_allocatable", - "evidenceRefs": [] + "evidenceRefs": ["ura:evidence:pending-pilot-3-capacity-verify"] } ], "evidencePackages": [ { - "evidencePackageId": "ura:example:evidence-ura-bootstrap", + "evidencePackageId": "ura:pilot:evidence-register-bootstrap", "resourceIds": [ - "ura:example:skr-pilot-placeholder", - "ura:example:server-funds-pilot", - "ura:example:infra-r630-01-capacity" + "ura:pilot-1:skr-custody-record", + "ura:pilot-2:server-funds-treasury-pool", + "ura:pilot-3:infra-r630-01-api-small" ], "actionType": "REGISTER", - "initiator": "repo_bootstrap", - "timestamp": "2026-04-24T00:00:00Z", - "reconciliationStatus": "matched", - "explanation": "Bootstrap example package linking the three template resources; replace with real packages per UNIVERSAL_RESOURCE_PILOT_PLAN.md" + "initiator": "pilot_bootstrap", + "timestamp": "2026-04-25T12:00:00Z", + "reconciliationStatus": "open", + "custodyOrSourceEvidence": "PILOT-1: TBD — custodian statement or attestation hash per UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md; remove when real ref linked.", + "accountingRef": "PILOT-2: TBD — OMNL/Fineract journal or batch id when server-funds path posts (see URA_PILOT_CLOSURE_RUNBOOK.md).", + "settlementOrChainRef": "PILOT-2/3: TBD — MintAuth messageId / tx hash / rail ref per DBIS_RAIL_TECHNICAL_SPEC_V1.md when settlement leg exists.", + "deploymentRef": "PILOT-3: TBD — VMID, FQDN, health URL after deploy per UNIVERSAL_RESOURCE_PILOT_PLAN.md.", + "explanation": "REGISTER package binding three pilots. Set reconciliationStatus to matched only after mandatory joins per UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md and jurisdiction matrix rows." } ] } diff --git a/config/universal-resource-activation/policy-profiles.json b/config/universal-resource-activation/policy-profiles.json new file mode 100644 index 00000000..8bfa6095 --- /dev/null +++ b/config/universal-resource-activation/policy-profiles.json @@ -0,0 +1,53 @@ +{ + "schemaVersion": "1.0.0", + "updatedAt": "2026-04-25T00:00:00Z", + "description": "Machine-readable URA policy profile registry. Manifest policyProfileRefs must reference ids listed here. See UNIVERSAL_RESOURCE_POLICY_PROFILES.md and compliance-matrices/.", + "profiles": [ + { + "policyProfileId": "institutional_custody_skr_v1", + "version": "1", + "effectiveFrom": "2026-04-25", + "jurisdictions": ["*", "ID"], + "participantClasses": ["institutional", "sovereign"], + "resourceFamilies": ["SKR_SAFEKEEPING", "STRATEGIC_RECORD"], + "tokenizationModesAllowed": ["NONE", "CLAIM", "ENTITLEMENT"], + "ledgerModel": "off_chain_omnl", + "standards": ["ISO20022_LOGGING"], + "minimumGruGovernanceLevel": 2, + "complianceMatrixPaths": [ + "docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md" + ], + "notes": "SKR / custody evidence-backed; conservative transfer defaults per policy doc." + }, + { + "policyProfileId": "server_funds_treasury_v1", + "version": "1", + "effectiveFrom": "2026-04-25", + "jurisdictions": ["*", "ID"], + "participantClasses": ["institutional", "sovereign"], + "resourceFamilies": ["SERVER_FUNDS"], + "tokenizationModesAllowed": ["NONE"], + "ledgerModel": "hybrid", + "standards": ["ISO20022_LOGGING", "TRAVEL_RULE"], + "minimumGruGovernanceLevel": 3, + "complianceMatrixPaths": [ + "docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md" + ], + "notes": "Good-funds, GL mapping, holds/releases; Rail settlement when on-chain leg used." + }, + { + "policyProfileId": "infra_capacity_ops_v1", + "version": "1", + "effectiveFrom": "2026-04-25", + "jurisdictions": ["*", "LAN"], + "participantClasses": ["institutional", "internal_ops"], + "resourceFamilies": ["INFRA_CAPACITY"], + "tokenizationModesAllowed": ["NONE", "ENTITLEMENT"], + "ledgerModel": "off_chain_omnl", + "standards": ["IPSAS"], + "minimumGruGovernanceLevel": 1, + "complianceMatrixPaths": [], + "notes": "Internal capacity; not a traded security by default." + } + ] +} diff --git a/docs/03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md b/docs/03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md index 7270097d..a53c33d8 100644 --- a/docs/03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md +++ b/docs/03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md @@ -65,6 +65,7 @@ ## Related artifacts +- [DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md) — workstreams and exit criteria aligned to this matrix (multi-jurisdiction master plan execution). - [dbis_chain_138_technical_master_plan.md](../../dbis_chain_138_technical_master_plan.md) - [docs/00-meta/TODO_TASK_LIST_MASTER.md](../00-meta/TODO_TASK_LIST_MASTER.md) - [docs/03-deployment/DBIS_PHASES_1_TO_3_PRODUCTION_GATE.md](DBIS_PHASES_1_TO_3_PRODUCTION_GATE.md) diff --git a/docs/03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md b/docs/03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md new file mode 100644 index 00000000..266a30b8 --- /dev/null +++ b/docs/03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md @@ -0,0 +1,90 @@ +# DBIS RTGS — master plan implementation tracker + +**Last updated:** 2026-04-25 +**Purpose:** Executable tracker mapping the **multi-jurisdiction institutional onboarding master plan** to [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md) rows and slice-1 scope ([SLICE1_SCOPE_FREEZE.md](../04-configuration/jurisdictions/SLICE1_SCOPE_FREEZE.md)). **Status here is documentation of intent;** the canonical component status remains the E2E matrix until rows are updated there. + +## How to use + +1. Pick a **workstream** below. +2. Execute engineering / ops tasks until **exit criteria** match the matrix row’s **Production gate** column. +3. Update **DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md** `Current state` to `Complete` (or `Retired` with rationale). +4. Link evidence to URA packages per [ID-INDONESIA/banking_v1.md](../04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md) where applicable. + +--- + +## Workstream W1 — Canonical OMNL / Fineract rail + +| Matrix rows (indicative) | OMNL / Fineract API rail; Mifos X frontend / tenant | +|--------------------------|-----------------------------------------------------| +| **Exit criteria** | Tenant and operator rail **frozen**; reproducible posting, office/GL mapping, reconciliation package path. | +| **Owner** | OMNL / banking ops | +| **URA link** | `SERVER_FUNDS` resources get real `accountingRef`; [URA_PILOT_CLOSURE_RUNBOOK.md](../04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md) pilot 2. | + +## Workstream W2 — `server-funds-sidecar` + +| Matrix rows | `server-funds-sidecar` (VMID 5803) | +|-------------|-------------------------------------| +| **Exit criteria** | Treasury SoR boundaries frozen; **draw / hold / release** validated with auth; Phoenix `SERVER_FUNDS_SIDECAR_URL` set in prod. | +| **Owner** | HYBX integration lead | +| **URA link** | Pilot 2; [UNIVERSAL_RESOURCE_WIRING.md](../04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) probe returns 200. | + +## Workstream W3 — `off-ledger-2-on-ledger-sidecar` + +| Matrix rows | Off-ledger → Chain 138 settlement | +|-------------|-----------------------------------| +| **Exit criteria** | Canonical event → settlement **end-to-end** with durable evidence; finality handling closed. | +| **Owner** | HYBX + Chain 138 settlement lead | +| **URA link** | `settlementOrChainRef` in evidence packages. | + +## Workstream W4 — ISO 20022 + institutional 4.995 package + +| Matrix rows | ISO evidence and vault path; Institutional 4.995 package path | +|-------------|---------------------------------------------------------------| +| **Exit criteria** | `--strict` or institution-agreed readiness; reproducible archive/hash path. | +| **Owner** | Regulatory / compliance + eng | +| **Compliance link** | [INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md](../04-configuration/mifos-omnl-central-bank/INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md) | + +## Workstream W5 — Indonesia BNI domestic path + +| Matrix rows | Indonesia / BNI domestic banking path | +|-------------|----------------------------------------| +| **Exit criteria** | Live endpoint/auth/message contract **or** explicit deferral documented in matrix + jurisdiction matrix. | +| **Owner** | Indonesia banking integration lead | +| **Compliance link** | [DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md](DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md) | + +## Workstream W6 — Global correspondent path + +| Matrix rows | Global correspondent / liquidity bank path | +|-------------|---------------------------------------------| +| **Exit criteria** | Same as matrix production gate; cross-border flow validated **or** out of slice 1. | +| **Owner** | Cross-border banking integration lead | + +## Workstream W7 — Identity stack (Fabric / Indy / Aries) + +| Matrix rows | Fabric, Indy, Aries, AnonCreds, etc. | +|-------------|--------------------------------------| +| **Exit criteria** | **Scope decision** in/out slice 1; if out, matrix shows Planned/Retired without production claims. | +| **Owner** | Identity architecture lead | + +## Workstream W8 — Depository / custody / securities + +| Matrix rows | Depository, global custodian, securities-sidecar, custody flow | +|-------------|----------------------------------------------------------------| +| **Exit criteria** | Canonical lifecycle documented + one path validated **or** deferred with rationale. | +| **Owner** | Custody / securities architecture leads | +| **URA link** | Pilot 1 SKR; policy profile `institutional_custody_skr_v1`. | + +## Workstream W9 — RTGS production gate + +| Matrix rows | RTGS production gate row | +|-------------|--------------------------| +| **Exit criteria** | All **mandatory** rows for **chosen architecture** = `Complete`. | +| **Owner** | DBIS program owner | + +--- + +## Related + +- [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md) +- [DBIS_HYBX_SIDECAR_BOUNDARY_MATRIX.md](DBIS_HYBX_SIDECAR_BOUNDARY_MATRIX.md) +- [INSTITUTION_ONBOARDING_CHARTER.md](../04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md) diff --git a/docs/03-deployment/URA_MANIFEST_WRITER_OPS.md b/docs/03-deployment/URA_MANIFEST_WRITER_OPS.md new file mode 100644 index 00000000..90383e53 --- /dev/null +++ b/docs/03-deployment/URA_MANIFEST_WRITER_OPS.md @@ -0,0 +1,63 @@ +# URA manifest writer — operations + +**Last updated:** 2026-04-25 +**Purpose:** Runbook for **ledger- and chain-driven** manifest updates: secrets, ETL, publish path, reconciliation, optional features, legal record, DR. + +## 1. Components + +| Piece | Role | +|-------|------| +| OMNL / Fineract | System of record for `accountingRef` (journal / batch ids). | +| Server-funds sidecar | Operational draws/holds; must correlate to ledger lines. | +| [`build-ledger-fragment.mjs`](../../scripts/ura/manifest-writer/build-ledger-fragment.mjs) | Maps export JSON → manifest fragment. | +| [`merge-manifest-fragments.mjs`](../../scripts/ura/merge-manifest-fragments.mjs) | Merges fragments; validates. | +| Phoenix | Serves canonical [`manifest.json`](../../config/universal-resource-activation/manifest.json) read-only. | + +## 2. Fineract / OMNL field inventory + +**Operator task:** Document the **exact** REST or batch export fields your deployment uses (tenant, office, product). Map them in [`omnl-ledger-mapping.v1.example.json`](../../config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json) (copy to `omnl-ledger-mapping.v1.json`). + +Minimum: one stable string for `accountingRef` (journal id or composite `officeId:transactionId`). + +## 3. Secrets and IAM + +- Store Fineract credentials in vault / `.env` on the writer host (never in git). +- Use read-only Fineract user where possible. +- Rotate keys on the same cadence as OMNL operator policy. + +## 4. Publish path (choose one) + +| Mode | Pattern | +|------|---------| +| **Git PR** | Writer opens PR updating `manifest.json` or a fragment; CI runs `pnpm ura:validate`. | +| **Secured sync** | Writer writes to `PHOENIX_REPO_ROOT` on deploy host; reload Phoenix. | +| **Authenticated API** | Future: POST internal-only (not the public GET routes). | + +## 5. Reconciliation + +- Nightly (or per batch): compare latest Fineract journal id set to manifest `accountingRef`. +- On mismatch: page on-call; do **not** auto-overwrite without human ack for production. + +## 6. Optional features + +- **Real-time:** Webhook from Fineract vs **batch** cron — feature-flag in writer. +- **Multi-pool:** Multiple rows in `resourceUpdates` / evidence mapping file. +- **DLQ:** Failed merges land in a queue path for replay. +- **Audit log:** Append-only log of fragment bytes + git SHA + operator id. + +## 7. Legal sign-off record + +When automation goes live, archive: + +- Compliance memo id or ticket referencing matrix rows satisfied by automated fields. +- Version of [`policy-profiles.json`](../../config/universal-resource-activation/policy-profiles.json) and [`ID-INDONESIA/banking_v1.md`](../04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md) (or relevant matrix). + +## 8. DR and rollback + +- **Backup:** Git history of `manifest.json` + weekly object-store copy if using direct sync. +- **Rollback:** Revert commit or restore file; re-run `pnpm ura:validate && pnpm ura:validate-profiles`. +- **Incident:** Disable writer cron/systemd; serve last known-good manifest from Phoenix override path. + +## Related + +- [`URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md`](../04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/docs/04-configuration/README.md b/docs/04-configuration/README.md index 4736a8ff..c853bc6f 100644 --- a/docs/04-configuration/README.md +++ b/docs/04-configuration/README.md @@ -93,9 +93,17 @@ This directory contains setup and configuration guides. - **[DBIS Rail Control Mapping v1](../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md)** ⭐⭐ - Control IDs mapped to checklist, Spec, Rulebook, and Threat Model for audit and SOC 2 / ISO 27001 alignment. - **[DBIS Rail and Project Completion Master v1](../dbis-rail/DBIS_RAIL_AND_PROJECT_COMPLETION_MASTER_V1.md)** ⭐⭐ - Project and deployment status; full task list (required and optional) for DBIS Rail and project completion. +**Multi-jurisdiction institutional onboarding (master plan artifacts):** +- **[compliance-matrices/README.md](compliance-matrices/README.md)** — Per-jurisdiction matrices, template, Indonesia + generic stub. +- **[compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md](compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md)** — RACI and definition of Complete. +- **[compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md](compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md)** — Repeatable onboarding steps. +- **[jurisdictions/JURISDICTION_CATALOG.md](jurisdictions/JURISDICTION_CATALOG.md)**, **[jurisdictions/SLICE1_SCOPE_FREEZE.md](jurisdictions/SLICE1_SCOPE_FREEZE.md)** — Catalog + slice-1 scope; machine: [`config/jurisdictions/catalog.v1.json`](../../config/jurisdictions/catalog.v1.json). +- **[../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md)** — Rail controls ↔ jurisdiction matrices ↔ profiles. + **Universal resource activation (SKR, server funds, infra capacity):** -- **[universal-resource-activation/README.md](universal-resource-activation/README.md)** ⭐⭐ — Ontology, policy profiles, lanes, pilots, JSON Schemas, in-repo [`manifest.json`](../../config/universal-resource-activation/manifest.json), `node scripts/validate/validate-universal-resource-activation.mjs`, Phoenix `GET /api/v1/universal-resource-activation/manifest`. -- **[universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md](universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md)** — Operator wiring: env (`UNIVERSAL_RESOURCE_MANIFEST_PATH`), CI, API resolution order. +- **[universal-resource-activation/README.md](universal-resource-activation/README.md)** ⭐⭐ — Ontology, policy profiles, lanes, pilots, [`manifest.json`](../../config/universal-resource-activation/manifest.json), [`policy-profiles.json`](../../config/universal-resource-activation/policy-profiles.json); `pnpm ura:validate`, `pnpm ura:validate-profiles`, `pnpm ura:keccak`, `pnpm ura:smoke` (`--http` + `PHOENIX_BASE_URL`). Phoenix: `GET /api/v1/universal-resource-activation/manifest`, `GET /api/v1/universal-resource-activation/server-funds-sidecar-probe`. [MASTER_INDEX.md](../MASTER_INDEX.md) §04-configuration. +- **[universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md](universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md)** — Operator wiring: `UNIVERSAL_RESOURCE_MANIFEST_PATH`, `SERVER_FUNDS_SIDECAR_URL`, CI, testing checklist. +- **RTGS execution tracker:** [../03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](../03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md). - **[Implementation coordination (transcript 540ae663)](../dbis-rail/IMPLEMENTATION_COORDINATION_WITH_TRANSCRIPT_540AE663.md)** ⭐⭐ - Coordinate implementations with PMM/DEX, tokens, GRU, cW*, deployments; maps Completion Master tasks to done/partial/open. - **[DBIS Rail Ledger Attestation Add-On v1.5](../dbis-rail/DBIS_RAIL_LEDGER_ATTESTATION_ADDON_V1_5.md)** ⭐⭐ - LPA state machine, reversal matrix, signer effectiveFromBlock/revokedAtBlock mandatory. - **[DBIS Rail Conversion Router Spec v1.5](../dbis-rail/DBIS_RAIL_CONVERSION_ROUTER_SPEC_V1_5.md)** ⭐⭐ - SwapAuth, best execution/MEV, quote provenance, venue allowlist, sanctions/AML for swaps. diff --git a/docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/README.md b/docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/README.md new file mode 100644 index 00000000..56bee6df --- /dev/null +++ b/docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/README.md @@ -0,0 +1,9 @@ +# GENERIC-COMMON-LAW-STUB — template only + +**Status:** template_only — **not** for production institutions. + +Use this folder to practice matrix structure before copying [_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md](../_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md) to a real jurisdiction code. + +| File | Purpose | +|------|---------| +| [banking_v1.md](banking_v1.md) | Illustrative obligation rows | diff --git a/docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/banking_v1.md b/docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/banking_v1.md new file mode 100644 index 00000000..92dfe538 --- /dev/null +++ b/docs/04-configuration/compliance-matrices/GENERIC-COMMON-LAW-STUB/banking_v1.md @@ -0,0 +1,36 @@ +# Compliance matrix — GENERIC-COMMON-LAW-STUB — banking_v1 (ILLUSTRATIVE ONLY) + +**Last updated:** 2026-04-25 +**Status:** **template_only** — do **not** use for production institutions. Copy [../_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md](../_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md) and replace with a real jurisdiction. + +**Purpose:** Train the onboarding process: obligation rows, control linkage, evidence columns. + +--- + +## 1. Law / regulation inventory (fictional placeholders) + +| Ref id | Short title | Scope | Notes | +|--------|-------------|-------|-------| +| STUB-BANK-001 | Illustrative banking supervision act | banking | Fictional — replace with real citations. | +| STUB-AML-001 | Illustrative AML law | AML | Fictional. | + +--- + +## 2. Requirement and control mapping (illustrative rows) + +| Matrix row id | Obligation summary | Participant classes | URA family | Enforcement | Control ids | Evidence expectation | +|---------------|-------------------|---------------------|------------|-------------|-------------|----------------------| +| STUB-001 | Illustrative: know your customer for institutional treasury | institutional | `SERVER_FUNDS` | off-chain | C7, STUB-KYB-001 | Onboarding file + audit log reference | +| STUB-002 | Illustrative: sanctions screening before funding draw | institutional | `SERVER_FUNDS` | hybrid | C7, STUB-SAN-001 | Screening vendor ref + timestamp in evidence package | +| STUB-003 | Illustrative: safekeeping evidence for custody record | institutional | `SKR_SAFEKEEPING` | off-chain | C9, STUB-CUST-001 | Custodian statement hash in `custodyOrSourceEvidence` | + +--- + +## 3. Residual risk + +All rows are **non-binding** examples. Production matrices require **counsel-approved** law inventory and signed control mapping. + +## Related + +- [JURISDICTION_CATALOG.md](../../jurisdictions/JURISDICTION_CATALOG.md) +- [ID-INDONESIA/banking_v1.md](../ID-INDONESIA/banking_v1.md) — real pilot jurisdiction example in this repo. diff --git a/docs/04-configuration/compliance-matrices/ID-INDONESIA/README.md b/docs/04-configuration/compliance-matrices/ID-INDONESIA/README.md new file mode 100644 index 00000000..36306010 --- /dev/null +++ b/docs/04-configuration/compliance-matrices/ID-INDONESIA/README.md @@ -0,0 +1,11 @@ +# Indonesia (ID) — compliance matrices + +**Status:** pilot_ready (counsel must validate legal inventory in `banking_v1.md`) + +| File | Regime / topic | +|------|----------------| +| [banking_v1.md](banking_v1.md) | Banking, OMNL, sidecars, Rail, ISO / 4.995, BNI path | + +**Catalog:** [`config/jurisdictions/catalog.v1.json`](../../../config/jurisdictions/catalog.v1.json) — `id: "ID"` + +**Related:** [INSTITUTION_ONBOARDING_PLAYBOOK.md](../INSTITUTION_ONBOARDING_PLAYBOOK.md), [DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md](../../../03-deployment/DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md) diff --git a/docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md b/docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md new file mode 100644 index 00000000..2be02d09 --- /dev/null +++ b/docs/04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md @@ -0,0 +1,59 @@ +# Compliance matrix — Indonesia (ID) — banking_v1 + +**Last updated:** 2026-04-25 +**Jurisdiction id:** ID +**Status:** **pilot_ready** — consolidate scattered repo guidance; **counsel must validate** all legal citations and obligation text before production claims. + +**Machine-readable catalog:** [`config/jurisdictions/catalog.v1.json`](../../../config/jurisdictions/catalog.v1.json) + +--- + +## 1. Law / regulation inventory (outline — verify with counsel) + +| Ref id | Short title | Scope | Repo anchor (non-legal) | +|--------|-------------|-------|-------------------------| +| ID-BI-PAYMENT | BI payment system / RTGS-related rules (confirm scope) | banking, payments | [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](../../../03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md), Indonesia rows | +| ID-OJK-SEC | OJK capital markets rules (if securities path in scope) | securities | Depository / securities sidecar rows in same matrix | +| ID-AML-CTF | AML / CTF obligations (confirm statutes) | AML | [DBIS_RAIL_RULEBOOK_V1.md](../../../dbis-rail/DBIS_RAIL_RULEBOOK_V1.md) good-funds / compliance alignment | +| ID-DP | Data protection (confirm PDP / sector rules) | data | Evidence vault / ISO path | + +*Replace summaries with counsel-approved citations and effective dates.* + +--- + +## 2. Requirement and control mapping (starter rows) + +| Matrix row id | Obligation summary | Participant classes | URA family | Enforcement | Control ids | Evidence expectation | +|---------------|-------------------|---------------------|------------|-------------|-------------|----------------------| +| ID-OMNL-001 | Institutional ledger / OMNL posting path for RTGS slice | institutional | `SERVER_FUNDS` | off-chain | C8, C9, C17 | Deterministic `accountingRef`; JE / package per [OMNL_JOURNAL_LEDGER_MATRIX.md](../../mifos-omnl-central-bank/OMNL_JOURNAL_LEDGER_MATRIX.md) | +| ID-SIDECAR-001 | Server-funds treasury orchestration aligned with good-funds policy | institutional | `SERVER_FUNDS` | hybrid | C17, C12 | Sidecar draw/hold/release + evidence package; Phoenix probe [UNIVERSAL_RESOURCE_WIRING.md](../../universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) | +| ID-RAIL-001 | On-chain settlement evidence (MintAuth / messageId) when rail used | institutional | `SERVER_FUNDS`, `FIAT_DIGITAL` (if applicable) | on-chain | C1–C6, C10 | `settlementOrChainRef` per [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md) | +| ID-ISO-001 | ISO 20022 / institutional evidence packaging | institutional | all lanes | off-chain | C9 | [INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md](../../mifos-omnl-central-bank/INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md), matrix ISO row | +| ID-BNI-001 | Domestic bank partner connectivity (when BNI path in scope) | institutional | payments | off-chain | — | [DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md](../../../03-deployment/DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md); freeze endpoint/auth | +| ID-SKR-001 | Custody / safekeeping evidence for SKR pilot | institutional | `SKR_SAFEKEEPING` | off-chain | C9 | `custodyOrSourceEvidence`, `evidenceRefs` on resource | + +--- + +## 3. Deep links (implementation) + +- HYBX operator: [HYBX_BATCH_001_OPERATOR_CHECKLIST.md](../../mifos-omnl-central-bank/HYBX_BATCH_001_OPERATOR_CHECKLIST.md) +- RTGS checklist: [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](../../../03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md) +- Rail controls: [DBIS_RAIL_CONTROL_MAPPING_V1.md](../../../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md) +- Traceability: [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) + +--- + +## 4. Residual risk / exceptions + +| Topic | Decision | Owner | +|-------|----------|-------| +| BNI live contract | Planned until live endpoint/auth evidenced — see RTGS matrix | Indonesia banking integration lead | +| Securities / CSD | Planned unless explicitly in slice 1 | Securities architecture lead | + +--- + +## Document control + +| Version | Date | Change | +|---------|------|--------| +| 0.1 | 2026-04-25 | Initial Indonesia banking_v1 matrix from master plan | diff --git a/docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md b/docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md new file mode 100644 index 00000000..b2dc926f --- /dev/null +++ b/docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md @@ -0,0 +1,47 @@ +# Institution onboarding charter — multi-jurisdiction compliance program + +**Last updated:** 2026-04-25 +**Purpose:** Governance for onboarding **institutions** under explicit **jurisdictions**, aligned with the multi-jurisdiction master plan (policy profiles, per-jurisdiction compliance matrices, RTGS/Rail evidence, URA). + +**Do not treat this document as legal advice.** Counsel owns interpretation of statutes and regulations; this charter defines **roles, artifacts, and “complete”** for program execution. + +--- + +## Definitions + +| Term | Meaning | +|------|---------| +| **Institution** | Licensed or contracted participant (bank, CSD, treasury entity, program operator) using DBIS RTGS / Rail / URA artifacts. | +| **Jurisdiction** | Legal regime under which the institution operates for a given activity (may be multiple per institution). | +| **Policy profile** | Versioned ruleset referenced by `policyProfileId` on URA resources — see [UNIVERSAL_RESOURCE_POLICY_PROFILES.md](../universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md) and [policy-profiles.json](../../../config/universal-resource-activation/policy-profiles.json). | +| **Compliance matrix** | Per-jurisdiction mapping: law / obligation → control id → evidence / system behavior — see [compliance-matrices/README.md](README.md). | +| **Complete (institution)** | All **in-scope** matrix rows for that institution’s jurisdictions are **implemented or explicitly waived** with sign-off; URA pilots or production resources carry **non-placeholder** evidence where policy requires; RTGS matrix rows for the **chosen architecture** are `Complete` or **excluded with rationale** (see [DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](../../03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md)). | + +--- + +## RACI (summary) + +| Activity | Responsible | Accountable | Consulted | Informed | +|----------|-------------|-------------|-----------|----------| +| Jurisdiction / law inventory | Compliance | Legal | Local counsel | Program, Eng | +| Compliance matrix draft | Compliance | Legal | Risk, Product | Eng | +| Policy profile version & registry | Product / Arch | Legal + Risk | Compliance | Eng | +| URA manifest & evidence packages | Ops | Compliance | Audit | Eng | +| RTGS / sidecar / OMNL integration | Eng | Program | Banking ops | Compliance | +| Rail / on-chain controls | Eng | Risk | Audit | Legal | +| Production gate sign-off | Program | Executive sponsor | Legal, Risk | All | + +--- + +## Exit criteria (program slice 1) + +1. [JURISDICTION_CATALOG.md](../jurisdictions/JURISDICTION_CATALOG.md) and [config/jurisdictions/catalog.v1.json](../../../config/jurisdictions/catalog.v1.json) list **in-scope** jurisdictions and activities. +2. [SLICE1_SCOPE_FREEZE.md](../jurisdictions/SLICE1_SCOPE_FREEZE.md) is agreed and references [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](../../03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md) immediate priorities. +3. At least one **full** jurisdiction matrix exists (see [ID-INDONESIA/banking_v1.md](ID-INDONESIA/banking_v1.md)) plus [GENERIC-COMMON-LAW-STUB](GENERIC-COMMON-LAW-STUB/banking_v1.md) for process training and a **draft second jurisdiction** ([US-DELAWARE-CORP-STUB](US-DELAWARE-CORP-STUB/README.md)) for multi-matrix workflow rehearsal. +4. Policy profiles registered and validated in CI (`pnpm ura:validate-profiles`). +5. Traceability doc links controls to matrices — [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md). + +## Related + +- [INSTITUTION_ONBOARDING_PLAYBOOK.md](INSTITUTION_ONBOARDING_PLAYBOOK.md) — step-by-step onboarding. +- [UNIVERSAL_RESOURCE_WIRING.md](../universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) — URA ops. diff --git a/docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md b/docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md new file mode 100644 index 00000000..785e38ca --- /dev/null +++ b/docs/04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md @@ -0,0 +1,67 @@ +# Institution onboarding playbook — jurisdictions and compliance matrices + +**Last updated:** 2026-04-25 +**Purpose:** Repeatable steps to onboard an **institution** under one or more **jurisdictions**, producing signed compliance matrices, registered policy profiles, and URA/RTGS artifacts. + +## Prerequisites + +- [INSTITUTION_ONBOARDING_CHARTER.md](INSTITUTION_ONBOARDING_CHARTER.md) acknowledged (RACI). +- [JURISDICTION_CATALOG.md](../jurisdictions/JURISDICTION_CATALOG.md) and [`config/jurisdictions/catalog.v1.json`](../../config/jurisdictions/catalog.v1.json) updated for new jurisdictions. +- [SLICE1_SCOPE_FREEZE.md](../jurisdictions/SLICE1_SCOPE_FREEZE.md) or successor scope doc current. + +--- + +## Steps + +### 1. Legal and compliance intake + +1. Institution name, regulator(s), licensed activities. +2. Build **law / regulation inventory** (counsel-owned citations). +3. Confirm **in-scope** vs **excluded** activities; align with RTGS matrix architecture choice. + +### 2. Compliance matrix + +1. Copy [_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md](_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md) to `docs/04-configuration/compliance-matrices//`. +2. Fill obligation rows; map **Control ids** to [DBIS_RAIL_CONTROL_MAPPING_V1.md](../../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md) and add `-*` ids as needed. +3. Link evidence expectations to ISO / 4.995 / institution package standards where applicable. +4. Update [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) when new obligation ↔ control links are stable. + +### 3. Policy profiles + +1. Add or extend entries in [`config/universal-resource-activation/policy-profiles.json`](../../config/universal-resource-activation/policy-profiles.json) (`jurisdictions[]`, `minimumGruGovernanceLevel`, `complianceMatrixPaths`). +2. Run `pnpm ura:validate-profiles`. +3. Update [UNIVERSAL_RESOURCE_POLICY_PROFILES.md](../universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md) if new profile semantics are introduced. + +### 4. URA resources + +1. Add or update rows in [`config/universal-resource-activation/manifest.json`](../../config/universal-resource-activation/manifest.json) with correct `policyProfileId`, `jurisdiction`, `ownerParticipantId`. +2. Follow [URA_PILOT_CLOSURE_RUNBOOK.md](../universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md) for evidence packages. +3. Run `pnpm ura:validate`. + +### 5. RTGS / technical closure + +1. Use [DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](../../03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md) to assign workstreams. +2. Update [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](../../03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md) when components reach **Complete**. + +### 6. Automation (recommended) + +| Action | Command / artifact | +|--------|-------------------| +| URA manifest + schemas | `pnpm ura:validate` | +| Policy registry + manifest refs | `pnpm ura:validate-profiles` | +| Merge manifest fragments (optional) | `pnpm ura:merge-manifest` · [`manifest-fragments/README.md`](../../../config/universal-resource-activation/manifest-fragments/README.md) | +| Production closure gate (no pilot/TBD) | `pnpm ura:validate-closure:strict` · or `URA_STRICT_CLOSURE=1` with `validate-config-files.sh` | +| Phoenix HTTP smoke (staging) | `pnpm ura:smoke -- --http` with `PHOENIX_BASE_URL` (manifest + policy-profiles + sidecar-probe) | +| On-chain id hashes | `pnpm ura:keccak` | + +**Service-bound next steps:** manifest/ledger writers fed by OMNL/sidecar events — out of repo until those APIs are stable; use merge + manual `manifest.json` until then. + +### 7. Exit + +Institution **Complete** per charter when: matrix rows implemented or waived with sign-off, mandatory RTGS rows green for chosen architecture, URA evidence **matched** where policy requires. + +## Related + +- [compliance-matrices/README.md](README.md) +- [UNIVERSAL_RESOURCE_WIRING.md](../universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) +- [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](../universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/docs/04-configuration/compliance-matrices/README.md b/docs/04-configuration/compliance-matrices/README.md new file mode 100644 index 00000000..5dbaa631 --- /dev/null +++ b/docs/04-configuration/compliance-matrices/README.md @@ -0,0 +1,24 @@ +# Per-jurisdiction compliance matrices + +**Last updated:** 2026-04-25 +**Purpose:** One **separate** matrix (or split by regime) per **onboarded jurisdiction**, mapping **local obligations** → **control IDs** (Rail + jurisdiction-specific) → **evidence / system behavior**. + +## Index + +| Jurisdiction code | Folder | Status | +|-------------------|--------|--------| +| _TEMPLATE | [_TEMPLATE/](_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md) | Use for new jurisdictions | +| GENERIC-COMMON-LAW-STUB | [GENERIC-COMMON-LAW-STUB/](GENERIC-COMMON-LAW-STUB/README.md) | Template only | +| ID (Indonesia) | [ID-INDONESIA/](ID-INDONESIA/README.md) | Pilot-ready | +| US-DELAWARE-CORP-STUB | [US-DELAWARE-CORP-STUB/](US-DELAWARE-CORP-STUB/README.md) | Draft (second jurisdiction exercise) | + +## Governance + +- [INSTITUTION_ONBOARDING_CHARTER.md](INSTITUTION_ONBOARDING_CHARTER.md) — RACI and definition of **Complete**. +- [JURISDICTION_CATALOG.md](../jurisdictions/JURISDICTION_CATALOG.md) — catalog index. +- [INSTITUTION_ONBOARDING_PLAYBOOK.md](INSTITUTION_ONBOARDING_PLAYBOOK.md) — onboarding steps (Phase 6). + +## Related + +- [DBIS_RAIL_CONTROL_MAPPING_V1.md](../../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md) +- [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) diff --git a/docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/README.md b/docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/README.md new file mode 100644 index 00000000..7961201c --- /dev/null +++ b/docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/README.md @@ -0,0 +1,9 @@ +# US-DELAWARE-CORP-STUB — draft (second jurisdiction template) + +**Status:** **draft** — placeholder for a second jurisdiction onboarding exercise. **Not** production-ready; no counsel review recorded. + +Replace this stub with a real US state / federal matrix when an institution requires it, or delete if out of scope. + +| File | Regime / topic | +|------|----------------| +| [banking_v1.md](banking_v1.md) | Draft starter rows (fictional placeholders) | diff --git a/docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/banking_v1.md b/docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/banking_v1.md new file mode 100644 index 00000000..163645b0 --- /dev/null +++ b/docs/04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/banking_v1.md @@ -0,0 +1,25 @@ +# Compliance matrix — US-DELAWARE-CORP-STUB — banking_v1 (DRAFT) + +**Last updated:** 2026-04-25 +**Status:** **draft** — second-jurisdiction process training only. **Do not** use for compliance claims. + +## 1. Law / regulation inventory (placeholders — replace with counsel research) + +| Ref id | Short title | Scope | Notes | +|--------|-------------|-------|-------| +| US-D-STUB-001 | Illustrative: corporate treasury governance | corporate | Fictional row for template practice. | +| US-D-STUB-002 | Illustrative: AML program expectations | AML | Fictional. | + +## 2. Requirement mapping (starter) + +| Matrix row id | Obligation summary | URA family | Control ids | Evidence | +|---------------|-------------------|------------|-------------|----------| +| US-STUB-001 | Illustrative: treasury policy for server funds | `SERVER_FUNDS` | C8, C17 | OMNL refs + policy attestation | +| US-STUB-002 | Illustrative: custody evidence for SKR | `SKR_SAFEKEEPING` | C9 | Custodian hash / WORM id | + +## 3. Next steps + +1. Rename jurisdiction folder to the agreed code (e.g. state + program). +2. Replace inventory with **real** citations. +3. Register profiles in [`policy-profiles.json`](../../../config/universal-resource-activation/policy-profiles.json) if new `policyProfileId`s are needed. +4. Add row to [`config/jurisdictions/catalog.v1.json`](../../../config/jurisdictions/catalog.v1.json) with `status: pilot_ready` when reviewed. diff --git a/docs/04-configuration/compliance-matrices/_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md b/docs/04-configuration/compliance-matrices/_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md new file mode 100644 index 00000000..6c03f8d3 --- /dev/null +++ b/docs/04-configuration/compliance-matrices/_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md @@ -0,0 +1,45 @@ +# Compliance matrix — `` — `_v1` + +**Last updated:** YYYY-MM-DD +**Jurisdiction id:** `` +**Owning counsel / compliance:** `` +**Effective from / to:** `` +**Related `policyProfileId`(s):** `` +**Related URA families:** `SKR_SAFEKEEPING` | `SERVER_FUNDS` | `INFRA_CAPACITY` | … + +--- + +## 1. Law / regulation inventory + +| Ref id | Short title | Scope (banking, securities, AML, DP, FX, digital assets) | Notes | +|--------|-------------|---------------------------------------------------------------|-------| +| LAW-001 | `` | `` | `` | + +--- + +## 2. Requirement and control mapping + +| Matrix row id | Obligation summary (non-legal) | Participant classes | URA family | Enforcement (on-chain / off-chain / hybrid) | Control ids | Evidence expectation | +|---------------|--------------------------------|---------------------|------------|---------------------------------------------|-------------|----------------------| +| `-001` | `` | `` | `SERVER_FUNDS` | off-chain | `C7` [Rail mapping](../../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md), `-AML-001` | `` | + +**Control id conventions** + +- **C1–C18:** [DBIS_RAIL_CONTROL_MAPPING_V1.md](../../dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md) where applicable. +- **`-*`** jurisdiction-specific controls not covered by Rail mapping. + +--- + +## 3. Residual risk / exceptions + +| Topic | Decision | Owner | +|-------|----------|-------| +| Manual vs automated control | `<>` | `<>` | + +--- + +## 4. Document control + +| Version | Date | Author | Change | +|---------|------|--------|--------| +| 0.1 | YYYY-MM-DD | `<>` | Draft | diff --git a/docs/04-configuration/jurisdictions/JURISDICTION_CATALOG.md b/docs/04-configuration/jurisdictions/JURISDICTION_CATALOG.md new file mode 100644 index 00000000..37c95e91 --- /dev/null +++ b/docs/04-configuration/jurisdictions/JURISDICTION_CATALOG.md @@ -0,0 +1,22 @@ +# Jurisdiction catalog (human index) + +**Last updated:** 2026-04-25 +**Machine-readable source:** [`config/jurisdictions/catalog.v1.json`](../../config/jurisdictions/catalog.v1.json) + +| ID | Label | Compliance matrix | Status | Notes | +|----|-------|-------------------|--------|--------| +| ID | Indonesia | [ID-INDONESIA/banking_v1.md](../compliance-matrices/ID-INDONESIA/banking_v1.md) | pilot_ready | Align with BNI / OMNL / 4.995 evidence paths. | +| GENERIC-COMMON-LAW-STUB | Template stub | [GENERIC-COMMON-LAW-STUB/README.md](../compliance-matrices/GENERIC-COMMON-LAW-STUB/README.md) | template_only | Train process only; not for production. | +| US-DELAWARE-CORP-STUB | US draft stub | [US-DELAWARE-CORP-STUB/README.md](../compliance-matrices/US-DELAWARE-CORP-STUB/README.md) | draft | Second-jurisdiction placeholder; replace or remove. | + +## Adding a jurisdiction + +1. Add an object to `catalog.v1.json` with `id`, `label`, paths, `status`. +2. Create `docs/04-configuration/compliance-matrices//` using [_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md](../compliance-matrices/_TEMPLATE/COMPLIANCE_MATRIX_TEMPLATE.md). +3. Register or extend [policy-profiles.json](../../config/universal-resource-activation/policy-profiles.json) entries with `jurisdictions[]`. +4. Update [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) when controls are mapped. + +## Related + +- [INSTITUTION_ONBOARDING_CHARTER.md](../compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md) +- [SLICE1_SCOPE_FREEZE.md](SLICE1_SCOPE_FREEZE.md) diff --git a/docs/04-configuration/jurisdictions/SLICE1_SCOPE_FREEZE.md b/docs/04-configuration/jurisdictions/SLICE1_SCOPE_FREEZE.md new file mode 100644 index 00000000..c53d2a76 --- /dev/null +++ b/docs/04-configuration/jurisdictions/SLICE1_SCOPE_FREEZE.md @@ -0,0 +1,36 @@ +# Slice 1 scope freeze (RTGS + URA alignment) + +**Last updated:** 2026-04-25 +**Purpose:** Operational **scope freeze** for production slice 1, aligned with [DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](../../03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md) **Immediate execution priority** and URA pilots. + +## Frozen priorities (from RTGS matrix) + +1. **Freeze the canonical banking rail** on the proven OMNL / Fineract tenant and authenticated posting path. +2. **Freeze participant / treasury / GL model** (and dependent depository, custody, FX, liquidity layers as in-scope for slice 1). +3. **Complete the canonical settlement path** from HYBX sidecars into Chain 138 with durable evidence. + +## In-scope for slice 1 (default) + +- OMNL / Fineract operator rail and office–GL mapping (as documented in matrix rows). +- HYBX first-slice sidecars: **`mifos-fineract-sidecar`**, **`server-funds-sidecar`**, **`off-ledger-2-on-ledger-sidecar`** — business flows and evidence, not only health. +- ISO 20022 / institutional evidence packaging toward **submission-grade** where matrix requires. +- Indonesia domestic path **when** institution is Indonesia-facing — see [ID-INDONESIA compliance matrix](../compliance-matrices/ID-INDONESIA/banking_v1.md). +- URA [pilot plan](../universal-resource-activation/UNIVERSAL_RESOURCE_PILOT_PLAN.md) closure per [URA_PILOT_CLOSURE_RUNBOOK.md](../universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md). + +## Explicitly out of scope for slice 1 (unless program re-opens) + +- Fabric / Indy / Aries **production** until matrix rows move from Planned/Reserved to Complete with validation. +- Mojaloop, card networks, flash-loan XAU, etc., unless a **written scope addendum** promotes them. +- **Template-only** jurisdiction [GENERIC-COMMON-LAW-STUB](../compliance-matrices/GENERIC-COMMON-LAW-STUB/banking_v1.md) — never production. + +## Change control + +Any change to this freeze requires: Program owner + Legal/Compliance acknowledgment and update to this file’s **Last updated** and a short **revision note** block (append below). + +--- + +## Revision history + +| Date | Change | +|------|--------| +| 2026-04-25 | Initial slice 1 freeze document created from master plan. | diff --git a/docs/04-configuration/universal-resource-activation/README.md b/docs/04-configuration/universal-resource-activation/README.md index 3b62db75..d789e85f 100644 --- a/docs/04-configuration/universal-resource-activation/README.md +++ b/docs/04-configuration/universal-resource-activation/README.md @@ -15,11 +15,17 @@ | [UNIVERSAL_RESOURCE_INFRA_CAPACITY_LANE.md](UNIVERSAL_RESOURCE_INFRA_CAPACITY_LANE.md) | Infrastructure capacity lane: inventory, bundles, broker, metering | | [UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md](UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md) | Shared evidence and reconciliation package | | [UNIVERSAL_RESOURCE_PILOT_PLAN.md](UNIVERSAL_RESOURCE_PILOT_PLAN.md) | First three pilots (SKR, server funds, infra) | +| [URA_PILOT_CLOSURE_RUNBOOK.md](URA_PILOT_CLOSURE_RUNBOOK.md) | Replace manifest placeholders; close pilots and evidence | +| [policy-profiles.json (registry)](../../config/universal-resource-activation/policy-profiles.json) | Machine-readable profiles + GRU governance level | +| [POLICY_PROFILES_REGISTRY.md](../../config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md) | Doc control / sign-off table per profile version | +| [MANIFEST_AUTOMATION_DESIGN.md](../../config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md) | Future manifest merge/CI design (not implemented) | +| [Compliance matrices / onboarding](../compliance-matrices/README.md) | Per-jurisdiction matrices, charter, playbook | +| [Jurisdiction catalog](../jurisdictions/JURISDICTION_CATALOG.md) | Catalog index + `config/jurisdictions/catalog.v1.json` | | [JSON Schema v1](../../../config/universal-resource-activation.resource.v1.schema.json) | Machine-readable resource body (`UniversalResource` subset) | | [URAWiring / ops](UNIVERSAL_RESOURCE_WIRING.md) | **Manifest, CI validation, Phoenix `GET` route, env overrides** | | [manifest.json (live store)](../../../config/universal-resource-activation/manifest.json) | In-repo `resources[]` and `evidencePackages[]` | -**Validate:** `node scripts/validate/validate-universal-resource-activation.mjs` (from repo root) · **smoke (schema ± HTTP):** `bash scripts/verify/smoke-universal-resource-activation.sh` — [wiring §2.1](UNIVERSAL_RESOURCE_WIRING.md#21-testing-checklist) +**Validate:** `pnpm ura:validate` · `pnpm ura:validate-profiles` · **merge fragments:** `pnpm ura:merge-manifest` · **ledger mapping:** `pnpm ura:validate-ledger-mapping` · **writers:** `pnpm ura:writer:ledger` / `pnpm ura:writer:settlement` · **profile hash (on-chain anchor):** `pnpm ura:profile-hash` · **closure gate:** `pnpm ura:validate-closure` / `pnpm ura:validate-closure:strict` · **smoke:** `pnpm ura:smoke` (add `--http` for Phoenix: manifest + policy-profiles + sidecar-probe) · **on-chain id hashes:** `pnpm ura:keccak` — [wiring §2.1](UNIVERSAL_RESOURCE_WIRING.md#21-testing-checklist) · **full automation tracker:** [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) ## Upstream anchors diff --git a/docs/04-configuration/universal-resource-activation/SKR_CUSTODY_AUTOMATION_NOTES.md b/docs/04-configuration/universal-resource-activation/SKR_CUSTODY_AUTOMATION_NOTES.md new file mode 100644 index 00000000..719966ff --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/SKR_CUSTODY_AUTOMATION_NOTES.md @@ -0,0 +1,27 @@ +# SKR / custody — automation notes for `evidenceRefs` + +**Last updated:** 2026-04-25 +**Purpose:** Guide for **Pilot 1** automation: populating [`manifest.json`](../../../config/universal-resource-activation/manifest.json) `evidenceRefs` and evidence package `custodyOrSourceEvidence` from custodian or internal systems. + +## 1. Typical sources + +| Source | Pattern | +|--------|---------| +| **Custodian API** | Poll or webhook for statement id / secure URL; store hash in manifest. | +| **Signed PDF / ISO package** | Landing zone (S3, SFTP); writer computes SHA-256; `evidenceRefs` = `sha256:…` or object URL + hash. | +| **Internal attestation** | HSM-signed payload; reference id in manifest. | + +## 2. Jurisdiction + +Obligations live in the per-jurisdiction matrix (e.g. [ID-INDONESIA/banking_v1.md](../compliance-matrices/ID-INDONESIA/banking_v1.md)). Automation must not change **meaning** of evidence without counsel review. + +## 3. Implementation sketch + +1. Custody ETL outputs JSON `{ "statementId", "hash", "effectiveDate" }`. +2. Extend [`build-ledger-fragment.mjs`](../../../scripts/ura/manifest-writer/build-ledger-fragment.mjs) pattern with a **custody fragment** script (future) or reuse merge fragments manually. +3. Run `pnpm ura:validate` and `pnpm ura:validate-closure:strict` before production CI enables strict mode. + +## Related + +- [`URA_PILOT_CLOSURE_RUNBOOK.md`](URA_PILOT_CLOSURE_RUNBOOK.md) §2 +- [`URA_MANIFEST_WRITER_OPS.md`](../../03-deployment/URA_MANIFEST_WRITER_OPS.md) diff --git a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md index a2895905..a4b3a687 100644 --- a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md +++ b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md @@ -1,6 +1,6 @@ # Shared Evidence and Reconciliation Package -**Last updated:** 2026-04-24 +**Last updated:** 2026-04-25 **Purpose:** A single **reproducible evidence package** for every **resource activation** and cross-lane action (SKR, server funds, infra, settlement). Aligns with ISO-20022 and institutional audit patterns referenced in [DBIS Rail technical spec](../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md) and the custody operating model in [DBIS_RTGS_DEPOSITORY_AND_CUSTODY_OPERATING_MODEL.md](../../03-deployment/DBIS_RTGS_DEPOSITORY_AND_CUSTODY_OPERATING_MODEL.md). ## Design principles @@ -30,6 +30,8 @@ | `reconciliationStatus` | `open`, `matched`, `exception` | | `explanation` | Human-readable for auditors | +Use **`reconciliationStatus = open`** when mandatory joins (e.g. a real `accountingRef` or `settlementOrChainRef` where policy requires them) are not yet present or verified; set **`matched`** only after those joins succeed in the same reconciliation window. Bootstrap packages with TBD text placeholders should stay **`open`**. + ## Minimum object set by lane | Lane | Must include | diff --git a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_ONTOLOGY.md b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_ONTOLOGY.md index 51aae65a..cc279acd 100644 --- a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_ONTOLOGY.md +++ b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_ONTOLOGY.md @@ -1,6 +1,6 @@ # Universal Resource Ontology -**Last updated:** 2026-04-24 +**Last updated:** 2026-04-25 **Purpose:** Define the canonical **resource** model used across financial and infrastructure lanes. This is the schema contract for registries, APIs, and (when applicable) on-chain mirrors. ## Design principles @@ -19,6 +19,8 @@ | `createdAt` | RFC3339 / epoch | Audit. | | `updatedAt` | RFC3339 / epoch | Audit. | +**In-repo manifest (human-readable URNs):** The [URA `manifest.json`](../../config/universal-resource-activation/manifest.json) may use stable string IDs such as `ura:pilot-1:…` for reviewability. For optional EVM anchoring, derive **`keccak256(utf8(resourceId))`** (same as `node scripts/ura/keccak-resource-ids.mjs`); the manifest string remains the canonical off-chain id unless you later standardize on bytes32 at rest. + ## Resource families `family` discriminates top-level behavior and which lane adapters apply. diff --git a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_PILOT_PLAN.md b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_PILOT_PLAN.md index 42c25b4f..6383c2de 100644 --- a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_PILOT_PLAN.md +++ b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_PILOT_PLAN.md @@ -1,10 +1,12 @@ # First Three Pilots — Universal Resource Activation -**Last updated:** 2026-04-24 +**Last updated:** 2026-04-25 **Purpose:** Operable, low-risk **pilots** that validate the ontology, policy profiles, each lane, and the shared [evidence package](UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md) before broad rollout. **Governance default:** `tokenizationMode = NONE` and conservative `deployabilityState` for all three pilots. +**In-repo `manifest.json` (bootstrap):** The shared [`config/universal-resource-activation/manifest.json`](../../config/universal-resource-activation/manifest.json) uses **pilot-scoped** `resourceId`s and may keep the pilot evidence package at **`reconciliationStatus: open`** while `accountingRef` / `settlementOrChainRef` (or other mandatory joins) are still TBD. The “Done when” columns below are **end states** for each pilot, not a live mirror of the JSON on every row. Update the manifest to **`matched`** when the corresponding pilot’s reconciliation is closed (see [UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md](UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md)). + --- ## Pilot 1 — SKR- or statement-backed resource record (custody or strategic with evidence) diff --git a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md index 5bf296ee..d74470cb 100644 --- a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md +++ b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_POLICY_PROFILES.md @@ -1,6 +1,6 @@ # Universal Resource Policy Profiles -**Last updated:** 2026-04-24 +**Last updated:** 2026-04-25 **Purpose:** Define **modular policy profiles** that bind legal, regulatory, compliance, accounting, valuation, and transferability rules to resources without hardcoding jurisdiction logic in each adapter. ## Why profiles @@ -105,6 +105,16 @@ Map to on-chain or off-chain enforcement: 3. `effectiveFrom` in production; keep prior versions for historical reconciliation. 4. Emit `PolicyProfileUpdated` (off-chain) or on-chain event if a chain registry is used. +## Machine-readable registry (CI) + +Production-facing profiles SHOULD be listed in [`config/universal-resource-activation/policy-profiles.json`](../../config/universal-resource-activation/policy-profiles.json) (JSON Schema: [`universal-resource-activation.policy-profile-registry.v1.schema.json`](../../config/universal-resource-activation.policy-profile-registry.v1.schema.json)). Each entry includes **`minimumGruGovernanceLevel`** (0–5) per [GRU_M00_DIAMOND_FACET_MAP.md](../GRU_M00_DIAMOND_FACET_MAP.md) §4. + +**Doc control:** [`POLICY_PROFILES_REGISTRY.md`](../../config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md) — sign-off table per profile version. + +**Validate:** `pnpm ura:validate-profiles` — also invoked from [`scripts/validation/validate-config-files.sh`](../../../scripts/validation/validate-config-files.sh). + +**Per-jurisdiction matrices:** [`docs/04-configuration/compliance-matrices/`](../compliance-matrices/README.md). + ## Related - [UNIVERSAL_RESOURCE_ONTOLOGY.md](UNIVERSAL_RESOURCE_ONTOLOGY.md) diff --git a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md index 430abfa4..22fc64f7 100644 --- a/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md +++ b/docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md @@ -1,6 +1,6 @@ # Universal Resource Activation — Wiring and Operations -**Last updated:** 2026-04-24 +**Last updated:** 2026-04-25 This document describes how the **in-repo** universal resource system is wired: config store, JSON schemas, validation in CI, and the Phoenix Deploy API. @@ -30,34 +30,45 @@ node scripts/validate/validate-universal-resource-activation.mjs | 1. JSON Schema (manifest, each resource, each evidence row) | `node scripts/validate/validate-universal-resource-activation.mjs` | Invalid or incomplete JSON vs schemas | | 2. Full config gate (includes step 1) | `bash scripts/validation/validate-config-files.sh` | Any required project config check fails | | 3. CI-style aggregate | `bash scripts/verify/run-all-validation.sh --skip-genesis` | Any step in the wrapper fails | -| 4. URA smoke (schema + optional HTTP) | `bash scripts/verify/smoke-universal-resource-activation.sh` | Step 1 fails. With `--http` (or `PHOENIX_BASE_URL=…`), also fails if Phoenix does not return HTTP 200 JSON with `.schemaVersion` at `/api/v1/universal-resource-activation/manifest` | -| 5. OpenAPI / Swagger | Open `http://:/api-docs` on `phoenix-deploy-api` and confirm `GET /api/v1/universal-resource-activation/manifest` is listed (see [`phoenix-deploy-api/openapi.yaml`](../../../phoenix-deploy-api/openapi.yaml)) | N/A (manual) | +| 4. URA smoke (schema + optional HTTP) | `bash scripts/verify/smoke-universal-resource-activation.sh` | Step 1 fails. With `--http` (or `PHOENIX_BASE_URL=…`), checks `GET …/manifest` (200 + `.schemaVersion`), `GET …/policy-profiles` (200 + `.profiles` array), and `GET …/server-funds-sidecar-probe` (**200** = sidecar or probe ok JSON; **503** + `configured: false` = URL unset, OK for dev; **502** = URL set but sidecar unreachable) | +| 4b. On-chain / GRU hash (optional) | `node scripts/ura/keccak-resource-ids.mjs` | Prints `keccak256(utf8(resourceId))` per row (requires root `ethers`); does not block CI | +| 4c. Server-funds sidecar probe (optional) | `curl` `GET /api/v1/universal-resource-activation/server-funds-sidecar-probe` on Phoenix | `503` + `configured:false` until `SERVER_FUNDS_SIDECAR_URL` is set; `200` when a health path returns 2xx | +| 5. OpenAPI / Swagger | Open `http://:/api-docs` on `phoenix-deploy-api` and confirm URA paths (see [`phoenix-deploy-api/openapi.yaml`](../../../phoenix-deploy-api/openapi.yaml)) | N/A (manual) | -**Operator note:** `smoke-universal-resource-activation.sh` without flags only runs steps that need Node (no live Phoenix). Use `PHOENIX_BASE_URL=http://127.0.0.1:4001 bash scripts/verify/smoke-universal-resource-activation.sh --http` when the API is up on that host. +**Operator note:** `smoke-universal-resource-activation.sh` without flags only runs steps that need Node (no live Phoenix). With Phoenix up: `PHOENIX_BASE_URL=http://127.0.0.1:4001 bash scripts/verify/smoke-universal-resource-activation.sh --http` (default base `http://127.0.0.1:4001` if unset with `--http`). ## 3. Phoenix Deploy API (read-only) -The API exposes the manifest as **JSON** without a partner API key (same pattern as the public-sector program manifest). +The API exposes the manifest and policy profile registry as **JSON** without a partner API key (same pattern as the public-sector program manifest). | | | |--|--| -| **Endpoint** | `GET /api/v1/universal-resource-activation/manifest` | -| **Override path** | Set `UNIVERSAL_RESOURCE_MANIFEST_PATH` to a full file path. | -| **Default resolution** | `PHOENIX_REPO_ROOT` (or `PROXMOX_REPO_PATH`) + `config/universal-resource-activation/manifest.json`, or `../config/...` when running with `phoenix-deploy-api` CWD. | +| **Manifest** | `GET /api/v1/universal-resource-activation/manifest` | +| **Policy profiles** | `GET /api/v1/universal-resource-activation/policy-profiles` | +| **Manifest override** | `UNIVERSAL_RESOURCE_MANIFEST_PATH` (full file path). | +| **Policy registry override** | `UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH` (full file path). | +| **Default resolution** | `PHOENIX_REPO_ROOT` (or `PROXMOX_REPO_PATH`) + `config/universal-resource-activation/{manifest.json,policy-profiles.json}`, or `../config/...` when running with `phoenix-deploy-api` CWD. | -**Implementation:** [phoenix-deploy-api/server.js](../../../phoenix-deploy-api/server.js) — `resolveUniversalResourceManifestPath`, route registered before `partnerKeyMiddleware`. +**Implementation:** [phoenix-deploy-api/server.js](../../../phoenix-deploy-api/server.js) — `resolveUniversalResourceManifestPath`, `resolveUniversalResourcePolicyProfilesPath`, routes registered before `partnerKeyMiddleware`. ## 4. Gitea / Phoenix deploy When Gitea deploy syncs the `d-bis/proxmox` archive, the `config/` tree (including `config/universal-resource-activation/`) is part of the synced subtree. The Phoenix host can serve the manifest as soon as the file is present under `PHOENIX_REPO_ROOT`. -## 5. Future wiring (out of this pass) +## 5. Integration tools (in-repo; operator or next phase) -- **On-chain / GRU M00:** When `UniversalAssetRegistry` and M00 are the SoR, mirror or hash `resourceId` into on-chain registries; keep the manifest as operator/air-gapped copy until a dedicated DB is introduced. -- **OMNL / `server-funds-sidecar`:** Add API calls to register draws/holds; store returned `accountingRef` in new evidence package rows in `manifest.json` or a database — follow [UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md](UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md). -- **DBIS Rail:** Link `settlementOrChainRef` in evidence packages to `MintAuth` / settlement router events per [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md). +- **Manifest fragments + merge:** Drop partial JSON under `config/universal-resource-activation/manifest-fragments/` and run `pnpm ura:merge-manifest` (validate-only) or `node scripts/ura/merge-manifest-fragments.mjs --out `. See [manifest-fragments/README.md](../../../config/universal-resource-activation/manifest-fragments/README.md) and [MANIFEST_AUTOMATION_DESIGN.md](../../../config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md). **Task index:** [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md). +- **Ledger / Rail fragments:** `pnpm ura:writer:ledger`, `pnpm ura:writer:settlement`, `pnpm ura:validate-ledger-mapping` — [manifest-writer/README.md](../../../scripts/ura/manifest-writer/README.md); settlement sources: [DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md](../../dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md); ops: [URA_MANIFEST_WRITER_OPS.md](../../03-deployment/URA_MANIFEST_WRITER_OPS.md). +- **On-chain policy anchor (standalone):** `PolicyProfileRegistry` in `smom-dbis-138` + `pnpm ura:profile-hash` — [GRU_REGISTRY_WIRING_CHECKLIST.md](../../runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md) §6. +- **Production closure gate:** `pnpm ura:validate-closure` (warnings) or `pnpm ura:validate-closure:strict` (exit 1 on pilot ids, pending evidence refs, `TBD` in evidence fields, or `reconciliationStatus: open`). Optional CI: `URA_STRICT_CLOSURE=1` with `validate-config-files.sh`. +- **On-chain / GRU M00:** Canonical manifest stays the off-chain store. To **derive** EVM keccak for optional registry anchoring: `node scripts/ura/keccak-resource-ids.mjs` (uses `ethers` v6; prints one hash per `resourceId`). On-chain contract wiring remains a separate deployment task. +- **OMNL / `server-funds-sidecar`:** Phoenix exposes **`GET /api/v1/universal-resource-activation/server-funds-sidecar-probe`** (no API key). Set `SERVER_FUNDS_SIDECAR_URL` to the sidecar base URL; optional `SERVER_FUNDS_SIDECAR_HEALTH_PATH` for a first path. Returns **503** with a configuration hint if unset. Draw/hold APIs and writing `accountingRef` into the manifest (or a DB) remain follow-on work per [UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md](UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md). +- **DBIS Rail / MintAuth:** Evidence packages support **`settlementOrChainRef`** in JSON Schema. Populate the manifest with live settlement or event refs when the pilot posts to the rail; see [UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md](UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md) and [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md). Automated mirroring is out of scope until services expose stable query endpoints. ## Related -- [README.md](README.md) — document map +- [README.md](README.md) — document map +- [technical-specs/README.md](technical-specs/README.md) — normative TS-* specs for OMNL/sidecar, settlement indexer, SKR ETL, GRU program, compliance sign-off +- [URA_PILOT_CLOSURE_RUNBOOK.md](URA_PILOT_CLOSURE_RUNBOOK.md) — close pilots / replace placeholders +- [../compliance-matrices/README.md](../compliance-matrices/README.md) — jurisdiction matrices and onboarding charter/playbook - [../README.md](../README.md) (04-configuration) — main index diff --git a/docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md b/docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md new file mode 100644 index 00000000..02e459aa --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md @@ -0,0 +1,54 @@ +# URA manifest automation — implementation tracker + +**Last updated:** 2026-04-25 +**Purpose:** Single checklist for **OMNL/ledger → manifest**, **chain/Rail → manifest**, **GRU/on-chain registry**, and **ops gates**. Repo artifacts are linked; rows that need live services name the owning team. + +**Legend:** **Done (repo)** = implemented or specified in this monorepo. **Operator** = execution on your LAN/RPC/Fineract deployment. + +**Normative technical specs (remaining implementation):** [technical-specs/README.md](technical-specs/README.md) — RFC 2119 requirements, interfaces, acceptance tests for pending workstreams. + +| ID | Task | Status | Artifact / next step | +|----|------|--------|----------------------| +| ura-auto-01 | OMNL/Fineract APIs → `accountingRef` | **Done (repo)** | [`URA_MANIFEST_WRITER_OPS.md`](../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §2; mapping schema | +| ura-auto-02 | Server-funds sidecar ↔ ledger | **Operator** | Todo `ura-auto-02`; RTGS tracker; Phoenix probe only today | +| ura-auto-03 | Mapping table (idempotency) | **Done (repo)** | [`omnl-ledger-mapping.v1.schema.json`](../../../config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json) | +| ura-auto-04 | Manifest writer job | **Done (repo)** | [`build-ledger-fragment.mjs`](../../../scripts/ura/manifest-writer/build-ledger-fragment.mjs), [`merge-manifest-fragments.mjs`](../../../scripts/ura/merge-manifest-fragments.mjs) | +| ura-auto-05 | Publish path (git/sync/API) | **Operator** | [`URA_MANIFEST_WRITER_OPS.md`](../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §4 | +| ura-auto-06 | Secrets & IAM | **Operator** | Same doc §3 | +| ura-auto-07 | Reconciliation / drift | **Done (repo)** | Spec in ops doc §5; implement alerts in your APM | +| ura-auto-08 | E2E staging | **Operator** | Todo `ura-auto-08`; run writer + `pnpm ura:validate` after real journal export | +| ura-auto-opt-a | Real-time vs batch | **Done (repo)** | Ops doc §6 optional | +| ura-auto-opt-b | Multi-pool / DLQ / audit log | **Done (repo)** | Ops doc §6 optional | +| chain-01 | Rail settlement event sources | **Done (repo)** | [`DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md`](../../dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md) | +| chain-02 | Indexer → `settlementOrChainRef` | **Partial (repo)** | Fragment CLI: [`build-settlement-fragment.mjs`](../../../scripts/ura/manifest-writer/build-settlement-fragment.mjs); **Operator:** Todo `chain-02` (live listener) | +| chain-03 | SKR custody automation | **Partial (repo)** | [`SKR_CUSTODY_AUTOMATION_NOTES.md`](SKR_CUSTODY_AUTOMATION_NOTES.md); **Operator:** custodian ETL | +| chain-opt-a | Anchor manifest hash on-chain | **Operator** | Optional pattern in settlement doc | +| chain-opt-b | `keccak(resourceId)` in registry | **Operator** | After GRU facet; use [`keccak-resource-ids.mjs`](../../../scripts/ura/keccak-resource-ids.mjs) | +| gru-01 | Lock GRC → M00 strategy | **Operator** | Todo `gru-01`; [`GRU_REGISTRY_WIRING_CHECKLIST.md`](../../runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md) §1 | +| gru-02 | GRUStorage + bitmask | **Operator** | Todo `gru-02`; checklist §2 + facet map | +| gru-03 | Minimum ship facets | **Operator** | Todo `gru-03`; checklist §3 (Solidity) | +| gru-04 | Asset registry / Token factory | **Operator** | Todo `gru-04`; checklist §4 | +| gru-05 | Deploy & verify M00 | **Operator** | Todo `gru-05`; [`GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md`](../../runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md) | +| gru-06 | Multisig / pause drills | **Operator** | Todo `gru-06`; checklist §5 | +| gru-07 | On-chain policy profile registry | **Done (repo)** | `smom-dbis-138/contracts/universal-resource/PolicyProfileRegistry.sol` + [`policy-profiles-content-hash.mjs`](../../../scripts/ura/policy-profiles-content-hash.mjs) | +| gru-08 | Doc handoff (Phoenix/URA) | **Done (repo)** | This file + [`UNIVERSAL_RESOURCE_WIRING.md`](UNIVERSAL_RESOURCE_WIRING.md) §5 | +| gru-opt-a | Oracle / cross-chain mirror | **Operator** | Checklist §7 | +| gru-opt-b | External audit / formal verification | **Cancelled** | Vendor scope; not automatable in-repo | +| xc-01 | `URA_STRICT_CLOSURE` in CI | **Done (repo)** | [`.gitea/workflows/validate-on-pr.yml`](../../../.gitea/workflows/validate-on-pr.yml) (documented env); [`validate-config-files.sh`](../../../scripts/validation/validate-config-files.sh) | +| xc-02 | Legal sign-off on automation | **Operator** | Todo `xc-02` (counsel); template in [`URA_MANIFEST_WRITER_OPS.md`](../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §7 | +| xc-03 | DR / rollback | **Done (repo)** | Ops doc §8 | + +## Quick commands + +```bash +pnpm ura:validate-ledger-mapping +pnpm ura:writer:ledger -- --mapping config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json --ledger config/universal-resource-activation/integration/examples/ledger-snapshot.example.json +pnpm ura:writer:settlement -- --evidence-package-id ura:pilot:evidence-register-bootstrap --message-id 0x1 --tx-hash 0x2 --chain-id 138 +pnpm ura:profile-hash institutional_custody_skr_v1 +cd smom-dbis-138 && FORGE_SCOPE=universal-resource bash scripts/forge/scope.sh test --match-contract PolicyProfileRegistryTest +``` + +## Related + +- [`MANIFEST_AUTOMATION_DESIGN.md`](../../../config/universal-resource-activation/MANIFEST_AUTOMATION_DESIGN.md) +- [`URA_PILOT_CLOSURE_RUNBOOK.md`](URA_PILOT_CLOSURE_RUNBOOK.md) diff --git a/docs/04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md b/docs/04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md new file mode 100644 index 00000000..9ab5f31b --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md @@ -0,0 +1,62 @@ +# URA pilot closure runbook — replace placeholders with working components + +**Last updated:** 2026-04-25 +**Purpose:** Operator checklist to move [`config/universal-resource-activation/manifest.json`](../../config/universal-resource-activation/manifest.json) from **bootstrap** to **pilot-closed** state, aligned with [UNIVERSAL_RESOURCE_PILOT_PLAN.md](UNIVERSAL_RESOURCE_PILOT_PLAN.md) and jurisdiction matrices (e.g. [ID-INDONESIA/banking_v1.md](../compliance-matrices/ID-INDONESIA/banking_v1.md)). + +**Before production:** run `pnpm ura:validate` and `pnpm ura:validate-profiles`; legal/compliance must sign off obligation coverage in the compliance matrix. + +--- + +## 1. Participant and jurisdiction (all resources) + +| Step | Action | Manifest fields | +|------|--------|-----------------| +| 1.1 | Register institution in your participant registry; assign stable id. | `ownerParticipantId` — replace `ura:participant:pilot-*-assign` with canonical id. | +| 1.2 | Confirm governing jurisdiction(s) with counsel. | `jurisdiction` — use catalog code (e.g. `ID`) or agreed tag; not `TBD`. | +| 1.3 | Align profile with registry. | `policyProfileId` must exist in [policy-profiles.json](../../config/universal-resource-activation/policy-profiles.json). | + +--- + +## 2. Pilot 1 — SKR / custody + +| Step | Action | Manifest / evidence | +|------|--------|---------------------| +| 2.1 | Attach custodian / strategic evidence. | `evidenceRefs[]` — hashes, object ids, or signed manifest refs. | +| 2.2 | Advance lifecycle per policy. | `lifecycleState` e.g. `pending_validation` → `active` when appropriate. | +| 2.3 | Evidence package | Add or update package with `custodyOrSourceEvidence` pointing to SKR row; keep `reconciliationStatus` **open** until validator sign-off, then **matched** if all joins satisfied. | + +--- + +## 3. Pilot 2 — Server funds + +| Step | Action | Manifest / evidence | +|------|--------|---------------------| +| 3.1 | Ensure `SERVER_FUNDS_SIDECAR_URL` and live draw/hold/release path. | Phoenix probe 200; see [UNIVERSAL_RESOURCE_WIRING.md](UNIVERSAL_RESOURCE_WIRING.md). | +| 3.2 | Capture ledger reference. | `accountingRef` — real OMNL / Fineract / batch id (not narrative TBD). | +| 3.3 | Capture rail / chain ref if used. | `settlementOrChainRef` — MintAuth `messageId`, tx hash, or rail id per [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md). | +| 3.4 | Update notional if policy tracks pool balance. | `quantity` / `unitOfMeasure` on SERVER_FUNDS resource. | + +--- + +## 4. Pilot 3 — Infra capacity + +| Step | Action | Manifest / evidence | +|------|--------|---------------------| +| 4.1 | Verify host and bundle against inventory. | `infraHostId`, `infraBundleId`; `evidenceRefs` may link to storage / VMID reports. | +| 4.2 | After deploy, record deployment. | Evidence package `deploymentRef` — VMID, FQDN, health URL. | +| 4.3 | Meter and reconcile. | Additional evidence package or same package with metering refs; `reconciliationStatus` **matched** when FinOps agrees. | + +--- + +## 5. Bootstrap evidence package closure + +| Step | Action | +|------|--------| +| 5.1 | When pilots 1–3 mandatory joins are satisfied, set `reconciliationStatus` to **`matched`**. | +| 5.2 | Set `manifest.json` top-level `updatedAt` to RFC3339 UTC. | +| 5.3 | Re-run `pnpm ura:validate` and deploy manifest path on Phoenix (`PHOENIX_REPO_ROOT` / `UNIVERSAL_RESOURCE_MANIFEST_PATH`). | + +## Related + +- [DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](../../03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md) +- [INSTITUTION_ONBOARDING_PLAYBOOK.md](../compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md) diff --git a/docs/04-configuration/universal-resource-activation/technical-specs/README.md b/docs/04-configuration/universal-resource-activation/technical-specs/README.md new file mode 100644 index 00000000..dee52145 --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/technical-specs/README.md @@ -0,0 +1,23 @@ +# URA / RTGS / GRU — technical specifications (remaining implementation) + +**Last updated:** 2026-04-25 +**Purpose:** Normative **implementation** specifications for work that is still **operator- or engineering-pending** after repo scaffolding (writers, mapping schema, `PolicyProfileRegistry`, docs). These specs **do not replace** authoritative architecture documents; they bind them to testable interfaces and acceptance criteria. + +## Document control + +| ID | Title | Covers (tracker / todo ids) | Normative references | +|----|--------|----------------------------|----------------------| +| [TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md](TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md) | OMNL + server-funds-sidecar → manifest | `ura-auto-02`, `ura-auto-05`, `ura-auto-06`, `ura-auto-08` | [UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md](../UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md), [DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md](../../../03-deployment/DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md) §7 | +| [TS-SETTLEMENT-INDEXER-MANIFEST-V1.md](TS-SETTLEMENT-INDEXER-MANIFEST-V1.md) | Chain / Rail events → `settlementOrChainRef` | `chain-02`, optional anchoring | [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md), [DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md](../../../dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md) | +| [TS-SKR-CUSTODY-ETL-MANIFEST-V1.md](TS-SKR-CUSTODY-ETL-MANIFEST-V1.md) | Custody evidence → manifest | `chain-03` | [SKR_CUSTODY_AUTOMATION_NOTES.md](../SKR_CUSTODY_AUTOMATION_NOTES.md), evidence package schema | +| [TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md](TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md) | GRU M00 program (strategy → deploy → ops) | `gru-01`–`gru-06`, `gru-opt-a` | [GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md](../../GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md), [GRU_M00_DIAMOND_FACET_MAP.md](../../GRU_M00_DIAMOND_FACET_MAP.md), [GRU_REGISTRY_WIRING_CHECKLIST.md](../../../runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md) | +| [TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md](TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md) | Legal / compliance gate for automation | `xc-02` | [INSTITUTION_ONBOARDING_CHARTER.md](../../compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md), [URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) | + +## Conventions + +- **MUST / SHOULD / MAY** follow [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) (and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174) for clarity when BCP 14 is intended). +- **Canonical SoR:** OMNL / Fineract owns `accountingRef`; chain owns settlement attestations only per DBIS Rail design principle ([DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md) §0). + +## Related + +- [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](../URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/docs/04-configuration/universal-resource-activation/technical-specs/TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md b/docs/04-configuration/universal-resource-activation/technical-specs/TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md new file mode 100644 index 00000000..90f08789 --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/technical-specs/TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md @@ -0,0 +1,52 @@ +# TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1 — Legal / compliance gate for URA automation + +**Version:** 1.0.0 +**Last updated:** 2026-04-25 +**Status:** Normative for **governance process** (not legal advice). +**Audience:** Legal, compliance, program office, engineering leads. + +## 1. Purpose + +Ensure **automated** updates to [`manifest.json`](../../../../config/universal-resource-activation/manifest.json) and related evidence fields **remain** within **counsel-approved** obligation coverage in per-jurisdiction compliance matrices. + +## 2. Normative references + +| Document | Role | +|----------|------| +| [INSTITUTION_ONBOARDING_CHARTER.md](../../compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md) | Definition of **Complete**, RACI | +| [INSTITUTION_ONBOARDING_PLAYBOOK.md](../../compliance-matrices/INSTITUTION_ONBOARDING_PLAYBOOK.md) | Operational steps | +| [POLICY_PROFILES_REGISTRY.md](../../../../config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md) | Profile version sign-off table | +| [URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §7 | Memo / ticket template | + +## 3. Triggers requiring sign-off + +Automation **SHALL NOT** be marked **production-ready** until **all** applicable rows below are satisfied: + +| # | Trigger | Owner | +|---|---------|-------| +| T-1 | First production writer for **ledger** (`accountingRef`) | Legal + Compliance | +| T-2 | First production **settlement indexer** (`settlementOrChainRef`) | Legal + Compliance + Risk | +| T-3 | First production **custody ETL** (`evidenceRefs` / custody fields) | Legal + Compliance | +| T-4 | Change to **mapping file** that alters which matrix obligation is evidenced | Legal + Compliance | +| T-5 | Change to **`policyProfileId`** or registry row affecting production resources | Legal + Risk (per registry doc) | + +## 4. Evidence package for auditors (recommended content) + +Each sign-off **SHOULD** archive: + +1. **Matrix reference:** Jurisdiction code + version + row ids (e.g. `ID-OMNL-001`) satisfied by automation. +2. **Field mapping:** Table: automation output field → matrix control id → system of record. +3. **Residual risk:** Known gaps, manual overrides, exception path. +4. **Test artifacts:** Staging E2E logs (see [TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md](TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md) §7, [TS-SETTLEMENT-INDEXER-MANIFEST-V1.md](TS-SETTLEMENT-INDEXER-MANIFEST-V1.md) §10). +5. **CI posture:** Whether `URA_STRICT_CLOSURE` / `vars.URA_STRICT_CLOSURE` is enabled for the branch. + +## 5. Engineering obligations after sign-off + +1. **R-COMP-1:** Manifest automation **MUST** log **immutable** correlation ids (ledger, chain, custody) per technical specs. +2. **R-COMP-2:** Rollback and DR **MUST** be documented ([URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §8). +3. **R-COMP-3:** Production manifest **SHOULD** pass `pnpm ura:validate-closure:strict` when pilots are closed. + +## 6. Related + +- [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) +- [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](../URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/docs/04-configuration/universal-resource-activation/technical-specs/TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md b/docs/04-configuration/universal-resource-activation/technical-specs/TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md new file mode 100644 index 00000000..f468b822 --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/technical-specs/TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1.md @@ -0,0 +1,92 @@ +# TS-GRU-M00-IMPLEMENTATION-PROGRAM-V1 — GRU M00 diamond implementation program + +**Version:** 1.0.0 +**Last updated:** 2026-04-25 +**Status:** Normative **program** specification (execution phases). Architecture remains in [GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md](../../GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md) and [GRU_M00_DIAMOND_FACET_MAP.md](../../GRU_M00_DIAMOND_FACET_MAP.md). +**Audience:** Solidity leads, governance ops, institutional spec owners. + +## 1. Purpose + +Turn the **GRU M00 institutional spec + facet map** into a **sequenced, testable delivery program** with explicit decision gates, without duplicating the full facet catalog here. + +## 2. Strategy gate (`gru-01`) — MUST complete first + +| Decision | Options | Output artifact | +|----------|---------|-----------------| +| **GRC → M00 path** | **Option A:** new diamond · **Option B:** migrate GRC-2535 in place | Signed ADR + pointer in [GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md](../../../runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md) §3–4 | + +**R-GRU-0:** No Phase 2 storage layout work **SHALL** begin until **GRC → M00** is recorded and storage collision analysis is approved (see [GRU_M00_DIAMOND_REVIEW_GAPS_AND_RECOMMENDATIONS.md](../../GRU_M00_DIAMOND_REVIEW_GAPS_AND_RECOMMENDATIONS.md) §4.3). + +## 3. Storage and governance (`gru-02`) + +### 3.1 Deliverables + +1. **D-GRU-S-1:** Written **GRUStorage** layout (namespaces, structs, slot discipline) reviewed by Solidity lead. +2. **D-GRU-S-2:** **Governance level** default per environment (dev/test/prod) aligned with [GRU_M00_DIAMOND_FACET_MAP.md](../../GRU_M00_DIAMOND_FACET_MAP.md). +3. **D-GRU-S-3:** **Bitmask / gate** mapping table: which gates invoke for levels 0–5. + +### 3.2 Acceptance + +- Forge (or Hardhat) **storage layout** diff shows **no collision** with existing GRC namespaces if Option B. + +## 4. Minimum ship spine (`gru-03`) + +Per gaps doc §5.1 “minimum ship list”, the program **MUST** deliver callable facets (stubs acceptable where marked): + +| Facet class | MUST | +|-------------|------| +| PolicyRouter + gates | Expose entrypoints; emit events or structured reverts for policy violations | +| StandardsRegistryFacet | Register at least one standards module id for tests | +| GovernanceLevelFacet | Read/write level with access control | +| TokenFactory / AssetRegistry path | Register at least one test asset type | + +**R-GRU-M-1:** `diamondCut` integration tests **MUST** pass on CI for the scoped tree before testnet deploy. + +## 5. Universal asset alignment (`gru-04`) + +1. **R-GRU-U-1:** Document **cutover** from `UniversalAssetRegistry` (smom-dbis-138) to M00 registry: mirror vs replace, per [UNIVERSAL_RESOURCE_ONTOLOGY.md](../UNIVERSAL_RESOURCE_ONTOLOGY.md) §Mapping to GRU M00. +2. **R-GRU-U-2:** `resourceId` ↔ on-chain `assetId` mapping **SHOULD** be tabulated in `docs/11-references` or deployment annex when addresses are known. + +## 6. Deploy and verify (`gru-05`) + +Follow [GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md](../../../runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md) §6 verification table. + +**Additional MUST for this program:** + +1. Record Diamond + facet addresses in [CONTRACT_ADDRESSES_REFERENCE.md](../../../11-references/CONTRACT_ADDRESSES_REFERENCE.md) (or successor inventory). +2. Run **loupe** + **governance level** + **PolicyRouter smoke** on each target chain before “complete” sign-off. + +## 7. Governance operations (`gru-06`) + +| Control | MUST | +|---------|------| +| Upgrade authority | Multisig or Timelock documented with addresses | +| Pause | Drill once per quarter; RTO documented | +| Incident | Rollback cut procedure documented (runbook §4.3 Option B) | + +## 8. Standalone policy anchor (already in repo) + +**PolicyProfileRegistry** ([`PolicyProfileRegistry.sol`](../../../../smom-dbis-138/contracts/universal-resource/PolicyProfileRegistry.sol)) **MAY** deploy **before** full M00 spine per [GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md](../../../runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md) §7. + +**R-GRU-P-1:** Published `contentHash` **MUST** match `pnpm ura:profile-hash ` for the same JSON canonicalization rule. + +## 9. Optional phase — oracle / cross-chain (`gru-opt-a`) + +**MAY** follow after Phase 6 stable: + +1. Define attestation format for off-chain evidence hashes. +2. Define mirror registry addresses per chain; document in multi-chain deployment annex. + +## 10. Program exit criteria (all phases) + +| Gate | Condition | +|------|------------| +| **G1** | ADR + storage signed off | +| **G2** | Spine facets on testnet + verification table green | +| **G3** | Mainnet (or Chain 138 prod) addresses recorded + ontology cutover doc updated | +| **G4** | Pause/upgrade drill log archived | + +## 11. Related + +- [GRU_REGISTRY_WIRING_CHECKLIST.md](../../../runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md) +- [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](../URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/docs/04-configuration/universal-resource-activation/technical-specs/TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md b/docs/04-configuration/universal-resource-activation/technical-specs/TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md new file mode 100644 index 00000000..006b6b5a --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/technical-specs/TS-OMNL-SIDECAR-MANIFEST-SYNC-V1.md @@ -0,0 +1,99 @@ +# TS-OMNL-SIDECAR-MANIFEST-SYNC-V1 — OMNL + server-funds-sidecar → URA manifest + +**Version:** 1.0.0 +**Last updated:** 2026-04-25 +**Status:** Normative for implementation (supplements [UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md](../UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md)). +**Audience:** HYBX integration, banking ops, platform SRE. + +## 1. Purpose + +Define **end-to-end technical requirements** so that: + +1. **OMNL / Fineract** remains the **system of record** for ledger postings and `accountingRef`. +2. **`server-funds-sidecar`** exposes **stable, authenticated** APIs (or exports) that correlate treasury actions with OMNL lines. +3. The **URA manifest** receives **non-placeholder** `accountingRef` (and optional quantity) on the correct `resourceId` / `evidencePackageId` rows, validated by `pnpm ura:validate` / `pnpm ura:validate-profiles`. + +## 2. Scope and non-goals + +### 2.1 In scope + +- Correlation model: sidecar draw/hold/release ↔ OMNL journal/batch identifiers. +- Writer / publish pipeline (batch or near-real-time) from SoR exports to manifest fragments. +- Idempotency, observability, and security for the sync path. +- Staging E2E acceptance criteria. + +### 2.2 Out of scope (this TS) + +- Replacing Fineract as SoR or defining full Fineract product configuration. +- Full OpenAPI for every OMNL deployment variant (this TS defines **required capability classes**; concrete paths MAY be tenant-specific annexes). +- On-chain settlement logic (see [TS-SETTLEMENT-INDEXER-MANIFEST-V1.md](TS-SETTLEMENT-INDEXER-MANIFEST-V1.md)). + +## 3. Normative references (answers consolidated from repo) + +| Topic | Source | +|-------|--------| +| Sidecar responsibilities (treasury, limits, handoff) | [DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md](../../../03-deployment/DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md) §7 `server-funds-sidecar` | +| SoR boundary | [UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md](../UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md) §System-of-record boundary | +| Workstream exit criteria | [DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](../../../03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md) W1, W2 | +| Mapping file schema | [`omnl-ledger-mapping.v1.schema.json`](../../../../config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json) | +| Fragment builder | [`build-ledger-fragment.mjs`](../../../../scripts/ura/manifest-writer/build-ledger-fragment.mjs) | +| Ops (secrets, publish, DR) | [URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) | + +## 4. Definitions + +| Term | Definition | +|------|------------| +| **Correlation id** | Stable string linking one sidecar operation to exactly one OMNL posting (or explicitly documented 1:N with parent ref). | +| **Ledger snapshot** | JSON export row (API response or batch file) containing at least the fields referenced by `accountingRefField` in the mapping file. | +| **Manifest fragment** | JSON object with optional `evidencePackages[]` / `resources[]` partial rows, mergeable per [merge-manifest-fragments.mjs](../../../../scripts/ura/merge-manifest-fragments.mjs). | + +## 5. Functional requirements + +### 5.1 Sidecar → OMNL correlation + +The implementation **MUST** satisfy: + +1. **R-OMNL-1:** Every **production** draw, hold, or release that affects a URA-tracked `SERVER_FUNDS` pool **MUST** emit or record a **correlation id** retrievable after the fact (log, DB row, or event). +2. **R-OMNL-2:** For each correlation id, operators **MUST** be able to obtain the **OMNL `accountingRef`** (journal entry id, batch id, or institution-agreed composite) that the mapping file can point at. +3. **R-OMNL-3:** If OMNL posting is **asynchronous**, the sidecar **MUST** expose **status** (pending / posted / failed) so the writer does not publish a final `accountingRef` until `posted`. + +### 5.2 Manifest writer pipeline + +1. **R-WR-1:** The writer **MUST** consume [`omnl-ledger-mapping.v1.json`](../../../../config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json) (or equivalent path) validated by `pnpm ura:validate-ledger-mapping`. +2. **R-WR-2:** Before any publish, merged output **MUST** pass `pnpm ura:validate` and `pnpm ura:validate-profiles`. +3. **R-WR-3:** Writes **SHOULD** be **idempotent**: same ledger snapshot + mapping **MUST NOT** create duplicate conflicting evidence rows (use deterministic merge; reject second publish with same `(evidencePackageId, accountingRef)` if policy forbids change). +4. **R-WR-4:** Publish path **MUST** follow one mode documented in [URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §4 (git PR, secured sync, or future authenticated API). + +### 5.3 Phoenix / runtime + +1. **R-PHX-1:** Production **SHOULD** set `SERVER_FUNDS_SIDECAR_URL` so [server-funds-sidecar-probe](../../../../phoenix-deploy-api/server.js) returns **200** when the sidecar is healthy (not only 503 unset). +2. **R-PHX-2:** After manifest update, Phoenix **MUST** serve updated JSON from `PHOENIX_REPO_ROOT` or `UNIVERSAL_RESOURCE_MANIFEST_PATH` without manual restart if your deploy model supports file watch; otherwise document reload step. + +## 6. Non-functional requirements + +| ID | Category | Requirement | +|----|----------|-------------| +| N-S-1 | Security | Fineract and sidecar credentials **MUST NOT** be stored in git; use vault / host env. | +| N-S-2 | Security | Writer service **MUST** use mutual TLS or private network to reach sidecar/OMNL where exposed beyond localhost. | +| N-O-1 | Observability | Emit structured logs: `correlationId`, `resourceId`, `evidencePackageId`, `accountingRef`, manifest git SHA or file version. | +| N-O-2 | Observability | Metric: `ura_manifest_ledger_sync_success_total`, `ura_manifest_ledger_sync_fail_total`, histogram of lag vs OMNL `postedAt`. | +| N-R-1 | Reliability | Failed merge/validate **MUST** land in DLQ or alert; **MUST NOT** partially write corrupt manifest. | + +## 7. Staging E2E acceptance (`ura-auto-08`) + +The following **MUST** pass in a non-production environment before production automation is enabled: + +1. Inject or use a real OMNL posting tied to a test sidecar operation. +2. Produce ledger snapshot JSON; run `pnpm ura:writer:ledger` → fragment. +3. Merge with `merge-manifest-fragments.mjs --out` (or production equivalent). +4. `pnpm ura:validate && pnpm ura:validate-profiles` exit 0. +5. Optional: `pnpm ura:smoke --http` against staging Phoenix shows updated `accountingRef` in served manifest. + +## 8. Optional capability annex (informative) + +Concrete REST paths for Fineract (`/journalentries`, `/savingstransactions`, etc.) **SHOULD** be recorded in a **tenant annex** (one Markdown or OpenAPI file per OMNL deployment), linked from this TS version header. + +## 9. Related + +- [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](../URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) +- [URA_PILOT_CLOSURE_RUNBOOK.md](../URA_PILOT_CLOSURE_RUNBOOK.md) §3 diff --git a/docs/04-configuration/universal-resource-activation/technical-specs/TS-SETTLEMENT-INDEXER-MANIFEST-V1.md b/docs/04-configuration/universal-resource-activation/technical-specs/TS-SETTLEMENT-INDEXER-MANIFEST-V1.md new file mode 100644 index 00000000..fcfe3a78 --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/technical-specs/TS-SETTLEMENT-INDEXER-MANIFEST-V1.md @@ -0,0 +1,95 @@ +# TS-SETTLEMENT-INDEXER-MANIFEST-V1 — Settlement / MintAuth events → URA manifest + +**Version:** 1.0.0 +**Last updated:** 2026-04-25 +**Status:** Normative for implementation (supplements [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md) for **off-chain mirror** only). +**Audience:** Chain 138 integrators, indexer operators, platform SRE. + +## 1. Purpose + +Specify how **on-chain (or ISO-gateway-derived) settlement identifiers** flow into [`settlementOrChainRef`](../../../../config/universal-resource-activation.evidence-package.v1.schema.json) on the correct evidence package rows, using the repo’s [`build-settlement-fragment.mjs`](../../../../scripts/ura/manifest-writer/build-settlement-fragment.mjs) as the **canonical string format** for v1. + +## 2. Design principle (normative) + +**Fiat finality and compliance remain off-chain** per DBIS Rail §0. This indexer **MUST NOT** infer good funds from `tx.status` alone; it **MUST** only record **authorization / settlement identifiers** already produced by the Rail / gateway. + +## 3. Scope and non-goals + +### 3.1 In scope + +- Event subscription (logs, websocket, or indexer) → deterministic `settlementOrChainRef` string. +- Reorg handling policy (minimum depth before write). +- Optional: manifest or evidence-package hash anchoring (see §8). + +### 3.2 Out of scope + +- Replacing MintAuth verification inside contracts. +- Parsing full ISO-20022 payloads on-chain. + +## 4. Normative references + +| Topic | Source | +|-------|--------| +| Event inventory | [DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md](../../../dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md) | +| Rail controls / IDs | [DBIS_RAIL_TECHNICAL_SPEC_V1.md](../../../dbis-rail/DBIS_RAIL_TECHNICAL_SPEC_V1.md) | +| Fragment CLI | [`build-settlement-fragment.mjs`](../../../../scripts/ura/manifest-writer/build-settlement-fragment.mjs) | + +## 5. `settlementOrChainRef` format (v1) + +Unless a future TS supersedes this, production automation **SHOULD** emit: + +```text +messageId=;tx=<0x-prefixed-tx-hash>;chain= +``` + +Omitted components **MAY** be dropped if not applicable; **MUST NOT** use ambiguous comma-separated free text without `key=` prefixes. + +## 6. Functional requirements + +### 6.1 Indexer + +1. **R-IX-1:** The indexer **MUST** subscribe to a **documented** contract/event set per environment (addresses in deployment annex). +2. **R-IX-2:** Before writing the manifest, the indexer **MUST** wait **N** confirmations (N **SHOULD** default to 12 on Chain 138 unless risk review says otherwise). +3. **R-IX-3:** On reorg deeper than N, the indexer **MUST** emit **alert** and **MUST NOT** silently delete manifest rows without human or policy-governed rollback ([URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §8). +4. **R-IX-4:** Each processed event **MUST** carry an **idempotency key** `(chainId, blockNumber, logIndex)` or equivalent to prevent duplicate `settlementOrChainRef` appends. + +### 6.2 Binding to evidence packages + +1. **R-BIND-1:** Configuration **MUST** map `(settlement profile | pool id | message route)` → `evidencePackageId` (YAML or JSON in secure config, not hard-coded in indexer binary). +2. **R-BIND-2:** If no mapping exists, the indexer **MUST** **fail closed** (alert, no manifest write). + +### 6.3 Validation gate + +Merged manifest **MUST** pass `pnpm ura:validate` before publish. + +## 7. Observability and security + +| ID | Requirement | +|----|-------------| +| N-IX-O-1 | Logs **MUST** include `blockNumber`, `txHash`, `evidencePackageId`, idempotency key. | +| N-IX-S-1 | RPC URLs and API keys **MUST** use secrets management. | +| N-IX-S-2 | Indexer write principal **SHOULD** be least-privilege (only manifest publish path, not chain admin). | + +## 8. Optional: evidence / manifest anchoring (`chain-opt-a`) + +If anchoring is required: + +1. Compute `sha256` (or keccak per policy) over canonical JSON of the **evidence package row** (or full manifest). +2. Publish hash via **PolicyProfileRegistry-style** pattern or dedicated anchor contract **MAY** be used; document address in deployment annex. +3. Anchoring **MUST NOT** replace manifest JSON as the operational read model for Phoenix. + +## 9. Optional: `keccak(resourceId)` (`chain-opt-b`) + +When a GRU or Rail registry facet accepts resource id hashes, use [`keccak-resource-ids.mjs`](../../../../scripts/ura/keccak-resource-ids.mjs) and document the facet’s expected encoding (UTF-8 string vs ABI-encoded). + +## 10. Acceptance criteria (staging) + +1. Deployed mock or testnet settlement emits event with known `messageId` / tx. +2. Indexer produces fragment matching §5. +3. After merge + validate, Phoenix GET manifest shows updated `settlementOrChainRef`. +4. Replay same event → no duplicate ref (idempotency). + +## 11. Related + +- [DBIS_RAIL_JURISDICTION_TRACEABILITY.md](../../../dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md) +- [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](../URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/docs/04-configuration/universal-resource-activation/technical-specs/TS-SKR-CUSTODY-ETL-MANIFEST-V1.md b/docs/04-configuration/universal-resource-activation/technical-specs/TS-SKR-CUSTODY-ETL-MANIFEST-V1.md new file mode 100644 index 00000000..69c04b99 --- /dev/null +++ b/docs/04-configuration/universal-resource-activation/technical-specs/TS-SKR-CUSTODY-ETL-MANIFEST-V1.md @@ -0,0 +1,71 @@ +# TS-SKR-CUSTODY-ETL-MANIFEST-V1 — Custody / SKR evidence → URA manifest + +**Version:** 1.0.0 +**Last updated:** 2026-04-25 +**Status:** Normative for implementation (supplements [SKR_CUSTODY_AUTOMATION_NOTES.md](../SKR_CUSTODY_AUTOMATION_NOTES.md)). +**Audience:** Custody ops, compliance engineering, integration. + +## 1. Purpose + +Define how **custodian or internal attestation outputs** become **`evidenceRefs`** and evidence-package **`custodyOrSourceEvidence`** fields without weakening jurisdiction matrix obligations ([ID-INDONESIA/banking_v1.md](../../compliance-matrices/ID-INDONESIA/banking_v1.md) or successor). + +## 2. Scope and non-goals + +### 2.1 In scope + +- Data model for custody **artifact** ingestion. +- Hashing, object storage references, and manifest field mapping. +- PII / retention constraints at integration boundary. +- Acceptance tests for Pilot 1 closure path. + +### 2.2 Out of scope + +- Legal interpretation of custody regulations (counsel-owned). +- Replacing custodian’s own audit trail. + +## 3. Definitions + +| Term | Definition | +|------|------------| +| **Artifact** | Statement file, API payload, or signed attestation representing a custody position. | +| **Fingerprint** | Cryptographic digest (SHA-256 **RECOMMENDED**) over canonical bytes of artifact. | +| **External ref** | URI or object key (e.g. `s3://…`, `https://…`) **SHOULD** be paired with fingerprint. | + +## 4. Functional requirements + +### 4.1 Ingestion + +1. **R-SKR-1:** ETL **MUST** accept artifacts only over **authenticated** channels (mTLS, signed webhook, or VPN). +2. **R-SKR-2:** Each artifact **MUST** produce `fingerprint` and **SHOULD** store `retrievedAt` (RFC 3339 UTC). +3. **R-SKR-3:** `evidenceRefs` entries **SHOULD** use **`sha256:`** or documented URI scheme agreed with audit. + +### 4.2 Manifest mapping + +1. **R-SKR-4:** Pilot 1 resource (`SKR_SAFEKEEPING`) **MUST** reference the same logical artifact in `evidenceRefs` and in the evidence package row required by [URA_PILOT_CLOSURE_RUNBOOK.md](../URA_PILOT_CLOSURE_RUNBOOK.md) §2. +2. **R-SKR-5:** Updates **MUST** be idempotent per `(resourceId, fingerprint)`. + +### 4.3 Evidence package text field + +`custodyOrSourceEvidence` **MAY** hold human-readable summary; **MUST** include fingerprint or stable id counsel approved for audit. + +## 5. Privacy and retention + +1. **N-SKR-P-1:** Personally identifiable data **MUST NOT** be copied into manifest JSON unless explicitly allowed by DPA and matrix. +2. **N-SKR-P-2:** Retention of manifest snapshots **MUST** follow institution policy; DR per [URA_MANIFEST_WRITER_OPS.md](../../../03-deployment/URA_MANIFEST_WRITER_OPS.md) §8. + +## 6. Validation + +Before production: + +1. `pnpm ura:validate` / `pnpm ura:validate-profiles` pass. +2. `pnpm ura:validate-closure:strict` passes **after** placeholders replaced per runbook. +3. Compliance sign-off recorded per [TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md](TS-COMPLIANCE-AUTOMATION-SIGNOFF-V1.md). + +## 7. Implementation note + +A dedicated `build-custody-fragment.mjs` **MAY** be added mirroring the ledger writer; until then, fragments **MAY** be hand-crafted JSON matching merge rules in [merge-manifest-fragments.mjs](../../../../scripts/ura/merge-manifest-fragments.mjs). + +## 8. Related + +- [UNIVERSAL_RESOURCE_SKR_CUSTODY_LANE.md](../UNIVERSAL_RESOURCE_SKR_CUSTODY_LANE.md) +- [UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md](../UNIVERSAL_RESOURCE_EVIDENCE_PACKAGE.md) diff --git a/docs/MASTER_INDEX.md b/docs/MASTER_INDEX.md index 05ee32a2..a2c30a00 100644 --- a/docs/MASTER_INDEX.md +++ b/docs/MASTER_INDEX.md @@ -102,7 +102,7 @@ | **00-meta** (tasks, next steps, phases) | [00-meta/NEXT_STEPS_INDEX.md](00-meta/NEXT_STEPS_INDEX.md), [00-meta/PHASES_AND_TASKS_MASTER.md](00-meta/PHASES_AND_TASKS_MASTER.md) | | **02-architecture** | [02-architecture/](02-architecture/) — **client / division terminology:** [02-architecture/CLIENT_DIVISION_TERMINOLOGY.md](02-architecture/CLIENT_DIVISION_TERMINOLOGY.md); **Public sector + Phoenix catalog baseline:** [02-architecture/PUBLIC_SECTOR_TENANCY_MARKETPLACE_AND_DEPLOYMENT_BASELINE.md](02-architecture/PUBLIC_SECTOR_TENANCY_MARKETPLACE_AND_DEPLOYMENT_BASELINE.md); **non-goals (incl. catalog vs marketing §9):** [02-architecture/NON_GOALS.md](02-architecture/NON_GOALS.md); **DeFi Oracle Meta Mainnet (Chain 138):** [dbis_chain_138_technical_master_plan.md](../dbis_chain_138_technical_master_plan.md), [02-architecture/DBIS_NODE_ROLE_MATRIX.md](02-architecture/DBIS_NODE_ROLE_MATRIX.md), [02-architecture/DBIS_PHASE2_PROXMOX_SOVEREIGNIZATION_ROADMAP.md](02-architecture/DBIS_PHASE2_PROXMOX_SOVEREIGNIZATION_ROADMAP.md) | | **03-deployment** | [03-deployment/OPERATIONAL_RUNBOOKS.md](03-deployment/OPERATIONAL_RUNBOOKS.md), [03-deployment/DEPLOYMENT_ORDER_OF_OPERATIONS.md](03-deployment/DEPLOYMENT_ORDER_OF_OPERATIONS.md), **Public sector live checklist:** [03-deployment/PUBLIC_SECTOR_LIVE_DEPLOYMENT_CHECKLIST.md](03-deployment/PUBLIC_SECTOR_LIVE_DEPLOYMENT_CHECKLIST.md), **Proxmox VE ops template:** [03-deployment/PROXMOX_VE_OPERATIONAL_DEPLOYMENT_TEMPLATE.md](03-deployment/PROXMOX_VE_OPERATIONAL_DEPLOYMENT_TEMPLATE.md) · [`config/proxmox-operational-template.json`](config/proxmox-operational-template.json); **DBIS Phase 1–3:** [03-deployment/PHASE1_DISCOVERY_RUNBOOK.md](03-deployment/PHASE1_DISCOVERY_RUNBOOK.md), [03-deployment/DBIS_PHASE3_E2E_PRODUCTION_SIMULATION_RUNBOOK.md](03-deployment/DBIS_PHASE3_E2E_PRODUCTION_SIMULATION_RUNBOOK.md), [03-deployment/CALIPER_CHAIN138_PERF_HOOK.md](03-deployment/CALIPER_CHAIN138_PERF_HOOK.md), [03-deployment/DBIS_HYPERLEDGER_RUNTIME_STATUS.md](03-deployment/DBIS_HYPERLEDGER_RUNTIME_STATUS.md), [03-deployment/DBIS_PHASES_1_TO_3_PRODUCTION_GATE.md](03-deployment/DBIS_PHASES_1_TO_3_PRODUCTION_GATE.md), **RTGS canonical production checklist and institutional-finance layers:** [03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md](03-deployment/DBIS_RTGS_E2E_REQUIREMENTS_MATRIX.md), [03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md](03-deployment/DBIS_RTGS_MASTER_PLAN_IMPLEMENTATION_TRACKER.md), [03-deployment/DBIS_RTGS_FX_TRANSACTION_CATALOG.md](03-deployment/DBIS_RTGS_FX_TRANSACTION_CATALOG.md), [03-deployment/DBIS_RTGS_DEPOSITORY_AND_CUSTODY_OPERATING_MODEL.md](03-deployment/DBIS_RTGS_DEPOSITORY_AND_CUSTODY_OPERATING_MODEL.md), [03-deployment/DBIS_RTGS_FX_AND_LIQUIDITY_OPERATING_MODEL.md](03-deployment/DBIS_RTGS_FX_AND_LIQUIDITY_OPERATING_MODEL.md), [03-deployment/DBIS_RTGS_CONTROL_PLANE_DEPLOYMENT_CHECKLIST.md](03-deployment/DBIS_RTGS_CONTROL_PLANE_DEPLOYMENT_CHECKLIST.md), [03-deployment/DBIS_RTGS_LATER_PHASE_SIDECARS_DEPLOYMENT_CHECKLIST.md](03-deployment/DBIS_RTGS_LATER_PHASE_SIDECARS_DEPLOYMENT_CHECKLIST.md), [03-deployment/DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md](03-deployment/DBIS_OMNL_INDONESIA_BNI_E2E_INTEGRATION_BLUEPRINT.md), [03-deployment/DBIS_RTGS_FIRST_SLICE_ARCHITECTURE.md](03-deployment/DBIS_RTGS_FIRST_SLICE_ARCHITECTURE.md), [03-deployment/DBIS_RTGS_FIRST_SLICE_DEPLOYMENT_CHECKLIST.md](03-deployment/DBIS_RTGS_FIRST_SLICE_DEPLOYMENT_CHECKLIST.md), [03-deployment/DBIS_HYBX_SIDECAR_BOUNDARY_MATRIX.md](03-deployment/DBIS_HYBX_SIDECAR_BOUNDARY_MATRIX.md), [03-deployment/DBIS_MOJALOOP_INTEGRATION_STATUS.md](03-deployment/DBIS_MOJALOOP_INTEGRATION_STATUS.md), [03-deployment/DBIS_HYPERLEDGER_IDENTITY_STACK_DECISION.md](03-deployment/DBIS_HYPERLEDGER_IDENTITY_STACK_DECISION.md) | -| **04-configuration** | [04-configuration/README.md](04-configuration/README.md), [04-configuration/ADDITIONAL_PATHS_AND_EXTENSIONS.md](04-configuration/ADDITIONAL_PATHS_AND_EXTENSIONS.md) (paths, registry, token-mapping, LiFi/Jumper); **Multi-jurisdiction compliance (matrices, charter, playbook):** [04-configuration/compliance-matrices/README.md](04-configuration/compliance-matrices/README.md), [04-configuration/jurisdictions/JURISDICTION_CATALOG.md](04-configuration/jurisdictions/JURISDICTION_CATALOG.md), [`config/jurisdictions/catalog.v1.json`](../config/jurisdictions/catalog.v1.json), [dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md](dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md); **Universal resource activation (SKR, server funds, infra):** [04-configuration/universal-resource-activation/README.md](04-configuration/universal-resource-activation/README.md), [UNIVERSAL_RESOURCE_WIRING.md](04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md), `pnpm ura:validate`, `pnpm ura:validate-profiles`, `pnpm ura:merge-manifest`, `pnpm ura:validate-closure` / `URA_STRICT_CLOSURE`, `pnpm ura:smoke`, `node scripts/ura/keccak-resource-ids.mjs`, Phoenix URA routes (manifest, policy-profiles, sidecar-probe), [`config/universal-resource-activation/manifest.json`](../config/universal-resource-activation/manifest.json), [`config/universal-resource-activation/policy-profiles.json`](../config/universal-resource-activation/policy-profiles.json), [manifest-fragments/README.md](../config/universal-resource-activation/manifest-fragments/README.md); **Chain 138 wallets:** [04-configuration/CHAIN138_WALLET_CONFIG_VALIDATION.md](04-configuration/CHAIN138_WALLET_CONFIG_VALIDATION.md); **Chain 2138 testnet wallets:** [04-configuration/CHAIN2138_WALLET_CONFIG_VALIDATION.md](04-configuration/CHAIN2138_WALLET_CONFIG_VALIDATION.md); **OMNL Indonesia / HYBX-BATCH-001:** [04-configuration/mifos-omnl-central-bank/HYBX_BATCH_001_OPERATOR_CHECKLIST.md](04-configuration/mifos-omnl-central-bank/HYBX_BATCH_001_OPERATOR_CHECKLIST.md), [04-configuration/mifos-omnl-central-bank/INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md](04-configuration/mifos-omnl-central-bank/INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md) | +| **04-configuration** | [04-configuration/README.md](04-configuration/README.md), [04-configuration/ADDITIONAL_PATHS_AND_EXTENSIONS.md](04-configuration/ADDITIONAL_PATHS_AND_EXTENSIONS.md) (paths, registry, token-mapping, LiFi/Jumper); **Multi-jurisdiction compliance (matrices, charter, playbook):** [04-configuration/compliance-matrices/README.md](04-configuration/compliance-matrices/README.md), [04-configuration/jurisdictions/JURISDICTION_CATALOG.md](04-configuration/jurisdictions/JURISDICTION_CATALOG.md), [`config/jurisdictions/catalog.v1.json`](../config/jurisdictions/catalog.v1.json), [dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md](dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md); **Universal resource activation (SKR, server funds, infra):** [04-configuration/universal-resource-activation/README.md](04-configuration/universal-resource-activation/README.md), [UNIVERSAL_RESOURCE_WIRING.md](04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md), [URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md](04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md), [technical-specs/README.md](04-configuration/universal-resource-activation/technical-specs/README.md) (normative TS-* for remaining implementation), [URA_MANIFEST_WRITER_OPS.md](03-deployment/URA_MANIFEST_WRITER_OPS.md), [GRU_REGISTRY_WIRING_CHECKLIST.md](runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md), `pnpm ura:*`, Phoenix URA routes, [`config/universal-resource-activation/`](../config/universal-resource-activation/); **Chain 138 wallets:** [04-configuration/CHAIN138_WALLET_CONFIG_VALIDATION.md](04-configuration/CHAIN138_WALLET_CONFIG_VALIDATION.md); **Chain 2138 testnet wallets:** [04-configuration/CHAIN2138_WALLET_CONFIG_VALIDATION.md](04-configuration/CHAIN2138_WALLET_CONFIG_VALIDATION.md); **OMNL Indonesia / HYBX-BATCH-001:** [04-configuration/mifos-omnl-central-bank/HYBX_BATCH_001_OPERATOR_CHECKLIST.md](04-configuration/mifos-omnl-central-bank/HYBX_BATCH_001_OPERATOR_CHECKLIST.md), [04-configuration/mifos-omnl-central-bank/INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md](04-configuration/mifos-omnl-central-bank/INDONESIA_PACKAGE_4_995_EVIDENCE_STANDARD.md) | | **Phoenix / Sankofa deploy handoff** | [04-configuration/PHOENIX_SANKOFA_OPERATOR_HANDOFF.md](04-configuration/PHOENIX_SANKOFA_OPERATOR_HANDOFF.md) — live CTs, env locations, secret split, rotate/reload/verify commands | | **06-besu** | [06-besu/MASTER_INDEX.md](06-besu/MASTER_INDEX.md) | | **Testnet (2138)** | [testnet/DEFI_ORACLE_META_TESTNET_2138_RUNBOOK.md](testnet/DEFI_ORACLE_META_TESTNET_2138_RUNBOOK.md), [testnet/TESTNET_DEPLOYMENT.md](testnet/TESTNET_DEPLOYMENT.md) | diff --git a/docs/dbis-rail/DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md b/docs/dbis-rail/DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md index 927880e2..fac52836 100644 --- a/docs/dbis-rail/DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md +++ b/docs/dbis-rail/DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md @@ -2,7 +2,7 @@ **Network:** DBIS Mainnet (ChainID 138) **Document type:** Control verification checklist (pre-audit) -**Companion documents:** [Technical Spec v1](DBIS_RAIL_TECHNICAL_SPEC_V1.md), [Rulebook v1](DBIS_RAIL_RULEBOOK_V1.md), [Security Threat Model v1](DBIS_RAIL_SECURITY_THREAT_MODEL_V1.md), [Regulator Brief v1](DBIS_RAIL_REGULATOR_BRIEF_V1.md) +**Companion documents:** [Technical Spec v1](DBIS_RAIL_TECHNICAL_SPEC_V1.md), [Rulebook v1](DBIS_RAIL_RULEBOOK_V1.md), [Security Threat Model v1](DBIS_RAIL_SECURITY_THREAT_MODEL_V1.md), [Regulator Brief v1](DBIS_RAIL_REGULATOR_BRIEF_V1.md), [Jurisdiction traceability](DBIS_RAIL_JURISDICTION_TRACEABILITY.md) (controls ↔ per-jurisdiction compliance matrices ↔ URA policy profiles) **Purpose:** Bridge documentation to operational evidence. Each item is verifiable (code, config, procedure, or test). Use this checklist before external audit or formal control mapping. diff --git a/docs/dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md b/docs/dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md index 261d05f2..6221c5b2 100644 --- a/docs/dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md +++ b/docs/dbis-rail/DBIS_RAIL_CONTROL_MAPPING_V1.md @@ -35,6 +35,20 @@ Section numbers refer to the respective document sections (e.g. Spec 6.5 = DBIS_ --- +## Jurisdiction matrices and policy profiles + +Obligations in **per-jurisdiction compliance matrices** map to these control IDs where the Rail is in scope. Full obligation → control → `policyProfileId` → URA field mapping lives in **[DBIS_RAIL_JURISDICTION_TRACEABILITY.md](DBIS_RAIL_JURISDICTION_TRACEABILITY.md)**. + +| Artifact | Role | +|----------|------| +| [compliance-matrices/README.md](../04-configuration/compliance-matrices/README.md) | Index of jurisdiction folders (ID, stubs, drafts). | +| [policy-profiles.json](../../config/universal-resource-activation/policy-profiles.json) | Machine-readable `policyProfileId` registry with `minimumGruGovernanceLevel`. | +| [POLICY_PROFILES_REGISTRY.md](../../config/universal-resource-activation/POLICY_PROFILES_REGISTRY.md) | Doc control and legal sign-off table for profile versions. | + +When a jurisdiction adds **local** controls (prefix e.g. `J-ID-AML-001`), document them in that jurisdiction’s matrix and extend the traceability doc; they do not replace C1–C18 for on-chain Rail behavior. + +--- + ## References - **Spec:** [DBIS_RAIL_TECHNICAL_SPEC_V1.md](DBIS_RAIL_TECHNICAL_SPEC_V1.md) diff --git a/docs/dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md b/docs/dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md new file mode 100644 index 00000000..a6460819 --- /dev/null +++ b/docs/dbis-rail/DBIS_RAIL_JURISDICTION_TRACEABILITY.md @@ -0,0 +1,42 @@ +# DBIS Rail — jurisdiction and compliance matrix traceability + +**Last updated:** 2026-04-25 +**Purpose:** Cross-link [DBIS_RAIL_CONTROL_MAPPING_V1.md](DBIS_RAIL_CONTROL_MAPPING_V1.md) controls to **jurisdiction compliance matrices** and **URA policy profiles**, so auditors can navigate: **obligation (matrix row) → Rail control → profile → evidence**. + +**Not legal advice.** Matrix obligation text must be counsel-approved per jurisdiction. + +--- + +## Rail controls → jurisdiction artifacts (starter mapping) + +| Control ID | Rail / ops intent | Example jurisdiction matrix rows | Policy profile(s) | Evidence / manifest fields | +|------------|-------------------|----------------------------------|-------------------|----------------------------| +| C1 | Mint path restricted to SettlementRouter | ID-RAIL-001 | `server_funds_treasury_v1` | `settlementOrChainRef` | +| C2 | Owner mint revoked / GRU pattern | ID-RAIL-001 | `server_funds_treasury_v1`, `institutional_custody_skr_v1` | On-chain config + evidence package | +| C3–C6 | EIP-712, replay, quorum, signers | ID-RAIL-001 | `server_funds_treasury_v1` | MintAuth / messageId | +| C7 | Signer allowlist / revocation | ID-OMNL-001, ID-SIDECAR-001 | all production profiles | Ops attestations | +| C8 | Deterministic accountingRef | ID-OMNL-001 | `server_funds_treasury_v1` | `accountingRef` | +| C9 | Evidence bundle hashed (isoHash) | ID-ISO-001, ID-SKR-001 | all | `custodyOrSourceEvidence`, ISO package | +| C10 | messageId / accountingRef / mint 1:1 | ID-RAIL-001 | `server_funds_treasury_v1` | Evidence package closure | +| C11–C15 | Router safety, caps, pause, corridor, suspension | ID-RAIL-001, ID-SIDECAR-001 | `server_funds_treasury_v1` | Rail + sidecar monitoring | +| C16 | Validator segregation | ID-RAIL-001 (infra) | `infra_capacity_ops_v1` | Ops runbooks | +| C17 | Good funds and finality | ID-OMNL-001, ID-SIDECAR-001 | `server_funds_treasury_v1` | Rulebook alignment + ledger | +| C18 | Documentation versioning | (program-wide) | registry in [policy-profiles.json](../../config/universal-resource-activation/policy-profiles.json) | Doc control tables | + +**Indonesia matrix row ids** reference [ID-INDONESIA/banking_v1.md](../04-configuration/compliance-matrices/ID-INDONESIA/banking_v1.md). + +**US-DELAWARE-CORP-STUB** is a draft second-jurisdiction exercise only ([README](../04-configuration/compliance-matrices/US-DELAWARE-CORP-STUB/README.md)); do not use its row ids in production traceability until counsel replaces the stub. + +--- + +## Audit checklist cross-reference + +When updating [DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md](DBIS_RAIL_AUDIT_READINESS_CHECKLIST_V1.md), add **jurisdiction matrix id** and **policyProfileId** to each section’s evidence appendix where a jurisdiction-specific obligation applies. + +--- + +## Related + +- [DBIS_RAIL_CONTROL_MAPPING_V1.md](DBIS_RAIL_CONTROL_MAPPING_V1.md) +- [INSTITUTION_ONBOARDING_CHARTER.md](../04-configuration/compliance-matrices/INSTITUTION_ONBOARDING_CHARTER.md) +- [URA_PILOT_CLOSURE_RUNBOOK.md](../04-configuration/universal-resource-activation/URA_PILOT_CLOSURE_RUNBOOK.md) diff --git a/docs/dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md b/docs/dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md new file mode 100644 index 00000000..3c219e58 --- /dev/null +++ b/docs/dbis-rail/DBIS_RAIL_SETTLEMENT_EVENT_SOURCES.md @@ -0,0 +1,33 @@ +# DBIS Rail — settlement event sources for URA `settlementOrChainRef` + +**Last updated:** 2026-04-25 +**Purpose:** Inventory of where **MintAuth / settlement** identifiers originate so an indexer or batch job can populate [`manifest.json`](../../config/universal-resource-activation/manifest.json) evidence fields (`settlementOrChainRef`). + +**Not exhaustive** — align field names with [`DBIS_RAIL_TECHNICAL_SPEC_V1.md`](DBIS_RAIL_TECHNICAL_SPEC_V1.md) and your deployed contracts in `smom-dbis-138`. + +## 1. On-chain (EVM) + +| Source | What to capture | Notes | +|--------|-----------------|--------| +| **Settlement / router events** | `messageId`, optional `accountingRef` echo | Subscribe via WebSocket or `eth_getLogs` with tuned filters. | +| **Transaction receipt** | `tx.hash`, `blockNumber`, `chainId` | Compose ref: `messageId=…;tx=…;chain=…` (see [`build-settlement-fragment.mjs`](../../scripts/ura/manifest-writer/build-settlement-fragment.mjs)). | +| **Indexed subgraph** | Same fields | If you run Graph Node / Ponder, expose a stable query for “last settlement for resource X”. | + +## 2. Off-chain / ISO path + +| Source | What to capture | +|--------|-----------------| +| ISO-20022 gateway / `dbis_core` | Business message id, end-to-end id, or gateway correlation id stored when mint authorized. | + +Store the chosen id in `settlementOrChainRef` and document the format in the evidence package `explanation` until a single canonical encoding is enforced. + +## 3. Wire-up checklist + +1. Pick authoritative source per environment (Chain 138 vs testnet). +2. Implement listener → call writer (`build-settlement-fragment`) → merge → validate → publish. +3. Add alert if no settlement event within SLA for an open `reconciliationStatus`. + +## Related + +- [`URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md`](../04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) +- [`DBIS_RAIL_JURISDICTION_TRACEABILITY.md`](DBIS_RAIL_JURISDICTION_TRACEABILITY.md) diff --git a/docs/runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md b/docs/runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md index 7f777c3a..8d7d494c 100644 --- a/docs/runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md +++ b/docs/runbooks/GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md @@ -106,7 +106,13 @@ Add Forge or Hardhat tests for facet upgrade and storage consistency when the sp --- -## 7. Related documents +## 7. Standalone URA policy anchor (pre–full M00) + +Before the full M00 spine is live, you can deploy **`PolicyProfileRegistry`** in `smom-dbis-138` to anchor `policyProfileId` content hashes on-chain (`pnpm ura:profile-hash` in the proxmox repo). See [GRU_REGISTRY_WIRING_CHECKLIST.md](GRU_REGISTRY_WIRING_CHECKLIST.md) §6 and `contracts/universal-resource/PolicyProfileRegistry.sol`. + +--- + +## 8. Related documents - [GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md](../04-configuration/GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md) — §1–§8, default governance level, event signatures appendix. - [GRU_M00_DIAMOND_FACET_MAP.md](../04-configuration/GRU_M00_DIAMOND_FACET_MAP.md) — Facet map, governance levels 0–5. @@ -114,3 +120,4 @@ Add Forge or Hardhat tests for facet upgrade and storage consistency when the sp - [MULTI_CHAIN_EXECUTION_DETERMINISTIC_DEPLOYMENT.md](MULTI_CHAIN_EXECUTION_DETERMINISTIC_DEPLOYMENT.md) — CREATE2 factory and salts. - [CONTRACT_DEPLOYMENT_RUNBOOK.md](../03-deployment/CONTRACT_DEPLOYMENT_RUNBOOK.md) — General deployment and env. - [gru-docs/contracts/README.md](../gru-docs/contracts/README.md) — GRC-2535 Diamond (Option B migration source). +- [GRU_REGISTRY_WIRING_CHECKLIST.md](GRU_REGISTRY_WIRING_CHECKLIST.md) — URA + GRU wiring checklist (includes PolicyProfileRegistry). diff --git a/docs/runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md b/docs/runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md new file mode 100644 index 00000000..67cac515 --- /dev/null +++ b/docs/runbooks/GRU_REGISTRY_WIRING_CHECKLIST.md @@ -0,0 +1,57 @@ +# GRU / on-chain registry wiring checklist + +**Last updated:** 2026-04-25 +**Purpose:** Operationalize URA + GRU alignment: diamond strategy, storage, facets, deployment, governance, **standalone PolicyProfileRegistry** (in `smom-dbis-138`), and optional hardening. + +**Specs:** [GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md](../04-configuration/GRU_M00_DIAMOND_INSTITUTIONAL_SPEC.md) · [GRU_M00_DIAMOND_FACET_MAP.md](../04-configuration/GRU_M00_DIAMOND_FACET_MAP.md) · [GRU_M00_DIAMOND_REVIEW_GAPS_AND_RECOMMENDATIONS.md](../04-configuration/GRU_M00_DIAMOND_REVIEW_GAPS_AND_RECOMMENDATIONS.md) · [GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md](GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md) + +## 1. Strategy (gru-01) + +- [ ] Decide **Option A** (new M00 diamond) vs **Option B** (migrate GRC-2535) per deployment runbook §3–4. +- [ ] Record decision + approvers in deployment ticket. + +## 2. Storage and governance model (gru-02) + +- [ ] Finalize GRUStorage namespaces (no collision with GRC if migrating). +- [ ] Document governance level defaults per env (dev 0, prod ≥2). + +## 3. Minimum ship facets (gru-03) + +- [ ] PolicyRouter + Compliance/Accounting gate stubs (or full implementations). +- [ ] StandardsRegistryFacet + GovernanceLevelFacet. +- [ ] TokenFactory / AssetRegistry path per spec. + +## 4. Universal asset alignment (gru-04) + +- [ ] Map `UniversalAssetRegistry` / token lists to future `assetId` — see [UNIVERSAL_RESOURCE_ONTOLOGY.md](../04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_ONTOLOGY.md) §Mapping to GRU M00. + +## 5. Deploy, verify, ops (gru-05 / gru-06) + +- [ ] Follow [GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md](GRU_M00_DIAMOND_DEPLOYMENT_RUNBOOK.md) §6 verification table. +- [ ] Multisig / Timelock on `diamondCut` and policy changes. +- [ ] Pause drill documented and executed once per quarter. + +## 6. Policy profile on-chain anchor (gru-07) — **standalone contract (shipped)** + +| Step | Command / action | +|------|------------------| +| Unit test | `cd smom-dbis-138 && FORGE_SCOPE=universal-resource bash scripts/forge/scope.sh test --match-contract PolicyProfileRegistryTest` | +| Content hash | `pnpm ura:profile-hash ` (proxmox repo root) | +| Deploy | `forge script script/universal-resource/DeployPolicyProfileRegistry.s.sol:DeployPolicyProfileRegistry --rpc-url $RPC_URL_138 --broadcast` (set `PRIVATE_KEY`, optional `POLICY_PROFILE_REGISTRY_ADMIN`) | +| Publish | Call `publishProfile(policyProfileId, contentHash, version, effectiveFrom)` with `PUBLISHER_ROLE` | + +Contract: [`smom-dbis-138/contracts/universal-resource/PolicyProfileRegistry.sol`](../../smom-dbis-138/contracts/universal-resource/PolicyProfileRegistry.sol) + +## 7. Optional (gru-opt-a) + +- [ ] Oracle or attestation bridge for off-chain evidence hashes. +- [ ] Cross-chain registry mirror addresses. + +## 8. Doc handoff (gru-08) + +- [ ] Record deployed `PolicyProfileRegistry` address in [CONTRACT_ADDRESSES_REFERENCE](../11-references/CONTRACT_ADDRESSES_REFERENCE.md) when live. +- [ ] Link from [UNIVERSAL_RESOURCE_WIRING.md](../04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) §5. + +## Related + +- [`URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md`](../04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/package.json b/package.json index 4388c64d..1bd3c938 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,17 @@ "test:basic": "cd mcp-proxmox && node test-basic-tools.js", "test:workflows": "cd mcp-proxmox && node test-workflows.js", "verify:ws-chain138": "node scripts/verify-ws-rpc-chain138.mjs", + "ura:validate": "node scripts/validate/validate-universal-resource-activation.mjs", + "ura:validate-profiles": "node scripts/validate/validate-ura-policy-profiles.mjs", + "ura:validate-closure": "node scripts/ura/validate-manifest-closure.mjs", + "ura:validate-closure:strict": "node scripts/ura/validate-manifest-closure.mjs --strict", + "ura:merge-manifest": "node scripts/ura/merge-manifest-fragments.mjs", + "ura:validate-ledger-mapping": "node scripts/validate/validate-omnl-ledger-mapping.mjs", + "ura:writer:ledger": "node scripts/ura/manifest-writer/build-ledger-fragment.mjs", + "ura:writer:settlement": "node scripts/ura/manifest-writer/build-settlement-fragment.mjs", + "ura:profile-hash": "node scripts/ura/policy-profiles-content-hash.mjs", + "ura:keccak": "node scripts/ura/keccak-resource-ids.mjs", + "ura:smoke": "bash scripts/verify/smoke-universal-resource-activation.sh", "mission-control:dev": "pnpm --filter mission-control dev", "mission-control:build": "pnpm --filter mission-control build", "mission-control:start": "pnpm --filter mission-control start", diff --git a/phoenix-deploy-api/.env.example b/phoenix-deploy-api/.env.example index 9a022606..6f671f69 100644 --- a/phoenix-deploy-api/.env.example +++ b/phoenix-deploy-api/.env.example @@ -32,8 +32,15 @@ PHOENIX_PARTNER_KEYS= # Optional: override path for GET /api/v1/public-sector/programs (else bundled copy, repo config/, or ../config/) PUBLIC_SECTOR_MANIFEST_PATH= +# Optional: URA manifest for GET /api/v1/universal-resource-activation/manifest +UNIVERSAL_RESOURCE_MANIFEST_PATH= +# Optional: URA policy profile registry for GET /api/v1/universal-resource-activation/policy-profiles +#UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH= # Optional: proxmox repo root on host (manifest = $PHOENIX_REPO_ROOT/config/public-sector-program-manifest.json) PHOENIX_REPO_ROOT=/home/intlc/projects/proxmox +# Optional: server-funds-sidecar base URL for GET /api/v1/universal-resource-activation/server-funds-sidecar-probe +#SERVER_FUNDS_SIDECAR_URL=http://192.168.x.x:8080 +#SERVER_FUNDS_SIDECAR_HEALTH_PATH=/actuator/health # Gitea "cloudflare-sync" deploy target: allow scripts/deployment/gitea-cloudflare-sync.sh to call Cloudflare (1/true) #PHOENIX_CLOUDFLARE_SYNC=0 # Optional zone for that sync: CLOUDFLARE_GITEA_SYNC_ZONE=d-bis.org diff --git a/phoenix-deploy-api/README.md b/phoenix-deploy-api/README.md index 4ed00f91..2d4a0fd2 100644 --- a/phoenix-deploy-api/README.md +++ b/phoenix-deploy-api/README.md @@ -19,9 +19,11 @@ Gitea webhook receiver and deploy endpoint for Gitea → Phoenix / Proxmox deplo | GET | /api/v1/health/summary | Aggregated health for Portal | | GET | /api/v1/public-sector/programs | Public-sector / eIDAS program manifest (JSON; **no API key**) | | GET | /api/v1/universal-resource-activation/manifest | Universal resource activation store: resources, evidence, profile refs (JSON; **no API key**) — see [docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md](../docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) | +| GET | /api/v1/universal-resource-activation/policy-profiles | URA policy profile registry: `policy-profiles.json` (JSON; **no API key**) | +| GET | /api/v1/universal-resource-activation/server-funds-sidecar-probe | Optional: proxy health check to `SERVER_FUNDS_SIDECAR_URL` (**no API key**; 503 if URL unset) | | GET | /health | Health check | -All `/api/v1/*` routes except **`GET /api/v1/public-sector/programs`** and **`GET /api/v1/universal-resource-activation/manifest`** accept optional partner API key when `PHOENIX_PARTNER_KEYS` is set (`X-API-Key` or `Authorization: Bearer `). +All `/api/v1/*` routes except **`GET /api/v1/public-sector/programs`**, **`GET /api/v1/universal-resource-activation/manifest`**, **`GET /api/v1/universal-resource-activation/policy-profiles`**, and **`GET /api/v1/universal-resource-activation/server-funds-sidecar-probe`** accept optional partner API key when `PHOENIX_PARTNER_KEYS` is set (`X-API-Key` or `Authorization: Bearer `). The same public path list is defined as `PUBLIC_V1_NO_PARTNER_KEY_PATHS` in [`server.js`](server.js) (keep in sync when adding a new unauthenticated read). ## Environment @@ -48,10 +50,13 @@ Copy `.env.example` to `.env` and set `GITEA_TOKEN` (and optionally `PHOENIX_DEP | PHOENIX_PARTNER_KEYS | | Comma-separated API keys for /api/v1/* (optional) | | PUBLIC_SECTOR_MANIFEST_PATH | | Override JSON path for `/api/v1/public-sector/programs` | | UNIVERSAL_RESOURCE_MANIFEST_PATH | | Override JSON path for `/api/v1/universal-resource-activation/manifest` (default: `config/universal-resource-activation/manifest.json` under `PHOENIX_REPO_ROOT` or `../config/…`) | +| UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH | | Override JSON path for `/api/v1/universal-resource-activation/policy-profiles` (default: `config/universal-resource-activation/policy-profiles.json` under repo root) | +| SERVER_FUNDS_SIDECAR_URL | | Base URL for `/api/v1/universal-resource-activation/server-funds-sidecar-probe` (e.g. `http://:8080`); if unset, probe returns 503 with hint | +| SERVER_FUNDS_SIDECAR_HEALTH_PATH | | Optional first path to try (e.g. `/actuator/health`); also tries `/actuator/health`, `/health`, `/api/health` | | PHOENIX_REPO_ROOT | | Proxmox repo root; loads `config/public-sector-program-manifest.json` if present | | DEPLOY_TARGETS_PATH | | Override deploy target file; default is `phoenix-deploy-api/deploy-targets.json` | -**URA smoke (proxmox repo):** `bash scripts/verify/smoke-universal-resource-activation.sh` validates the manifest with JSON Schema; add `--http` and set `PHOENIX_BASE_URL` (e.g. `http://127.0.0.1:4001`) to assert this API returns 200. See [UNIVERSAL_RESOURCE_WIRING.md](../docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) §2.1. +**URA smoke (proxmox repo):** `bash scripts/verify/smoke-universal-resource-activation.sh` validates the manifest with JSON Schema; add `--http` and set `PHOENIX_BASE_URL` to also GET `/api/v1/universal-resource-activation/manifest`, `/api/v1/universal-resource-activation/policy-profiles`, and `/api/v1/universal-resource-activation/server-funds-sidecar-probe` (503 + `configured: false` is OK if `SERVER_FUNDS_SIDECAR_URL` is unset). See [UNIVERSAL_RESOURCE_WIRING.md](../docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md) §2.1. **Program manifest:** From a full repo checkout, the file is `config/public-sector-program-manifest.json`. `scripts/install-systemd.sh` copies it next to `server.js` on `/opt/phoenix-deploy-api` so the endpoint works without a full tree. diff --git a/phoenix-deploy-api/openapi.yaml b/phoenix-deploy-api/openapi.yaml index ebed05a9..1843a346 100644 --- a/phoenix-deploy-api/openapi.yaml +++ b/phoenix-deploy-api/openapi.yaml @@ -123,6 +123,50 @@ paths: '500': { description: Invalid JSON or read error } '503': { description: Manifest file not found } + /api/v1/universal-resource-activation/policy-profiles: + get: + tags: [UniversalResource] + summary: URA policy profile registry (JSON) + description: | + Serves `config/universal-resource-activation/policy-profiles.json` (machine-readable profiles + GRU levels). + Override with `UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH`. No API key required. Returns 503 if the file is missing. + responses: + '200': + description: Policy profile registry JSON + content: + application/json: + schema: + type: object + properties: + schemaVersion: { type: string } + updatedAt: { type: string } + profiles: { type: array, items: { type: object } } + '500': { description: Invalid JSON or read error } + '503': { description: Registry file not found } + + /api/v1/universal-resource-activation/server-funds-sidecar-probe: + get: + tags: [UniversalResource] + summary: Optional health probe to server-funds-sidecar + description: | + If `SERVER_FUNDS_SIDECAR_URL` is set, tries `/actuator/health`, `/health`, `/api/health` (or `SERVER_FUNDS_SIDECAR_HEALTH_PATH`). + No API key. Returns 503 with hint when the env var is unset; 200 when a path returns 2xx with JSON or body. + responses: + '200': + description: Sidecar responded 2xx on a candidate path + content: + application/json: + schema: + type: object + properties: + configured: { type: boolean } + baseUrl: { type: string } + healthPath: { type: string } + status: { type: integer } + '500': { description: Server error when handling the probe } + '502': { description: All candidate paths failed or non-2xx } + '503': { description: SERVER_FUNDS_SIDECAR_URL not set } + /api/v1/infra/nodes: get: tags: [Infra] diff --git a/phoenix-deploy-api/server.js b/phoenix-deploy-api/server.js index e70ca29b..71dc2e94 100644 --- a/phoenix-deploy-api/server.js +++ b/phoenix-deploy-api/server.js @@ -11,6 +11,8 @@ * GET /api/v1/ve/vms/:node/:vmid/status — VM/CT status * GET /api/v1/public-sector/programs — Public-sector / eIDAS program manifest (JSON) * GET /api/v1/universal-resource-activation/manifest — Universal resource activation manifest (JSON; no secret) + * GET /api/v1/universal-resource-activation/policy-profiles — URA policy profile registry JSON (no secret) + * GET /api/v1/universal-resource-activation/server-funds-sidecar-probe — Optional health proxy to server-funds-sidecar (no secret; 503 if URL unset) * GET /health — Health check * * Env: PORT, GITEA_URL, GITEA_TOKEN, PHOENIX_DEPLOY_SECRET @@ -47,6 +49,18 @@ const PROXMOX_TOKEN_NAME = process.env.PROXMOX_TOKEN_NAME || ''; const PROXMOX_TOKEN_VALUE = process.env.PROXMOX_TOKEN_VALUE || ''; const hasProxmox = PROXMOX_HOST && PROXMOX_TOKEN_NAME && PROXMOX_TOKEN_VALUE; const VE_LIFECYCLE_ENABLED = process.env.PHOENIX_VE_LIFECYCLE_ENABLED === '1' || process.env.PHOENIX_VE_LIFECYCLE_ENABLED === 'true'; +const SERVER_FUNDS_SIDECAR_URL = (process.env.SERVER_FUNDS_SIDECAR_URL || '').trim(); + +/** + * GET paths that skip partner API key — each route must be registered *before* `app.use('/api/v1', partnerKeyMiddleware)`. + * Keep in sync with docs (AGENTS, phoenix-deploy-api README, OpenAPI) when adding a new public /api/v1 read. + */ +const PUBLIC_V1_NO_PARTNER_KEY_PATHS = [ + '/api/v1/public-sector/programs', + '/api/v1/universal-resource-activation/manifest', + '/api/v1/universal-resource-activation/policy-profiles', + '/api/v1/universal-resource-activation/server-funds-sidecar-probe', +]; const PROMETHEUS_URL = (process.env.PROMETHEUS_URL || 'http://localhost:9090').replace(/\/$/, ''); const PHOENIX_WEBHOOK_URL = process.env.PHOENIX_WEBHOOK_URL || ''; @@ -101,6 +115,23 @@ function resolveUniversalResourceManifestPath() { return path.join(__dirname, '..', 'config', 'universal-resource-activation', 'manifest.json'); } +/** + * URA policy profile registry (policy-profiles.json). + * 1) UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH + * 2) PHOENIX_REPO_ROOT / PROXMOX_REPO_PATH + config/universal-resource-activation/policy-profiles.json + * 3) ../config/... + */ +function resolveUniversalResourcePolicyProfilesPath() { + const override = (process.env.UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH || '').trim(); + if (override && existsSync(override)) return override; + const repoRoot = (process.env.PHOENIX_REPO_ROOT || process.env.PROXMOX_REPO_PATH || '').trim().replace(/\/$/, ''); + if (repoRoot) { + const fromRepo = path.join(repoRoot, 'config', 'universal-resource-activation', 'policy-profiles.json'); + if (existsSync(fromRepo)) return fromRepo; + } + return path.join(__dirname, '..', 'config', 'universal-resource-activation', 'policy-profiles.json'); +} + function resolveDeployTargetsPath() { const override = (process.env.DEPLOY_TARGETS_PATH || '').trim(); if (override && existsSync(override)) return override; @@ -711,6 +742,89 @@ app.get('/api/v1/universal-resource-activation/manifest', (req, res) => { } }); +/** + * GET /api/v1/universal-resource-activation/policy-profiles — URA policy profile registry (JSON; no secret). + */ +app.get('/api/v1/universal-resource-activation/policy-profiles', (req, res) => { + const registryPath = resolveUniversalResourcePolicyProfilesPath(); + try { + if (!existsSync(registryPath)) { + return res.status(503).json({ + error: 'Policy profile registry not found', + path: registryPath, + hint: 'Set UNIVERSAL_RESOURCE_POLICY_PROFILES_PATH or deploy with config/universal-resource-activation/policy-profiles.json under PHOENIX_REPO_ROOT', + }); + } + const raw = readFileSync(registryPath, 'utf8'); + const data = JSON.parse(raw); + res.type('application/json').json(data); + } catch (err) { + res.status(500).json({ error: err.message, path: registryPath }); + } +}); + +/** + * GET /api/v1/universal-resource-activation/server-funds-sidecar-probe — forward probe to server-funds-sidecar when SERVER_FUNDS_SIDECAR_URL is set. + * No API key. Returns 503 with hint when unset (operator LAN / VM path per pilot plan). + */ +app.get('/api/v1/universal-resource-activation/server-funds-sidecar-probe', async (req, res) => { + if (!SERVER_FUNDS_SIDECAR_URL) { + return res.status(503).json({ + configured: false, + error: 'SERVER_FUNDS_SIDECAR_URL not set', + hint: 'Set to base URL (e.g. http://:8080) to probe /actuator/health or /health. See UNIVERSAL_RESOURCE_WIRING.md and UNIVERSAL_RESOURCE_SERVER_FUNDS_LANE.md.', + }); + } + const base = SERVER_FUNDS_SIDECAR_URL.replace(/\/$/, ''); + const extra = (process.env.SERVER_FUNDS_SIDECAR_HEALTH_PATH || '').trim(); + const candidates = []; + if (extra) candidates.push(extra.startsWith('/') ? extra : `/${extra}`); + for (const p of ['/actuator/health', '/health', '/api/health']) { + if (!candidates.includes(p)) candidates.push(p); + } + const attempts = []; + for (const p of candidates) { + if (!p.startsWith('/')) continue; + const url = `${base}${p}`; + const controller = new AbortController(); + const t = setTimeout(() => controller.abort(), 8000); + try { + const r = await fetch(url, { + signal: controller.signal, + headers: { Accept: 'application/json, text/plain, */*' }, + }); + const text = await r.text(); + let body; + try { + body = JSON.parse(text); + } catch { + body = { raw: text.length > 4000 ? `${text.slice(0, 4000)}…` : text }; + } + if (r.ok) { + clearTimeout(t); + return res.json({ + configured: true, + baseUrl: base, + healthPath: p, + status: r.status, + body, + }); + } + attempts.push({ path: p, status: r.status }); + } catch (err) { + attempts.push({ path: p, error: err.message || String(err) }); + } finally { + clearTimeout(t); + } + } + return res.status(502).json({ + configured: true, + baseUrl: base, + error: 'All server-funds-sidecar health paths failed or returned non-2xx', + attempts, + }); +}); + app.use('/api/v1', partnerKeyMiddleware); /** @@ -937,12 +1051,17 @@ app.listen(PORT, () => { if (PHOENIX_WEBHOOK_URL) console.log('Outbound webhook enabled:', PHOENIX_WEBHOOK_URL); if (WEBHOOK_DEPLOY_ENABLED) console.log('Inbound webhook deploy execution enabled'); if (PARTNER_KEYS.length > 0) { - console.log('Partner API key auth enabled for /api/v1/* (except GET /api/v1/public-sector/programs and GET /api/v1/universal-resource-activation/manifest)'); + console.log('Partner API key auth: /api/v1/* except', PUBLIC_V1_NO_PARTNER_KEY_PATHS.join(', ')); } const mpath = resolvePublicSectorManifestPath(); const urapath = resolveUniversalResourceManifestPath(); + const uraprof = resolveUniversalResourcePolicyProfilesPath(); const dpath = resolveDeployTargetsPath(); console.log(`Public-sector manifest: ${mpath} (${existsSync(mpath) ? 'ok' : 'missing'})`); console.log(`URA manifest: ${urapath} (${existsSync(urapath) ? 'ok' : 'missing'})`); + console.log(`URA policy-profiles: ${uraprof} (${existsSync(uraprof) ? 'ok' : 'missing'})`); + if (SERVER_FUNDS_SIDECAR_URL) { + console.log('Server-funds sidecar probe target:', SERVER_FUNDS_SIDECAR_URL); + } console.log(`Deploy targets: ${dpath} (${existsSync(dpath) ? 'ok' : 'missing'})`); }); diff --git a/scripts/README.md b/scripts/README.md index a1acd1b0..3c0bbc1e 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -204,7 +204,7 @@ CT 2301 (besu-rpc-private-1) may fail to start with `lxc.hook.pre-start` due to - **Daily/weekly checks:** `./scripts/maintenance/daily-weekly-checks.sh [daily|weekly|all]` — explorer sync (135), RPC health (136), config API (137). **Cron:** `./scripts/maintenance/schedule-daily-weekly-cron.sh [--install|--show]` (daily 08:00, weekly Sun 09:00). See [OPERATIONAL_RUNBOOKS.md](../docs/03-deployment/OPERATIONAL_RUNBOOKS.md) § Maintenance. - **Start firefly-ali-1 (6201):** `./scripts/maintenance/start-firefly-6201.sh [--dry-run] [--host HOST]` — start CT 6201 on r630-02 when needed (optional ongoing). -- **Config validation (pre-deploy):** `./scripts/validation/validate-config-files.sh` — set `VALIDATE_REQUIRED_FILES` for required paths. **CI / all validation:** `./scripts/verify/run-all-validation.sh [--skip-genesis] [--json-out reports/status/run-all-validation-latest.json]` — dependencies, config files, **cW\* mesh matrix** (merge of `cross-chain-pmm-lps/config/deployment-status.json` and `reports/extraction/promod-uniswap-v2-live-pair-discovery-latest.json` when that file exists; no RPC), optional genesis (no LAN/SSH). **Matrix only:** `./scripts/verify/build-cw-mesh-deployment-matrix.sh` — stdout markdown; `--json-out reports/status/cw-mesh-deployment-matrix-latest.json` for machine-readable rows. **URA (universal resource activation) smoke:** `./scripts/verify/smoke-universal-resource-activation.sh` (JSON Schema only) or the same with `--http` and optional `PHOENIX_BASE_URL` to assert Phoenix `GET /api/v1/universal-resource-activation/manifest`; see `docs/04-configuration/universal-resource-activation/UNIVERSAL_RESOURCE_WIRING.md` §2.1. +- **Config validation (pre-deploy):** `./scripts/validation/validate-config-files.sh` — set `VALIDATE_REQUIRED_FILES` for required paths. **CI / all validation:** `./scripts/verify/run-all-validation.sh [--skip-genesis] [--json-out reports/status/run-all-validation-latest.json]` — dependencies, config files, **cW\* mesh matrix** (merge of `cross-chain-pmm-lps/config/deployment-status.json` and `reports/extraction/promod-uniswap-v2-live-pair-discovery-latest.json` when that file exists; no RPC), optional genesis (no LAN/SSH). **Matrix only:** `./scripts/verify/build-cw-mesh-deployment-matrix.sh` — stdout markdown; `--json-out reports/status/cw-mesh-deployment-matrix-latest.json` for machine-readable rows. **URA (universal resource activation):** **`pnpm ura:validate`**, **`pnpm ura:validate-profiles`**, **`pnpm ura:merge-manifest`**, **`pnpm ura:validate-ledger-mapping`**, **`pnpm ura:writer:ledger`**, **`pnpm ura:writer:settlement`**, **`pnpm ura:profile-hash`**, **`pnpm ura:validate-closure`** / **`pnpm ura:validate-closure:strict`**, **`pnpm ura:keccak`**, **`pnpm ura:smoke`**. Optional **`URA_STRICT_CLOSURE=1`**. Tracker: `docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md`. See `UNIVERSAL_RESOURCE_WIRING.md` §2.1 and §5; multi-jurisdiction: `docs/04-configuration/compliance-matrices/README.md`. - **Wrapper summaries:** `./scripts/run-completable-tasks-from-anywhere.sh --json-out reports/status/run-completable-tasks-latest.json`, `./scripts/run-e2e-flow-tasks-full-parallel.sh --json-out reports/status/run-e2e-flow-tasks-latest.json`, `./scripts/deployment/run-all-next-steps-chain138.sh --json-out reports/status/run-all-next-steps-chain138-latest.json`, and `./scripts/run-all-operator-tasks-from-lan.sh --json-out reports/status/run-all-operator-tasks-latest.json` produce machine-readable step summaries that match the terminal progress output. ### 13. Phase 2, 3 & 4 Deployment Scripts diff --git a/scripts/ura/keccak-resource-ids.mjs b/scripts/ura/keccak-resource-ids.mjs new file mode 100755 index 00000000..bbea4cec --- /dev/null +++ b/scripts/ura/keccak-resource-ids.mjs @@ -0,0 +1,38 @@ +#!/usr/bin/env node +/** + * Emit keccak256(utf8(resourceId)) for each row in the URA manifest. + * Use when anchoring resourceId in on-chain / GRU registries (operator step; not automatic mirroring). + * + * Usage: from repo root — node scripts/ura/keccak-resource-ids.mjs + * Requires: root devDependency `ethers` (v6). + */ +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { keccak256, toUtf8Bytes } from 'ethers'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.join(__dirname, '../..'); +const manifestPath = path.join(projectRoot, 'config', 'universal-resource-activation', 'manifest.json'); + +if (!existsSync(manifestPath)) { + console.error(`[keccak-ura] Missing ${manifestPath}`); + process.exit(1); +} + +const m = JSON.parse(readFileSync(manifestPath, 'utf8')); +const resources = m.resources || []; + +console.log( + '# keccak256(utf8(resourceId)) for universal-resource-activation resources\n# Use for optional on-chain / GRU registry rows; keep manifest as canonical off-chain store.\n', +); + +for (const r of resources) { + const id = r.resourceId; + if (typeof id !== 'string' || !id) continue; + const h = keccak256(toUtf8Bytes(id)); + console.log(id); + console.log(` ${h}`); + console.log(''); +} +console.log(`[keccak-ura] ${resources.length} resource(s)`); diff --git a/scripts/ura/lib/validate-ura-manifest.mjs b/scripts/ura/lib/validate-ura-manifest.mjs new file mode 100644 index 00000000..03c57263 --- /dev/null +++ b/scripts/ura/lib/validate-ura-manifest.mjs @@ -0,0 +1,134 @@ +#!/usr/bin/env node +/** + * Shared URA manifest validation (schemas + cross-checks). + * Used by validate-universal-resource-activation.mjs and merge-manifest-fragments.mjs. + */ +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import Ajv from 'ajv'; +import addFormats from 'ajv-formats'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export function getProjectRoot() { + return path.resolve(path.join(__dirname, '..', '..', '..')); +} + +export function getDefaultManifestPath(projectRoot = getProjectRoot()) { + return path.join(projectRoot, 'config', 'universal-resource-activation', 'manifest.json'); +} + +/** + * @returns {{ validateManifest: import('ajv').ValidateFunction, validateResource: import('ajv').ValidateFunction, validateEvidence: import('ajv').ValidateFunction, ajv: import('ajv').default }} + */ +export function loadUraManifestValidators(projectRoot = getProjectRoot()) { + const manifestSchemaPath = path.join(projectRoot, 'config', 'universal-resource-activation.manifest.v1.schema.json'); + const resourceSchemaPath = path.join(projectRoot, 'config', 'universal-resource-activation.resource.v1.schema.json'); + const evidenceSchemaPath = path.join(projectRoot, 'config', 'universal-resource-activation.evidence-package.v1.schema.json'); + + const ajv = new Ajv({ + allErrors: true, + strict: false, + validateSchema: false, + }); + addFormats(ajv); + + const manifestSchema = JSON.parse(readFileSync(manifestSchemaPath, 'utf8')); + const resourceSchema = JSON.parse(readFileSync(resourceSchemaPath, 'utf8')); + const evidenceSchema = JSON.parse(readFileSync(evidenceSchemaPath, 'utf8')); + + return { + validateManifest: ajv.compile(manifestSchema), + validateResource: ajv.compile(resourceSchema), + validateEvidence: ajv.compile(evidenceSchema), + ajv, + }; +} + +/** + * @param {unknown} data + * @param {{ validateManifest: import('ajv').ValidateFunction, validateResource: import('ajv').ValidateFunction, validateEvidence: import('ajv').ValidateFunction }} validators + * @returns {string[]} empty if valid + */ +export function validateUraManifestData(data, validators) { + const errors = []; + const { validateManifest, validateResource, validateEvidence, ajv } = validators; + + if (!validateManifest(data)) { + return [`Manifest failed manifest schema: ${ajv.errorsText(validateManifest.errors, { separator: '\n' })}`]; + } + + if (!Array.isArray(data.resources)) { + return ['resources must be an array']; + } + if (!Array.isArray(data.evidencePackages)) { + return ['evidencePackages must be an array']; + } + + data.resources.forEach((r, i) => { + if (!validateResource(r)) { + errors.push( + `resources[${i}] (resourceId=${r?.resourceId}): ${ajv.errorsText(validateResource.errors, { separator: '\n' })}` + ); + } + }); + + data.evidencePackages.forEach((p, i) => { + if (!validateEvidence(p)) { + errors.push( + `evidencePackages[${i}] (id=${p?.evidencePackageId}): ${ajv.errorsText(validateEvidence.errors, { separator: '\n' })}` + ); + } + }); + + if (errors.length) return errors; + + const ids = new Set(data.resources.map((r) => r.resourceId).filter(Boolean)); + data.evidencePackages.forEach((p, pi) => { + (p.resourceIds || []).forEach((rid) => { + if (!ids.has(rid)) { + errors.push(`evidencePackages[${pi}] references unknown resourceId: ${rid}`); + } + }); + }); + + return errors; +} + +/** + * CLI-style: read file, validate, log, exit 0 or 1. + * @param {string} [manifestPath] + */ +export function validateUraManifestFileCli(manifestPath) { + const projectRoot = getProjectRoot(); + const pathToUse = manifestPath || getDefaultManifestPath(projectRoot); + + function fail(msg) { + console.error(`[validate-ura] ${msg}`); + process.exit(1); + } + + if (!existsSync(pathToUse)) { + fail(`Missing ${pathToUse}`); + } + + let data; + try { + data = JSON.parse(readFileSync(pathToUse, 'utf8')); + } catch (e) { + fail(`Invalid JSON: ${e.message}`); + } + + const validators = loadUraManifestValidators(projectRoot); + const errs = validateUraManifestData(data, validators); + if (errs.length) { + errs.forEach((e) => console.error(`[validate-ura] ${e}`)); + process.exit(1); + } + + console.log( + `[validate-ura] OK: ${data.resources.length} resource(s), ${data.evidencePackages.length} evidence package(s)` + ); + process.exit(0); +} diff --git a/scripts/ura/manifest-writer/README.md b/scripts/ura/manifest-writer/README.md new file mode 100644 index 00000000..eeb7b0be --- /dev/null +++ b/scripts/ura/manifest-writer/README.md @@ -0,0 +1,36 @@ +# URA manifest writer (ledger + settlement fragments) + +**Purpose:** Build **partial manifest fragments** from machine-readable inputs so ops or a batch job can merge them (`pnpm ura:merge-manifest` or manual paste) after validation. + +## Ledger → `accountingRef` + +1. Define mapping: [`omnl-ledger-mapping.v1.example.json`](../../../config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json) → copy to `omnl-ledger-mapping.v1.json` (gitignored or secured). +2. Export ledger snapshot JSON (Fineract/OMNL/sidecar ETL). +3. Run: + +```bash +pnpm ura:writer:ledger -- \ + --mapping config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json \ + --ledger config/universal-resource-activation/integration/examples/ledger-snapshot.example.json +``` + +4. Pipe output into a file under `manifest-fragments/` or merge with `merge-manifest-fragments.mjs --out`. + +Validate mapping: `pnpm ura:validate-ledger-mapping -- config/.../omnl-ledger-mapping.v1.example.json` + +## Rail / chain → `settlementOrChainRef` + +```bash +pnpm ura:writer:settlement -- \ + --evidence-package-id ura:pilot:evidence-register-bootstrap \ + --message-id 0xabc \ + --tx-hash 0xdef \ + --chain-id 138 +``` + +Emits a fragment with a single `evidencePackages[]` row (shallow merge by id). + +## Related + +- [`URA_MANIFEST_WRITER_OPS.md`](../../../docs/03-deployment/URA_MANIFEST_WRITER_OPS.md) +- [`URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md`](../../../docs/04-configuration/universal-resource-activation/URA_MANIFEST_AUTOMATION_IMPLEMENTATION_TRACKER.md) diff --git a/scripts/ura/manifest-writer/build-ledger-fragment.mjs b/scripts/ura/manifest-writer/build-ledger-fragment.mjs new file mode 100644 index 00000000..826e36b9 --- /dev/null +++ b/scripts/ura/manifest-writer/build-ledger-fragment.mjs @@ -0,0 +1,71 @@ +#!/usr/bin/env node +/** + * Build a manifest fragment from a ledger snapshot JSON + omnl-ledger-mapping.v1.json + * See scripts/ura/manifest-writer/README.md + */ +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { getByPath, asString } from './lib/get-by-path.mjs'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.join(__dirname, '..', '..', '..'); + +function parseArgs() { + const a = process.argv.slice(2); + const o = {}; + for (let i = 0; i < a.length; i++) { + if (a[i] === '--mapping') o.mapping = a[++i]; + else if (a[i] === '--ledger') o.ledger = a[++i]; + } + return o; +} + +const args = parseArgs(); +const mappingPath = path.resolve(projectRoot, args.mapping || 'config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json'); +const ledgerPath = path.resolve( + projectRoot, + args.ledger || 'config/universal-resource-activation/integration/examples/ledger-snapshot.example.json' +); + +for (const p of [mappingPath, ledgerPath]) { + if (!existsSync(p)) { + console.error(`[writer-ledger] Missing file: ${p}`); + process.exit(1); + } +} + +let mapping; +let ledger; +try { + mapping = JSON.parse(readFileSync(mappingPath, 'utf8')); + ledger = JSON.parse(readFileSync(ledgerPath, 'utf8')); +} catch (e) { + console.error(`[writer-ledger] JSON error: ${e.message}`); + process.exit(1); +} + +const evidencePackages = []; +for (const row of mapping.evidencePackages || []) { + const pkg = { evidencePackageId: row.evidencePackageId }; + if (row.accountingRefField) { + const v = getByPath(ledger, row.accountingRefField); + pkg.accountingRef = asString(v); + } + evidencePackages.push(pkg); +} + +const resources = []; +for (const ru of mapping.resourceUpdates || []) { + const v = getByPath(ledger, ru.quantityField); + resources.push({ + resourceId: ru.resourceId, + quantity: asString(v), + }); +} + +const fragment = {}; +if (evidencePackages.length) fragment.evidencePackages = evidencePackages; +if (resources.length) fragment.resources = resources; + +process.stdout.write(`${JSON.stringify(fragment, null, 2)}\n`); diff --git a/scripts/ura/manifest-writer/build-settlement-fragment.mjs b/scripts/ura/manifest-writer/build-settlement-fragment.mjs new file mode 100644 index 00000000..4a2c07c8 --- /dev/null +++ b/scripts/ura/manifest-writer/build-settlement-fragment.mjs @@ -0,0 +1,38 @@ +#!/usr/bin/env node +/** + * Build a manifest fragment with settlementOrChainRef on an evidence package. + */ +function parseArgs() { + const a = process.argv.slice(2); + const o = {}; + for (let i = 0; i < a.length; i++) { + if (a[i] === '--evidence-package-id') o.evidencePackageId = a[++i]; + else if (a[i] === '--message-id') o.messageId = a[++i]; + else if (a[i] === '--tx-hash') o.txHash = a[++i]; + else if (a[i] === '--chain-id') o.chainId = a[++i]; + } + return o; +} + +const args = parseArgs(); +if (!args.evidencePackageId) { + console.error('[writer-settlement] Required: --evidence-package-id'); + process.exit(1); +} + +const parts = []; +if (args.messageId) parts.push(`messageId=${args.messageId}`); +if (args.txHash) parts.push(`tx=${args.txHash}`); +if (args.chainId) parts.push(`chain=${args.chainId}`); +const settlementOrChainRef = parts.length ? parts.join(';') : ''; + +const fragment = { + evidencePackages: [ + { + evidencePackageId: args.evidencePackageId, + settlementOrChainRef, + }, + ], +}; + +process.stdout.write(`${JSON.stringify(fragment, null, 2)}\n`); diff --git a/scripts/ura/manifest-writer/lib/get-by-path.mjs b/scripts/ura/manifest-writer/lib/get-by-path.mjs new file mode 100644 index 00000000..e478c3b0 --- /dev/null +++ b/scripts/ura/manifest-writer/lib/get-by-path.mjs @@ -0,0 +1,25 @@ +/** + * @param {Record} obj + * @param {string} dotPath e.g. "a.b.c" + * @returns {unknown} + */ +export function getByPath(obj, dotPath) { + if (!dotPath || typeof dotPath !== 'string') return undefined; + const parts = dotPath.split('.').filter(Boolean); + let cur = obj; + for (const p of parts) { + if (cur == null || typeof cur !== 'object') return undefined; + cur = /** @type {Record} */ (cur)[p]; + } + return cur; +} + +/** + * @param {unknown} v + * @returns {string} + */ +export function asString(v) { + if (v == null) return ''; + if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') return String(v); + return JSON.stringify(v); +} diff --git a/scripts/ura/merge-manifest-fragments.mjs b/scripts/ura/merge-manifest-fragments.mjs new file mode 100644 index 00000000..3a35d957 --- /dev/null +++ b/scripts/ura/merge-manifest-fragments.mjs @@ -0,0 +1,162 @@ +#!/usr/bin/env node +/** + * Merge optional JSON fragments into the URA manifest and validate (dry-run or --out). + * + * Fragments: partial objects with optional keys resources[], evidencePackages[], policyProfileRefs[]. + * Later files in sort order override same resourceId / evidencePackageId. + * + * Usage (repo root): + * node scripts/ura/merge-manifest-fragments.mjs + * node scripts/ura/merge-manifest-fragments.mjs --out /tmp/merged-manifest.json + * node scripts/ura/merge-manifest-fragments.mjs --base config/universal-resource-activation/manifest.json --fragments-dir config/universal-resource-activation/manifest-fragments + */ +import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs'; +import path from 'path'; +import { + getProjectRoot, + getDefaultManifestPath, + loadUraManifestValidators, + validateUraManifestData, +} from './lib/validate-ura-manifest.mjs'; + +function parseArgs() { + const argv = process.argv.slice(2); + const out = {}; + for (let i = 0; i < argv.length; i++) { + const a = argv[i]; + if (a === '--out') out.out = argv[++i]; + else if (a === '--base') out.base = argv[++i]; + else if (a === '--fragments-dir') out.fragmentsDir = argv[++i]; + } + return out; +} + +function deepClone(o) { + return JSON.parse(JSON.stringify(o)); +} + +function profileKey(ref) { + if (!ref || typeof ref.id !== 'string') return null; + const v = ref.version != null ? String(ref.version) : ''; + return `${ref.id}@${v}`; +} + +function mergeFragment(base, frag, fragmentLabel) { + const issues = []; + + if (frag.policyProfileRefs && Array.isArray(frag.policyProfileRefs)) { + const map = new Map(); + (base.policyProfileRefs || []).forEach((r) => { + const k = profileKey(r); + if (k) map.set(k, r); + }); + frag.policyProfileRefs.forEach((r) => { + const k = profileKey(r); + if (k) map.set(k, r); + }); + base.policyProfileRefs = [...map.values()].sort((a, b) => { + const ka = profileKey(a); + const kb = profileKey(b); + return ka.localeCompare(kb); + }); + } + + if (frag.resources && Array.isArray(frag.resources)) { + const byId = new Map((base.resources || []).map((r) => [r.resourceId, r])); + frag.resources.forEach((r) => { + if (!r || typeof r.resourceId !== 'string') { + issues.push(`${fragmentLabel}: skip resource without resourceId`); + return; + } + issues.push( + `${fragmentLabel}: ${byId.has(r.resourceId) ? 'replace' : 'add'} resource ${r.resourceId}` + ); + byId.set(r.resourceId, { ...(byId.get(r.resourceId) || {}), ...r }); + }); + base.resources = [...byId.values()].sort((a, b) => String(a.resourceId).localeCompare(String(b.resourceId))); + } + + if (frag.evidencePackages && Array.isArray(frag.evidencePackages)) { + const byId = new Map((base.evidencePackages || []).map((p) => [p.evidencePackageId, p])); + frag.evidencePackages.forEach((p) => { + if (!p || typeof p.evidencePackageId !== 'string') { + issues.push(`${fragmentLabel}: skip evidence package without evidencePackageId`); + return; + } + issues.push( + `${fragmentLabel}: ${byId.has(p.evidencePackageId) ? 'replace' : 'add'} evidencePackage ${p.evidencePackageId}` + ); + const prev = byId.get(p.evidencePackageId) || {}; + byId.set(p.evidencePackageId, { ...prev, ...p }); + }); + base.evidencePackages = [...byId.values()].sort((a, b) => + String(a.evidencePackageId).localeCompare(String(b.evidencePackageId)) + ); + } + + return issues; +} + +function main() { + const args = parseArgs(); + const projectRoot = getProjectRoot(); + const basePath = path.resolve(projectRoot, args.base || getDefaultManifestPath(projectRoot)); + const fragmentsDir = path.resolve( + projectRoot, + args.fragmentsDir || path.join('config', 'universal-resource-activation', 'manifest-fragments') + ); + + if (!existsSync(basePath)) { + console.error(`[merge-ura-manifest] Missing base: ${basePath}`); + process.exit(1); + } + + let merged; + try { + merged = JSON.parse(readFileSync(basePath, 'utf8')); + } catch (e) { + console.error(`[merge-ura-manifest] Invalid base JSON: ${e.message}`); + process.exit(1); + } + + const mergeNotes = []; + if (existsSync(fragmentsDir)) { + const files = readdirSync(fragmentsDir) + .filter((f) => f.endsWith('.json') && !f.startsWith('_')) + .sort(); + for (const f of files) { + const fp = path.join(fragmentsDir, f); + let frag; + try { + frag = JSON.parse(readFileSync(fp, 'utf8')); + } catch (e) { + console.error(`[merge-ura-manifest] Invalid JSON in ${fp}: ${e.message}`); + process.exit(1); + } + mergeNotes.push(...mergeFragment(merged, frag, f)); + } + } + + const validators = loadUraManifestValidators(projectRoot); + const errs = validateUraManifestData(merged, validators); + if (errs.length) { + errs.forEach((e) => console.error(`[merge-ura-manifest] ${e}`)); + process.exit(1); + } + + mergeNotes.forEach((n) => console.log(`[merge-ura-manifest] ${n}`)); + console.log( + `[merge-ura-manifest] OK: ${merged.resources.length} resource(s), ${merged.evidencePackages.length} evidence package(s)` + ); + + if (args.out) { + writeFileSync(path.resolve(args.out), `${JSON.stringify(merged, null, 2)}\n`, 'utf8'); + console.log(`[merge-ura-manifest] Wrote ${path.resolve(args.out)}`); + } else { + console.log('[merge-ura-manifest] Dry-run (pass --out to write merged JSON)'); + } + + process.exit(0); +} + +main(); diff --git a/scripts/ura/policy-profiles-content-hash.mjs b/scripts/ura/policy-profiles-content-hash.mjs new file mode 100644 index 00000000..9266a769 --- /dev/null +++ b/scripts/ura/policy-profiles-content-hash.mjs @@ -0,0 +1,46 @@ +#!/usr/bin/env node +/** + * Compute a content hash for one policy profile row (for PolicyProfileRegistry.publishProfile on-chain). + * Uses keccak256(utf8(canonicalJson)) where canonicalJson is stable key-sorted JSON of the profile object. + * + * Usage: node scripts/ura/policy-profiles-content-hash.mjs + */ +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { keccak256, toUtf8Bytes } from 'ethers'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.join(__dirname, '..', '..'); +const registryPath = path.join(projectRoot, 'config/universal-resource-activation/policy-profiles.json'); + +const id = process.argv[2]; +if (!id) { + console.error('Usage: node scripts/ura/policy-profiles-content-hash.mjs '); + process.exit(1); +} + +if (!existsSync(registryPath)) { + console.error(`Missing ${registryPath}`); + process.exit(1); +} + +const data = JSON.parse(readFileSync(registryPath, 'utf8')); +const profile = (data.profiles || []).find((p) => p.policyProfileId === id); +if (!profile) { + console.error(`Unknown policyProfileId: ${id}`); + process.exit(1); +} + +function sortKeys(obj) { + if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) return obj; + const out = {}; + for (const k of Object.keys(obj).sort()) { + out[k] = sortKeys(obj[k]); + } + return out; +} + +const canonical = JSON.stringify(sortKeys(profile)); +const hash = keccak256(toUtf8Bytes(canonical)); +console.log(JSON.stringify({ policyProfileId: id, contentHash: hash, canonicalBytes: canonical.length }, null, 2)); diff --git a/scripts/ura/validate-manifest-closure.mjs b/scripts/ura/validate-manifest-closure.mjs new file mode 100644 index 00000000..4c869e5c --- /dev/null +++ b/scripts/ura/validate-manifest-closure.mjs @@ -0,0 +1,81 @@ +#!/usr/bin/env node +/** + * Optional production gate: fail if manifest still contains pilot placeholders or open reconciliation. + * + * Usage (repo root): + * node scripts/ura/validate-manifest-closure.mjs # warnings only, exit 0 + * node scripts/ura/validate-manifest-closure.mjs --strict # exit 1 on violations + * + * CI: set URA_STRICT_CLOSURE=1 and run validate-config-files.sh (see script header there). + */ +import { readFileSync, existsSync } from 'fs'; +import { getProjectRoot, getDefaultManifestPath } from './lib/validate-ura-manifest.mjs'; + +const PILOT_PARTICIPANT = /ura:participant:pilot-/i; +const PENDING_EVIDENCE = /^ura:evidence:pending-/i; +const TBD_RE = /\bTBD\b/i; + +const strict = process.argv.includes('--strict'); +const projectRoot = getProjectRoot(); +const manifestPath = getDefaultManifestPath(projectRoot); + +function main() { + const log = (m) => console.log(`[validate-ura-closure] ${m}`); + const warn = (m) => console.warn(`[validate-ura-closure] WARN: ${m}`); + const err = (m) => console.error(`[validate-ura-closure] ${strict ? 'FAIL' : 'WARN'}: ${m}`); + + if (!existsSync(manifestPath)) { + console.error(`[validate-ura-closure] Missing ${manifestPath}`); + process.exit(1); + } + + let data; + try { + data = JSON.parse(readFileSync(manifestPath, 'utf8')); + } catch (e) { + console.error(`[validate-ura-closure] Invalid JSON: ${e.message}`); + process.exit(1); + } + + const violations = []; + + (data.resources || []).forEach((r, i) => { + const pid = r.ownerParticipantId; + if (typeof pid === 'string' && PILOT_PARTICIPANT.test(pid)) { + violations.push(`resources[${i}] ownerParticipantId is pilot placeholder: ${pid}`); + } + (r.evidenceRefs || []).forEach((ref, j) => { + if (typeof ref === 'string' && PENDING_EVIDENCE.test(ref)) { + violations.push(`resources[${i}] evidenceRefs[${j}] pending: ${ref}`); + } + }); + }); + + (data.evidencePackages || []).forEach((p, i) => { + if (p.reconciliationStatus === 'open') { + violations.push(`evidencePackages[${i}] (${p.evidencePackageId}) reconciliationStatus is open`); + } + const checkFields = ['custodyOrSourceEvidence', 'accountingRef', 'settlementOrChainRef', 'deploymentRef', 'explanation']; + for (const f of checkFields) { + const v = p[f]; + if (typeof v === 'string' && TBD_RE.test(v)) { + violations.push(`evidencePackages[${i}] (${p.evidencePackageId}).${f} contains TBD`); + } + } + }); + + if (violations.length === 0) { + log('OK: no pilot/TBD/open-reconciliation patterns detected'); + process.exit(0); + } + + violations.forEach((v) => (strict ? err : warn)(v)); + if (strict) { + err(`${violations.length} violation(s) — close pilots per URA_PILOT_CLOSURE_RUNBOOK.md`); + process.exit(1); + } + log(`${violations.length} notice(s) (use --strict to fail CI)`); + process.exit(0); +} + +main(); diff --git a/scripts/validate/validate-omnl-ledger-mapping.mjs b/scripts/validate/validate-omnl-ledger-mapping.mjs new file mode 100644 index 00000000..c33de083 --- /dev/null +++ b/scripts/validate/validate-omnl-ledger-mapping.mjs @@ -0,0 +1,51 @@ +#!/usr/bin/env node +/** + * Validate omnl-ledger-mapping.v1.json against omnl-ledger-mapping.v1.schema.json + * Usage: node scripts/validate/validate-omnl-ledger-mapping.mjs [path] + */ +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import Ajv from 'ajv'; +import addFormats from 'ajv-formats'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.join(__dirname, '../..'); +const defaultPath = path.join( + projectRoot, + 'config/universal-resource-activation/integration/omnl-ledger-mapping.v1.example.json' +); +const schemaPath = path.join( + projectRoot, + 'config/universal-resource-activation/integration/omnl-ledger-mapping.v1.schema.json' +); + +const file = path.resolve(projectRoot, process.argv[2] || defaultPath); + +if (!existsSync(file)) { + console.error(`[validate-ledger-mapping] Missing ${file}`); + process.exit(1); +} +if (!existsSync(schemaPath)) { + console.error(`[validate-ledger-mapping] Missing schema ${schemaPath}`); + process.exit(1); +} + +const ajv = new Ajv({ allErrors: true, strict: false, validateSchema: false }); +addFormats(ajv); +const validate = ajv.compile(JSON.parse(readFileSync(schemaPath, 'utf8'))); +let data; +try { + data = JSON.parse(readFileSync(file, 'utf8')); +} catch (e) { + console.error(`[validate-ledger-mapping] Invalid JSON: ${e.message}`); + process.exit(1); +} + +if (!validate(data)) { + console.error(`[validate-ledger-mapping] FAIL: ${ajv.errorsText(validate.errors, { separator: '\n' })}`); + process.exit(1); +} + +console.log(`[validate-ledger-mapping] OK: ${file}`); +process.exit(0); diff --git a/scripts/validate/validate-universal-resource-activation.mjs b/scripts/validate/validate-universal-resource-activation.mjs index c619078c..6c23b44d 100644 --- a/scripts/validate/validate-universal-resource-activation.mjs +++ b/scripts/validate/validate-universal-resource-activation.mjs @@ -1,100 +1,10 @@ #!/usr/bin/env node /** - * Validate config/universal-resource-activation/manifest.json against - * - universal-resource-activation.manifest.v1.schema.json - * - universal-resource-activation.resource.v1.schema.json (per item in resources[]) - * - universal-resource-activation.evidence-package.v1.schema.json (per item in evidencePackages[]) + * Validate config/universal-resource-activation/manifest.json against URA JSON Schemas. * - * Usage: from repo root: node scripts/validate/validate-universal-resource-activation.mjs - * Exit 0 on success, 1 on error. + * Usage: from repo root: node scripts/validate/validate-universal-resource-activation.mjs [path/to/manifest.json] */ -import { readFileSync, existsSync } from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import Ajv from 'ajv'; -import addFormats from 'ajv-formats'; +import { validateUraManifestFileCli } from '../ura/lib/validate-ura-manifest.mjs'; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const projectRoot = path.join(__dirname, '../..'); -const configDir = path.join(projectRoot, 'config', 'universal-resource-activation'); - -const manifestPath = path.join(configDir, 'manifest.json'); -const manifestSchemaPath = path.join(projectRoot, 'config', 'universal-resource-activation.manifest.v1.schema.json'); -const resourceSchemaPath = path.join(projectRoot, 'config', 'universal-resource-activation.resource.v1.schema.json'); -const evidenceSchemaPath = path.join(projectRoot, 'config', 'universal-resource-activation.evidence-package.v1.schema.json'); - -function fail(msg) { - console.error(`[validate-ura] ${msg}`); - process.exit(1); -} - -if (!existsSync(manifestPath)) { - fail(`Missing ${manifestPath}`); -} - -const ajv = new Ajv({ - allErrors: true, - strict: false, - validateSchema: false, -}); -addFormats(ajv); - -const manifestSchema = JSON.parse(readFileSync(manifestSchemaPath, 'utf8')); -const resourceSchema = JSON.parse(readFileSync(resourceSchemaPath, 'utf8')); -const evidenceSchema = JSON.parse(readFileSync(evidenceSchemaPath, 'utf8')); - -const validateManifest = ajv.compile(manifestSchema); -const validateResource = ajv.compile(resourceSchema); -const validateEvidence = ajv.compile(evidenceSchema); - -const raw = readFileSync(manifestPath, 'utf8'); -let data; -try { - data = JSON.parse(raw); -} catch (e) { - fail(`Invalid JSON: ${e.message}`); -} - -if (!validateManifest(data)) { - fail(`Manifest failed manifest schema: ${ajv.errorsText(validateManifest.errors, { separator: '\n' })}`); -} - -if (!Array.isArray(data.resources)) { - fail('resources must be an array'); -} -if (!Array.isArray(data.evidencePackages)) { - fail('evidencePackages must be an array'); -} - -data.resources.forEach((r, i) => { - if (!validateResource(r)) { - fail( - `resources[${i}] (resourceId=${r?.resourceId}): ${ajv.errorsText(validateResource.errors, { separator: '\n' })}` - ); - } -}); - -data.evidencePackages.forEach((p, i) => { - if (!validateEvidence(p)) { - fail( - `evidencePackages[${i}] (id=${p?.evidencePackageId}): ${ajv.errorsText(validateEvidence.errors, { separator: '\n' })}` - ); - } -}); - -// Cross-check: all resourceIds referenced in evidence exist -const ids = new Set(data.resources.map((r) => r.resourceId).filter(Boolean)); -data.evidencePackages.forEach((p, pi) => { - (p.resourceIds || []).forEach((rid) => { - if (!ids.has(rid)) { - fail( - `evidencePackages[${pi}] references unknown resourceId: ${rid}` - ); - } - }); -}); - -console.log( - `[validate-ura] OK: ${data.resources.length} resource(s), ${data.evidencePackages.length} evidence package(s)` -); -process.exit(0); +const arg = process.argv[2]; +validateUraManifestFileCli(arg || undefined); diff --git a/scripts/validate/validate-ura-policy-profiles.mjs b/scripts/validate/validate-ura-policy-profiles.mjs new file mode 100644 index 00000000..74331112 --- /dev/null +++ b/scripts/validate/validate-ura-policy-profiles.mjs @@ -0,0 +1,65 @@ +#!/usr/bin/env node +/** + * Validate config/universal-resource-activation/policy-profiles.json against + * universal-resource-activation.policy-profile-registry.v1.schema.json + * and ensure manifest policyProfileRefs[] ids exist in the registry. + * + * Usage: from repo root — node scripts/validate/validate-ura-policy-profiles.mjs + */ +import { readFileSync, existsSync } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import Ajv from 'ajv'; +import addFormats from 'ajv-formats'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.join(__dirname, '../..'); + +const registryPath = path.join(projectRoot, 'config', 'universal-resource-activation', 'policy-profiles.json'); +const registrySchemaPath = path.join( + projectRoot, + 'config', + 'universal-resource-activation.policy-profile-registry.v1.schema.json', +); +const manifestPath = path.join(projectRoot, 'config', 'universal-resource-activation', 'manifest.json'); + +function fail(msg) { + console.error(`[validate-ura-profiles] ${msg}`); + process.exit(1); +} + +if (!existsSync(registryPath)) fail(`Missing ${registryPath}`); +if (!existsSync(registrySchemaPath)) fail(`Missing ${registrySchemaPath}`); + +const ajv = new Ajv({ allErrors: true, strict: false, validateSchema: false }); +addFormats(ajv); + +const registrySchema = JSON.parse(readFileSync(registrySchemaPath, 'utf8')); +const validateRegistry = ajv.compile(registrySchema); +const registry = JSON.parse(readFileSync(registryPath, 'utf8')); + +if (!validateRegistry(registry)) { + console.error('[validate-ura-profiles] policy-profiles.json failed schema:', validateRegistry.errors); + process.exit(1); +} + +const ids = new Set(registry.profiles.map((p) => p.policyProfileId)); +console.log(`[validate-ura-profiles] OK: ${ids.size} profile(s) in registry`); + +if (existsSync(manifestPath)) { + const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + const refs = manifest.policyProfileRefs || []; + for (const r of refs) { + const pid = r.id; + if (!pid || !ids.has(pid)) { + fail(`manifest policyProfileRefs contains unknown or missing id: "${pid}"`); + } + } + for (const res of manifest.resources || []) { + const pid = res.policyProfileId; + if (pid && !ids.has(pid)) { + fail(`resource ${res.resourceId} references unknown policyProfileId: "${pid}"`); + } + } + console.log('[validate-ura-profiles] OK: manifest refs match registry'); +} diff --git a/scripts/validation/validate-config-files.sh b/scripts/validation/validate-config-files.sh index 35350876..6086698a 100755 --- a/scripts/validation/validate-config-files.sh +++ b/scripts/validation/validate-config-files.sh @@ -188,6 +188,15 @@ else log_warn "Optional config/universal-resource-activation/policy-profiles.json missing; skipping" fi # Optional production gate: URA_STRICT_CLOSURE=1 fails if pilots/TBD/open reconciliation remain + if [[ -f "$PROJECT_ROOT/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.json" ]] && command -v node &>/dev/null && [[ -f "$PROJECT_ROOT/scripts/validate/validate-omnl-ledger-mapping.mjs" ]]; then + log_ok "Found: config/universal-resource-activation/integration/omnl-ledger-mapping.v1.json" + if node "$PROJECT_ROOT/scripts/validate/validate-omnl-ledger-mapping.mjs" "$PROJECT_ROOT/config/universal-resource-activation/integration/omnl-ledger-mapping.v1.json"; then + log_ok "omnl-ledger-mapping.v1.json: JSON Schema OK" + else + log_err "omnl-ledger-mapping.v1.json: validation failed" + ERRORS=$((ERRORS + 1)) + fi + fi if [[ "${URA_STRICT_CLOSURE:-}" == "1" ]] && [[ -f "$PROJECT_ROOT/scripts/ura/validate-manifest-closure.mjs" ]]; then log_info "URA_STRICT_CLOSURE=1: running URA manifest closure gate…" if node "$PROJECT_ROOT/scripts/ura/validate-manifest-closure.mjs" --strict; then diff --git a/scripts/verify/smoke-universal-resource-activation.sh b/scripts/verify/smoke-universal-resource-activation.sh index 9ccb1ab6..8fb4384d 100755 --- a/scripts/verify/smoke-universal-resource-activation.sh +++ b/scripts/verify/smoke-universal-resource-activation.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash # Universal resource activation — local smoke: JSON Schema validation (always) + -# optional HTTP GET to Phoenix (when --http or PHOENIX_BASE_URL is set). +# optional HTTP GETs to Phoenix (when --http or PHOENIX_BASE_URL is set): +# 1) GET /api/v1/universal-resource-activation/manifest (expect 200 + .schemaVersion) +# 2) GET /api/v1/universal-resource-activation/policy-profiles (expect 200 + .profiles array) +# 3) GET /api/v1/universal-resource-activation/server-funds-sidecar-probe +# — expect 200 (sidecar ok or probe JSON) or 503 with .configured == false (URL unset) +# — 502 = fail (URL set but sidecar paths not healthy) # # Usage (repo root): # bash scripts/verify/smoke-universal-resource-activation.sh @@ -61,7 +66,9 @@ fi log "GET $URL (expect 200, JSON with .schemaVersion)…" body_file="$(mktemp)" -trap 'rm -f "$body_file"' EXIT +probe_file="$(mktemp)" +profiles_file="$(mktemp)" +trap 'rm -f "$body_file" "$probe_file" "$profiles_file"' EXIT code=$(curl -sS -o "$body_file" -w '%{http_code}' --connect-timeout 5 --max-time 15 "$URL" || true) if [[ "$code" != "200" ]]; then @@ -78,4 +85,42 @@ if ! jq -e '.schemaVersion | type == "string"' "$body_file" &>/dev/null; then exit 1 fi log "HTTP OK (.schemaVersion present; HTTP $code)" + +PROFILES_URL="${BASE}/api/v1/universal-resource-activation/policy-profiles" +log "GET $PROFILES_URL (expect 200, JSON with .profiles array)…" +prcode=$(curl -sS -o "$profiles_file" -w '%{http_code}' --connect-timeout 5 --max-time 15 "$PROFILES_URL" || true) +if [[ "$prcode" != "200" ]]; then + log_err "policy-profiles HTTP $prcode (expected 200). BASE=$BASE" + exit 1 +fi +if ! jq -e '(.profiles | type == "array")' "$profiles_file" &>/dev/null; then + log_err "policy-profiles response missing .profiles array" + cat "$profiles_file" >&2 + exit 1 +fi +log "policy-profiles HTTP OK" + +PROBE_URL="${BASE}/api/v1/universal-resource-activation/server-funds-sidecar-probe" +log "GET $PROBE_URL (expect 200 OK response or 503 with configured not true when URL unset)…" +pcode=$(curl -sS -o "$probe_file" -w '%{http_code}' --connect-timeout 5 --max-time 20 "$PROBE_URL" || true) + +if [[ "$pcode" == "200" ]]; then + if ! jq -e 'type == "object"' "$probe_file" &>/dev/null; then + log_err "Probe response is not a JSON object" + exit 1 + fi + log "sidecar-probe HTTP 200 (JSON object returned)" +elif [[ "$pcode" == "503" ]]; then + if ! jq -e '.configured == false' "$probe_file" &>/dev/null; then + log_err "Probe expected 503 with .configured==false when SERVER_FUNDS_SIDECAR_URL unset; got: $(head -c 400 "$probe_file")" + exit 1 + fi + log "sidecar-probe HTTP 503 (SERVER_FUNDS_SIDECAR_URL not set — expected in dev)" +elif [[ "$pcode" == "502" ]]; then + log_err "sidecar-probe HTTP 502 — SERVER_FUNDS_SIDECAR_URL is set but sidecar health paths failed. Fix env or sidecar. Body: $(head -c 400 "$probe_file")" + exit 1 +else + log_err "sidecar-probe HTTP $pcode (expected 200, 503, or 502). Body: $(head -c 400 "$probe_file")" + exit 1 +fi exit 0 diff --git a/smom-dbis-138 b/smom-dbis-138 index f3d2961b..4540ec44 160000 --- a/smom-dbis-138 +++ b/smom-dbis-138 @@ -1 +1 @@ -Subproject commit f3d2961b9747fe6010f5e3303905f28b61c20a89 +Subproject commit 4540ec44808676fa9ef143495a52ee004cb9144f