Skip to main content
Jira progress: loading…

SSSR-URL

Asset/URL Link Registry

(Addendum to SSSR – Smart Searchable Signal Registry)

1. Introduction

The Smart Searchable Signal Registry (SSSR) is the authoritative, cross-module control plane for all semantic references in ZAYAZ. While its core purpose is to govern data signals (metrics, codes, formulas), the same principles apply to digital assets — such as hazard pictograms, logos, templates, documents and other URL-addressable resources.

The Asset/URL Link extension of SSSR centralizes the definition, classification, and resolution of all external and internal file references. Instead of embedding brittle, hard-coded URLs in data tables, ZAYAZ stores semantic asset identifiers (sssr:asset.<class>.<asset_id>[.<ext>]) which are dynamically resolved into valid URLs at runtime.

This approach delivers four strategic benefits:

  1. Durability – Asset references remain valid even if file locations, CDN providers, or folder structures change.
  2. Governance & Auditability – Every asset is registered with metadata, versioning rules, usage scope, and compliance tags, ensuring traceability across all consuming modules.
  3. Dynamic Optimization – The resolver can select the most appropriate asset variant (e.g., SVG for web, CMYK TIF for print) based on runtime context, without changing stored references.
  4. Cross-Module Consistency – All engines (FOGE, EXPORT, DAIM, APIs) resolve assets through the same policy layer, guaranteeing uniform output.

In practice, the asset subsystem introduces two dedicated registry tables alongside the core SSSR:

  • sssr_asset_class_registry – Defines asset classes (e.g., hazard_pictograms), their path templates, default folders, fallback order, and resolution policies.
  • sssr_assets_registry – Defines individual assets, their available variants, template overrides, and the source table/column where they are referenced.

Together with sssr_global_config (for system-wide defaults like cdn_base), these tables enable a dedicated assets-URL-resolver service to translate [SSSR_REF: …] markers into correct, policy-compliant URLs in real time.

This design ensures that asset linking in ZAYAZ is as robust, auditable, and future-proof as its core data signal referencing, while also enabling direct integration into internal modules, partner APIs, and client-facing endpoints.


Here’s why:

  1. Traceable Asset Management
  • If we reference [SSSR_REF: sssr:hazard_pictograms.gif_url @ HZP-0003] (example), we can later change the storage location, CDN provider, or file format without breaking any references.
  • The SSSR keeps the logical link (“hazard pictogram – GIF variant”) separate from the physical URL, so only the registry entry needs updating.
  1. Multi-Format Routing
  • A single pictogram may exist in GIF, EPS, TIFF, SVG, etc.
  • By registering all variants in the signal metadata (symbol_url_gif, symbol_url_eps, symbol_url_label_tiff), we can let engines (FOGE, DAIM, exporters) pick the right one for the output context (web dashboard = GIF/SVG, print = EPS/TIFF) without hardcoding it.
  1. Compliance & Auditability
  • As an example, some hazard pictograms are legally regulated (GHS, CLP) — linking them via SSSR ensures we can log which exact official asset was served and from which source version. This is important for traceability in SDS or chemical safety reports.
  1. CDN & Localization Support
  • The SSSR entry can route to a different URL based on:
  • Geo (EU/US CDNs)
  • Language (localized hazard labels)
  • Theme (dark/light UI)
  • Direct linking in the symbol_url column skips all that intelligence.
  1. Future-proofing for Theming/Branding
  • If Viroway or a client wants custom hazard icon styling, only the SSSR entry changes.
  • Direct links in our tables would require bulk updates and risk breaking historical data.

Implementation

  • In code_registry.symbol_url, store the SSSR_REF pointing to the canonical pictogram entry (e.g., GIF version for default use).
  • Keep the hazard_pictograms table as the asset source table in SSSR with columns for each format.
  • Let FOGE or your export logic resolve the right format at runtime via preferred_format or output_context.

3.1. SSSR Signal Registry

The signal registry (signal_registry) provides a universal way to reference any row in any table.

Each signal_id has three parts:

  1. "sssr:" (prefix marking it as a system reference)
  2. The source table
  3. The source column

The table and column are separated by a dot ".".

Example:

sssr:label_elements.label_element_id

Here:

  • label_elements = table name
  • label_element_id = column name

To reference a specific row, append " @ <row_id>". Example:

sssr:label_elements.label_element_id @ LEID-0001

Finally, wrap it with [SSSR_REF: … ] to create the full inline reference:

[SSSR_REF: sssr:label_elements.label_element_id @ LEID-0001]

Rules:

  • Always put a space after "SSSR_REF:".
  • Always put spaces around "@".
  • All links in all tables (except inside the signal registry itself) must use this format.

3.2. SSSR Asset Registry

Assets are managed in a dedicated registry: sssr_asset_registry.

Assets are different from signals because they are independent objects (files, images, pictograms, logos, etc.) that are referenced by many rows across the system.


3.2.1. Basic asset reference**

To link to an asset, the format is similar, but with "asset." after “sssr:":

sssr:asset.hazard_pictograms.GHS01.gif

  • asset = registry type
  • hazard_pictograms = asset class (defined in the sssr_asset_class_registry table)
  • GHS01.gif = the asset code + file extension

Since each asset already has its own row in sssr_asset_registry, we do not append a row reference (@ ROWID) in the basic form.


3.2.2. Extended Inline Form

However, when we want to track provenance — i.e. which tables/columns/rows are linking to an asset — we use the extended inline form:

[SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif @ sssr:label_elements.symbol_sssr @ LEID-0029]

This tells us:

  • The asset = hazard_pictograms.GHS01.gif
  • The source column = label_elements.symbol_sssr
  • The source row = LEID-0029

The extended form is essential for auditing, AI self-healing, and exports, because it embeds full provenance directly in the reference.

Summary:

  • Signals (sssr:<table>.<column> @ row_id) = references to data rows.
  • Assets (sssr:asset.<class>.<asset_code>) = references to files/resources.
  • Extended inline form = adds source provenance (@ table.column @ row_id) to assets (and optionally signals) for auditing and portability.

In tables: store the compact string form:

[SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif @ sssr:code_registry.code_type @ CR-00213]

Everything before the first @ is the target (what to resolve as a URL). The @ sssr:table.column @ row_id part is provenance (only used for export/ audit/ feed AI). On export / in APIs: convert to JSON on the fly. This gives a human-readable cells, a single canonical string format..

Precise grammar (so it’s easy to parse)!

EBNF:

SSSR_REF  := "[SSSR_REF: " TARGET ( " @ " SRC_REG ( " @ " ROW_ID )? )? "]"
TARGET := "sssr:" 1*( CHAR - WHITESPACE - "]" )
SRC_REG := "sssr:" 1*( CHAR - WHITESPACE - "@" - "]" )
ROW_ID := 1*( CHAR - "]" )

Rules:

  • Exactly one space after the colon and around each @.
  • No trailing spaces.
  • TARGET MUST start with sssr: and contain no ].
  • SRC_REG MUST be sssr:<table>.<column>.
  • ROW_ID should be the row’s PK (e.g., CR-00213).

Examples:

