DataShield Ontology · documentation
Data Catalog
Measured from the codebase at v0.22.188 (2026-09-22). Every claim cites file:line; where a claim is inferred rather than read, it says so. Audience: developers, governance teams, analysts and AI agents driving the data_catalog umbrella.
On this page
1. What the Data Catalog is
The Data Catalog is the platform's system-object estate map: registered providers (a database, warehouse, SaaS API, storage bucket or open-data portal), the objects (tables, views, schemas, endpoints…) a scan discovered under them, the columns of those objects with their type/class/constraints, optional profiles, business-term glossary, and bindings that feed catalogued objects into MDM mastering.
It is exposed on three parity surfaces built from ONE contract:
| Surface | Entry point | Notes |
|---|---|---|
MCP umbrella data_catalog | scripts/mcp-server/umbrellas/data_catalog.ts (111 lines; kernel-only imports, "no logic in the umbrella", header lines 1-11) | Zod union DATA_CATALOG_COMMAND_SCHEMA in lib/data_catalog/wire.ts:40; executor dispatchDataCatalog in lib/data_catalog/dispatch.ts |
REST bridge /api/app/data_catalog/<verb> | app/api/app/data_catalog/[verb]/route.ts | Verb table, door floors and arg validation DERIVED from the same wire contract + COMMAND_AUTH (route header lines 6-17) |
| Data Catalog app | app/app/data-catalog/ (dashboard + 11 sections) and app/data-catalog/lineage/page.tsx | Section registry is data: config/data-catalog-nav.config.ts:181-212 |
Tier floor: the umbrella is a developer-tier addition (config/mcp-tiers.config.ts:186-187, in DEVELOPER_TIER_ADDITIONS declared at line 174). Per-command floors above that are in config/command-auth.config.ts:551-564; ownership gates (owner-or-admin, per-account rows) are in config/authorization-policy.config.ts:556 (UMBRELLA_COMMAND_GATES.data_catalog) and run BEFORE the switch (umbrella header line 9).
2. Command reference
Verbs are derived, never hand-listed (DATA_CATALOG_VERBS, wire.ts:328). 29 commands (counted from the discriminated union; DATA_CATALOG_VERB_METHODS carries the same 29 keys — 15 GET, 14 POST). "Floor" = developer tier unless admin is stated (command-auth.config.ts:551-564). REST method per verb from DATA_CATALOG_VERB_METHODS (wire.ts:411-419).
2.1 Providers
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
provider_create | Registers a provider over exactly ONE identity source: connection_id (vault connection; database/warehouse/storage/SaaS/stream kinds) or crawler_project_id (portal kinds). Optional role (source/target/both, default source), scan_cadence/extract_cadence (ISO 8601 duration or RFC 5545 RRULE), sample_policy, resolver_strategy (local_vault/auth_broker), notification_channel_ref | kind, name (+ one identity) | dev | POST |
provider_list | Lists providers you may see; filters kind, role; paginated (default 20, max 200 — LIST_LIMITS, config:4022) | — | dev | GET |
provider_get | One provider; detail minimal/compact(default: row + capabilities + summary tiles)/full(+ identity status) | provider_id | dev | GET |
provider_update | Patches name/role/cadences/sample_policy/resolver/notification; null clears to family/platform default | provider_id | dev (owner or admin) | POST |
provider_retire | Soft-delete (deleted_at), disables its crawlers, history kept | provider_id, confirm: true | dev (owner-scoped; command-auth.config.ts:563) | POST |
provider_test | Probes the identity source and PERSISTS the resulting health | provider_id | dev | POST |
2.2 Crawlers and scans
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
crawler_create | Creates a collection job over a provider. purpose ∈ discover | profile | extract | rescan (CRAWLER_PURPOSES, config:910). Scope JSON: schemas[], include_glob, exclude_glob, object_kinds[], sample_policy, profiling_mode (M0–M3, config:1002), max_entities. schedule_cron (5-field) or null = manual. Tunables: concurrency 1–10 (default 2), rate_limit_rps 0.1–10 (default 1), max_requests_per_run ≤ 50000 (default 500) | provider_id, purpose, name | dev | POST |
crawler_list | Crawlers of one provider | provider_id | dev | GET |
scan_run | Enqueues one scan for a crawler project. Optional acknowledge_sweep: true + reason (12–500 chars) to ratify a sweep the blast-radius guard refused (see §5) | crawler_project_id | dev | POST |
2.3 Reading the estate
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
assets_list | Objects IN one provider; filters kind, parent_id (null = top level), q, include_deleted. Carries per-object attrs document plus column_count, child_count, tags, quality (assets.ts:83) | provider_id | dev | GET |
objects_search | Cross-provider object browse; VALUE-FREE by SELECT list (drops attrs) — STANDARD-009 (wire.ts comment above the verb) | — | dev | GET |
asset_get | One object with the per-axis quality table | asset_id | dev | GET |
columns_list | Columns of ONE object incl. stored samples/profile documents; acknowledge_plain_samples governs whether plain samples are returned in the clear | asset_id | dev | GET |
columns_search | Cross-object column browse; VALUE-FREE; q matches column name OR qualified object name | — | dev | GET |
profile_get | Current AnalysisContract profile of an object; sections[] to restrict; acknowledge_plain_samples as above | asset_id | dev | GET |
flow_summary | Collected → profiled → bound → mastered map, "every declared zero disclosed"; RFC 3339 from/to bound only the alerts leg | — | dev | GET |
2.4 Tags
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
asset_tag_set | Adds 1–32 tags; already-present tags are a no-op; returns the FULL resulting set | asset_id, tags[] | dev (owner) | POST |
asset_tag_remove | Removes tags; absent tags a no-op; returns remaining set | asset_id, tags[] | dev (owner) | POST |
Tag grammar (ONE sentence, ASSET_TAG_RULE_SENTENCE at config:807-809, rendered from ASSET_TAGS, config:781-792): lowercase, 1–64 chars, starts with a letter or digit, may contain ., :, -, _ inside (e.g. pii:reviewed, team.finance). The DB CHECK asset_tags_tag_check (migration 0235) retypes the same regex; audit:catalog-config-agreement binds the two (config:795-797).
2.5 Glossary
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
terms_materialize | Rebuilds the glossary from MDM entity types + validation rules (+ product concepts per TERMS.defaultMode, modes entity_fields_only | entity_fields_plus_free, config:2774) | confirm: true | admin (command-auth.config.ts:553) | POST |
terms_list | One row per SOURCE entry; filters q, source (entity_field | product_concept | manual, config:2776), entity_type_id, include_retired | — | dev | GET |
terms_grouped_list | One row per CANONICAL term (case-insensitive, whitespace-trimmed grouping, config/data-catalog-browse.config.ts); pages over TERMS, not entries | — | dev | GET |
2.6 Bindings and remaster (MDM seam)
These reach the same writers the mdm umbrella admin-floors, so they are admin-floored too ("a second door must not be a lower floor than the first", command-auth.config.ts:554-558).
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
bind_inbound | Binds an OWNED object to an entity type with field_map {field → {column, transform?, pk?}}; schedule default PT6H (config:2812); remaster_policy ∈ auto | agent_review | steward_review (config:2789); supersede:true versions a changed contract | asset_id, field_map, one of entity_type_id/entity_type | admin | POST |
bindings_list | Filter by provider/asset/entity type(s) — entity_type_ids[] answers many types in ONE read | — | dev | GET |
binding_get | One binding incl. last run and next extract | binding_id | dev | GET |
unbind | Retires the binding, deactivates its MDM mapping; history kept | binding_id, confirm: true | admin | POST |
remaster | action ∈ run | skip | rescope (config:2799); mode full/delta; a run writes MDM state | binding_id, action, confirm: true | admin | POST |
2.7 REST-endpoint capture and enrichers
| Command | Does | Required params | Floor | REST |
|---|---|---|---|---|
capture_payload | Executes a saved rest endpoint (must be bound to a connection) and CAPTURES its body as a catalogued payload; optional dataset_id attaches the file for ingest. Envelope keys (CAPTURE_PAYLOAD_KEYS, config:856-863): http_response_code, catalog_enrolment (provider_id, crawler_project_id, job_id, created flags), scan_status (the ENQUEUED discover scan's state — never the HTTP response's) | endpoint_id | dev | POST |
asset_register_enricher | Thin wrapper over mdm.enricher_create: an endpoint-kind asset becomes a rest_lookup enricher for an entity type (input_fields, output_attrs, spec:{var_map,json_path}, stage, failure_policy skip/null/fail/flag, exec_order default 100) | asset_id, name, input_fields, output_attrs, spec, one of entity_type/entity_type_id | admin (command-auth.config.ts:562) | POST |
help | Kind labels, what each kind implements this release, governance sources, standards cited | — | dev | GET |
2.8 Typical sequence
provider_create {kind, name, connection_id} → provider_id
provider_test {provider_id} → health persisted (dial/credential classified)
crawler_create {provider_id, purpose:"discover", name, scope?} → crawler_project_id
scan_run {crawler_project_id} → job enqueued (job.* to follow it)
assets_list {provider_id} → asset_id …
asset_get / columns_list {asset_id}
crawler_create {purpose:"profile", scope:{profiling_mode:"M3"}} → scan_run → profile_get {asset_id}
bind_inbound {asset_id, entity_type, field_map} (admin; needs an M3 extract dataset — see errors)
3. Provider kinds — what each implements today
Source: PROVIDER_KIND_DECLARATIONS → PROVIDER_KINDS (config/data-catalog.config.ts:227-477, derivation at 483); 26 declared kinds. "Identity" below is the row's auth_source field (config:119). path follows STANDARD-010 §1: A = native dial with a declared driver module, B = REST + vault credential, ingest = reached through a pre-existing ingest/crawler lane (not the catalog's own dial). implemented flags are {discover, profile, extract, write, stream}; write/stream are false for every kind in this release.
| Kind | Family | Identity | Phase | Path | discover | profile | extract | Line |
|---|---|---|---|---|---|---|---|---|
postgresql | relational | connection | DC-1 | A | yes | yes | yes | 229 |
snowflake | warehouse | connection | DC-2 | A | yes | yes | yes | 254 |
databricks | warehouse | connection | DC-3 | A (@databricks/sql) | yes | yes | yes | 279 |
bigquery | warehouse | connection | DC-3 | A (@google-cloud/bigquery) | yes | yes | yes | 303 |
sqlserver | relational | connection | DC-3 | A | yes | yes | yes | 314 |
mysql | relational | connection | DC-4 | A (mysql2) | yes | yes | yes | 347 |
iceberg_rest | lakehouse | connection | DC-3 | B | — | — | — | 350 |
salesforce | saas | connection | DC-3 | B | yes | — | — | 380 |
rest_api | saas | connection | DC-3 | B | yes | — | yes (reads a CAPTURED body) | 403 |
dynamics365 | saas | connection | DC-3 | B (Dataverse Web API, OAuth2 client-credentials) | yes | — | — | 428 |
kafka | stream | connection | DC-2 | B (by ruling) | — | — | — | 434 |
s3 | object_store | connection | DC-3 | A | yes | — | — | 443 |
azure_blob, gcs, sftp, ftp, remote_storage | object_store | connection | DC-3 | ingest | — | — | — | 462-466 |
imap | mailbox | connection | DC-4 | ingest | — | — | — | 467 |
socrata, tyler, ckan, arcgis, opendatasoft, dcat, other | portal | crawler_project | DC-2 | ingest | — | — | — | 469-474, 476 |
filesystem | object_store | crawler_project | DC-2 | ingest | — | — | — | 475 |
A declared-but-unbuilt kind is admitted by the enum but provider_create/scan_run refuse with provider_kind_not_implemented / provider_not_scannable (§9). Harvest lanes on disk: lib/data_catalog/harvest/{postgres,snowflake,databricks,bigquery,sqlserver,mysql,rest_api,s3,s3Lake,saas,salesforce,dynamics365}.ts; profile lanes: lib/data_catalog/profile/{postgres,snowflake,databricks,bigquery,sqlserver,mysql}.ts; extract lanes: lib/data_catalog/extract/{postgres,rest_api}.ts plus extractDialects.ts (other SQL engines share the dialect table — inferred from filenames, not read).
4. Sample-value policy ladder
SAMPLE_VALUE_POLICIES = ["plain","masked","omit"] (config:1110). Default omit — no source values stored. Standards cited on the wire: GDPR Art. 5(1)(c), Art. 25, HIPAA 45 CFR 164.502(b) (config:1135). Detection (PII pattern label, lib/data_catalog/piiLabel.ts) ALWAYS runs; only PERSISTING values is gated (config:1107-1108).
Resolution ladder, most specific wins (SAMPLE_VALUE_POLICY.ladder, config:1128): column → scope (crawler) → provider → platform (admin.settings_set key data_catalog.sample_value_policy) → config default. Resolver: resolveSamplePolicy (lib/data_catalog/policyLadder.ts:72) returns {policy, source} so every read can say which rung decided.
Acknowledgement: plain is in requiresAcknowledgement (config:1133). Setting it at provider_create/provider_update or in a crawler scope REQUIRES acknowledge_plain_samples: true; the acknowledgement is written to the job log as an audit row. Reading stored plain values back (columns_list, profile_get) again requires acknowledge_plain_samples: true on the read. The UI's Acknowledgements section (§7) lists providers holding values in the clear and the recorded decision.
5. Scan purposes and the blast-radius sweep guard
Purposes (config:910): discover (harvest objects/columns), profile (column statistics into an AnalysisContract, modes M0–M3), extract (read a relation's ROWS into a dataset for mastering), rescan. Handlers: lib/data_catalog/scan/{run,handlers}.ts; applier lib/data_catalog/harvest/apply.ts.
Sweep guard (SWEEP_GUARD, config:3066-3069): after a harvest, objects no longer seen would be soft-deleted ("swept"). The applier REFUSES the sweep (sweep_refused, apply.ts:263-271) when (a) the harvest saw ZERO objects while the estate still held live ones (zero_objects), or (b) the estate before had ≥ 5 live objects (minEstateForFractionGuard) and the delete would exceed 50 % of it (maxFractionDeleted). Reasons vocabulary SWEEP_GUARD_REASONS = ["zero_objects","magnitude"] (config:3063). Contract violations (harvester spelled scanned_schemas in an undeclared vocabulary) are a SEPARATE, non-ratifiable vocabulary (config:3072-3080).
Acknowledgement (SWEEP_ACKNOWLEDGEMENT, config:3189+): scan_run {acknowledge_sweep:true, reason} — reason 12–500 chars; persisted under catalog.scans.scope.acknowledge_sweep; consumed once; expires after the declared ISO 8601 TTL PT1H (ttl, config:3203); bound to the crawler project AND to the principal the job is attributed to; not carried through job.retry (discloses acknowledgement_not_carried). An expired/foreign/malformed carried acknowledgement is refused with sweep_acknowledgement_rejected — never silently ignored (wire.ts scan_run describe).
6. Quality scoring at read time
quality_basis is ALWAYS derived_at_read (QUALITY_BASIS, config/asset-quality.config.ts:253; wire wire.ts:373): the headline overall (0–100 or null) is projected from stored per-axis measurements and the profile's sampling denominator by projectAssetQuality (lib/data_catalog/profile/qualityProjection.ts:140) — a stored headline is never served, and a 0-row profile reads as unmeasurable estate-wide with no backfill. assets_list returns the compact HEADLINE projection only — no prior contract, so no trend on a list page (assets.ts:104); asset_get carries the per-axis table and compares against the prior profile for trend (assets.ts:163-164). When no honest headline exists, quality_unavailable_reason names why (QUALITY_UNAVAILABLE_REASONS, asset-quality.config.ts:183, e.g. extract_quality_in_dataset_store, extract_backing_dataset_unrecorded — dispatch.ts:744). Privacy runs first: withholdUnmeasuredContractScores (dispatch.ts:777-816) strips producer-side scores the kernel did not measure.
7. The Data Catalog app
Route /app/data-catalog (app/app/data-catalog/page.tsx → DataCatalogDashboard.tsx). Sections are data in config/data-catalog-nav.config.ts:181-212 (order IS the nav) and bound to components in app/app/data-catalog/sections/index.ts:35-47; checkSectionRegistry fails at module load if any declared section lacks a component. Each row declares its feed verb, non-admin writes, adminWrites (⊆ the admin-floored commands) and needsProvider; test:data-catalog-shell L6 asserts those against the live config.
| Section id | Label | Feed verb | Writes | Needs provider | Role floor |
|---|---|---|---|---|---|
overview | Overview | provider_list | — | no | READ |
estate | Estate | provider_list (providers → objects → columns, each a filter for the next; app/app/data-catalog/lib/estate.ts) | — | no | READ |
providers | Providers | provider_list | provider_create/update/test/retire | no | READ |
collections | Objects | assets_list | — | yes | READ |
columns | Columns | columns_search | — | no | READ |
tiles | Sensitivity | provider_get | provider_update | yes | READ |
flow | Processing flow | flow_summary | — | no | READ |
scans | Scans | crawler_list | crawler_create, scan_run | yes | READ |
glossary | Glossary | terms_grouped_list | admin: terms_materialize | no | DEVELOPER |
bindings | Bindings | bindings_list | admin: bind_inbound/unbind/remaster | no | DEVELOPER |
acknowledgements | Acknowledgements | provider_get | provider_update, scan_run (+ SamplePolicyConsent.tsx) | no | DEVELOPER |
Lineage page — app/data-catalog/lineage/page.tsx (segment LINEAGE_ROUTE_SEGMENT = "lineage", label "Lineage", config/lineage-view.config.ts:348-351; nav row at config/app-nav.config.ts:464). It is anchored on one asset (?start=<type>:<id>, parsed by lib/server/lineage/contract.ts) and draws the derivation tree + stored relationships via components/lineage/LineageCanvas. Its honest-empty state is deliberate data, not a defect (LINEAGE_EMPTY_COPY, lineage-view.config.ts:368-377): noAnchor — "Pick something to trace"; noLayers — "No derived files and no snapshots": a typical sub-1GB CSV genuinely has one original file and no derivation layer; layers appear when something derives from it — dataset_snapshot.create writes a snapshot, and the declarative JSON ingest writes a transform step per pipeline operation. Rendered through components/flow/ui HonestEmpty. The config self-check refuses a view with no enabled VIEW_SOURCES (line 881). The catalog's own dependency edges from harvest (dependency_edges in ApplyStats, apply.ts:51, written at apply.ts:489) are recorded, but whether they feed this canvas was not measured here.
8. REST bridge
app/api/app/data_catalog/[verb]/route.ts is the single generic dispatcher (header lines 6-17): verb table from _bridge/registry.ts ← DATA_CATALOG_VERB_METHODS (wire.ts:411-419); door floor per verb from COMMAND_AUTH.data_catalog + tier config; args parsed by the same Zod union; executed by the same dispatchDataCatalog inside a request scope carrying the REAL principal (resolveCatalogPrincipal; the DC-2 fix that removed a constant isAdmin: true, lines 18-27). Success: 200 { data }. Refusal: RFC 9457 problem+json (lib/server/problem.ts) whose code is the registry key and status from REFUSAL_HTTP_STATUS; door refusals are explicit 403 with their own type. Usage metered as web:data_catalog.<verb>.
GET verbs: help, provider_list, provider_get, crawler_list, assets_list, asset_get, columns_list, columns_search, objects_search, profile_get, terms_list, terms_grouped_list, bindings_list, binding_get, flow_summary. POST verbs: every writer (provider_create/update/test/retire, crawler_create, scan_run, terms_materialize, bind_inbound, unbind, remaster, asset_tag_set/remove, capture_payload, asset_register_enricher).
9. Common errors and their fix hints
From the ONE registry lib/mcp/dataCatalogErrors.ts (envelope {ok:false, error:{code, message, retryable, fix:{tool, command?, args, why}}}, line 9). The registry declares 58 codes; the table below covers all 58. Hints are the registry's own fix.why, condensed.
| Code | Meaning | Fix hint |
|---|---|---|
provider_not_found / asset_not_found / crawler_not_found / binding_not_found / term_not_found | Id absent — or foreign; foreign ≡ absent (not-found parity) | provider_list / assets_list {provider_id} / crawler_list / bindings_list / terms_list to obtain a valid id |
endpoint_not_found | REST endpoint id absent/foreign | rest.endpoint_list |
connection_not_found | Vault connection not yours/shared | list your connections |
provider_identity_required / provider_identity_mismatch | Zero or two identities, or wrong one for the kind | connection-backed kinds need connection_id; portal kinds need crawler_project_id |
provider_kind_unknown / provider_kind_not_implemented / provider_not_scannable | Not a declared kind / declared for a later release / kind lacks this purpose | help lists kinds and which implement discover/profile/extract |
provider_exists | One provider per identity source (or crawler name taken) | provider_list to find it |
provider_in_use | Retire refused while bindings feed mastering | unbind {confirm:true} first |
sample_policy_acknowledgement_required | plain requested without acknowledgement | add acknowledge_plain_samples: true (SAMPLE_VALUE_POLICY.acknowledgementFixWhy) |
invalid_cadence | Not ISO 8601 duration / RFC 5545 RRULE | e.g. PT6H, P1D |
invalid_tag | Tag breaks the grammar | skeleton asset_tag_set {tags:["example-tag"]}; rule sentence in fix.why |
scan_in_progress | Another scan holds the provider's harvest lock | provider_get, retry after it finishes |
scan_budget_exhausted | Object budget reached, stopped cleanly | re-run to resume, or narrow scope |
invalid_sweep_acknowledgement / sweep_acknowledgement_rejected | Reason too short / acknowledgement expired, foreign crawler, or foreign principal | re-issue scan_run {acknowledge_sweep:true, reason} (not job.retry) |
credential_expired / cleartext_refused / credential_shape_invalid / host_unresolvable | Connection-side defects; nothing about the credential was proven | recreate/re-store the connection (https, declared shape, future expires_at) |
provider_dial_auth_failed / provider_dial_timeout / provider_dial_unreachable / provider_dial_config_rejected / provider_dial_failed_unclassified | Classified dial outcomes from provider_test/scan | auth: fix stored credential (retry changes nothing); timeout/unreachable: retry, check host/egress; config: check database/catalog/bucket name; unclassified: details.driver_code |
token_acquire_failed / token_endpoint_unreachable / credential_rejected / token_response_too_large | OAuth2 grant failures (Path B kinds) | retry later / verify token URL / fix client id, secret, scope, audience / RFC 6749 §5.1 response too large |
provider_response_malformed | Endpoint answered but not the expected metadata JSON / over byte ceiling | check the endpoint |
asset_not_profiled / profile_count_unavailable | No profile yet / row count undeterminable | run a profile crawler; profiling on an unknown denominator is refused |
binding_dataset_required | Binding masters the FULL extract dataset | profile crawler with scope.profiling_mode:"M3", scan_run, then bind |
binding_exists / binding_contract_changed / binding_pk_unsupported | One ACTIVE binding per (direction, asset, entity type) / contract differs / composite PK | reuse or retire / supersede:true / mark exactly one pk:true on a unique column |
entity_type_not_found | Bad entity_type(_id) | pass a registered entity type by id or exact name |
remaster_not_pending / run_in_progress / automation_stopped | Nothing pending / a run already queued / MDM pause or kill flag | binding_get / job.list_mine / mdm.control_clear |
asset_not_endpoint / enricher_refused / endpoint_unbound_not_catalogable | Wrong asset kind for an enricher / MDM writer refused / endpoint has no bound connection | assets_list {kind:"endpoint"} / read context.reason / bind the endpoint to a connection you own |
strategy_unavailable | auth_broker resolver not usable for this connection type yet | use local_vault |
driver_unavailable | This deploy does not carry the kind's declared driver module (Path A dial) | a DEPLOYMENT state, not a credential one — install the release's dependencies (npm ci); other kinds unaffected |
owner_unresolvable | Caller identity resolves to no account | verify your key (writes never create NULL-owner rows) |
provider_readonly_violation / write_dialer_not_declared / write_shape_required / write_shape_lane_mismatch | Catalog sessions are READ-only at the connection boundary; no write grammar declared this release | not actionable by callers this release (write:false for every kind, §3) |
governance_read_unavailable | Requested governance source not servable for this kind | help → governance_control |
param_retired | Project-level sampling_config is dead | dataset_admin.settings_update |
self_database_undeterminable | Platform cannot prove the provider is not itself; fails closed | operator action |
10. Trust notes
- Everything above was read from source; nothing was executed against the live database, so counts (e.g. glossary size "18,223 entries" quoted in
wire.tscomments) are as of the comment, not measured now. - Unmeasured here: the full
QUALITY_UNAVAILABLE_REASONSvocabulary, the per-kind governance-source table (help), and whether harvestdependency_edgesreach the lineage canvas. - Standards applied on this surface: ISO 8601 durations / RFC 5545 RRULE for cadences, RFC 3339 for
flow_summarybounds, RFC 9457 for REST refusals (MCP surface uses the compact envelope), RFC 9110 §15 forhttp_response_code, GDPR Art. 5/25 and HIPAA 164.502(b) for the sample-value default.
Measured against the release named in the text. Raw Markdown: /ontology/documentation/data-catalog.md. This page is also served as raw Markdown at the same URL with a .md suffix, for agents and search tools that prefer plain text. Every capability statement cites the source file and line it was measured from.
You've seen the proof
Ready for a number? Scope your deployment and we'll price it against your own economics.
Get your quote →