ZRR
ZAYAZ Ruleset Registry
1. Purpose and Positioning
The ZAYAZ Ruleset Registry (ZRR) formalizes every enforceable logic construct within the ZAYAZ platform into a first-class, versioned, auditable governance object.
ZRR transforms rules from implicit code fragments into explicit, declarative, traceable artifacts governed under the ZAR (ZAYAZ Artifact Registry) framework.
ZRR ensures that:
- Every validation rule is addressable.
- Every compliance rule is traceable to framework obligations.
- Every computation rule is version-controlled.
- Every enforcement action is auditable.
- Every rule lifecycle event is logged.
- Every rule is compatible with CMCB schema governance.
- Every rule execution can be explained to verifiers, regulators, and stakeholders.
ZRR is the enforcement abstraction layer between:
- Signals (SSSR)
- Ontology (USO)
- Engines (MICE)
- Dispatcher (ZSSR)
- Validation Layer (DICE / DaVE / VTE)
- Audit Layer (ALTD / DAL)
- AI Governance Systems
ZRR enables ZAYAZ to operate as a declarative ESG logic platform — not merely a SaaS interface.
2. Canonical Rule Identifier (CRID) Architecture
Every rule registered in ZRR must possess a Canonical Rule Identifier (CRID).
CRID Format
<crid_prefix>.<rule_type>.<domain>.<framework>.<topic>.<profile>.<SEVERITY>.<X_Y_Z>
^ruleset\.(validation|computation|transformation|aggregation|classification|tagging|governance|risk_mapping|ai_assisted)\.[a-z0-9][a-z0-9_-]{0,39}\.[a-z0-9][a-z0-9_-]{0,39}\.[a-z0-9][a-z0-9_-]{0,79}\.[a-z0-9][a-z0-9_-]{0,79}\.(INFO|WARNING|CRITICAL|BLOCKING)\.(0|[1-9][0-9]*)_(0|[1-9][0-9]*)_(0|[1-9][0-9]*)$
Examples
ruleset.validation.ghg.esrs.e1-6.standard.CRITICAL.1_0_0
ruleset.computation.ghg.global.scope3-category4.standard.BLOCKING.2_1_0
ruleset.governance.gov.csrd.g1-4.policy-required.CRITICAL.1_0_0
ruleset.transformation.meta.global.unit-conversion.standard.INFO.3_0_2
CRID Components
| Component | Description |
|---|---|
crid_prefix | Fixed prefix identifying CRID namespace. Must be ruleset for ruleset artifacts. |
rule_type | One of: validation, computation, transformation, aggregation, classification, tagging, governance, risk_mapping, ai_assisted. Must match zrr.rule_type. |
domain | Domain code (lowercase) such as ghg, finance, gov, meta, waste, etc. |
framework | Framework namespace such as esrs, csrd, gri, global, iso14001. |
topic | The subject identifier: a clause, metric family, or logical object like e1-6, scope3-category4, g1-4, unit-conversion. |
profile | Variant/profile of the ruleset logic (e.g., standard, policy-required, strict, tenant-acme, sector-mining). |
SEVERITY | Enforcement severity enum: INFO, WARNING, CRITICAL, BLOCKING (UPPERCASE). |
X_Y_Z | Ruleset semantic version encoded as major_minor_patch (e.g., 1_0_0). |
CRIDs are immutable.
A new version always generates a new CRID.
3. Rule Classification Model
Every rule must be classified into one of the following categories:
| Ruleset Type | Description |
|---|---|
| Validation | Range checks, completeness checks, structural validation |
| Computation | Mathematical transformations, derived metrics |
| Transformation | Unit conversion, structural normalization |
| Aggregation | Multi-signal summarization |
| Governance | Policy requirement enforcement |
| Risk Mapping | Risk categorization and threshold enforcement |
| AI-Assisted | AI-based inference or extrapolation rules |
Each ruleset must define:
- Enforcement Mode
- Severity Level
- Execution Engine Binding
- Fallback Logic
- Audit Requirements
4. ZRR Core Schema (Logical Model)
ZRR is implemented as a formal registry object under ZAR.
ruleset_registry
| Column | Type | Description |
|---|---|---|
zar_ruleset_ref | text (PK) | ZAR:ruleset:<artifact_name>@sha256:<hash> immutable id |
rule_id | text | CRID (canonical rule identifier), from zrr.crid |
rule_name | text | Human title; recommend adding zrr.title |
scope | text | `global |
tenant_id | text null | tenant scope id |
entity_id | text null | entity scope id |
domain | text | from zrr.domain |
ruleset_kind | text | e.g. `tag_detection |
rule_type | text | from zrr.rule_type (Validation/Computation/…) |
linked_signal_ids | jsonb | array of signal ids |
linked_frameworks | jsonb | array of frameworks |
severity_level | text | INFO/WARNING/CRITICAL/BLOCKING |
enforcement_mode | text | advisory/soft/hard/blocking/audit_only |
execution_engine | text | MEID that executes it (zrr.execution_engine) |
fallback_logic | text | none/manual_escalation/… |
ontology_binding | text null | reference (USO etc.) |
schema_min_ref | text null | from compatibility.min_schema_ref |
schema_max_ref | text null | from compatibility.max_schema_ref |
version | text | semver (explicit), or derived from CRID tail |
lifecycle_status | text | draft/approved/frozen/superseded/deprecated |
audit_required | boolean | from policy/constraints |
zar_content_hash | text | sha256 hash (redundant but useful) |
created_by | text | system/governance/admin |
created_at | timestamptz | artifact lifecycle created time |
updated_at | timestamptz | registry update timestamp |
ZRR is part of the ZAR Artifact Layer and inherits:
- Version lineage tracking
- DAL registration
- Federation readiness
- Assurance cloud propagation
Field mapping: YAML → ruleset_registry
| ruleset_registry field | Source |
|---|---|
rule_id | zrr.crid (ruleset.…__) |
rule_name | zar.artifact_name or add zrr.title (recommended) |
| domain | zrr.domain |
rule_type | zrr.rule_type (validation/computation/classification/tagging…) |
linked_signal_ids | zrr.linked_signal_ids |
linked_frameworks | zrr.linked_frameworks |
severity_level | zrr.severity |
execution_engine | zrr.execution_engine |
schema_version_binding | compatibility.min_schema_ref + compatibility.max_schema_ref (store both) |
version | derived from CRID tail X_Y_Z (or store explicitly as zrr.version if preferred) |
active_status | lifecycle.status mapped: approved→active, draft→experimental, deprecated→deprecated |
created_at | lifecycle.created_at |
updated_at | set by registry service on ingest/update |
5. Rule Binding Architecture
Every rule must bind to at least one of the following:
- Signal (
signal_id) - Framework obligation
- Ontology node (USO)
- Micro Engine (
MEID) - Validation engine (DICE / DaVE)
- Agent profile (optional)
- AI risk tier (if applicable)
This creates full traceability across:
Signal → Rule → Engine → Enforcement → Audit Log → Assurance Ledger
No rule may execute outside this binding model.
6. Rule Execution Logging
All rule executions must generate a Rule Execution Event.
rule_execution_log (event table)
| Column | Type | Description |
|---|---|---|
execution_id | uuid (PK) | unique execution event |
zar_ruleset_ref | text | exact artifact executed |
rule_id | text | CRID |
meid | text | engine id that executed |
signal_id | text null | if single-signal event |
signal_ids | jsonb null | if multi-signal event |
execution_timestamp | timestamptz | UTC |
execution_result | text | pass/fail/warn |
enforcement_action_taken | text | none/notify/block/escalate |
confidence_score | double precision null | 0–1 for AI-assisted |
override_flag | boolean | whether an override applied |
overridden_by | text null | identity |
audit_hash | text null | integrity anchor |
Execution logs are stored in:
- ALTD (Audit Logging & Tamper Detection)
- DAL (Digital Assurance Ledger)
- Federation export (if applicable)
Rule logs are immutable.
7. Integrity Governance Model
7.1. Scope and Object of Status
Integrity status applies at three levels (all three can exist):
- Job Integrity (
job_integrity_status) - Dataset Integrity (
dataset_integrity_status) — e.g., canonical GL set for a period/entity - Artifact Integrity (
artifact_integrity_status) — e.g.,transition_project_cost_profile
Normative Rule:
Only dataset_integrity_status controls regulatory reporting eligibility.
Artifact-level integrity may be stricter but cannot override dataset eligibility.
7.2. Canonical Status Enum
7.2.1. Primary states (normative)
| State | Meaning | Reporting eligible? |
|---|---|---|
PENDING | Job started; integrity not assessed yet | ❌ |
IN_PROGRESS | Canonicalization or checks running | ❌ |
PASSED | All blocking and hard checks satisfied | ✅ |
PASSED_WITH_WARNINGS | Passed but has warnings (soft/hard warnings below thresholds) | ✅ (flagged) |
FAILED | Integrity checks failed beyond tolerance / blocking rules triggered | ❌ |
PASSED_WITH_EXCEPTION | Failed originally, but a governed exception is approved and attached | ✅ (flagged + exception) |
REVOKED | Previously passed/exceptioned status invalidated (ruleset change, exception expiry, data change) | ❌ |
7.2.2. Optional operational states (if useful)
- CANCELLED (job cancelled)
- ERROR (system/runtime error; not a data-integrity conclusion)
7.3. Deterministic Inputs to State Transitions
Integrity status is computed from a set of check results produced by rulesets:
- Tag detection checks (
MEID_ACCT_CRAWLERtag ruleset) - Classification checks (
MEID_ACCT_CRAWLERclassification ruleset) - Reconciliation checks (
MEID_ACCT_CRAWLERreconciliation ruleset)
Each check yields:
result:PASS|WARN|FAILenforcement_mode:advisory|soft|hard|blockingmetrics: diffs, counts, ratioscridruleset_reftimestamp
7.4. Transition Rules
7.4.1. Start / execution
PENDING → IN_PROGRESSTrigger: JobStartedIN_PROGRESS → FAILEDTrigger: any blocking check FAIL and no valid exception exists.IN_PROGRESS → PASSED_WITH_WARNINGSTrigger: no blocking FAILs, but one or more soft/hard warnings exist.IN_PROGRESS → PASSEDTrigger: all checks PASS (or only advisory warnings).
7.4.2. Exception handling (governed override)
FAILED → PASSED_WITH_EXCEPTIONTrigger: IntegrityExceptionApproved event with:
- matching
job_id - matching
failed_rule_crid - matching
ruleset_ref(or compatible lineage rule) - exception not expired
PASSED_WITH_WARNINGS → PASSED_WITH_EXCEPTION(rare)
Trigger: exception applied to a warning that is treated as blocking for reporting in a specific context (e.g., EU filing requires strict mode). Optional, only if if/when we support “strict compliance mode.”
7.4.3. Revocation (critical for replay + audit)
PASSED → REVOKEDTriggers (any):
- dataset content hash changed (re-ingest, re-canonicalize)
ruleset_refchanged for integrity-critical rulesets (reconciliation/classification)- schema compatibility boundary violated
- manual tamper detection / DAL violation
Revocation does not mutate historical artifacts. It creates a new integrity evaluation event referencing the same dataset with updated governance context.
-
PASSED_WITH_WARNINGS → REVOKEDSame triggers as above. -
PASSED_WITH_EXCEPTION → REVOKEDTriggers (any):
- exception expired
- exception deprecated/revoked
- job/dataset hash changed
- referenced
ruleset_refchanged - exception evidence invalidated (optional governance action)
7.4.4. Re-run / recomputation
REVOKED → IN_PROGRESSTrigger: job replay/recompute requested using a specificruleset_refset.
7.5. enforcement_mode
7.5.1. What “enforcement_mode” Actually Controls:
It defines:
What happens when the ruleset determines a failure condition. So the key is: what exactly gets blocked?
There are three different “layers” where blocking can apply:
| Layer | What gets blocked |
|---|---|
| Engine layer | The microservice job execution |
| Artifact layer | Publication of output artifacts |
| Integrity layer | “Integrity = PASSED” status |
These are very different in terms of operational impact.
The Four Modes — Operational Meaning
🟢 advisory
- Rule failure logged
- No flags
- No status change
- No UI impact
Use when:
- Low-risk signals
- Informational rules
🟡 soft
- Rule failure logged
- Integrity flag attached
- Warning surfaced in UI/API
- Artifacts still published
Use when:
- Data quality issue
- Not materially misleading
- CFO review recommended
🟠 hard
- Rule failure logged
- Integrity status downgraded
- Must acknowledge or override
- Artifacts published but marked non-compliant
Use when:
- Financial classification uncertainty
- High unknown ratio
- Partial reconciliation
This is typically the sweet spot for most finance policy rules.
🔴 blocking
- Rule failure logged
- Artifact cannot be marked “valid”
- Either:
- Prevent publishing entirely
- OR publish but status = INVALID and not eligible for downstream reporting
- Requires manual resolution before progressing workflow
Use when:
- Ledger integrity failure
- Double counting risk
- Currency mismatch without FX policy
- Schema incompatibility
- Reconciliation beyond tolerance
| Ruleset | enforcement_mode | Interpretation |
|---|---|---|
| Tag detection | soft | Flag if tagging weak |
| Classification | hard | Must review if unknown high |
| Reconciliation | blocking | Block integrity_passed status |
Blocking in the ZRR means:
“Prevents dataset from achieving integrity_passed status and from being used in compliance-critical outputs until resolved or formally overridden.”
7.5.2. Integrity Exception Framework
We treat overrides as Governance Events. An override must:
- Never delete the original failure
- Never change the ruleset
- Never mutate the underlying data
- Create a separate, immutable governance artifact
Override = “accept deviation with documented justification”
An override does not convert a FAIL into PASS. It produces a distinct state:
PASSED_WITH_EXCEPTION.
The following artifact is a first-class governance object.
ZAR:integrity_exception:<entity>:<job_id>@sha256:<hash>
YAML name:
integrity-exception--<job_id>--<ruleset_family>--1_0_0.yaml
Artifact Index Table: zar_artifact_index
-- ZAR Artifact Index (minimal)
-- Purpose: fast lookup of ANY ZAR artifact by ref, and filtering by tenant/entity/job/type.
CREATE TABLE zar_artifact_index (
zar_ref TEXT PRIMARY KEY, -- e.g. ZAR:ruleset:acct_crawler_tag_detection@sha256:...
artifact_type TEXT NOT NULL, -- ruleset | schema | integrity_check_report | integrity_exception | dataset | event | ...
artifact_name TEXT NOT NULL, -- human/stable name, not necessarily unique globally
content_hash TEXT NOT NULL, -- sha256:<64hex>
schema_ref TEXT NOT NULL, -- e.g. ZAR:schema:integrity_check_report@v1
tenant_id TEXT NULL, -- null => global artifact
entity_id TEXT NULL, -- null => not entity-scoped
job_id TEXT NULL, -- populated for execution artifacts
run_id TEXT NULL, -- retry/attempt id if applicable
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by TEXT NULL, -- system|governance|admin|user OR user id/email
lifecycle_status TEXT NULL, -- draft|approved|deprecated (mainly for rulesets/schemas); null for immutable outputs
storage_uri TEXT NOT NULL, -- canonical storage location (S3/GCS/file/DB blob ref)
size_bytes BIGINT NULL,
mime_type TEXT NULL, -- application/yaml, application/json, etc.
metadata JSONB NOT NULL DEFAULT '{}'::jsonb -- optional indexing hints, non-authoritative
);
-- Useful indexes
CREATE INDEX idx_zar_artifact_type ON zar_artifact_index (artifact_type);
CREATE INDEX idx_zar_tenant_entity ON zar_artifact_index (tenant_id, entity_id);
CREATE INDEX idx_zar_job_run ON zar_artifact_index (job_id, run_id);
CREATE INDEX idx_zar_hash ON zar_artifact_index (content_hash);
7.5.3. Minimum required fields for an override:
zar:
artifact_type: integrity_exception
artifact_name: integrity_exception_JOB-XYZ-123
applies_to_meid: MEID_ACCT_CRAWLER
zrr:
crid: ruleset.validation.finance.global.reconciliation.override.standard.critical.1_0_0
rule_type: governance
domain: finance
severity: critical
execution_engine: MEID_ACCT_CRAWLER
enforcement_mode: blocking
audit_required: true
lifecycle:
status: approved
created_by: governance
owners:
- finance.controller@client.com
approved_by:
- finance.controller@client.com
created_at: 2026-03-02T12:34:00Z
supersedes: null
deprecated_by: null
changelog: "Approved reconciliation exception for timing difference."
exception_scope:
level: job
reporting_eligibility_restored: true
context:
exception_id: INT-EXC-2026-0001
job_id: JOB-XYZ-123
ruleset_ref: ZAR:ruleset:acct_crawler_reconciliation_policy@sha256:abc
failed_rule_crid: ruleset.validation.finance.global.reconciliation.standard.critical.1_0_0
failure_snapshot:
entity_diff_abs: 12.45
entity_diff_rel: 0.0008
failed_accounts:
- "6100"
- "6200"
justification: >
Timing difference due to late journal posting.
Verified against closing Trial Balance extract.
supporting_evidence_refs:
- ledger_export_2026_01_v2.pdf
- tb_reconciliation_workpaper.xlsx
risk_assessment: immaterial
expiry_policy:
scope: reporting_year
valid_for: 2026
This ensures:
- Full traceability
- Snapshot of failure context
- Evidence attachment
- Role-based approval
- Time-bound validity
7.5.4. Runtime Logic After Override
If exception exists and is valid:
integrity_status = PASSED_WITH_EXCEPTIONreporting_eligible = trueaudit_flag = trueoverride_flag = true
Downstream artifacts must include:
"integrity_status": "PASSED_WITH_EXCEPTION",
"exception_ref": "ZAR:integrity_exception:entity@sha256:xyz"
Auditor can then inspect the exception object.
7.5.5. Auditor-Safe Design Principles
To satisfy assurance requirements:
- Override Must Be Additive
Original failure event remains immutable.
- Override Must Be Linked to Specific Job + Ruleset
If ruleset changes → override invalid.
- Override Must Expire
Cannot carry forward silently into next year.
- Override Must Be Role-Restricted
Only:
- Controller
- CFO
- Designated governance role
- Override Must Be Logged in DAL
Every override creates:
- RuleExecutionEvent (override=true)
- DAL hash entry
- Governance event log
7.5.6. Safe “Fix” vs “Override”
There are two types of resolution:
A. Data Fix (Preferred)
- Correct connector config
- Re-run extraction
- Re-run reconciliation
- Pass legitimately
No override needed.
B. Accepted Deviation (Controlled Exception)
Used only when:
- Timing differences
- FX rounding immaterial
- Known ERP quirks
- Minor TB extraction limitations
This is where exception artifact applies.
7.5.7. UX Design (Important)
When reconciliation fails, UI must show:
Integrity Panel
- Difference amount
- Threshold
- Failed accounts
- Root cause category suggestion
Options:
- Fix data and re-run
- Adjust ruleset (requires governance approval)
- Create exception (requires controller approval)
This ensures:
✔ Structured workflow ✔ No shadow overrides ✔ No hidden toggles
7.5.8. Strategically Powerful
With this system, ZAYAZ can say:
“All integrity deviations are explicitly governed, time-bound, evidence-backed, and auditable.”
- That is exactly what auditors want.
- We are not suppressing issues.
- We are documenting them formally.
7.5.9. Should Overrides Modify Tolerances?
No.
Never mutate ruleset automatically.
If tolerance is wrong:
- Create new ruleset version
- Activate new version
- Re-run job
That maintains replay safety.
7.6. State Machine Diagram (textual)
PENDING
└──(JobStarted)──> IN_PROGRESS
├──(IntegrityEvaluated: Blocking FAIL, no exception)──> FAILED
│ └──(IntegrityExceptionApproved & valid)──> PASSED_WITH_EXCEPTION
├──(IntegrityEvaluated: No blocking FAIL, warnings exist)──> PASSED_WITH_WARNINGS
└──(IntegrityEvaluated: All PASS)──> PASSED
PASSED ──(dataset_hash change OR bundle_ref/ruleset_ref change OR schema_ref incompatibility)──> REVOKED
PASSED_WITH_WARNINGS ──(dataset_hash change OR bundle_ref/ruleset_ref change OR schema_ref incompatibility)──> REVOKED
PASSED_WITH_EXCEPTION ──(exception expiry OR exception revoked OR dataset_hash/bundle_ref change)──> REVOKED
REVOKED ──(Replay/Recompute requested)──> IN_PROGRESS
Pipeline alignment:
JobStarted
↓
Canonicalized
↓
Reconciled
↓
IntegrityEvaluated
↓
Published (publish_allowed may be true even if FAILED)
> Key: we don’t “block artifact generation”; we block **reporting eligibility** (integrity_passed/reporting_eligible).
7.7. Integrity “Blocking” Semantics
Blocking prevents a dataset from reaching PASSED status and from being marked reporting_eligible = true. Blocking does not prevent artifact generation unless a system-level ERROR occurs.
The formal rule is:
- Artifact generation: always allowed (unless system error)
- Reporting eligibility: depends on integrity status
Reporting eligibility mapping
| Integrity status | reporting_eligible | publish_allowed |
|---|---|---|
PASSED | true | true |
PASSED_WITH_WARNINGS | true (flagged) | true |
PASSED_WITH_EXCEPTION | true (flagged + exception_ref required) | true |
FAILED | false | true |
REVOKED | false | false |
PENDING/IN_PROGRESS | false | false |
7.8. Required Metadata Fields (for audit + replay)
Every dataset/artifact must include:
integrity_statusintegrity_ruleset_bundle_refs(all ruleset refs used)integrity_check_results_ref(pointer to check report artifact)exception_ref(nullable; required ifPASSED_WITH_EXCEPTION)input_dataset_hashjob_idtimestamp
7.9. Events (align with the pipeline)
You already have: JobStarted, Canonicalized, Reconciled, Published.
Add two governance events:
IntegrityEvaluated(emits computed status + check summary ref)IntegrityExceptionApproved(links exception artifact ref)
Optional:
- IntegrityRevoked (when status becomes REVOKED)
7.10. Practical guardrails for auditors
To make overrides “safe and sound”:
PASSED_WITH_EXCEPTIONmust always carry:exception_reffailed_rule_cridruleset_refexpiry_policy- evidence refs
- Any change to dataset hash or ruleset ref forces REVOKED
- Recompute with original refs reproduces original status
7.11. Implementation notes
- Model as a pure function:
integrity_status = f(check_results, exception?, hashes, ruleset_refs, schema_refs, now)
So it’s deterministic and replayable.
- Store “check results” as a separate artifact:
ZAR:integrity_check_report:<job_id>@sha256:<hash>
This makes the evaluation explainable.
7.12. ZAR Integrity Check Report Artifact
7.12.1. Artifact definition
Artifact type
integrity_check_report
Normative invariants
- Must be content-addressable and stored in ZAR:
ZAR:integrity_check_report:<job_id>@sha256:<hash>- Must include:
job_idapplies_to_meiddataset_hash(hash of the canonicalized dataset being assessed)- all ruleset refs used
- all check results (including
PASS/WARN/FAIL) - computed
integrity_status(one of the canonical states)
- Must be replay-safe:
- same inputs + same rulesets + same
dataset_hash⇒ identical report content (except timestamps if you choose to exclude them from hash; see §4)
- same inputs + same rulesets + same
7.13. Schemas
7.13.1. Schema & Report Example
[SchemaSnippet] Loading schema "zar/integrity_check_report.v1.schema.json" on client...
Notes:
zar_refis the canonical ID. Everything else is query convenience.- metadata is non-authoritative (the artifact file is authoritative). It’s for search/filter performance and UI summaries.
Example integrity_check_report instance
{
"zar": {
"artifact_type": "integrity_check_report",
"artifact_name": "integrity_check_report_JOB-XYZ-123",
"applies_to_meid": "MEID_ACCT_CRAWLER",
"content_hash": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"schema_ref": "ZAR:schema:integrity_check_report@v1"
},
"scope": {
"level": "dataset",
"object_ref": "<ZAR:dataset:...@sha256:...>"
},
"context": {
"job_id": "JOB-XYZ-123",
"run_id": "RUN-XYZ-123-1",
"tenant_id": "TENANT-ACME",
"entity_id": "ENTITY-ACME-DE",
"generated_at": "2026-02-17T10:12:00Z",
"initiated_by": "system",
"mode": "standard"
},
"dataset": {
"dataset_type": "canonical_trial_balance",
"dataset_hash": "sha256:2222222222222222222222222222222222222222222222222222222222222222",
"schema_ref": "ZAR:schema:canonical_trial_balance@v1",
"period": { "start": "2026-01-01", "end": "2026-01-31", "reporting_year": 2026 },
"source_systems": ["netsuite"],
"record_counts": { "lines_total": 12045, "accounts_total": 412, "projects_total": 18 }
},
"rulesets": {
"bundle_ref": "ZAR:ruleset_bundle:acct_crawler_default@sha256:3333333333333333333333333333333333333333333333333333333333333333",
"resolved": [
{
"ruleset_ref": "ZAR:ruleset:acct_crawler_tag_detection@sha256:aaaa",
"artifact_name": "acct_crawler_tag_detection",
"crid": "ruleset.tag_detection.finance.global.transition.standard.warning.1_0_0",
"enforcement_mode": "soft"
},
{
"ruleset_ref": "ZAR:ruleset:acct_crawler_classification@sha256:bbbb",
"artifact_name": "acct_crawler_classification",
"crid": "ruleset.classification.finance.global.capex-opex.standard.warning.1_0_0",
"enforcement_mode": "hard"
},
{
"ruleset_ref": "ZAR:ruleset:acct_crawler_reconciliation_policy@sha256:cccc",
"artifact_name": "acct_crawler_reconciliation_policy",
"crid": "ruleset.validation.finance.global.reconciliation.standard.critical.1_0_0",
"enforcement_mode": "blocking"
}
]
},
"checks": [
{
"check_id": "TB_ENTITY_DIFF",
"crid": "ruleset.validation.finance.global.reconciliation.standard.critical.1_0_0",
"ruleset_ref": "ZAR:ruleset:acct_crawler_reconciliation_policy@sha256:cccc",
"category": "reconciliation",
"result": "FAIL",
"severity": "BLOCKING",
"enforcement_layer": "integrity",
"message": "Entity-level TB reconciliation diff exceeds absolute tolerance.",
"metrics": { "entity_diff_abs": 12.45, "entity_diff_rel": 0.0008, "abs_tol": 5.0, "rel_tol": 0.0001 }
},
{
"check_id": "UNKNOWN_CLASSIFICATION_RATIO",
"crid": "ruleset.classification.finance.global.capex-opex.standard.warning.1_0_0",
"ruleset_ref": "ZAR:ruleset:acct_crawler_classification@sha256:bbbb",
"category": "classification",
"result": "WARN",
"severity": "WARNING",
"message": "Unknown classification ratio exceeds preferred threshold but below hard fail threshold.",
"metrics": { "unknown_ratio": 0.012, "warn_threshold": 0.01, "fail_threshold": 0.02 }
}
],
"summary": {
"integrity_status": "FAILED",
"reporting_eligible": false,
"publish_allowed": true,
"exception_ref": null,
"counts": { "pass": 0, "warn": 1, "fail": 1 },
"failed_rule_crids": [
"ruleset.validation.finance.global.reconciliation.standard.critical.1_0_0"
],
"warnings": [
"Classification unknown ratio above preferred threshold."
]
}
}
Tie to IntegrityEvaluated event
When IntegrityEvaluated is emitted, include:
integrity_check_report_ref(ZAR ref)integrity_statusfailed_rule_cridsdataset_hashruleset_bundle_ref
This makes the event log minimal but fully traceable.
7.13.2. Canonicalization + hashing rules (so ZAR refs are stable)
To ensure deterministic content_hash:
- Canonicalize JSON before hashing:
- UTF-8
- sorted object keys recursively
- arrays preserve order
- remove insignificant whitespace
- Either:
- include generated_at in hash (strict immutability), OR
- move timestamps into a separate non-hashed envelope and hash only a hash_basis object.
Recommendation: For audit trails, keep timestamp in the artifact, but compute hash over everything except generated_at if you want stable reproduction across replays. If you want strict immutability per run, keep it included.
Given the replay goal (“same inputs, same outputs”), we'll do:
generated_atincluded in artifactcontent_hash_basisexcludes it
7.13.3. integrity_report_registry (SSSR table spec)
Purpose
A query-optimized registry of integrity outcomes produced by integrity evaluation runs. Each row represents the integrity conclusion for a specific (scope, tenant, entity, period, dataset_hash, ruleset_bundle_ref) and links to the authoritative ZAR artifacts:
integrity_check_report_ref(full check details)- optional
exception_ref(governed override) - optional
revocation_ref(revocation event/artifact)
Table
Postgres SQL DDL — integrity_report_registry
DO $$ BEGIN
CREATE TYPE integrity_mode AS ENUM ('standard', 'strict_compliance');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE integrity_scope_level AS ENUM ('job','dataset','artifact');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE integrity_status_enum AS ENUM (
'PENDING','IN_PROGRESS','PASSED','PASSED_WITH_WARNINGS','FAILED','PASSED_WITH_EXCEPTION','REVOKED'
);
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
CREATE TABLE IF NOT EXISTS integrity_report_registry (
integrity_id TEXT PRIMARY KEY,
-- ZAR binding (if you have the ZAR ref at write-time)
artifact_ref TEXT UNIQUE NULL, -- recommended to populate; can be backfilled from zar_artifact_index
artifact_name TEXT NOT NULL,
artifact_type TEXT NOT NULL DEFAULT 'integrity_check_report',
applies_to_meid TEXT NOT NULL,
content_hash TEXT NOT NULL,
schema_ref TEXT NOT NULL,
-- scope
scope_level integrity_scope_level NOT NULL DEFAULT 'dataset',
scope_object_ref TEXT NOT NULL,
scope_hash TEXT NOT NULL,
-- context
job_id TEXT NOT NULL,
run_id TEXT NULL,
tenant_id TEXT NOT NULL,
entity_id TEXT NOT NULL,
generated_at TIMESTAMPTZ NOT NULL,
initiated_by TEXT NOT NULL DEFAULT 'system',
mode integrity_mode NOT NULL DEFAULT 'standard',
-- dataset
dataset_type TEXT NOT NULL,
dataset_hash TEXT NOT NULL,
dataset_schema_ref TEXT NOT NULL,
period_start DATE NOT NULL,
period_end DATE NOT NULL,
reporting_year INT NOT NULL,
source_systems JSONB NOT NULL DEFAULT '[]'::jsonb,
record_counts JSONB NOT NULL DEFAULT '{}'::jsonb,
-- rulesets
ruleset_bundle_ref TEXT NOT NULL,
ruleset_resolved JSONB NOT NULL DEFAULT '[]'::jsonb,
ruleset_refs JSONB NOT NULL DEFAULT '[]'::jsonb,
ruleset_crids JSONB NOT NULL DEFAULT '[]'::jsonb,
-- summary
integrity_status integrity_status_enum NOT NULL,
reporting_eligible BOOLEAN NOT NULL DEFAULT FALSE,
publish_allowed BOOLEAN NOT NULL DEFAULT FALSE,
integrity_passed BOOLEAN NOT NULL DEFAULT FALSE,
exception_ref TEXT NULL,
counts_pass INT NOT NULL DEFAULT 0,
counts_warn INT NOT NULL DEFAULT 0,
counts_fail INT NOT NULL DEFAULT 0,
failed_rule_crids JSONB NOT NULL DEFAULT '[]'::jsonb,
warnings JSONB NOT NULL DEFAULT '[]'::jsonb,
-- checks (optional denormalized cache)
check_results JSONB NOT NULL DEFAULT '[]'::jsonb,
check_ids_failed JSONB NOT NULL DEFAULT '[]'::jsonb,
check_ids_warn JSONB NOT NULL DEFAULT '[]'::jsonb,
top_failure_category TEXT NULL,
flags JSONB NOT NULL DEFAULT '[]'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- constraints
ALTER TABLE integrity_report_registry
ADD CONSTRAINT chk_dataset_hash_format
CHECK (dataset_hash ~ '^sha256:[0-9a-f]{64}$');
ALTER TABLE integrity_report_registry
ADD CONSTRAINT chk_content_hash_format
CHECK (content_hash ~ '^sha256:[0-9a-f]{64}$');
ALTER TABLE integrity_report_registry
ADD CONSTRAINT chk_exception_ref_required
CHECK (
(integrity_status <> 'PASSED_WITH_EXCEPTION')
OR (exception_ref IS NOT NULL)
);
-- indexes
CREATE INDEX IF NOT EXISTS idx_ir_tenant_entity_year
ON integrity_report_registry (tenant_id, entity_id, reporting_year);
CREATE INDEX IF NOT EXISTS idx_ir_status_eligible
ON integrity_report_registry (integrity_status, reporting_eligible);
CREATE INDEX IF NOT EXISTS idx_ir_dataset_hash
ON integrity_report_registry (dataset_hash);
CREATE INDEX IF NOT EXISTS idx_ir_job
ON integrity_report_registry (job_id);
CREATE INDEX IF NOT EXISTS idx_ir_ruleset_bundle
ON integrity_report_registry (ruleset_bundle_ref);
CREATE INDEX IF NOT EXISTS gin_ir_failed_rule_crids
ON integrity_report_registry USING GIN (failed_rule_crids);
CREATE INDEX IF NOT EXISTS gin_ir_ruleset_refs
ON integrity_report_registry USING GIN (ruleset_refs);
CREATE INDEX IF NOT EXISTS gin_ir_flags
ON integrity_report_registry USING GIN (flags);
CREATE INDEX idx_integrity_scope_hash
ON integrity_report_registry(scope_hash);
Note: the “revocation_ref required on REVOKED” constraint is strict. If we want to allow REVOKED without an explicit artifact, remove that constraint and treat it as recommended.
7.13.3. Projection mapping — integrity_check_report → integrity_report_registry
This assumes the integrity_check_report JSON schema includes these (or similar) top-level structures:
- meta (
job_id,tenant_id,entity_id,meid,timestamps) - scope (level + object ref)
- dataset (
type,hash,schema_ref,period) - rulesets (bundle ref + array refs + mode)
- summary (
integrity_status,reporting_eligible,publish_allowed,counts) - checks (array of check objects with
result,crid,enforcement_mode,category,flags)
If the actual report differs, keep the same mapping approach—just adjust paths.
Deterministic derivations (normative)
A) integrity_id (deterministic)
Recommended formula (stable, unique enough, replay-safe):
integrity_id =
"INT-" + tenant_id + "-" + entity_id + "-" + scope_level + "-" +
reporting_year + "-" + period_label + "-" +
substring(dataset_hash, 8, 12) + "-" +
substring(sha256(ruleset_bundle_ref), 1, 8) + "-" +
mode
- Use
dataset_hash+ruleset_bundle_ref+ period as anchor inputs. - It is also possible to store
supersedes_integrity_idif lineage chains is needed/wanted.
B) integrity_passed (canonical)
integrity_passed = integrity_status IN (
'PASSED', 'PASSED_WITH_WARNINGS', 'PASSED_WITH_EXCEPTION'
)
C) reporting_eligible and publish_allowed (canonical)
From the governance model:
| integrity_status | reporting_eligible | publish_allowed |
|---|---|---|
PASSED | true | true |
PASSED_WITH_WARNINGS | true | true |
PASSED_WITH_EXCEPTION | true | true |
FAILED | false | true |
REVOKED | false | false |
PENDING/IN_PROGRESS | false | false |
So:
- If report contains these booleans in summary, trust them.
- Otherwise compute them deterministically from
integrity_status.
Field-by-field mapping table
| Registry Column | Source in integrity_check_report | Rule |
|---|---|---|
artifact_type | zar.artifact_type | Must equal integrity_check_report. |
artifact_name | zar.artifact_name | Required. |
applies_to_meid | zar.applies_to_meid | Required. |
content_hash | zar.content_hash | Required, format sha256:<hash>. |
schema_ref | zar.schema_ref | Required. |
scope_level | scope.level | Must be one of job / dataset / artifact. |
scope_object_ref | scope.object_ref | Preferred: ZAR ref for the scoped object (e.g., ZAR:dataset:...@sha256:...). Required for deterministic identity. |
job_id | context.job_id | Required. |
run_id | context.run_id | Optional. |
tenant_id | context.tenant_id | Required. |
entity_id | context.entity_id | Required. |
generated_at | ± | Required. |
initiated_by | context.initiated_by | Optional; default system. |
mode | context.mode | Default standard. |
dataset_type | dataset.dataset_type | Required. |
dataset_hash | dataset.dataset_hash | Required, format sha256:<hash>. |
dataset_schema_ref | dataset.schema_ref | Required. |
period_start | dataset.period.start | Required. |
period_end | dataset.period.end | Required. |
reporting_year | dataset.period.reporting_year | Required. |
source_systems | dataset.source_systems | Optional array. |
record_counts | dataset.record_counts | Optional object. |
ruleset_bundle_ref | rulesets.bundle_ref | Required. |
ruleset_resolved | rulesets.resolved | Full resolved ruleset list (good to store). |
ruleset_refs | derived from rulesets.resolved[].ruleset_ref | Normalize + unique. |
ruleset_crids | derived from rulesets.resolved[].crid | Normalize + unique. |
integrity_status | summary.integrity_status | Required enum. |
reporting_eligible | summary.reporting_eligible | If missing, compute from status mapping. |
publish_allowed | summary.publish_allowed | If missing, compute from status mapping. |
integrity_passed | derived from summary.integrity_status | true if status in {PASSED, PASSED_WITH_WARNINGS, PASSED_WITH_EXCEPTION}. |
exception_ref | summary.exception_ref | Nullable. Can later be updated via IntegrityExceptionApproved. |
counts_pass | summary.counts.pass | If missing, count checks where result=PASS. |
counts_warn | summary.counts.warn | If missing, count checks where result=WARN. |
counts_fail | summary.counts.fail | If missing, count checks where result=FAIL. |
failed_rule_crids | summary.failed_rule_crids OR derive from checks[] | Prefer summary; else all FAIL checks[].crid. |
warning_rule_crids | derive from checks[] | All WARN checks[].crid (this is currently not stored this in summary). |
warnings | summary.warnings | Optional list of warning strings. |
top_failure_category | derive from checks[] | First FAIL’s category (or null). |
check_results | checks | Store full checks[] if you want fast UI. |
check_ids_failed | derive from checks[] | FAIL checks[].check_id. |
check_ids_warn | derive from checks[] | WARN checks[].check_id. |
flags | derive (future) | If you later add checks[].flags or summary.flags, normalize + unique. |
artifact_ref | known at persistence OR from ZAR index | Not present in JSON; comes from ZAR when stored (recommended). |
integrity_id | derived | Deterministic ID based on (tenant_id, entity_id, mode, dataset_hash, period) (see below). |
revocation_ref | from revocation event | Not present in report; updated on IntegrityRevoked. |
exception_status | derived from exception artifact | Not present in report; projection field from exception lifecycle. |
created_by | context.initiated_by | Your report uses initiated_by not created_by; map it here. |
supersedes_integrity_id | optional (registry-only) | Not in report; used when we explicitly supersede an old record. |
notes | optional (registry-only) | Not in report. |
Exact mapping from the JSON → table columns
Given the payload:
Direct mappings
artifact_name←zar.artifact_nameapplies_to_meid←zar.applies_to_meidcontent_hash←zar.content_hashschema_ref←zar.schema_refjob_id←context.job_idrun_id←context.run_idtenant_id←context.tenant_identity_id←context.entity_idgenerated_at←context.generated_atinitiated_by←context.initiated_bymode←context.modedataset_type←dataset.dataset_typedataset_hash←dataset.dataset_hashdataset_schema_ref←dataset.schema_refperiod_start←dataset.period.startperiod_end←dataset.period.endreporting_year←dataset.period.reporting_yearsource_systems←dataset.source_systemsrecord_counts←dataset.record_countsruleset_bundle_ref←rulesets.bundle_refruleset_resolved←rulesets.resolvedintegrity_status←summary.integrity_statusreporting_eligible←summary.reporting_eligiblepublish_allowed←summary.publish_allowedexception_ref←summary.exception_refcounts_pass←summary.counts.passcounts_warn←summary.counts.warncounts_fail←summary.counts.failfailed_rule_crids←summary.failed_rule_cridswarnings←summary.warningscheck_results←checks(full array)
Derived mappings (deterministic)
artifact_type← constantintegrity_check_reportscope_level← default dataset (until we explicitly add scope to the report schema)scope_object_ref←dataset.dataset_hash(or dataset artifact ref if you have it)ruleset_refs←rulesets.resolved[].ruleset_refruleset_crids←rulesets.resolved[].cridcheck_ids_failed←checks[].check_idwhereresult == "FAIL"check_ids_warn←checks[].check_idwhereresult == "WARN"top_failure_category← first check whereresult == "FAIL"then category else nullintegrity_passed←integrity_statusIN ("PASSED","PASSED_WITH_WARNINGS","PASSED_WITH_EXCEPTION")flags←empty []for now (unless/ until we add flags per check or summary)
integrity_id formula
Use a deterministic stable ID:
integrity_id =
"INT-" + tenant_id + "-" + entity_id + "-" +
scope_level + "-" +
slug(scope_object_ref) + "-" +
mode
Where slug(scope_object_ref) is a deterministic shortening function, e.g.:
- extract the sha256 tail if present and take first 12 chars
(
...@sha256:abcdef...→ abcdef123456) - else fallback to md5(
scope_object_ref) first 12 chars
Practical example
If:
tenant_id = TENANT-ACMEentity_id = ENTITY-ACME-DEscope.level = datasetscope.object_ref = ZAR:dataset:canonical_trial_balance:ENTITY-ACME-DE:2026M01@sha256:2222...mode = standard
Then:
INT-TENANT-ACME-ENTITY-ACME-DE-dataset-222222222222-standard
This is:
- stable across replays
- changes if
dataset_hashorbundle_refchanges (correct) - human-readable enough to debug
Update semantics (what changes a row)
Insert
On IntegrityEvaluated:
- insert new row (preferred), OR upsert by unique anchor
Update
On IntegrityExceptionApproved:
set exception_ref, exception_status='active'set integrity_status='PASSED_WITH_EXCEPTION'set reporting_eligible=true, publish_allowed=true, integrity_passed=truebump updated_at
On IntegrityRevoked:
set integrity_status='REVOKED'set reporting_eligible=false, publish_allowed=false, integrity_passed=falseset revocation_refbump updated_at
Implementation hint for the team (very practical)
Treat integrity_report_registry as a projection written by an event consumer that listens to:
IntegrityEvaluatedIntegrityExceptionApprovedIntegrityRevoked
This keeps it consistent with ZSSR and avoids ad hoc writes.
8. Rule Lifecycle Management (CMCB Integration)
ZRR integrates directly with the Change Management & Compatibility (CMCB) Framework.
Change Types
| Change Type | Description |
|---|---|
PATCH | Metadata adjustment (non-breaking) |
MINOR | Threshold adjustment |
MAJOR | Structural logic change |
DEPRECATION | Rule replacement required |
MIGRATION | Automatic remapping to new CRID |
MAJOR changes require:
- Deprecation window
- Canary execution simulation
- ZSSR impact classification
- AI risk re-evaluation (if applicable)
- Governance sign-off
All lifecycle changes must be logged in:
rule_change_log- DAL
- AI Governance Register (if high risk)
9. Formal CRID semantic versioning policy (PATCH/MINOR/MAJOR)
9.1. CRID Version Format
CRID ends with X_Y_Z where:
- X = MAJOR
- Y = MINOR
- Z = PATCH
Example:
ruleset.validation.finance.global.reconciliation.standard.critical.1_2_3
Definitions
- CRID version = governance-visible semantic version of the ruleset’s behavior
- ZAR hash = execution-identity of the exact ruleset content
- A given CRID version may map to multiple historical hashes (draft iterations), but only one approved + active hash per scope (global/tenant/entity) at a time.
9.2. Change Classifications
PATCH (Z increment)
Intent: Non-behavioral or behavior-neutral changes. Compatibility: Must remain fully backward compatible in output meaning.
Typical PATCH changes:
- Metadata-only changes:
owners,approved_by,created_at,changelogtext edits (if not altering meaning)
- Documentation / comments updates
- Reordering rules without changing precedence or results
- Tightening validations that only improve error messaging (no new rejects)
- Expanding explicit allowlists in a way that does not change classification of existing inputs (rare; see below)
PATCH must NOT:
- Change any computed numeric result given identical inputs
- Change pass/warn/fail outcomes for previously valid inputs
- Change precedence rules
- Change default assumptions used in computations
Required tests for PATCH:
- Schema validation
- Static lint checks
- “Golden replay” on canonical sample set: outputs must be identical byte-for-byte (except metadata timestamps)
MINOR (Y increment)
Intent: Backward-compatible behavior extension. Compatibility: Existing consumers remain valid; outputs may expand but not break contracts.
Typical MINOR changes:
- Adding new optional rule branches that apply only when new fields exist
- Expanding mappings to cover new accounts/dimensions without reclassifying existing mapped values
- Introducing new flags/warnings (non-blocking) for edge cases
- Adding new optional output fields (must be additive and documented)
- Increasing granularity in rollups (new grouping keys allowed) while keeping defaults unchanged
- New thresholds that only affect previously “unknown/unclassified” items (doesn’t change already-classified items)
MINOR must NOT:
- Change meaning of existing output fields
- Change default calculation assumptions (unless gated behind an explicit input param defaulted off)
- Change reject/blocking behavior for requests that previously passed validation
Required tests for MINOR:
- Schema validation + contract tests
- Golden replay:
- For baseline input set: existing outputs unchanged
- New scenarios: new behavior demonstrated
- Compatibility check:
min_schema_ref/max_schema_refmust remain compatible
MAJOR (X increment)
Intent: Breaking behavioral change. Compatibility: May change outputs, validations, or semantics; requires controlled migration.
Typical MAJOR changes:
- Any change that can alter numeric outputs for the same inputs
- e.g., PV discounting default changes (t0 vs spread)
- abatement cost formula changes
- Precedence changes
- tag detection precedence order changes
- classification precedence changes (attribute vs account)
- Threshold changes that flip pass/warn/fail outcomes
- Changing default inclusion rules (e.g., include R=0 projects in ratio rollups)
- Changing field semantics or units
- Removing fields or renaming outputs
- Changing interpretation of “reconciliation passed_with_warnings” behavior
- Any change requiring downstream migration work or re-baselining
Required tests for MAJOR:
- Schema validation + full contract suite
- Golden replay with documented diffs (expected deltas)
- Canary execution on representative tenant extracts (if available)
- Governance sign-off (CMCB approval)
- Migration notes required in changelog with:
- “what changed”
- “why”
- “what breaks”
- “how to migrate”
- “recommended rollout plan”
9.3. Decision Matrix
| Change | Patch | Minor | Major |
|---|---|---|---|
| Metadata changes only | ✅ | ||
| Doc/comment changes | ✅ | ||
| Add new optional output field | ✅ | ||
| Add new flag/warning only | ✅ | ||
| New mapping for previously UNKNOWN items only | ✅ | ||
| Change precedence order | ✅ | ||
| Change tolerance thresholds affecting pass/fail | ✅ | ||
| Change formula or default assumption | ✅ | ||
| Remove/rename output fields | ✅ | ||
| Tighten validation to reject previously accepted inputs | ✅ |
9.4. CRID ↔ Ruleset Artifact Governance Rules
- CRID version must increment according to the change class above.
- A CRID version is immutable once any approved hash exists for it.
- Draft iterations may update the hash under the same CRID version until approval.
- Once approved, further changes require:
- PATCH/MINOR/MAJOR bump (new CRID), and
supersedeslinking.
Required lifecycle linkage fields
supersedes: prior CRID or prior ZAR ruleset refdeprecated_by: next CRID once retired
9.5. Activation & Rollout Policy (CMCB-aligned)
Default rollout sequence
- Create draft ruleset (new hash)
- Validate (unit tests + replay)
- Approve
- Activate as tenant default (or entity override)
- Monitor via rule execution logs
- Deprecate prior CRID after defined window
Compatibility enforcement
ZAR must block activation if:
applies_to_meidmismatch- current engine schema outside
[min_schema_ref, max_schema_ref] - rule status not approved (unless sandbox mode)
B.5 Practical examples (so engineers don’t argue later)
Example 1 — Patch
“Fix typo in changelog and reorder tag_sources keys.”
→ ...1_0_0 → ...1_0_1
Example 2 — Minor
“Add new accepted project code pattern for a new client program; does not affect existing matches.”
→ ...1_0_0 → ...1_1_0
Example 3 — Major
“Change PV assumption from t0 to spread_evenly_over_year when timeline missing.”
→ ...1_1_0 → ...2_0_0
10. AI Governance Integration
If a rule:
- Uses AI inference,
- Impacts compliance decisions,
- Alters financial or regulatory outputs,
It must:
- Be registered in the AI Risk Register.
- Define trust threshold.
- Require human oversight if below threshold.
- Log model version used.
- Log dataset version used.
- Record explainability metadata.
ZRR ensures AI rules remain compliant with:
- EU AI Act
- CSRD traceability
- ESG audit requirements
11. Federation & Cross-ECO Interoperability
Rules may be:
- Federated
- Shared
- Version-mapped
- Trust-scored across ecosystems
ZRR supports:
- Rule lineage exchange
- CRID translation across partners
- Federation compatibility scoring
- Cross-ECO validation transparency
No federated rule may execute without CRID validation.
12. Governance Mandates
The following are mandatory:
- No validation logic may exist outside ZRR registration.
- No compliance rule may execute without CRID.
- No rule may bypass execution logging.
- No rule may be altered without lifecycle tracking.
- No AI-assisted rule may operate without trust metadata.
ZRR is a compliance-critical subsystem.
13. Strategic Outcome
ZRR establishes:
- Declarative ESG enforcement
- Versioned compliance logic
- Audit-ready validation chains
- Explainable AI integration
- Trust amplification across the ecosystem
- Future-proof regulatory adaptation
ZRR is not a feature.
It is the enforcement spine of ZAYAZ.
Precision Before Automation.
Integrity Above Velocity.
14. Ruleset Bundles as First-Class ZAR Artifacts
Rulesets define individual executable logic. Ruleset bundles define the deterministic composition of rulesets used by a job.
A bundle is a first-class, content-addressed ZAR artifact:
ZAR:ruleset_bundle:<bundle_name>@sha256:<hash>
Bundles are immutable and replay-safe. Any change to membership or ordering produces a new bundle hash.
14.1. Storage Model (Defaults and Overrides)
Bundle resolution is an orchestration responsibility (dispatcher/orchestrator), not a MICE responsibility.
ZAYAZ stores bundle pointers at three governance levels:
- Platform default (global)
Stored in
zar_platform_meid_defaults:
- one default bundle per MEID
- Tenant override (optional, approved)
Stored in
zar_tenant_meid_bundle_overrides:
- allows tenant-level policy customization per MEID
- Entity override (optional, approved)
Stored in
zar_entity_meid_bundle_overrides:
- highest priority override per entity per MEID
14.2. Orchestrator Resolution Algorithm (Normative)
At JobStarted, the orchestrator must resolve an effective bundle ref using:
Priority order (highest → lowest):
entity_bundle_override_ref(if exists and status=active)tenant_bundle_override_ref(if exists and status=active)global_default_bundle_ref(from platform defaults)
The orchestrator MUST validate:
- bundle
lifecycle.statusis approved or frozen bundle.applies_to_meid == requested MEID- schema compatibility (
compatibility.min_engine_schema_ref / max_engine_schema_ref) - (optional)
bundle.allow_tenant_overridesif resolution attempts tenant/entity overrides
The resolved bundle ref must be written into:
JobStartedevent payload- all downstream pipeline events
integrity_check_report.rulesets.bundle_refintegrity_report_registry.ruleset_bundle_ref- all output artifacts as provenance metadata
This guarantees deterministic replay and auditability.
14.3. Deterministic Execution Order
A ruleset bundle defines:
- the exact set of rulesets
- the ordered execution sequence
Engines must execute rulesets strictly in bundle.execution_order to ensure deterministic results.
14.4. Governance Outcome
With bundle refs recorded in job events and artifacts, ZAYAZ can:
- reproduce any historical run using the exact bundle hash
- prove which governance logic was applied
- prevent “silent configuration drift”
15 Ruleset Bundles
15.1. What Is a Ruleset Bundle (Formal Definition)
A Ruleset Bundle is a content-addressed ZAR artifact that defines:
The exact ordered set of rulesets to be used for a specific MEID and execution context.
It is not:
- A ruleset
- A rule
- A config file
It is:
- A deterministic composition object
15.2. ZAR Artifact Identity
ZAR Reference Format
ZAR:ruleset_bundle:<bundle_name>@sha256:<hash>
Example:
ZAR:ruleset_bundle:acct_crawler_default@sha256:3333...
This must be immutable.
15.3. Bundle YAML Structure (Canonical)
15.3.1. acct_crawler_default (Canonical example bundle YAMLs)
zar:
artifact_type: ruleset_bundle
artifact_name: acct_crawler_default
applies_to_meid: MEID_ACCT_CRAWLER
content_hash: null
schema_ref: "ZAR:schema:ruleset_bundle@v1"
lifecycle:
status: approved
owners: ["cto@viroway.com"]
approved_by: ["cto@viroway.com"]
created_at: 2026-02-19T00:00:00.000Z
supersedes: null
deprecated_by: null
changelog: "Initial approved default bundle for tagged accounting crawler."
compatibility:
min_engine_schema_ref: "ZAR:schema:canonical_trial_balance@v1"
max_engine_schema_ref: "ZAR:schema:canonical_trial_balance@v1"
allowed_modes: ["standard"]
bundle:
strict_mode: false
allow_tenant_overrides: true
labels: ["default", "finance", "acct_crawler"]
execution_order:
- acct_crawler_tag_detection
- acct_crawler_classification
- acct_crawler_reconciliation_policy
rulesets:
- name: acct_crawler_tag_detection
ref: "ZAR:ruleset:acct_crawler_tag_detection@sha256:aaaa"
required: true
notes: "Project tag detection (regex, segments, precedence)."
- name: acct_crawler_classification
ref: "ZAR:ruleset:acct_crawler_classification@sha256:bbbb"
required: true
notes: "CapEx/OpEx classification rules and UNKNOWN thresholds."
- name: acct_crawler_reconciliation_policy
ref: "ZAR:ruleset:acct_crawler_reconciliation_policy@sha256:cccc"
required: true
notes: "TB reconciliation tolerances and pass/warn/fail policy."
15.3.2. transition_roi_default bundle YAML
zar:
artifact_type: ruleset_bundle
artifact_name: transition_roi_default
applies_to_meid: MEID_CALC_TRANSITION_ROI
content_hash: null
schema_ref: "ZAR:schema:ruleset_bundle@v1"
lifecycle:
status: approved
owners: ["cto@viroway.com"]
approved_by: ["cto@viroway.com"]
created_at: 2026-02-19T00:00:00.000Z
supersedes: null
deprecated_by: null
changelog: "Initial approved default bundle for Transition ROI Calculator."
compatibility:
min_engine_schema_ref: "ZAR:schema:transition_roi_request@v1"
max_engine_schema_ref: "ZAR:schema:transition_roi_request@v1"
allowed_modes: ["standard"]
bundle:
strict_mode: false
allow_tenant_overrides: true
labels: ["default", "finance", "transition_roi"]
execution_order:
- transition_roi_calculation_policy
- transition_roi_rollup_policy
- transition_roi_validation_policy
- transition_roi_abatement_cost_policy
rulesets:
- name: transition_roi_calculation_policy
ref: "ZAR:ruleset:transition_roi_calculation_policy@sha256:1111"
required: true
notes: "PV timing assumption, discounting behavior, rounding policy."
- name: transition_roi_rollup_policy
ref: "ZAR:ruleset:transition_roi_rollup_policy@sha256:2222"
required: true
notes: "Allowed group_by keys, weighting, inclusion/exclusion rules."
- name: transition_roi_validation_policy
ref: "ZAR:ruleset:transition_roi_validation_policy@sha256:3333"
required: true
notes: "Reject vs warn mapping and standardized flags."
- name: transition_roi_abatement_cost_policy
ref: "ZAR:ruleset:transition_roi_abatement_cost_policy@sha256:4444"
required: false
notes: "Defines which benefits count and when abatement cost is computed."
15.4. Why Bundles Must Be Content-Addressed
Because:
If someone changes only one ruleset reference inside the bundle, the bundle hash changes.
That gives:
✔ Deterministic replay ✔ Immutable compliance configuration ✔ Clear governance delta ✔ No “hidden rule changes”
15.5. Activation Model Update
Modify orchestrator resolution:
Current:
global_default_ruleset_ref
tenant_ruleset_override_ref
entity_ruleset_override_ref
New:
global_default_bundle_ref
tenant_bundle_override_ref
entity_bundle_override_ref
Then:
- Resolve bundle
- Load ruleset refs from bundle
- Execute in defined order
- Persist
bundle_refin:
JobStartedIntegrityEvaluatedintegrity_check_reportintegrity_report_registry- all downstream artifacts
15.7. Bundle Governance Model
Bundles follow same lifecycle rules as rulesets:
| State | Meaning |
|---|---|
| draft | editable |
| approved | activatable |
| deprecated | cannot be newly activated |
| frozen | compliance-locked |
Advanced state:
compliance_locked(for regulatory filing year)
15.8. Why Bundles Are Strategically Powerful
Because we you can support:
15.8.1. Strict Compliance Mode
Example:
acct_crawler_esrs_strict_bundle
Differences:
- stricter reconciliation tolerance
- stricter unknown classification thresholds
strict_mode: true
One click → compliance mode.
15.8.2. Sandbox Mode
acct_crawler_sandbox_bundle
- enforcement downgraded to soft
- no blocking rules
Perfect for ERP onboarding.
15.8.3. Filing-Year Locking
For CSRD 2026 filing:
acct_crawler_esrs_2026_locked_bundle
Immutable.
Auditor can verify exact hash used.
15.9. Table: ruleset_bundle_registry
ruleset_bundle_registry
| Field | Type | Description |
|---|---|---|
bundle_id | UUID | PK |
bundle_name | TEXT | Human-readable name |
bundle_ref | TEXT | ZAR reference |
applies_to_meid | TEXT | Engine |
bundle_hash | TEXT | sha256 |
strict_mode | BOOLEAN | Strict mode flag |
allow_tenant_overrides | BOOLEAN | Governance flag |
execution_order | JSONB | Ordered ruleset names |
ruleset_refs | JSONB | Array of refs |
status | TEXT | draft / approved / deprecated / frozen |
created_at | TIMESTAMP | Created |
approved_at | TIMESTAMP | Approved |
supersedes_bundle_id | UUID | Optional lineage |
notes | TEXT | Governance notes |
Postgres DDL
CREATE TABLE IF NOT EXISTS ruleset_bundle_registry (
bundle_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
bundle_name TEXT NOT NULL,
bundle_ref TEXT NOT NULL UNIQUE,
applies_to_meid TEXT NOT NULL,
schema_ref TEXT NOT NULL,
bundle_hash TEXT NOT NULL,
strict_mode BOOLEAN NOT NULL DEFAULT false,
allow_tenant_overrides BOOLEAN NOT NULL DEFAULT true,
execution_order JSONB NOT NULL,
ruleset_refs JSONB NOT NULL,
status TEXT NOT NULL CHECK (
status IN ('draft', 'approved', 'deprecated', 'frozen')
),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
approved_at TIMESTAMPTZ NULL,
supersedes_bundle_id UUID NULL,
notes TEXT NULL,
CONSTRAINT fk_supersedes_bundle
FOREIGN KEY (supersedes_bundle_id)
REFERENCES ruleset_bundle_registry(bundle_id)
ON DELETE SET NULL
);
ALTER TABLE ruleset_bundle_registry
ADD CONSTRAINT chk_bundle_hash_format
CHECK (bundle_hash ~ '^sha256:[0-9a-f]{64}$');
CREATE INDEX IF NOT EXISTS idx_rsb_meid_status
ON ruleset_bundle_registry (applies_to_meid, status);
CREATE INDEX IF NOT EXISTS idx_rsb_bundle_hash
ON ruleset_bundle_registry (bundle_hash);
CREATE INDEX IF NOT EXISTS idx_rsb_execution_order_gin
ON ruleset_bundle_registry USING GIN (execution_order);
CREATE INDEX IF NOT EXISTS idx_rsb_ruleset_refs_gin
ON ruleset_bundle_registry USING GIN (ruleset_refs);
15.10. ZRR Integration
Ruleset bundles are:
- Not CRIDs
- Not rules
- Not signals
They are governance compositions.
ZRR references rulesets. Bundle registry references ZAR artifacts. Execution engine references bundle.
Clear separation.
15.11. Schema
[SchemaSnippet] Loading schema "zar/ruleset_bundle.v1.schema.json" on client...
15.12. What This Unlocks Later
With bundles in place, we can later:
- Add cross-engine compliance bundles
- Create “Assurance Bundle”
- Create “Limited Assurance Mode”
- Create “ESRS Simplified Mode”
- Create “Client-Specific Finance Policy Bundle”
Without touching MEID code.
15 Platform config table (global default bundles)
15.1. Table: zar_platform_meid_defaults (Global default per MEID)
| Name | Type | Description |
|---|---|---|
applies_to_meid | TEXT (PK) | MEID this policy applies to (e.g., MEID_ACCT_CRAWLER). |
global_default_bundle_ref | TEXT | ZAR ref: ZAR:ruleset_bundle:<name>@sha256:<hash> |
status | TEXT | active | deprecated (guardrail for emergency cutovers). |
created_at | TIMESTAMPTZ | Insert timestamp. |
updated_at | TIMESTAMPTZ | Update timestamp. |
notes | TEXT NULL | Optional governance notes. |
Postgres DDL
CREATE TABLE IF NOT EXISTS zar_platform_meid_defaults (
applies_to_meid TEXT PRIMARY KEY,
global_default_bundle_ref TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
notes TEXT NULL
);
CREATE INDEX IF NOT EXISTS idx_zpmd_status
ON zar_platform_meid_defaults(status);
15.2. Formalized defaults + overrides + orchestrator resolution (Tenants)
| Name | Type | Description |
|---|---|---|
tenant_id | TEXT (PK part) | Tenant identifier |
applies_to_meid | TEXT (PK part) | MEID |
tenant_bundle_override_ref | TEXT | Approved bundle ref |
status | TEXT | active | paused | deprecated |
approved_by | TEXT NULL | Email/actor |
approved_at | TIMESTAMPTZ NULL | Approval timestamp |
created_at | TIMESTAMPTZ | Insert timestamp |
updated_at | TIMESTAMPTZ | Update timestamp |
notes | TEXT NULL | Governance notes |
Postgres DDL
CREATE TABLE IF NOT EXISTS zar_tenant_meid_bundle_overrides (
tenant_id TEXT NOT NULL,
applies_to_meid TEXT NOT NULL,
tenant_bundle_override_ref TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
approved_by TEXT NULL,
approved_at TIMESTAMPTZ NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
notes TEXT NULL,
PRIMARY KEY (tenant_id, applies_to_meid)
);
CREATE INDEX IF NOT EXISTS idx_ztmbo_status
ON zar_tenant_meid_bundle_overrides(status);
15.3. Formalized defaults + overrides + orchestrator resolution (Entities)
| Name | Type | Description |
|---|---|---|
tenant_id | TEXT (PK part) | Tenant identifier |
entity_id | TEXT (PK part) | Entity identifier |
applies_to_meid | TEXT (PK part) | MEID |
entity_bundle_override_ref | TEXT | Approved bundle ref |
status | TEXT | active | paused | deprecated |
approved_by | TEXT NULL | Email/actor |
approved_at | TIMESTAMPTZ NULL | Approval timestamp |
created_at | TIMESTAMPTZ | Insert timestamp |
updated_at | TIMESTAMPTZ | Update timestamp |
notes | TEXT NULL | Governance notes |
Postgres DDL
CREATE TABLE IF NOT EXISTS zar_entity_meid_bundle_overrides (
tenant_id TEXT NOT NULL,
entity_id TEXT NOT NULL,
applies_to_meid TEXT NOT NULL,
entity_bundle_override_ref TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
approved_by TEXT NULL,
approved_at TIMESTAMPTZ NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
notes TEXT NULL,
PRIMARY KEY (tenant_id, entity_id, applies_to_meid)
);
CREATE INDEX IF NOT EXISTS idx_zembo_status
ON zar_entity_meid_bundle_overrides(status);
15.4. Orchestrator: Resolve effective ruleset bundle for a job (deterministic + auditable)
/**
* Orchestrator: Resolve effective ruleset bundle for a job (deterministic + auditable).
*
* Priority (highest → lowest):
* 1) entity override
* 2) tenant override
* 3) platform default
*
* Output:
* - resolved_bundle_ref
* - resolved_bundle_hash
* - resolved_ruleset_refs[] in deterministic execution order
* - persisted into JobStarted + all downstream events/artifacts
*/
type BundleStatus = "draft" | "approved" | "deprecated" | "frozen";
type ResolveMode = "standard" | "strict_compliance";
type BundleRegistryRow = {
bundle_id: string;
bundle_name: string;
bundle_ref: string; // ZAR:ruleset_bundle:...@sha256:...
applies_to_meid: string; // MEID_...
schema_ref: string; // ZAR:schema:ruleset_bundle@v1
bundle_hash: string; // sha256:<hash>
strict_mode: boolean;
allow_tenant_overrides: boolean;
execution_order: string[]; // ordered ruleset names
ruleset_refs: string[]; // array of ZAR:ruleset:...@sha256:...
status: BundleStatus;
created_at: string;
approved_at: string | null;
supersedes_bundle_id: string | null;
notes: string | null;
};
type DefaultRow = {
applies_to_meid: string;
global_default_bundle_ref: string;
status: "active" | "deprecated";
};
type TenantOverrideRow = {
tenant_id: string;
applies_to_meid: string;
tenant_bundle_override_ref: string;
status: "active" | "paused" | "deprecated";
approved_by: string | null;
approved_at: string | null;
};
type EntityOverrideRow = {
tenant_id: string;
entity_id: string;
applies_to_meid: string;
entity_bundle_override_ref: string;
status: "active" | "paused" | "deprecated";
approved_by: string | null;
approved_at: string | null;
};
type ResolutionDecision = {
resolved_bundle_ref: string;
resolved_bundle_hash: string;
resolved_bundle_id: string;
resolved_ruleset_refs: string[]; // already ordered
resolved_execution_order: string[];
strict_mode_effective: boolean;
provenance: {
source: "entity_override" | "tenant_override" | "platform_default";
entity_override_ref?: string;
tenant_override_ref?: string;
platform_default_ref: string;
applied_override_allowed: boolean;
requested_mode: ResolveMode;
};
};
/**
* DB access helpers (pseudocode signatures)
*/
async function getEntityOverride(
tenant_id: string,
entity_id: string,
meid: string
): Promise<EntityOverrideRow | null> { /* ... */ return null; }
async function getTenantOverride(
tenant_id: string,
meid: string
): Promise<TenantOverrideRow | null> { /* ... */ return null; }
async function getPlatformDefault(meid: string): Promise<DefaultRow | null> {
/* ... */ return null;
}
async function getBundleByRef(bundle_ref: string): Promise<BundleRegistryRow | null> {
/* ... */ return null;
}
/**
* Optional: schema compatibility check (engine input schema vs bundle compatibility)
* In v1 you can keep this as a ZAR-side verification, but the orchestrator must enforce it.
*/
function assertBundleCompatibleOrThrow(args: {
bundle: BundleRegistryRow;
applies_to_meid: string;
requested_mode: ResolveMode;
}): void {
const { bundle, applies_to_meid, requested_mode } = args;
if (bundle.applies_to_meid !== applies_to_meid) {
throw new Error(
`BUNDLE_MEID_MISMATCH: bundle.applies_to_meid=${bundle.applies_to_meid} != ${applies_to_meid}`
);
}
// lifecycle gate
if (!(bundle.status === "approved" || bundle.status === "frozen")) {
throw new Error(`BUNDLE_NOT_ACTIVATABLE: status=${bundle.status}`);
}
// strict_compliance mode requires strict_mode bundle OR explicit policy
if (requested_mode === "strict_compliance" && bundle.strict_mode !== true) {
// You can choose: either allow (and just run "standard"), or require strict_mode.
// Recommended for determinism: require strict_mode for strict_compliance.
throw new Error(`BUNDLE_NOT_STRICT: requested strict_compliance but bundle.strict_mode=false`);
}
// sanity check ordering
const eo = bundle.execution_order || [];
const refs = bundle.ruleset_refs || [];
if (eo.length === 0 || refs.length === 0) {
throw new Error("BUNDLE_INVALID: missing execution_order or ruleset_refs");
}
// (Optional) deeper check: enforce a naming map in the YAML to ensure eo names exist.
// Since registry stores only refs, we assume bundle authoring validated this.
}
/**
* Primary resolution function
*/
export async function resolveRulesetBundleForJob(args: {
tenant_id: string;
entity_id: string;
applies_to_meid: string;
requested_mode: ResolveMode; // standard | strict_compliance
}): Promise<ResolutionDecision> {
const { tenant_id, entity_id, applies_to_meid, requested_mode } = args;
// 0) platform default is mandatory fallback
const platformDefault = await getPlatformDefault(applies_to_meid);
if (!platformDefault || platformDefault.status !== "active") {
throw new Error(`NO_PLATFORM_DEFAULT_BUNDLE: meid=${applies_to_meid}`);
}
// 1) load overrides (if any)
const [entityOverride, tenantOverride] = await Promise.all([
getEntityOverride(tenant_id, entity_id, applies_to_meid),
getTenantOverride(tenant_id, applies_to_meid),
]);
// 2) candidate selection (priority)
// NOTE: we only consider overrides that are active and approved (approved_at present).
const entityCandidateRef =
entityOverride &&
entityOverride.status === "active" &&
!!entityOverride.approved_at
? entityOverride.entity_bundle_override_ref
: null;
const tenantCandidateRef =
tenantOverride &&
tenantOverride.status === "active" &&
!!tenantOverride.approved_at
? tenantOverride.tenant_bundle_override_ref
: null;
const platformRef = platformDefault.global_default_bundle_ref;
const candidateChain: Array<{ source: ResolutionDecision["provenance"]["source"]; ref: string }> =
entityCandidateRef
? [{ source: "entity_override", ref: entityCandidateRef }, { source: "tenant_override", ref: tenantCandidateRef || "" }, { source: "platform_default", ref: platformRef }]
: tenantCandidateRef
? [{ source: "tenant_override", ref: tenantCandidateRef }, { source: "platform_default", ref: platformRef }]
: [{ source: "platform_default", ref: platformRef }];
// 3) attempt resolution in order, with governance constraints
// If an override is not allowed by the selected bundle, fall back.
// Key: allow_tenant_overrides belongs to the *base bundle* we would otherwise use.
// Policy:
// - entity override allowed only if the platform default bundle allows overrides
// - tenant override allowed only if the platform default bundle allows overrides
// - (optional) if tenant override bundle itself sets allow_tenant_overrides=false, that prevents *entity* override layering.
//
// Practical v1 approach:
// - Resolve platform default first (for override permission)
// - If platform default disallows overrides, ignore tenant/entity overrides
const platformBundle = await getBundleByRef(platformRef);
if (!platformBundle) throw new Error(`PLATFORM_BUNDLE_NOT_FOUND: ${platformRef}`);
assertBundleCompatibleOrThrow({ bundle: platformBundle, applies_to_meid, requested_mode: "standard" });
const overridesPermitted = platformBundle.allow_tenant_overrides === true;
// helper to resolve a candidate ref into a validated bundle
async function tryResolveBundle(ref: string): Promise<BundleRegistryRow | null> {
if (!ref) return null;
const b = await getBundleByRef(ref);
if (!b) return null;
// For strict_compliance: require strict_mode bundle (enforced by assert)
assertBundleCompatibleOrThrow({ bundle: b, applies_to_meid, requested_mode });
return b;
}
let chosenSource: ResolutionDecision["provenance"]["source"] = "platform_default";
let chosenBundle: BundleRegistryRow | null = null;
// If overrides not permitted, force platform default
if (!overridesPermitted) {
chosenBundle = platformBundle;
chosenSource = "platform_default";
} else {
// Try entity first, then tenant, else platform
if (entityCandidateRef) {
const b = await tryResolveBundle(entityCandidateRef);
if (b) {
// if chosen tenant bundle disallows further overrides, that only matters when entity sits above tenant.
// We are already at entity level, so ok.
chosenBundle = b;
chosenSource = "entity_override";
}
}
if (!chosenBundle && tenantCandidateRef) {
const b = await tryResolveBundle(tenantCandidateRef);
if (b) {
chosenBundle = b;
chosenSource = "tenant_override";
}
}
if (!chosenBundle) {
// default (already validated)
chosenBundle = platformBundle;
chosenSource = "platform_default";
}
}
// 4) deterministic ordering (registry stores execution_order + ruleset_refs)
// Engine expects ordered refs. We assume bundle authoring validated 1:1 mapping.
// If you store only refs without names, treat execution_order as authoritative and
// keep ruleset_refs already ordered in registry. (Best: store ordered refs in registry.)
const resolvedExecutionOrder = chosenBundle.execution_order;
const resolvedRulesetRefs = chosenBundle.ruleset_refs;
if (resolvedRulesetRefs.length === 0) throw new Error("BUNDLE_EMPTY_RULESET_REFS");
// 5) strict mode effective:
// if requested strict_compliance, it must already be strict bundle.
const strictModeEffective =
requested_mode === "strict_compliance" ? true : chosenBundle.strict_mode === true;
return {
resolved_bundle_ref: chosenBundle.bundle_ref,
resolved_bundle_hash: chosenBundle.bundle_hash,
resolved_bundle_id: chosenBundle.bundle_id,
resolved_ruleset_refs: resolvedRulesetRefs,
resolved_execution_order: resolvedExecutionOrder,
strict_mode_effective: strictModeEffective,
provenance: {
source: chosenSource,
entity_override_ref: entityCandidateRef || undefined,
tenant_override_ref: tenantCandidateRef || undefined,
platform_default_ref: platformRef,
applied_override_allowed: overridesPermitted,
requested_mode,
},
};
}
/**
* Persist into JobStarted event (pseudocode)
*/
export function buildJobStartedEvent(args: {
job_id: string;
tenant_id: string;
entity_id: string;
applies_to_meid: string;
resolution: ResolutionDecision;
}) {
const { job_id, tenant_id, entity_id, applies_to_meid, resolution } = args;
return {
event_type: "JobStarted",
job_id,
tenant_id,
entity_id,
applies_to_meid,
generated_at: new Date().toISOString(),
rulesets: {
bundle_ref: resolution.resolved_bundle_ref,
bundle_hash: resolution.resolved_bundle_hash,
resolved_ruleset_refs: resolution.resolved_ruleset_refs,
execution_order: resolution.resolved_execution_order,
strict_mode_effective: resolution.strict_mode_effective,
resolution_provenance: resolution.provenance
}
};
}
- Approved gating: overrides should require approved_at IS NOT NULL + status='active'.
- Bundle activatable: bundle must be approved or frozen.
- Override permission: simplest v1 rule is: if platform default bundle has allow_tenant_overrides=false then ignore all overrides.
- Strict compliance: if requested_mode='strict_compliance', require bundle.strict_mode=true (or explicitly downgrade to standard, but then the job must record that downgrade).
Production-grade Postgres queries for the orchestrator resolution flow
(platform default → tenant override → entity override → bundle lookup)
Platform default bundle ref
-- Q0: Get platform default bundle ref for a MEID
SELECT
applies_to_meid,
global_default_bundle_ref,
status
FROM zar_platform_meid_defaults
WHERE applies_to_meid = $1
AND status = 'active';
Param
$1 = MEID_ACCT_CRAWLER(or other MEID)
Entity override (highest priority; optional)
-- Q1: Get entity override bundle ref (only active + approved overrides should be considered)
SELECT
tenant_id,
entity_id,
applies_to_meid,
entity_bundle_override_ref,
status,
approved_by,
approved_at
FROM zar_entity_meid_bundle_overrides
WHERE tenant_id = $1
AND entity_id = $2
AND applies_to_meid = $3
AND status = 'active'
AND approved_at IS NOT NULL;
Params
$1 = tenant_id$2 = entity_id$3 = applies_to_meid(MEID)
Tenant override (highest priority; optional)
-- Q2: Get tenant override bundle ref (only active + approved)
SELECT
tenant_id,
applies_to_meid,
tenant_bundle_override_ref,
status,
approved_by,
approved_at
FROM zar_tenant_meid_bundle_overrides
WHERE tenant_id = $1
AND applies_to_meid = $2
AND status = 'active'
AND approved_at IS NOT NULL;
Params
$1 = tenant_id$2 = applies_to_meid(MEID)
Bundle lookup by ref (for any candidate ref)
-- Q3: Resolve bundle registry row by bundle_ref
SELECT
bundle_id,
bundle_name,
bundle_ref,
applies_to_meid,
schema_ref,
bundle_hash,
strict_mode,
allow_tenant_overrides,
execution_order,
ruleset_refs,
status,
created_at,
approved_at,
supersedes_bundle_id,
notes
FROM ruleset_bundle_registry
WHERE bundle_ref = $1;
Param
$1 = candidate bundle_ref
Single-shot “best candidate ref” resolver (optional optimization)
This query returns one ref: entity override if present, else tenant override, else platform default.
-- Q4: Resolve best candidate bundle ref for a job (ref only)
WITH platform AS (
SELECT global_default_bundle_ref AS ref
FROM zar_platform_meid_defaults
WHERE applies_to_meid = $3 AND status = 'active'
),
entity_override AS (
SELECT entity_bundle_override_ref AS ref
FROM zar_entity_meid_bundle_overrides
WHERE tenant_id = $1
AND entity_id = $2
AND applies_to_meid = $3
AND status = 'active'
AND approved_at IS NOT NULL
LIMIT 1
),
tenant_override AS (
SELECT tenant_bundle_override_ref AS ref
FROM zar_tenant_meid_bundle_overrides
WHERE tenant_id = $1
AND applies_to_meid = $3
AND status = 'active'
AND approved_at IS NOT NULL
LIMIT 1
)
SELECT ref FROM entity_override
UNION ALL
SELECT ref FROM tenant_override
UNION ALL
SELECT ref FROM platform
LIMIT 1;
Params
$1 tenant_id$2 entity_id$3 applies_to_meid
Enforce “platform default disallows overrides”
Because allow_tenant_overrides lives in the bundle, we need one extra step:
- Fetch platform default ref (Q0)
- Fetch platform bundle row (Q3)
- If
allow_tenant_overrides = false→ ignore Q1/Q2 entirely
A single SQL query that bakes this in:
-- Q5: Resolve effective bundle_ref with override permission enforced by platform default bundle
WITH platform_ref AS (
SELECT global_default_bundle_ref AS ref
FROM zar_platform_meid_defaults
WHERE applies_to_meid = $3 AND status = 'active'
),
platform_bundle AS (
SELECT
r.bundle_ref AS ref,
r.allow_tenant_overrides AS allow_overrides
FROM ruleset_bundle_registry r
JOIN platform_ref p ON p.ref = r.bundle_ref
WHERE r.status IN ('approved', 'frozen')
),
entity_override AS (
SELECT e.entity_bundle_override_ref AS ref
FROM zar_entity_meid_bundle_overrides e
JOIN platform_bundle pb ON pb.allow_overrides = true
WHERE e.tenant_id = $1
AND e.entity_id = $2
AND e.applies_to_meid = $3
AND e.status = 'active'
AND e.approved_at IS NOT NULL
LIMIT 1
),
tenant_override AS (
SELECT t.tenant_bundle_override_ref AS ref
FROM zar_tenant_meid_bundle_overrides t
JOIN platform_bundle pb ON pb.allow_overrides = true
WHERE t.tenant_id = $1
AND t.applies_to_meid = $3
AND t.status = 'active'
AND t.approved_at IS NOT NULL
LIMIT 1
)
SELECT ref FROM entity_override
UNION ALL
SELECT ref FROM tenant_override
UNION ALL
SELECT ref FROM platform_bundle
LIMIT 1;
This returns the correct effective ref while respecting “no overrides” policy.
Resolve full bundle row in one query (end-to-end)
Returns the bundle row directly (not just the ref):
-- Q6: End-to-end resolution returning the selected bundle row
WITH platform_ref AS (
SELECT global_default_bundle_ref AS ref
FROM zar_platform_meid_defaults
WHERE applies_to_meid = $3 AND status = 'active'
),
platform_bundle AS (
SELECT r.*
FROM ruleset_bundle_registry r
JOIN platform_ref p ON p.ref = r.bundle_ref
WHERE r.status IN ('approved', 'frozen')
AND ($4 <> 'strict_compliance' OR r.strict_mode = true)
),
candidate_ref AS (
SELECT e.entity_bundle_override_ref AS ref, 1 AS prio
FROM zar_entity_meid_bundle_overrides e
JOIN platform_bundle pb ON pb.allow_tenant_overrides = true
WHERE e.tenant_id = $1
AND e.entity_id = $2
AND e.applies_to_meid = $3
AND e.status = 'active'
AND e.approved_at IS NOT NULL
UNION ALL
SELECT t.tenant_bundle_override_ref AS ref, 2 AS prio
FROM zar_tenant_meid_bundle_overrides t
JOIN platform_bundle pb ON pb.allow_tenant_overrides = true
WHERE t.tenant_id = $1
AND t.applies_to_meid = $3
AND t.status = 'active'
AND t.approved_at IS NOT NULL
UNION ALL
SELECT pb.bundle_ref AS ref, 3 AS prio
FROM platform_bundle pb
),
chosen AS (
SELECT ref
FROM candidate_ref
ORDER BY prio
LIMIT 1
)
SELECT
r.bundle_id,
r.bundle_name,
r.bundle_ref,
r.applies_to_meid,
r.schema_ref,
r.bundle_hash,
r.strict_mode,
r.allow_tenant_overrides,
r.execution_order,
r.ruleset_refs,
r.status,
r.created_at,
r.approved_at,
r.supersedes_bundle_id,
r.notes
FROM ruleset_bundle_registry r
JOIN chosen c ON c.ref = r.bundle_ref;
WHERE ($4 <> 'strict_compliance' OR r.strict_mode = true);
Param
$4 = requested_mode('standard' | 'strict_compliance')
APPENDIX A - ZAR Validator Checklist — ruleset_bundle Registration (v1)
This ZAR ruleset_bundle validator function checklist written to be:
- Engineer-friendly (clear steps, return codes, inputs/outputs)
- CODEX App–ready (each step is an atomic “automation action” with deterministic success/fail + structured output). It can be used as the blueprint for a CODEX App workflow.
A.0. Function signature (contract)
Function
validate_and_register_ruleset_bundle(bundle_doc, context) -> result
Inputs
bundle_doc: parsed YAML/JSON object (ruleset_bundle.v1)context(object):requested_meid(string) — MEID being registered forrequested_status(string|null) — draft/approved/frozen/deprecated (optional if in doc)env(string) — dev|staging|prodactor(string) — user/system identitynow(ISO datetime)zar_lookup(function) — resolves refs to artifactszar_registry(function) — writes registry recordhash_fn(function) — canonical hash calculator
Outputs
result:ok(boolean)bundle_ref(string|null)bundle_hash(string|null)ordered_ruleset_refs(array)warnings(array of objects)errors(array of objects)normalized_doc(object) — canonicalized payload used for hashing
Error object format
{ "code": "BUNDLE_SCHEMA_INVALID", "path": "bundle.rulesets[0].ref", "message": "..." }
A.1. Parse + basic input checks
Step 1.1 — Parse input
- Accept YAML or JSON.
- Reject if parse fails.
Fail codes
BUNDLE_PARSE_ERROR
Step 1.2 — Enforce top-level shape exists
- Must contain:
zar,lifecycle,compatibility,bundle.
Fail codes
BUNDLE_MISSING_REQUIRED_FIELD
A.2. JSON Schema validation (hard gate)
Step 2.1 — Validate against JSON Schema
- Validate
bundle_docagainstZAR:schema:ruleset_bundle@v1. - Reject on any schema violation.
Fail codes
BUNDLE_SCHEMA_INVALID
Notes (CODEX)
- Keep the schema validator output; map each issue to
{code, path, message}.
A.3. Canonicalization (deterministic hashing)
Step 3.1 — Normalize string fields
- Trim leading/trailing whitespace on all string fields (deep).
- Normalize line endings in
lifecycle.changelog(if present).
Warn codes
BUNDLE_NORMALIZED_WHITESPACE(optional warning)
Step 3.2 — Normalize arrays (order rules)
Sort lexicographically
lifecycle.ownerslifecycle.approved_bybundle.labels
Do NOT reorder
bundle.execution_order(semantic)bundle.rulesets(author order ok)
Step 3.3 — Remove non-hash fields
Exclude from hashing:
zar.content_hash(server assigned)- Any registry-only metadata (if present)
Fail codes
BUNDLE_CANONICALIZATION_FAILED(only if your canonicalizer errors)
Output
normalized_doc
A.4. MEID and identity checks
Step 4.1 — MEID match
- Enforce:
bundle_doc.zar.applies_to_meid == context.requested_meid
Fail codes
BUNDLE_MEID_MISMATCH
Step 4.2 — Artifact name constraints (semantic)
- Enforce uniqueness of
zar.artifact_namescoped to: - recommended: (
artifact_type,applies_to_meid,artifact_name) - If collision exists and hash differs → reject.
Fail codes
BUNDLE_NAME_CONFLICT
A.5. Execution order integrity (critical)
Let:
EO = bundle.execution_orderRS = bundle.rulesetsRSN = set(rs.name for rs in RS)REQ = set(rs.name for rs in RS if rs.required != false)
Step 5.1 — All execution_order names exist
- Enforce: every name in EO must exist in RSN.
Fail codes
BUNDLE_EXECUTION_ORDER_UNKNOWN_NAME
Step 5.2 — All required rulesets are ordered
- Enforce: every name in REQ must appear in EO.
Fail codes
BUNDLE_REQUIRED_RULESET_NOT_ORDERED
Step 5.3 — Compute ordered_ruleset_refs
Build:
ordered_ruleset_refs = [ ruleset.ref where ruleset.name == EO[i] ]
Fail codes
BUNDLE_EXECUTION_ORDER_RESOLUTION_FAILED(should not happen if steps above passed)
A.6. Reference resolution checks (rulesets exist + correct type)
Policy depends on lifecycle.status:
draft: allow unresolved refs only if required=falseapproved|frozen: all refs must resolve
For each ruleset in bundle.rulesets[]:
Step 6.1 — Validate ref format
- Must match
ZAR:ruleset:<name>@sha256:<hash> - In prod: require 64 hex
- In dev: may allow shorter (but warn)
Fail codes
BUNDLE_RULESET_REF_INVALIDBUNDLE_RULESET_REF_HASH_LENGTH_INVALID(prod)
Warn codes
BUNDLE_RULESET_REF_SHORT_HASH_DEV
Step 6.2 — Resolve ruleset ref in ZAR
artifact = zar_lookup(ref)- Must exist if required or status is approved/frozen.
Fail codes
BUNDLE_RULESET_REF_NOT_FOUND
Step 6.3 — Enforce resolved artifact type = ruleset
artifact.zar.artifact_type == "ruleset"
Fail codes
BUNDLE_RULESET_REF_WRONG_TYPE
Step 6.4 — Enforce MEID match
artifact.zar.applies_to_meid == bundle.zar.applies_to_meid
Fail codes
BUNDLE_RULESET_MEID_MISMATCH
Step 6.5 — Enforce ruleset lifecycle status
- If bundle is approved|frozen:
- ruleset must not be deprecated
- ruleset must be approved or frozen (recommended)
Fail codes
BUNDLE_RULESET_DEPRECATEDBUNDLE_RULESET_NOT_APPROVED
A.7. Compatibility checks (approved/frozen hard gate)
Step 7.1 — Bundle compatibility range sanity
- Ensure
min_engine_schema_refandmax_engine_schema_refare same schema family - Ensure
min <= max(you’ll compare version numbers)
Fail codes
BUNDLE_COMPATIBILITY_RANGE_INVALID
Step 7.2 — Ruleset compatibility overlap
For each resolved ruleset:
- Require overlap between:
- bundle range:
[min_bundle, max_bundle] - ruleset range:
[min_ruleset, max_ruleset]
Overlap condition:
min_ruleset <= max_bundle AND max_ruleset >= min_bundle
Fail codes
BUNDLE_RULESET_COMPATIBILITY_VIOLATION
Step 7.3 — Strict mode consistency
If compatibility.allowed_modes contains strict_compliance:
- Require
bundle.bundle.strict_mode == true
Fail codes
BUNDLE_STRICT_MODE_INCONSISTENT
A.8. Lineage checks (supersedes/deprecated_by)
Step 8.1 — supersedes exists and matches MEID
If lifecycle.supersedes != null:
- ref must resolve
- must be a
ruleset_bundle - must have same
applies_to_meid
Fail codes
BUNDLE_LINEAGE_REF_NOT_FOUNDBUNDLE_LINEAGE_WRONG_TYPEBUNDLE_LINEAGE_MEID_MISMATCH
Step 8.2 — cycle detection
- Ensure no cycles in supersedes chain.
Fail codes
BUNDLE_LINEAGE_CYCLE_DETECTED
Step 8.3 — deprecated_by points to valid bundle
If lifecycle.deprecated_by != null:
- must resolve, same MEID, and be approved/frozen
Fail codes
BUNDLE_DEPRECATED_BY_INVALID
A.9. Hashing + ref generation
Step 9.1 — Compute content hash
bundle_hash = sha256(canonical_json(normalized_doc))- Output as
sha256:<64hex>
Fail codes
BUNDLE_HASH_COMPUTE_FAILED
Step 9.2 — Validate provided content_hash (if present)
If zar.content_hash provided:
- must equal computed hash
Fail codes
BUNDLE_HASH_MISMATCH
Step 9.3 — Generate canonical ZAR ref
bundle_ref = "ZAR:ruleset_bundle:<artifact_name>@<bundle_hash>"
A.10. Registration decision rules
Step 10.1 — Status enforcement
- If
lifecycle.statusisapproved|frozen: approved_bymust be non-emptyapproved_atmust exist (if you store it here or at registry level)- all required refs must resolve
Fail codes
BUNDLE_APPROVAL_MISSINGBUNDLE_APPROVAL_INCOMPLETE
Step 10.2 — Registry uniqueness
- If
bundle_refalready exists → idempotent success - If (
artifact_type,artifact_name,applies_to_meid) exists with different hash: - allow only if status is draft and old is deprecated (policy)
- else reject
Fail codes
BUNDLE_REF_CONFLICTBUNDLE_NAME_HASH_CONFLICT
A.11. Registry write (side effect)
Step 11.1 — Write to ruleset_bundle_registry
Persist:
bundle_id(uuid)bundle_name(artifact_name)bundle_refapplies_to_meidschema_refbundle_hashstrict_modeallow_tenant_overridesexecution_order(JSONB)ruleset_refs(JSONB) ← storeordered_ruleset_refs(recommended)statuscreated_at/approved_atsupersedes_bundle_idnotes
Fail codes
BUNDLE_REGISTRY_WRITE_FAILED
''Step 11.2 — Return result''
Return:
ok=truebundle_ref,bundle_hashordered_ruleset_refsnormalized_doc- warnings/errors arrays
A.12. CODEX App Automation Steps (suggested task graph)
This is the “automation-friendly” view (each step is a job node):
ParseDocumentValidateJsonSchemaCanonicalizePayloadValidateMeidAndNameValidateExecutionOrderResolveRulesetRefsValidateCompatibilityValidateLineageComputeHashAndRefEnforceApprovalPolicyUpsertRegistryRowEmitRegistrationEvent(optional)
RulesetBundleRegistered(bundle_ref, hash, actor, time)
Each step outputs:
step_okstep_errors[]step_warnings[]- plus step-specific artifacts (normalized payload, ordered refs, resolved metadata)
Machine-readable YAML Recipe
Below is a machine-readable YAML recipe for the CODEX App that validates and registers a ruleset_bundle artifact in ZAR.
It is structured as:
- deterministic steps
- explicit inputs/outputs
- formal error codes
- clear side-effects
- suitable for automation pipelines
This can be treated as:
codex_app:
zar.ruleset_bundle.register.v1
codex_app:
id: zar.ruleset_bundle.register.v1
name: ZAR Ruleset Bundle Registration
version: 1.0.0
artifact_type: ruleset_bundle
description: >
Validates, canonicalizes, resolves, hashes, and registers a ruleset_bundle
artifact in ZAR. Enforces schema, compatibility, lineage, and governance rules.
inputs:
bundle_doc:
type: object
description: Parsed YAML/JSON ruleset_bundle document.
context:
type: object
required:
- requested_meid
- env
- actor
- now
properties:
requested_meid:
type: string
env:
type: string
enum: [dev, staging, prod]
actor:
type: string
now:
type: string
format: date-time
outputs:
ok:
type: boolean
bundle_ref:
type: string
nullable: true
bundle_hash:
type: string
nullable: true
ordered_ruleset_refs:
type: array
items: string
normalized_doc:
type: object
warnings:
type: array
errors:
type: array
steps:
- id: parse_document
action: validate_input_object
description: Ensure bundle_doc is present and structured.
fail_codes:
- BUNDLE_PARSE_ERROR
- BUNDLE_MISSING_REQUIRED_FIELD
- id: validate_schema
action: json_schema_validate
schema_ref: ZAR:schema:ruleset_bundle@v1
description: Validate bundle_doc against JSON schema.
fail_codes:
- BUNDLE_SCHEMA_INVALID
- id: canonicalize_payload
action: canonicalize_object
rules:
trim_all_strings: true
sort_arrays:
- lifecycle.owners
- lifecycle.approved_by
- bundle.labels
exclude_from_hash:
- zar.content_hash
outputs:
normalized_doc: canonical_object
fail_codes:
- BUNDLE_CANONICALIZATION_FAILED
- id: validate_meid
action: assert_equal
left: bundle_doc.zar.applies_to_meid
right: context.requested_meid
fail_codes:
- BUNDLE_MEID_MISMATCH
- id: validate_execution_order
action: validate_execution_mapping
inputs:
execution_order: bundle_doc.bundle.execution_order
rulesets: bundle_doc.bundle.rulesets
checks:
- all_execution_names_exist
- all_required_rulesets_in_execution_order
- no_duplicate_execution_entries
outputs:
ordered_ruleset_refs: resolved_refs_in_execution_order
fail_codes:
- BUNDLE_EXECUTION_ORDER_UNKNOWN_NAME
- BUNDLE_REQUIRED_RULESET_NOT_ORDERED
- BUNDLE_EXECUTION_ORDER_DUPLICATE
- id: validate_ruleset_refs
action: resolve_artifact_refs
for_each: bundle_doc.bundle.rulesets
checks:
- ref_format_valid
- resolve_exists_if_required_or_status_approved
- artifact_type_is_ruleset
- applies_to_meid_matches_bundle
- not_deprecated_if_bundle_approved
fail_codes:
- BUNDLE_RULESET_REF_INVALID
- BUNDLE_RULESET_REF_NOT_FOUND
- BUNDLE_RULESET_REF_WRONG_TYPE
- BUNDLE_RULESET_MEID_MISMATCH
- BUNDLE_RULESET_DEPRECATED
- id: validate_compatibility
condition: bundle_doc.lifecycle.status in [approved, frozen]
action: validate_compatibility_ranges
checks:
- bundle_range_valid
- ruleset_range_overlap
- strict_mode_consistency
fail_codes:
- BUNDLE_COMPATIBILITY_RANGE_INVALID
- BUNDLE_RULESET_COMPATIBILITY_VIOLATION
- BUNDLE_STRICT_MODE_INCONSISTENT
- id: validate_lineage
action: validate_lineage_references
checks:
- supersedes_exists_if_present
- supersedes_same_meid
- no_lineage_cycles
- deprecated_by_valid_if_present
fail_codes:
- BUNDLE_LINEAGE_REF_NOT_FOUND
- BUNDLE_LINEAGE_CYCLE_DETECTED
- BUNDLE_LINEAGE_MEID_MISMATCH
- id: compute_hash
action: compute_sha256
input: normalized_doc
output: bundle_hash
fail_codes:
- BUNDLE_HASH_COMPUTE_FAILED
- id: validate_hash_if_provided
condition: bundle_doc.zar.content_hash != null
action: assert_equal
left: bundle_doc.zar.content_hash
right: bundle_hash
fail_codes:
- BUNDLE_HASH_MISMATCH
- id: generate_bundle_ref
action: format_string
template: "ZAR:ruleset_bundle:{artifact_name}@{bundle_hash}"
inputs:
artifact_name: bundle_doc.zar.artifact_name
bundle_hash: bundle_hash
output: bundle_ref
- id: validate_approval_policy
condition: bundle_doc.lifecycle.status in [approved, frozen]
action: validate_approval_fields
required_fields:
- lifecycle.approved_by
fail_codes:
- BUNDLE_APPROVAL_MISSING
- id: check_registry_uniqueness
action: registry_lookup
checks:
- no_name_hash_conflict
fail_codes:
- BUNDLE_NAME_HASH_CONFLICT
- BUNDLE_REF_CONFLICT
- id: upsert_registry_row
action: registry_upsert
table: ruleset_bundle_registry
mapping:
bundle_name: bundle_doc.zar.artifact_name
bundle_ref: bundle_ref
applies_to_meid: bundle_doc.zar.applies_to_meid
schema_ref: bundle_doc.zar.schema_ref
bundle_hash: bundle_hash
strict_mode: bundle_doc.bundle.strict_mode
allow_tenant_overrides: bundle_doc.bundle.allow_tenant_overrides
execution_order: bundle_doc.bundle.execution_order
ruleset_refs: ordered_ruleset_refs
status: bundle_doc.lifecycle.status
created_at: context.now
fail_codes:
- BUNDLE_REGISTRY_WRITE_FAILED
- id: emit_event
action: emit_domain_event
event_type: RulesetBundleRegistered
payload:
bundle_ref: bundle_ref
bundle_hash: bundle_hash
actor: context.actor
timestamp: context.now
success_condition: no_errors_present
error_model:
structure:
code: string
path: string
message: string
warning_model:
structure:
code: string
message: string