[SSSR_REF: sssr:asset.hazard_pictograms.GHS01]
[SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif]
[SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif @ sssr:code_registry.code_type @ CR-00213]

Converter → JSON (TypeScript)

json-converter.tsGitHub ↗
type Enriched =
| { target: string; source?: { registry: string; row_id?: string } };

export function parseSSSRRef(ref: string): Enriched | null {
const m = ref.match(/^\[SSSR_REF:\s*(.+?)\s*(?:@\s*(sssr:[\w.]+)\s*(?:@\s*([^\]]+))?)?\]$/);
if (!m) return null;
const [, target, srcReg, rowId] = m;
const out: Enriched = { target: target.trim() };
if (srcReg) out.source = { registry: srcReg.trim(), ...(rowId ? { row_id: rowId.trim() } : {}) };
return out;
}

Converter → JSON (Postgres SQL)

json-converter-pg.sqlGitHub ↗
CREATE OR REPLACE FUNCTION sssr_to_json(ref text)
RETURNS jsonb LANGUAGE plpgsql IMMUTABLE AS $$
DECLARE
m text[];
BEGIN
-- regex groups: 1=target, 2=source registry, 3=row_id
SELECT regexp_match(ref, '^\[SSSR_REF:\s*(.+?)\s*(?:@\s*(sssr:[\w.]+)\s*(?:@\s*([^\]]+))?)?\]$') INTO m;
IF m IS NULL THEN
RETURN NULL;
END IF;
RETURN jsonb_strip_nulls(jsonb_build_object(
'target', m[1],
'source', CASE WHEN m[2] IS NULL THEN NULL
ELSE jsonb_strip_nulls(jsonb_build_object('registry', m[2], 'row_id', m[3])) END
));
END $$;

Direct Link Behavior

  • The resolvers can safely treat the target alone (sssr:asset…) as a complete link for URL resolution.
  • The @ sssr:<table>.<column> @ <row> part is ignored by URL resolution, used only for provenance when exporting, logging, or AI autonomy.

Array-of-Refs Pattern Example:

pattern-example.jsonGitHub ↗
[
"[SSSR_REF: sssr:asset.hazard_pictograms.explos @ sssr:label_elements.symbol_sssr @ LEID-0029]",
"[SSSR_REF: sssr:asset.hazard_pictograms.flamme @ sssr:label_elements.symbol_sssr @ LEID-0029]"
]
  • Each string is a full SSSR_REF with:
    • the asset target (hazard_pictograms.explos, hazard_pictograms.flamme),
    • the source table + column (label_elements.symbol_sssr),
    • and the row ID (LEID-0029).
  • The array tells the resolver that multiple assets are bound to the same label element.
  • When enriched/exported, this can either remain as a JSON array of refs, or be expanded into atomic enriched JSON objects for each pictogram.

This is consistent with the “multiple target references” pattern in the SSSR design: use an array of valid SSSR_REF strings when more than one reference applies .

Recommendation:

  • Keep this array-of-refs structure in the tables.
  • At export/API time, the resolver can emit them either as a JSON array of enriched objects or flatten them into multiple rows depending on consumer needs.

SSSR Link Examples: Signals vs Assets

TypeBasic FormExtended Inline Form (with provenance)Meaning
Signal (row in a table)[SSSR_REF: sssr:label_elements.label_element_id @ LEID-0001][SSSR_REF: sssr:label_elements.label_element_id @ LEID-0001] (extended form is the same because signals always need the row id)Points to the label_element_id in the label_elements table, row LEID-0001.
Asset (file in asset registry)[SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif][SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif @ sssr:label_elements.symbol_sssr @ LEID-0029]Points to the asset GHS01.gif in the hazard_pictograms class. Extended form also records which source table/column (label_elements.symbol_sssr) and row (LEID-0029) is using this asset.

3.4. Key Takeaways

  • Signals always need @ row_id, because they’re row-level references.
  • Assets don’t use @ row_id in the basic form (they are global rows in sssr_asset_registry).
  • The extended inline form adds provenance (table + column + row) for traceability, audits, and AI self-healing.

We have a dedicated SSSR “Asset/URL Link” section and route every file/link through it. That keeps links portable, auditable, and swappable without touching data tables or code. It’s fully aligned with how SSSR is meant to centralize column-level references and cross-table links (incl. the [SSSR_REF: <signal_id> @ <row_id>] pattern).

We use

  • A registry area: assets_registry (as part of SSSR).
  • Resolver microservice: assets-url-resolver that expands an sssr: asset ID into the correct URL at runtime (UI, exports, APIs).
  • Tokenized URL templates: so we can flip base domains/folders once and everything updates.

sssr_asset_registry schema (SSSR → assets_registry)

FieldPurpose
asset_id (PK)Canonical signal, e.g. sssr:assets.hazard_pictograms.GHS01
asset_classhazard_pictogram, logo, policy_pdf, etc.
variants[]Array of objects: {format, mime, dpi, width_px, usage_hint} (e.g., gif, svg, eps, tiff_label)
template_varsDefaults: cdn_base, version, locale, theme, folder
fallback_order[]e.g., ["svg","gif","tiff_label"]
hash / etagIntegrity/audit (and cache-busting)
license/sourceLegal metadata (e.g., GHS/CLP source)
visibility_scopeadmin/user/system/public (matches SSSR visibility)
availability_statusactive/draft/deprecated
created_at/updated_atGovernance/audit trail

sssr_asset_class_registry schema

ColumnTypeDescriptionExample / Rules
asset_classtext (PK)Canonical class name for a family of assets.hazard_pictograms, logos, templates_pdf
path_templatetextURL “recipe” with placeholders resolved by the resolver. Must include {{cdn_base}} and {{code}}. {{ext}} strongly recommended.{{cdn_base}}/{{folder}}/{{code}}.{{ext}}
defaultsjsonbClass‑level default variables used to fill the template and drive selection logic. Required keys: folder, fallback_order.{"folder":"library/images/pictograms/hazard_pictograms","fallback_order":["svg","gif","tif"]}
availability_statustext (enum)Lifecycle: active, draft, deprecated.active
created_at / updated_attimestamptzGovernance/audit timestamps.auto‑managed triggers
descriptiontextHuman‑readable purpose of the class.“GHS/CLP hazard pictograms for SDS & labeling.”
integrity_rulesjsonbClass‑level integrity constraints.{"allowed_ext":["svg","gif","tif","eps"],"path_regex":"^library/images/pictograms/.\*"}
resolver_policyjsonbHow to pick variants at runtime (context/locale/version).{"variant_selection":{"print":["tif","eps"],"web":["svg","gif"]},"collapse_empty_segments":true}
cdn_policyjsonbCDN behaviors.{"cache_control":"public,max-age=604800","signing_required":false,"ttl_seconds":604800}
visibility_scopetext (enum)Access semantics aligned with SSSR.admin,user,system,public
owner_moduletextOwning engine/team for ops.ZHIF, SIS
maintainer_contacttextEmail/Slack/Group for break‑glass.cto@viroway.com
versioning_modetextpinned, latest, or inherit. Affects {{version}} handling.latest
localization_modetextnone, optional, required. Drives {{locale}}.optional
tenancy_modetextglobal, tenant_overrides_allowed.tenant_overrides_allowed
override_rulesjsonbDeclarative per‑tenant/per‑region overrides.{"tenant:eco-196-...":{"folder":"tenants/acme/hazards"}}
compliance_tagstext[]Legal or standard tags for audit.{"GHS","CLP"}
license_infojsonbLicense/source metadata.{"source":"UNECE","license":"permitted-use"}
telemetry_flagsjsonbEmit resolver telemetry, sample rates, alerting.{"emit_resolution_events":true}
deprecation_policyjsonbSunset plan for class.{"requires_migration_ticket":true,"replacement_class":"hazard_pictograms_v2"}

