Skip to main content
Version: v0.0.75

Governance

Governance runs are automated review checks that gate publishing. Before an asset can be promoted from is_test=true (visible only to the creator + admins) to live, it has to pass — or at least be reviewed against — a curated set of advisory and blocking checks.

The pipeline shipped in v0.0.62 along with Cobuild and the promote_to_live lifecycle. It is available for recipes, dashboards, and agents.

Checks

CheckSeverityAsset typesWhat it verifies
asset_resolvedblockingrecipe, dashboard, agentThe asset exists in (project, org) scope. A cross-tenant ID can't slip through.
has_executable_bodyadvisoryrecipeThe recipe has at least one step — not an empty stub.
has_cardsadvisorydashboardThe dashboard has at least one card.
has_toolsadvisoryagentThe agent has at least one row in agent_tool_assignments. A toolless agent is a stub — the LLM can chat but can't query datasets / search a KB / call any external surface.
no_unmasked_piiadvisoryrecipe, dashboard, agentWalks the assets' referenced datasets, classifies columns through masking.classify_columns, flags columns whose effective masking strategy is 'none' on a non-None sensitivity.

Severity drives the verdict:

  • A single blocking failure makes the run verdict failpromote_to_live refuses to fire.
  • One or more advisory failures make the verdict warn — promotion is still allowed, but the run records which checks flagged for audit.
  • All checks pass → verdict pass.

no_unmasked_pii — masking resolution order

The PII check uses the same column classifier as the rest of the platform, so the rule resolution stays in one place:

  1. Dataset-level overridedatasets.settings.masking[col].strategy.
  2. Org-level defaultorganizations.data_policies.masking_defaults[semantic_type].
  3. Auto-maskPII_DEFAULTS based on the column's inferred semantic type (email, phone, ssn, address, ...).

A per-dataset 'partial' rule beats an org-wide 'none' — tenants that opt out of an org policy via a dataset override remain unflagged. DB errors on the lookup degrade to "no defaults" (empty {}); the verdict falls back to whatever per-dataset overrides + auto-mask produce. Posture is degrade, don't block — a governance probe that can't load data_policies shouldn't 500 the activation gate.

Where governance runs from

Three entry points:

From Cobuild

The planner can call run_governance_review as a tool mid-loop. The verdict surfaces in the next PlanCard along with the contributing checks; if the verdict is pass, the planner can chain promote_to_live in the same approval batch. See Cobuild → Governance and promotion lifecycle.

From an asset page (recipe / dashboard / agent)

Recipe and dashboard pages carry a Run governance action that fires a one-off review. The result drawer lists each check's verdict and a friendly explanation for any warn / fail.

From the API

# Fire a review
curl -X POST https://platform.your-domain.com/api/governance/run \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "asset_type": "dashboard", "asset_id": 42 }'

# List runs in scope
curl https://platform.your-domain.com/api/governance/runs?asset_type=dashboard&asset_id=42 \
-H "Authorization: Bearer $TOKEN"

API reference

EndpointDescription
POST /api/governance/runFires run_governance_review on one asset, persists the row, returns the serialized GovernanceRun.
GET /api/governance/runsLists in (project, org) scope, newest first; optional asset_type + asset_id filters. Cap 200, default 50.

Pydantic Literal["recipe", "dashboard", "agent"] rejects unsupported asset_type values at the boundary (HTTP 422).

Promote-to-live

A new is_test boolean on published_assets underpins the lifecycle:

  • Newly created assets default to is_test=true — visible only to the creator and org admins.
  • The promote_to_live planner tool flips is_test=false. The tool is gated by a passing F10 governance run: if there's no GovernanceRun row with verdict='pass' for this asset within a reasonable window, promote_to_live refuses and the planner surfaces the failing checks.
  • Once flipped, the asset becomes visible to everyone with the matching read permission (dashboard.read, recipe.read, etc.).

Promotion is one-way in the current release — to revert an asset to test mode, edit it manually. A future release may add a demote_to_test lifecycle once we see the access patterns it should support.

Schema

governance_runs
├── id bigserial
├── project_id int
├── org_id int
├── asset_type text CHECK (asset_type IN ('recipe','dashboard','agent'))
├── asset_id int
├── verdict text CHECK (verdict IN ('pass','warn','fail'))
├── checks jsonb -- per-check result records
├── started_at timestamptz
├── finished_at timestamptz
└── created_by int

checks is a JSONB array of {name, severity, status, detail} entries — one per check that ran. Use JSONB containment queries to audit specific check histories ("which recipes ever had no_unmasked_pii: fail?").