Skip to content

Rule governance

Business Rules and Remediation read the console’s Atlas governance API, GovernanceService (grpc/operators/core/api/proto/runink/core/atlas/v1/governance.proto, implemented in internal/console/atlas_gov.go and atlas_gov_store.go).

Atlas showed a rule status, an owner and Approve / Edit buttons, but none of it was wired. CORE makes every piece of it change what is scored, or states plainly that it cannot.

What a rule status does

RuleStatusRuleEffect (from the server)Meaning
APPROVEDRULE_EFFECT_SCOREDFindings count in the DQ score, KPIs, dashboards and scan history. The default for every engine rule
PENDING, DRAFTRULE_EFFECT_DRY_RUNThe rule is still evaluated and its findings are listed with Finding.dry_run, but they are excluded from every figure. Each excluded rule is named in provenance.unmeasured, so a DQ figure never silently changes meaning
REJECTEDRULE_EFFECT_NOT_EVALUATEDThe rule is not evaluated, and its findings do not exist

Clients read the effect from the server and never derive it from the status. ListRules returns each rule with its status, effect, owner (or the reason there is none), finding count and open changes.

Proposing and deciding changes (four eyes)

A rule change is proposed by one identity and decided by another.

RuleChangeKindCarries
STATUSrule_id + proposed_status
PARAMETERparameter (and optionally rule_id)
NEW_RULEnew_rule (title, expression, sheet, severity)

A rationale is required for every proposal (rationale is required — a change nobody can explain is not reviewable).

PARAMETER changes may set only the engine thresholds in govParamDefs. The allowed ranges exclude values that would switch a rule off by arithmetic. A rule is switched off by a REJECTED status, visibly.

ParameterMovesRange
tolerance_daysCP-007, CR-0060..365, whole days
unit_price_capital_thresholdCP-0060.01..1e9
approval_lag_min_daysCR-0070..365, whole days
request_plan_tolerance_pctCR-0090..100
overspend_factorSP-0031..10

DecideRuleChange approves or rejects an OPEN change. The decider must be the rule’s owner or an Atlas admin, and never the proposer. A proposer who tries to decide gets:

four eyes: … proposed … and may not decide it — it needs … (the proposer may only WITHDRAW)

The proposer may withdraw their own open change (DECISION_WITHDRAW), and that is the only decision they may make. Approving applies the change:

  • a status change re-scopes scoring;
  • a threshold change updates the engine configuration;
  • a new rule is recorded as approved but unevaluated.

A rule may have only one open change at a time (… already has an open change (…) — decide or withdraw it first).

A NEW rule is never evaluated. CORE has no evaluator for free-text expressions, and pretending to run one would fabricate a verdict. The rule is stored and governed, and its effect stays RULE_EFFECT_NOT_EVALUATED.

SetRuleOwner names (or clears) the identity that decides a rule’s changes and remediations. It is admin only. The owner must be an email address as the console knows it.

The remediation queue

ListRemediations returns one item per current finding, scored and dry-run alike, with its fix, the required approver and its state.

FixKindMeaning
FIX_KIND_DETERMINISTICA mechanical rewrite exists (for example CP-006 “reclassify to Non-Capital”). DryRunRemediation can simulate it
FIX_KIND_ADVISORYThe fix needs a human or a source-system action. A dry run answers FAILED_PRECONDITION with the reason (… cannot be dry-run: …), never a simulated guess
  • DryRunRemediation applies a deterministic fix to a copy of the current feeds, re-runs the engine, and returns before/after. It writes nothing, so it is classed as a read.
  • DecideRemediation records APPROVE or DISMISS. It does not modify any feed. CORE holds a copy of the uploaded feeds, not the source system, and has no write-back path. An approved fix is applied at the source and resolves on the next ingest. A dismissal is bound to the upload of the finding’s sheet, so re-ingesting that sheet re-opens the item if the finding persists.
  • Remediation confidence is always absent. Every fix is the rule book’s remediation, not a model’s inference. (Atlas displayed a hard-coded 89%.)

The decision log

ListDecisions returns rule changes, owner changes, remediation decisions and playbook decisions, newest first. Each DecisionRecord mirrors the audit event that the same write appended to the hash chain, and audit_seq links the two. The governance store keeps a 500-entry decision log.

Policy classes (atlasPolicies)

Every Atlas RPC has exactly one class in atlasPolicies (internal/console/atlas_grpc.go). A method missing from the table is treated as admin-write, so it fails closed.

ClassWho may callExamples
readAny admitted identity, including on an open consoleListRules, ListRemediations, DryRunRemediation, ListDecisions
attributable-writeA session on a console with sign-in configuredProposeRuleChange
decider-writeAttributable at the gate. The handler then requires the rule owner or an Atlas admin, never the proposer, inside the governance store’s CASDecideRuleChange, DecideRemediation, ActivatePlaybook, DecideApproval
admin-writeadminRefusal with CORE_ATLAS_ADMINSSetRuleOwner, every CapEx write, every workspace write

CORE_ATLAS_ADMINS is optional. Unset means every identity this console admits (sign-in itself fails closed through CONSOLE_ALLOWED_EMAILS / _HD). Set, it narrows admin rights to the list.

On a console with no sign-in, reads are allowed and every other class is refused. Every non-read attempt is audited under resource atlas-governance, with actions such as atlas.rules.propose, atlas.rules.decide, atlas.remediation.decide and atlas.rules.owner. That includes refusals at the gate and four-eyes denials by the handler.

Rules reconciliation (the recon agent)

Below the governance section, Business Rules shows /api/rules-recon: the recon agent’s reconciliation of the tenant’s governance rule book against the CapEx engine the console runs. Each rule gets one verdict (grpc/agents/recon/reconcile.go):

VerdictMeaning
AlignedThe implementation matches the governing policy
DriftThe implementation diverges from it (for example an approved threshold differs from the value the engine evaluates with, or a status disagrees with its effect)
ShadowLogic exists with no governing policy
MissingA policy exists with no implementation (governed but never raised, or a governed id the engine lacks)
A fresh workspace is mostly Shadow, and that is correct. The governance document records a rule only when the tenant did something: decided a status change, named an owner, or approved a threshold. A rule running on the engine’s built-in default (approved, no owner) is CORE’s code, not a policy anyone wrote, so it cites no policy document.

Every comparison is deterministic. The model is asked only whether an approved free-text NEW rule is already implemented by an engine rule. Unknown is never a verdict:

  • an unread governance document is zero rules and complete:false;
  • an unread engine threshold is a gap;
  • with no model, new rules are gaps, not Missing.

The agent runs daily at 09:37 UTC, on an @core_recon comment, on workflow_dispatch, and as a playbook step (core-agent-recon.yml). Its read door is GET /api/rules-recon/inputs and its write door is POST /api/rules-recon/report. Both doors take the token CORE_RECON_INGEST_TOKEN (Secret core-recon-token). The browser reads the result through the session-gated GET /api/rules-recon. See the agent fleet.