Validation & constraints (practical guardrails)

  • Template requirements: reject rows where path_template lacks {{cdn_base}} or {{code}}. Prefer {{ext}}; if omitted, engine must supply it.
  • Defaults integrity: defaults.folder must be non‑empty; defaults.fallback_order must be a non‑empty array whose values appear in integrity_rules.allowed_ext (if provided).
  • Enum checks: constrain availability_status, visibility_scope, tenancy_mode, etc.
  • Indexing: PK on asset_class; add BTREE index on availability_status and GIN index on defaults/integrity_rules (jsonb_path_ops) for ops queries.

Example row (hazard pictograms)

hazard-pictograms-example.jsonGitHub ↗
{
"asset_class": "hazard_pictograms",
"description": "GHS/CLP hazard pictograms for SDS printing and UI.",
"path_template": "{{cdn_base}}/{{folder}}/{{code}}.{{ext}}",
"defaults": {
"folder": "library/images/pictograms/hazard_pictograms",
"fallback_order": ["svg","gif","tif"],
"preferred_format_by_context": {
"web": ["svg","gif"],
"print": ["tif","eps"]
}
},
"integrity_rules": {
"allowed_ext": ["svg","gif","tif","eps"],
"path_regex": "^library/images/pictograms/hazard_pictograms/.*"
},
"resolver_policy": {
"collapse_empty_segments": true,
"variant_selection": {"print":["tif","eps"],"web":["svg","gif"]},
"locale_inheritance": "optional",
"versioning": "latest"
},
"cdn_policy": {"cache_control":"public,max-age=604800","signing_required":false},
"visibility_scope": "public",
"owner_module": "ZHIF",
"maintainer_contact": "cto@zayaz.io",
"availability_status": "active"
}

sssr_global_config schema (for system‑wide defaults inherited by many asset classes)

ColumnTypePurpose / NotesExample
key (PK)textConfig item namecdn_base
valuejsonbArbitrary JSON to allow rich settings{"url":"https://lib.zayaz.io"}
scopetext enumglobal | tenant | region | env (prod/stage) — lets you override per contextglobal
selectorjsonbWhen scope != global, the selector describing “who” this applies to{"tenant":"ECO-196-000-000-000"}
descriptiontextHuman description so ops knows why it exists“Primary CDN for public assets”
availability_statustext enumactive | draft | deprecatedactive
updated_bytextChange accountability[cto@viroway.com](mailto:cto@viroway.com)
updated_attimestamptzGovernanceauto
effective_from / effective_totimestamptzTime‑boxed rollouts, blue/greenoptional
integrity_rulesjsonbOptional checks (regexes, URL allowlists)\`{“url_regex”:”^https://(lib

Common keys used day‑to‑day

  • cdn_base: {"url":"https://lib.zayaz.io"}
  • default_locale: {"value":"en"}
  • default_version: {"value":"latest"}
  • theme_defaults: {"value":"light"}
  • asset_resolution_policy: e.g. {"web":["svg","gif"],"print":["tif","eps"]}
  • region_overrides: e.g. {"EU":{"cdn_base":"https://cdn-eu.zayaz.net"}}

This preserves the SSSR pattern: global → class → instance; engines read from the registry rather than hardcoding.

How consumers should store references

  • In tables like code_registry.symbol_url, store only the SSSR reference, not a URL:
    • "[SSSR_REF: sssr:asset.hazard_pictograms.GHS01.gif @ sssr:code_registry.code_type @ CR-00213]".
  • Engines (FOGE/SEM/DAIM/exports) call assets-url-resolver with:
    • asset_id, optional hints {context:"print" | "web", preferred_format:"gif", locale:"en", theme:"light"}, and it returns the best URL.
  • This matches the doc’s cross-table link idiom and lets engines auto-pick formats without hardcoding.

URL resolution logic (tiny, robust)

  1. Fetch asset_id → registry entry.
  2. Apply path_template with precedence: request hints → tenant overrides → registry defaults.
  3. Choose variant by rules: preferred_format or usage_hint (web/print) → fallback_order.
  4. Emit URL + integrity metadata; log to ALTD for traceability.
  5. If missing, trigger SEM/ops fallback and raise a registry notification (keeps auditability intact).

Ops conveniences

  • One-click base switch: cdn_base is kept in a global SSSR config row (sssr_global_config); changing it flips every link.
  • Folder refactors: do them by editing path_template once.
  • Version pinning: support version="latest" vs. explicit v2025.08 per tenant/report.
  • Localization/theming: drive {{locale}} / {{theme}} from user/session—no schema churn.

5. Migration plan

  1. Register assets in assets_registry with variants (e.g. pictograms with GIF/EPS/TIFF/SVG variants).
  2. Add cdn_base + default version to sssr_global_config.
  3. Replace direct URLs in tables with [SSSR_REF: …] strings (Excel CONCAT works great).
  4. Point UI/export code to assets-url-resolver.
  5. Turn on telemetry: log every resolution event for audits.

This keeps ZAYAZ consistent with SSSR’s purpose—semantic, traceable indirection for anything other modules consume—so links gain the same durability and auditability as data signals.

5.1. The path_template - {{cdn_base}}/{{folder}}/{{version}}/{{locale}}/{{code}}.{{ext}}

The path_template is just a parameterized blueprint for generating the actual file URL at runtime. It works like a URL “recipe” where placeholders (inside {{...}}) get replaced with values from the SSSR entry, the global config, or runtime context. Example:

https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/1-1.tif


5.1.1. Breaking it into components

Using the SSSR asset registry pattern, we’d map it to:

PlaceholderValue in this caseWhere it comes from
cdn_basehttps://lib.zayaz.ioGlobal SSSR config (sssr_global_config) so we can change CDN easily.
folderlibrary/images/pictograms/hazard_pictogramsAsset registry entry for this asset class.
versionomitted in this case (could be v1, 2025.08 etc.)Optional — can be blank if no versioning is in the URL.
localenone here (could be en, fr, etc.)Runtime context (user/report locale).
code1-1The asset’s logical code inside the hazard pictograms category.
exttifVariant/format selection (chosen by engine: print/web/etc.).

5.1.2. For this specific URL, a working template could be:

{{cdn_base}}/{{folder}}/{{code}}.{{ext}}

To support versioning and localization later without breaking current URLs, we can plan ahead with:

{{cdn_base}}/{{folder}}/{{version}}/{{locale}}/{{code}}.{{ext}}

And set version="" and locale="" when not in use.


5.1.3. Resolution process

When a consumer (UI, export engine, API) requests the asset:

  1. Look up SSSR asset entry — e.g., sssr:asset.hazard_pictograms.1-1.tiff_label.
  2. Get template: {{cdn_base}}/{{folder}}/{{code}}.{{ext}}.
  3. Pull defaults from:
  • Global config (sssr_global_config): cdn_base = https://lib.zayaz.io
  • Asset class config (sssr_asset_class_registry): folder = library/images/pictograms/hazard_pictograms
  • Asset record (sssr_asset_registry): code = 1-1
  • Format/variant mapping: ext = tif
  1. Substitute placeholders into the template →

https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/1-1.tif

  1. Serve the file, with optional integrity hash for audit.

5.1.4. Why this matters

  • Base URL change? → Update cdn_base in one SSSR config row.
  • Folder restructure? → Update folder for the asset class in one place.
  • Format change? → Update ext mapping; all consuming modules get the right variant.
  • Localization/versioning in future? → Fill in locale / version without rewriting URLs in the data tables.

Summary

  1. Three-layer fill-in process
  • Layer 1 – Global defaults (sssr_global_config)

    • Values that apply to all assets, stored in global config rows in SSSR.
    • Examples:
    • These can be swapped in one place to move all assets to a new CDN or switch a default locale.
  • Layer 2 – Asset class defaults

    • Stored in the sssr_asset_class_registry entry for the asset class.
    • Examples:
      • folder = library/images/pictograms/hazard_pictograms
      • fallback_order = ["svg", "gif", "tiff_label"]
    • This ensures all hazard pictograms share the same base folder and format fallback rules.
  • Layer 3 – Asset instance values

    • tored in the sssr_asset_registry entry for that specific asset.
    • Examples:
      • code = 1-1
      • variants = gif, svg, eps, tiff
      • primary_format = tif
    • These define what makes that specific pictogram unique.
  1. Example resolution step-by-step
  • To resolve: [SSSR_REF: sssr:asset.hazard_pictograms.1-1.tif]

  • Step 1 – Get path_template

    • From sssr_asset_class_registry for hazard_pictograms: path_template = {{cdn_base}}/{{folder}}/{{code}}.{{ext}}
  • Step 2 – Pull values

    • cdn_base → https://lib.zayaz.io (global config)
    • folder → library/images/pictograms/hazard_pictograms (class default)
    • code → 1-1 (asset instance)
    • ext → tif (from request or asset default)
  • Step 3 - Substitute placeholders

https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/1-1.tif

  1. Why this is powerful
  • Moving the hazard pictogram library to /assets/icons/hazards? → Update 1 row in the asset class config.
  • Switching CDN from lib.zayaz.io to cdn.zayaz.net? → Update 1 global config row.
  • Adding a localization? → Add {{locale}} in template and populate it from user session.

5.2. assets-url-resolver

The assets-url-resolver is the “URL kitchen” that cooks up the final link using the “recipe” (path_template) and the “ingredients” (metadata from global config, asset class defaults, and asset instance values). It’s a:

  • A microservice (or internal module) in the ZAYAZ backend.
  • Could be implemented as:
    • A REST endpoint → /resolve_asset_url?sssr_id=sssr:asset.hazard_pictograms.1-1.tif
    • A library function inside the platform → resolveAssetURL(sssr_id, options).
  • Uses the SSSR registry tables as its data source — it doesn’t store URLs itself.

5.3.SSSR Assets URL Resolver — Architecture & Flow

The following shows how the assets-url-resolver service (logic) works with the SSSR assets registry tables (data). It includes a component map, data model, API contract, and the step-by-step URL resolution flow.


5.3.1. Components (High-Level)

Key idea: Tables hold metadata; the resolver composes the final URL at runtime.


5.3.2. Minimal Data Model

  1. Global Config — sssr_global_config
  • key: cdn_base, default_locale, default_version, default_theme
  • value
  1. Asset Class Registry — sssr_asset_class_registry
  • asset_class (PK): e.g., hazard_pictograms, docs, logos, templates
  • path_template: e.g., {{cdn_base}}/{{folder}}/{{version}}/{{locale}}/{{code}}.{{ext}}
  • defaults: JSON (e.g., { "folder": "library/images/pictograms/hazard_pictograms", "fallback_order": [“svg","gif","tif"] })
  1. Assets Registry — sssr_assets_registry
  • asset_id (PK): e.g., GHS01, 1-1, company_logo
  • asset_class: FK → sssr_asset_class_registry.asset_class
  • variants: JSON array of objects, e.g., [ {"ext":"svg"}, {"ext":"gif"}, {"ext":"tif","usage_hint":"label_print"} ]
  • template_vars: JSON (overrides), e.g., { "code": "1-1" }
  • license, hash, availability_status, created_at, updated_at

5.3.3. Resolver API Contract (Service)

HTTP (REST) option

GET /api/assets/resolve?sssr_id=sssr:asset.hazard_pictograms

Library (in-process) option

library-ip-options.tsGitHub ↗
/**
* Types
*/

export type AssetContext = 'web' | 'print' | 'pdf';
export type AssetTheme = 'light' | 'dark';

export interface ResolveAssetOptions {
preferredFormat?: string; // e.g. 'svg' | 'gif' | 'tif'
locale?: string; // e.g. 'en', 'no'
version?: string; // e.g. 'latest', 'v2025.08'
context?: AssetContext; // influences variant choice
theme?: AssetTheme;
}

export interface ResolvedAsset {
url: string;
format: string;
locale?: string;
version?: string;
context?: AssetContext;
theme?: AssetTheme;
}

/**
* Example implementation
*/

export function resolveAssetURL(
sssrId: string, // e.g. 'sssr:asset.hazard_pictograms.1-1.tif'
opts: ResolveAssetOptions = {}
): ResolvedAsset {

const {
preferredFormat = 'svg',
locale = 'en',
version = 'latest',
context = 'web',
theme = 'light'
} = opts;

// Example base CDN path (adjust to your system)
const baseURL = 'https://cdn.example.com/assets';

const url = `${baseURL}/${version}/${locale}/${context}/${theme}/${sssrId}.${preferredFormat}`;

return {
url,
format: preferredFormat,
locale,
version,
context,
theme
};
}

Response

library-ip-options-response.jsonGitHub ↗
{
"url": "https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/1-1.tif",
"resolved": {
"cdn_base": "https://lib.zayaz.io",
"folder": "library/images/pictograms/hazard_pictograms",
"code": "1-1",
"ext": "tif",
"version": "",
"locale": ""
},
"variant": {"ext":"tif","usage_hint":"label_print"},
"integrity": {"hash":"sha256:…"},
"meta": {"asset_class":"hazard_pictograms","asset_id":"1-1"}
}

5.3.4. URL Resolution Flow (Step-by-Step)

The resolution process works as follows:

  1. The consumer (UI, FOGE, Exporter, etc.) calls the resolver with an sssr:asset ID and optional options.
  2. The resolver parses the ID into its parts (asset class, code, extension).
  3. It retrieves global defaults (like cdn_base, default locale, version, theme).
  4. It looks up the class template and defaults for the given asset class.
  5. It loads the asset record (variants, template variables, integrity, etc.).
  6. It decides the best variant to serve based on the options, context, and fallback order.
  7. It composes the URL by substituting variables into the path template.
  8. It returns the resolved URL and metadata to the consumer, which then fetches the asset from the CDN.

Variant choice logic (simplified):

  1. If opts.preferredFormat available → use it.
  2. Else if context=print → prefer tif/eps if available.
  3. Else → prefer svg/gif.
  4. Else → follow fallback_order from class defaults.

5.3.5. Path Template Examples

Example of simple flat structure:

{{cdn_base}}/{{folder}}/{{code}}.{{ext}}

Works for:

Future-ready with version & locale:

{{cdn_base}}/{{folder}}/{{version}}/{{locale}}/{{code}}.{{ext}}

  • With version="latest" or v2025.08, and locale="en"|"no".
  • If empty, resolver collapses empty segments to avoid double slashes.

Tenant-branding override:

{{cdn_base}}/{{tenant}}/{{folder}}/{{code}}.{{ext}}

tenant comes from auth context; lets us theme per client.


5.3.6. Example SQL Sketches

Illustrative only — adapt types/indexes to the DB.

sssr-asset-tables.sqlGitHub ↗
-- Global config
CREATE TABLE sssr_global_config (
key text PRIMARY KEY,
value jsonb NOT NULL,
updated_at timestamptz DEFAULT now()
);

-- Asset classes
CREATE TABLE sssr_asset_class_registry (
asset_class text PRIMARY KEY,
path_template text NOT NULL,
defaults jsonb NOT NULL,
updated_at timestamptz DEFAULT now()
);

-- Assets
CREATE TABLE sssr_assets_registry (
asset_id text PRIMARY KEY,
asset_class text NOT NULL REFERENCES sssr_asset_class_registry(asset_class),
variants jsonb NOT NULL,
template_vars jsonb,
license text,
hash text,
availability_status text DEFAULT 'active',
created_at timestamptz DEFAULT now(),
updated_at timestamptz DEFAULT now()
);

CREATE INDEX ON sssr_assets_registry(asset_class);

5.3.7. Caching & Performance

  • In-memory cache for class templates and global config (TTL 5–15 min).
  • Per-asset cache for resolved URLs keyed by (sssr_id, locale, version, preferredFormat, theme, context).
  • Cache busting when updated_at changes on relevant rows.

5.3.8. Error Handling & Telemetry

  • If asset/variant missing → return structured error with fallback_attempted=true and candidates list.
  • Emit telemetry event: asset_resolve_failed with asset_id, asset_class, requested_ext, fallback_path, reason.
  • Optionally route a task to “Registry Ops” queue to fix broken entries; link to ALTD audit trail.

5.3.9. Governance & Audit (Why this is SSSR-aligned)

  • Traceability: Every URL comes from registry metadata → auditable.
  • Swap safety: Change cdn_base or folder once → all consumers updated.
  • Version pinning: Reports can pin version for reproducibility.
  • Locale-aware: Localized assets can be served without altering data tables

5.3.10. Quick Usage Cheat Sheet

  • Store in tables: [SSSR_REF: sssr:asset.<class>.<asset_id>.<ext> @ <row_id>].
  • Call resolver from UI/engines with optional preferredFormat, locale, version, context.
  • Get back a stable URL + integrity + metadata.

5.4. Resolver variable mapping (DB → template vars → URL)

The resolver variable-mapping table shows exactly how DB columns → template vars → final URLs.

SourceField (DB / runtime)Template varNotes / Precedence
sssr_global_configcdn_base.urlcdn_baseGlobal default; can be overridden by region/tenant config at runtime.
sssr_asset_class_registry.defaultsfolderfolderClass-level folder; typically the only place you change folder structure.
sssr_asset_class_registry.defaultsversion (optional)versionClass default; can be empty. Runtime can override (e.g., v2025.08).
sssr_asset_class_registry.defaultslocale (optional)localeClass default; runtime/user session can override (e.g., no, en).
sssr_assets_registryasset_codecodeAsset code → mapped to {{code}} (keep DB name as asset_code).
sssr_assets_registry.template_varsarbitrary keyssame key namePer-asset overrides for any var (e.g., folder, version, locale, code).
Runtime (resolver input)preferredFormat or extextHighest precedence for format if provided explicitly.
Policy (class defaults / resolver_policy)fallback_orderext (chosen)Used when ext not explicit; picks first available variant.
sssr_assets_registry.variants[]ext, color_space, dpi, …n/aSource of available formats and technical constraints.

Example: vars bag assembly Inputs

  • Template (class): {{cdn_base}}/{{folder}}/{{version}}/{{locale}}/{{code}}.{{ext}}
  • Global: cdn_base = https://lib.zayaz.io
  • Class defaults: folder = library/images/pictograms/hazard_pictograms, fallback_order = ["svg","gif","tif"]
  • Asset row: asset_code = "1-1", variants = [svg, gif, tif]
  • template_vars (asset): { "locale": "no" }
  • Runtime: context = "web" (no explicit ext, no version)

Resolver chooses ext

  • From policy (web): prefer svg, else fallback order.
  • svg exists → pick ext = “svg".

Final variable bag

final-variable-bag.jsonGitHub ↗
{
"cdn_base": "https://lib.zayaz.io",
"folder": "library/images/pictograms/hazard_pictograms",
"version": "",
"locale": "no",
"code": "1-1",
"ext": "svg"
}

Rendered URL

https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/no/1-1.svg

(Empty version collapses cleanly if the renderer removes empty path segments.)

Pseudocode (the tiny mapper)

tiny-mapper.pyGitHub ↗
def build_vars(sssr_id, runtime):
cls = load_class(sssr_id.asset_class) # path_template, defaults, policy
asset = load_asset(sssr_id.asset_class, sssr_id.asset_code, runtime.eco_number)

vars = {}
# 1) global
vars["cdn_base"] = get_global("cdn_base.url")
# 2) class defaults
vars.update(cls.defaults) # folder, version?, locale?, etc.
# 3) asset specifics
vars["code"] = asset.asset_code
if asset.template_vars:
vars.update(asset.template_vars)
# 4) ext selection
ext = sssr_id.ext or runtime.preferredFormat or choose_ext(cls.policy, asset.variants, runtime.context)
vars["ext"] = ext
# 5) runtime overrides (last write wins)
for k in ("version","locale"):
if getattr(runtime, k, None):
vars[k] = getattr(runtime, k)

return vars, cls.path_template

5.4. Quick validator checks (nice guardrails)

  • Template must reference required vars: {{cdn_base}}, {{code}}, {{ext}} (reject row otherwise).
  • Folder non-empty: class.defaults.folder must be present.
  • Variant sanity: chosen ext must exist in asset.variants[] (or after fallback selection).
  • Collapse empties: strip double slashes when version/locale are empty.

5.5. How variants[] is chosen (EPS/TIFF for print, GIF/SVG for web)

Use a deterministic policy the resolver applies; AI is optional seasoning, not the core rule.

Where the choice lives

  1. Explicit in the ID (highest priority): sssr:asset.hazard_pictograms.1-1.tif → use TIF, no questions asked.
  2. Runtime options from the caller (UI/export): preferredFormat="svg" or context="print" / context="web".
  3. Class policy (in sssr_asset_class_registry.resolver_policy or defaults): {"variant_selection":{"web":["svg","gif"],"print":["tif","eps"]}}
  4. Fallback order (class defaults): {"fallback_order":["svg","gif","tif","eps"]}

variants[] shape (per asset instance)

variants-shape.jsonGitHub ↗
{
"variants": [
{"ext":"svg", "usage_hint":"web", "color_space":"RGB"},
{"ext":"gif", "usage_hint":"web", "color_space":"RGB"},
{"ext":"tif", "usage_hint":"print","color_space":"CMYK","dpi":300},
{"ext":"eps", "usage_hint":"print"}
]
}

5.6. Selection algorithm (resolver)

  1. If ID includes .<ext> → pick that.
  2. Else if preferredFormat supplied and present in variants → pick it.
  3. Else if context supplied → consult class variant_selection[context], pick first available.
  4. Else → use class fallback_order.
  5. If multiple candidates remain, match technical constraints (e.g., color_space="CMYK" and dpi>=300 for print). If none match, fall back and log a structured warning.

This keeps the decision declarative and auditable (aligned with SSSR’s design), while still allowing an AI helper to suggest alternatives when constraints aren’t met. The canonical link remains the [SSSR_REF: …] form so lineage and routing are preserved across modules.


5.7. Concrete URL conversion (sanity check)

Current:

https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/1-1.gif

After populating:

  • cdn_base (global) = https://lib.zayaz.io
  • Class defaults: folder = library/images/pictograms/hazard_pictograms
  • Template: {{cdn_base}}/{{folder}}/{{code}}.{{ext}}

Use either:

  • Explicit: [SSSR_REF: sssr:asset.hazard_pictograms.1-1.gif] → exact same GIF URL resolves.
  • Auto: [SSSR_REF: sssr:asset.hazard_pictograms.1-1] → web might resolve to SVG, print to TIF, depending on policy.

5.8. API additions

  • Implement an endpoint over the existing resolver logic, e.g.*GET /api/assets/resolve?sssr_id=sssr:asset.hazard_pictograms.1-1.tif&locale=en&context=web
  • Return { url, variant, meta, integrity } plus HTTP cache headers (ETag, Cache-Control, Last-Modified).
  • Enforce auth (JWT/OAuth) and scope checks in the service, using visibility_scope from class and asset (logical AND).

Schema Tweaks sssr_asset_class_registry

Column NameTypeDescription
api_enabledbool, default trueAllow/deny class via API.
api_slugtextFriendly path fragment (e.g., hazards).
cors_policyjsonb{ "origins": ["\*"] } or stricter.
rate_limit_buckettextLink to gateway settings.
signing_requiredboolRequire pre‑signed or tokenized URLs.
content_dispositiontextInline | attachment (default per class).
filename_templatetextE.g., {{asset_class}}-{{code}}.{{ext}}.

sssr_assets_registry (asset-level)

Column NameTypeDescription
api_enabledboolPer‑asset override (default null = inherit).
legal_restrictionsjsonbExport constraints (regions, licenses).
download_filenametextOverride for Content-Disposition.
integrityjsonb{ "hash":"sha256:…", "size":12345 }.

sssr_global_config (global)

Column NameTypeDescription
asset_api_defaultsjsonbGlobal API behaviors. {“cache_control":"public,max-age=604800","etag_strategy":"hash"}
token_signingjsonbKey ids, TTL for pre‑signed URLs.

5.9. API shapes (minimal and clean)

5.9.1. Resolution API (metadata forwarder)

GET /api/assets/resolve
?sssr_id=sssr:asset.hazard_pictograms.1-1
&context=print&locale=no&preferredFormat=tif

5.9.2. 200 JSON

print-usage.jsonGitHub ↗
{
"url": "https://lib.zayaz.io/library/images/pictograms/hazard_pictograms/1-1.tif",
"variant": {"ext":"tif","usage_hint":"print","color_space":"CMYK","dpi":300},
"meta": {"asset_class":"hazard_pictograms","asset_id":"1-1","locale":"no"},
"integrity": {"hash":"sha256:...","size": 481233}
}

Headers: ETag, Cache-Control, Last-Modified, optional x-sssr-id.


5.9.3. Direct fetch API (proxy with policy)

GET /api/assets/fetch/hazards/1-1
?context=web&locale=en
Authorization: Bearer …

Service chooses variant, applies signing if required, sets Content-Type and Content-Disposition from class/asset rules, streams the bytes (or 302 to CDN).


5.9.3. Selection logic (where “EPS/TIFF vs GIF/SVG” is decided)

Priority order:

  1. Explicit ext in ID → use it.
  2. Caller hint → preferredFormat or context (web/print).
  3. Class policyresolver_policy.variant_selection.
  4. Fallbackdefaults.fallback_order.
  5. Constraints → choose variant matching color_space, dpi (from variants).

This keeps decisions declarative in tables, not in opaque code or “AI magic”. AI helper can be added to suggest alternatives, but the authoritative source remains the registry.


5.9.4. Security & governance touches

  • Enforce visibility_scope (public/user/admin/system) and api_enabled at both class and asset; deny if either blocks.
  • Optional tenancy/region guards using scope/selector in global config.
  • Log every API resolution with SSSR ID, variant chosen, and caller scope for audits.
  • Use pre‑signed URLs if signing_required=true at class/asset.

5.9.5. Migration checklist

  1. Populate resolver_policy, fallback_order, and rich variants.
  2. Stand up /api/assets/resolve (metadata) and optionally /api/assets/fetch/:class/:id (proxy).
  3. Wire gateway: auth scopes, rate limits, CORS, caching.
  4. Record structured telemetry for audits and SLA.

6. Keeping Assets with the Same Name (code) Unique

6.1. Keys & uniqueness (safe schema)

  • Primary key (surrogate): asset_uid UUID→ Opaque, never exposed to users or in SSSR IDs.
  • Natural key (human/semantic): asset_code TEXT (e.g., "1-1", "logo")
  • Tenant scoping: eco_number UUID NULL (NULL = global/shared asset)
  • Class scoping: class_id UUID (FK → sssr_asset_class_registry)
  • Uniqueness constraint:UNIQUE(eco_number, class_id, asset_code)

→ Allows each tenant to have e.g. a "logo" in client_logos without clashing; also allows a global "logo" when tenant_id IS NULL.


6.2. What the SSSR ID looks like (no collisions)

Keep the SSSR ID stable and simple:

sssr:asset.<asset_class>.<asset_code>[.<ext>]

Examples:

  • Global hazard pictogram: sssr:asset.hazard_pictograms.1-1
  • Client logo: sssr:asset.client_logos.logo

How tenant is handled: the resolver takes the tenant from auth/context (session, API token) and first tries:

(eco_number = caller.eco_number, class_id = <class>, asset_code = <code>)

If not found, it falls back to global:

(eco_number IS NULL, class_id = <class>, asset_code = <code>)

This gives each tenant its own "logo" while preserving a global default.


6.3. Version pinning (if e.g. multiple dated logos is needed)

If multiple versions per tenant/class/code (e.g., a rebrand) is needed/wanted:

  • Add version TEXT to the unique key or create a separate table for versions.
  • Recommended uniqueness when enabling versions:UNIQUE(tenant_id, class_id, asset_code, COALESCE(version,'latest'))
  • Resolution order:
      1. If SSSR ID (or request) specifies version, use it.
      1. Else use class policy default_version (often "latest").
      1. Fall back to the newest active version.

6.4. Concrete examples

Two clients, both want client_logos.logo:

  • Row A: (eco_number = ECO-197-123-456-789, class = client_logos, asset_code = 'logo', variants = […])
  • Row B: (eco_number = ECO-197-987-654-321, class = client_logos, asset_code = 'logo', variants = […])
  • Global fallback (optional): (eco_number = NULL, class = client_logos, asset_code = 'logo', variants = […])

Resolution:

  • ECO-197-123-456-789 (ACME) calling sssr:asset.client_logos.logo → gets ACME’s logo.
  • ECO-197-987-654-321 (BRAVO) calling the same ID → gets BRAVO’s logo. A public/anon context → gets the global logo (if present).

Hazard pictograms (global library): Keep tenant_id = NULL, class = hazard_pictograms, asset_code = '1-1'. Tenants can override specific pictograms by inserting tenant‑scoped rows; otherwise they inherit the global set.


6.5. Why not encode tenant into the SSSR ID?

We could do sssr:asset.client_logos. ECO-197-123-456-789.logo, but we don’t need to:

  • Tenant (eco_number) is already in auth context; keeping IDs tenant‑agnostic makes references portable across sandboxes and easier to move/merge tenants.
  • If you ever need to resolve “as another tenant”, you can pass tenantOverride to the resolver (ops/admin use).

6.6. Migration checklist

  • For global items, set eco_number = NULL or ECO-197-000-000-000 (Viroway Ltd).
  • For client items, set eco_number from the tenant/org table.
  • Create the unique index on (eco_number, class_id, asset_code).
  • Keep SSSR IDs unchanged (sssr:asset.<class>.<code>[.<ext>]).
  • Ensure resolver reads tenant from auth and applies the two‑step lookup with global fallback.

7. fallback_order[]

We keep fallback_order[] in both sssr_asset_registry and sssr_asset_class_registry because they operate at different scopes — one is the class-level default policy, and one is the per-asset override.

7.1. Class-level (sssr_asset_class_registry.defaults.fallback_order)

  • Purpose: define the standard order for selecting variants when no asset-specific rule exists.
  • Scope: applies to all assets in that class unless overridden.
  • **Example:**In hazard_pictograms, most assets might be small vector or raster icons — so it might default to:
pictogram-fallback.jsonGitHub ↗
{ "folder": "library/images/pictograms/hazard_pictograms",
"fallback_order": ["svg","gif","tif"] }
  • Usage: Resolver checks class.defaults.fallback_order only if the asset doesn’t have its own fallback_order.

7.2. Asset-level (sssr_assets_registry.fallback_order)

  • Purpose: override the class policy for this specific asset.
  • Scope: only affects that one row in sssr_assets_registry.
  • Example: One pictogram is a high-detail photo, not a vector. For that asset, we might say:

json ["tif","eps","gif"]

so the resolver tries high-resolution print formats first.


7.3. Resolution order in practice

When the resolver needs to pick a format (no explicit ext in the SSSR_REF):

  1. Check asset-level fallback_order[]
  • If present → use it directly.
  • If not present → go to class level.
  1. If class has fallback_order[] → use it.
  2. If neither is present → use system/global default from sssr_global_config.asset_resolution_policy.

7.4. Why not only keep it in the asset table?

Because most assets don’t need their own override — 90%+ will follow the class default.

If we only stored it in the asset table:

  • We’d have to copy the same list into hundreds of rows.
  • Changing the default for a class would require bulk updates instead of a single class row edit.

By having both:

  • We set once at class level.
  • We override only when needed at asset level.
  • The resolver has a clear hierarchy:

asset-level override → class default → global default


8. AI autonomy

Below is the schema design that lets us move from AI-assisted to AI-autonomous asset management without losing control.

8.1. Clear Override Hierarchy

Because we’ve separated:

  • Global default (in sssr_global_config)
  • Class default (in sssr_asset_class_registry.defaults)
  • Per-asset override (in sssr_assets_registry)

…an AI agent can:

  • Detect patterns in overrides (e.g., “80% of assets in hazard_pictograms have ['tif','eps'] instead of the default”).
  • Suggest updating the class default rather than touching 100 individual rows.
  • Roll back a bad change easily — just restore the default at the right scope.

If a variant is missing (404 or checksum mismatch):

  • AI can try the next item in fallback_order[] without human intervention.
  • It can log the failure, suggest updating variants[] or the fallback order in the right place.
  • It can also spot global issues (e.g., “All .gif variants in hazard_pictograms are failing — check CDN folder path in defaults.folder”).

8.3. Autonomous optimization

Given usage telemetry:

  • AI can see which variant is actually being served most often for a context.
  • It can propose re-ordering fallback_order[] to match real-world demand.
  • For example:“In web context, svg load times are consistently better — moved svg to top of fallback list for hazard_pictograms.”

8.4. Controlled learning scope

The AI doesn’t have to “guess” where to change things:

  • Global change → update sssr_global_config.
  • Class change → update sssr_asset_class_registry.defaults.
  • One-off fix → update sssr_assets_registry for that asset.

This scoping means autonomous changes can be reviewed, sandboxed, and rolled back in a predictable way — no silent drift.


8.5. Easy audit trail

Because all overrides are explicit fields, not hidden in code:

  • Every AI “healing” action becomes a data mutation with timestamp, user/agent ID, and diff.
  • We can run a periodic SSSR diff to see AI-driven changes vs. human changes.

9. Self-Healing Asset Resolver – AI Autonomy Sketch

This sketch shows how the resolver + AI agent collaborate to detect issues, auto-fallback, propose or apply fixes at the right scope (global → class → asset), and keep the whole loop auditable and safe.


9.1. High-Level Flow


9.2. Resolution + Self-Heal Sequence


9.3. AI Autonomy Loop (Detect → Plan → Act → Verify → Rollback)


9.4. Decision Tree (Where to Change?)

  1. Is the problem systemic? (e.g., CDN base 5xx globally) → change sssr_global_config.cdn_base.
  2. Is it class-wide? (e.g., all hazard_pictograms .gif 404) → update sssr_asset_class_registry.defaults.folder or fallback_order.
  3. Is it isolated to one asset? → update sssr_assets_registry.variants or per-asset fallback_order.
  4. Only context-specific regression? → adjust resolver_policy.variant_selection for that class/context.

Always prefer the highest applicable scope to minimize per-row churn and maximize consistency.


9.5. Policy & Constraints (Declarative)

  • Variant selection (class):
policy-and-constraints.jsonGitHub ↗
{
"variant_selection": { "web": ["svg","gif"], "print": ["tif","eps"] },
"fallback_order": ["svg","gif","tif","eps"],
"constraints": {
"print": { "color_space": "CMYK", "min_dpi": 300 }
}
}

Per-asset variants:

per-asset.variants.jsonGitHub ↗
{
"variants": [
{"ext":"svg","usage_hint":"web","size":18345},
{"ext":"gif","usage_hint":"web"},
{"ext":"tif","usage_hint":"print","color_space":"CMYK","dpi":300}
]
}

Resolver applies: explicit ext → caller hint → class policy → asset fallback → global default.


9.6. Telemetry Events (for Learning & Audits)

  • asset_resolution_success { sssr_id, eco_number, class, asset_code, ext, latency_ms, cache_hit, etag }
  • asset_resolution_fallback { from_ext, to_ext, reason, frequency }
  • asset_resolution_failed { class, asset_code, tried_exts[], error_codes[], last_seen }
  • asset_policy_change_proposed { scope, diff }
  • asset_policy_change_applied { scope, diff, actor, ticket }
  • asset_policy_change_rolled_back { scope, reason, rollback_id }

Stream to the MON/DET components. Use thresholds (e.g., >2% failure over 15 min) to trigger autonomous plans.


9.7. Pseudocode (Resolver w/ Self-Heal Hooks)

resolver-with-self-heal-hooks.pyGitHub ↗
result = try_resolve(sssr_id, opts)
if result.ok:
emit('asset_resolution_success', result.meta)
return result

# First failure: try policy fallback
for ext in policy.next_variants():
result = try_resolve(sssr_id.with_ext(ext), opts)
if result.ok:
emit('asset_resolution_fallback', {"from": opts.ext, "to": ext})
return result

# Total failure: emit and exit
emit('asset_resolution_failed', failure_meta)
return failure(404, "Asset not available”)

9.8. Change Safety & Rollback

  • Dry-run: run synthetic resolves against the proposed change; ensure ≥95% success and no size/latency regressions.
  • Time-box: apply change with effective_from/effective_to for phased rollouts.
  • Shadow mode: evaluate new policy in parallel, compare KPIs before switching.
  • Rollback: keep previous policy/version in history; one-click revert.

9.9. What the AI Actually Edits

  • sssr_global_config: cdn_base, global asset_resolution_policy.
  • sssr_asset_class_registry: defaults.folder, resolver_policy.variant_selection, defaults.fallback_order.
  • sssr_assets_registry: add/remove variants, set per-asset fallback_order, tweak template_vars.

All edits generate audit records and can be constrained behind approval gates per environment (dev/stage/prod).


9.10. Quick “Why This Works”

  • Declarative → AI edits data, not code.
  • Scoped → Fixes land at the smallest surface that solves the problem.
  • Auditable → Every change is a registry diff with metadata.
  • Reversible → Rollback is a data write, not a redeploy.

This is the foundation for trustworthy AI autonomy in asset delivery.


For machine-only fields inside the DB use a pure JSON form because it’s safer, faster to process, and easier to evolve than storing an array of human-formatted strings.

The preferred format is:

preferred-link-format.jsonGitHub ↗
{ "registry": "sssr:code_registry.code_registry_id", "ids": ["CR-00213","CR-00214"] }

10.1. Benefits

  • Zero string parsing. We avoid brittle regex/splitting. ETL/API/AI can read registry once and iterate ids directly.
  • Schema evolution. We can add more keys without breaking anything (filters, constraints, notes, eco_number, etc.).
  • Validation & constraints. Easy to enforce with DB checks (e.g., keys must exist, ids must be array of text).
  • Indexing & querying. Postgres JSONB operators work cleanly:
    • jsonb_array_elements_text(payload->'ids') to unnest
    • GIN indexes (jsonb_path_ops) for fast membership queries.
  • Lower storage & duplication. One copy of the registry string; many IDs. (The stringy form repeats the registry per item.)
  • Safer AI/autonomy edits. Agents can append/remove IDs without worrying about bracket/spacing typos.
  • Cleaner provenance. We can enrich to the extended form only when exporting, instead of storing verbose strings everywhere.

10.2. Single reference column (one target)

  • If humans edit this cell (e.g., in Excel): store the short string [SSSR_REF: …].
  • If it’s machine-only: store as JSON:{"target": "sssr:asset.hazard_pictograms.GHS01.gif"}

10.3. Multiple references from the same registry (common cases)

  • Recommended column type: jsonb
  • Value:{"registry":"sssr:code_registry.code_registry_id","ids":["CR-00213","CR-00214", ...]}
  • To query:
query-registry.sqlGitHub ↗
SELECT row_id, j.elem AS code_id
FROM your_table t
CROSS JOIN LATERAL jsonb_array_elements_text(t.refs->'ids') AS j(elem)
WHERE t.refs->>'registry' = 'sssr:code_registry.code_registry_id';

10.4. Multiple references across different registries (mixed set)

  • Use a list of objects:
mixed-set-references.jsonGitHub ↗
[
{"registry":"sssr:code_registry.code_registry_id","ids":["CR-00213","CR-00214"]},
{"registry":"sssr:nace_registry.nace_code","ids":["C10.1","C10.2"]}
]
  • This avoids mixing everything into one string soup.

10.5. Validation & indexes (Postgres examples)

  • Checks
validation-and-indexes.sqlGitHub ↗
ALTER TABLE your_table
ADD CONSTRAINT refs_has_keys
CHECK (refs ? 'registry' AND refs ? 'ids' AND jsonb_typeof(refs->'ids') = 'array');
  • Index (fast membership by ID)
membership-by-id.sqlGitHub ↗
CREATE INDEX your_table_refs_gin
ON your_table USING GIN ((refs->'ids') jsonb_path_ops);
  • Generated column to expose first registry
add-column-reg-txt.sqlGitHub ↗
ALTER TABLE your_table
ADD COLUMN registry_txt TEXT GENERATED ALWAYS AS (refs->>'registry') STORED;
CREATE INDEX your_table_registry_idx ON your_table(registry_txt);

10.6. Human-friendly views

  • Keep the DB clean, but provide a view that renders the bracketed form for readability:
human-friendly-views.sqlGitHub ↗
CREATE VIEW your_table_human AS
SELECT
row_id,
format(
'[SSSR_REF: %s @ {%s}]',
refs->>'registry',
string_agg(q.id, ', ')
) AS refs_compact
FROM your_table
CROSS JOIN LATERAL (
SELECT jsonb_array_elements_text(refs->'ids') AS id
) q
GROUP BY row_id, refs;

10.7. Provenance (extended form)

  • Don’t store provenance redundantly on every cell. Generate it on export:
provenance.jsonGitHub ↗
{
"target_registry": "sssr:code_registry.code_registry_id",
"targets": ["CR-00213","CR-00214"],
"source": {"registry":"sssr:label_elements.symbol_sssr","row_id":"LEID-0029"}
}

We already have table, column, and row_id in the DB context—attach them only when needed (API/output/AI).

Simple rule of thumb Inside DB (machine fields): use structured JSON ({"registry": "...","ids": [...]}) or a join table; avoid parsing strings. At the edges (docs, Excel, emails): use the human string form [SSSR_REF: …]. On export/APIs: enrich to the extended JSON with provenance.




GitHub RepoRequest for Change (RFC)