Skip to content

#260 — render: governance chips — access/deprecation/version/group + access-violation (Slice 4) - #351

Merged
cmbays merged 2 commits into
mainfrom
governance-260-slice4-chips
Jun 13, 2026
Merged

cmbays merged 2 commits into
mainfrom
governance-260-slice4-chips

Conversation

@cmbays

@cmbays cmbays commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor

Part of #260 (Slice 4). The five founder-approved dbt-native lifecycle chips on GovernanceFacts, gated behind Experiment::Governance, server-rendered in the gated governance section.

The five chips (one PURE PREDICATE each — CRAP all < 15)

  1. public-surface-changed — access==public ∧ Slice 5's classify_contract is Breaking. Public contract — breaking change.
  2. ref-to-deprecated{model,date} — DUAL STATE: future date ⇒ scheduled (data-chip-severity="info"); today-or-past ⇒ elapsed (severity="danger"). Malformed date ⇒ no panic, no chip. Severity rides the attr → theme semantic tokens, never a hardcoded color.
  3. version-bump-without-latest — version != latest_version (ADVISORY, no severity — latest_version lag during migration is legitimate).
  4. group-owner-touch — grouped model whose group owner declares an email.
  5. access-violation — a private model ref'd across a group boundary.

Critical semantics (verified vs the real playground fixture)

  • access defaults to protected when unset (missing ≠ public — effective_access); confirmed the fixture carries protected on all 34 models.
  • version/latest_version are post-normalized strings (2 == "2").
  • deprecation_date is %Y-%m-%d, parsed by the pure std-only DepDate::parse (malformed → None → no chip).

Golden-determinism (the gotcha you flagged)

The scheduled/elapsed split compares deprecation_date to "today". To keep the domain pure + deterministic, "today" is computed at the I/O boundary (cli today_dep_date → civil_from_days, Hinnant's algorithm, std-only — the domain forbids chrono) and threaded into gather_governance as Option<DepDate>. Tests pass fixed far-past (2020) / far-future (2099) dates so the golden + headless never drift.

Hooks (intentionally unstyled — Claude Design owns the visual pass)

data-testid="gov-chip" + data-chip-kind (+ data-chip-severity for the dual-state). No bespoke CSS — chips inherit the shared chip/semantic classes.

Dogfood

The chip fires naturally on the existing diff-showcase data: dim_payers (grouped clinical_quality, owner email, in scope) → the golden gains ONE group-owner-touch chip. Regenerated (chip span + JSON lifecycle_chips field only; no root_path leak). All other goldens byte-identical (jaffle/playground governance-off; explore gate-free — the gating holds). The richer access/deprecation/version declarations are Slice 6 dogfood — Slice 4 uses synthetic in-test fixtures.

Tests

  • One unit test per chip predicate + the negatives: protected-not-public, malformed-date-no-panic, version-normalize-equal, dual-state (scheduled/elapsed/today-boundary/unknown-today), private-within-group-ok, public/protected-target-no-violation, missing/non-model-ref skip.
  • DepDate::parse (well-formed + 10 malformed); civil_from_days vs known epoch days.
  • DOM-targeted chip render tests (kind/label, dual-state severity attr, off=no-DOM); chip headless guard (real Chromium, on the showcase).

Gates (all green, both golden arms)

  • fmt · clippy --all-targets --locked -D warnings on a clean build (exit 0) · nextest (1870) · coverage 98.62% (≥85) · crap4rs PASS
  • bdd (28) · doc -D warnings · deny · heuristics ledger byte-identical
  • REPORT goldens (jaffle/playground/diff-showcase) AND EXPLORE golden (dag.html + tests.html) byte-identical · governance/enforcement/composite/chip + explore-zero-egress headless (real Chromium)

🤖 Generated with Claude Code


Open in Stage

…/group + access-violation (Slice 4)

Part of #260 (Slice 4). The five founder-approved dbt-native lifecycle
chips on GovernanceFacts, gated behind Experiment::Governance, rendered
server-side in the gated governance section.

Chips (one PURE PREDICATE each — CRAP all < 15):
- public-surface-changed — access==public ∧ classify_contract (Slice 5)
  is Breaking. `Public contract — breaking change`.
- ref-to-deprecated{model,date} — DUAL STATE: future date ⇒ scheduled
  (data-chip-severity="info"); today-or-past ⇒ elapsed (severity="danger").
  Malformed date ⇒ no panic, no chip. Severity maps to theme semantic
  tokens via the attr, never hardcoded color (Claude Design owns visuals).
- version-bump-without-latest — version != latest_version (ADVISORY, no
  severity — latest lag during migration is legitimate).
- group-owner-touch — grouped model whose group owner declares an email.
- access-violation — a `private` model ref'd across a group boundary.

Critical semantics (verified vs the real playground fixture): `access`
defaults to `protected` when unset (missing ≠ public — `effective_access`);
`version`/`latest_version` are post-normalized strings (`2`==`"2"`);
`deprecation_date` is `%Y-%m-%d`, parsed by the pure std-only `DepDate`.

GOLDEN-DETERMINISM: the scheduled/elapsed split compares deprecation_date
to "today". To keep the domain PURE + deterministic, "today" is computed
at the I/O boundary (cli `today_dep_date` → `civil_from_days`, Hinnant's
algorithm, std-only — the domain forbids chrono) and threaded into
`gather_governance` as `Option<DepDate>`. Tests pass fixed far-past
(2020) / far-future (2099) dates so the golden + headless never drift.

Chips carry `data-testid="gov-chip"` + `data-chip-kind` (+
`data-chip-severity` for the dual-state) — intentionally unstyled beyond
the shared chip classes (Claude Design's pass).

Dogfood: the chip fires NATURALLY on the existing diff-showcase data —
dim_payers (grouped `clinical_quality`, owner email) is in scope, so the
golden gains ONE group-owner-touch chip. Regenerated (chip span + JSON
lifecycle_chips field only; no root_path leak). All OTHER goldens
byte-identical (jaffle/playground governance-off; explore gate-free — the
gating holds).

Tests: one unit test per chip predicate + protected-not-public negative,
malformed-date-no-panic, version-normalize-equal, dual-state
scheduled/elapsed/today/unknown-today, private-within-group-ok,
public/protected-target-no-violation, missing/non-model-ref skip; DepDate
parse (well-formed + 10 malformed); civil_from_days vs known dates;
DOM-targeted chip render tests (kind/label, dual-state severity attr,
off=no-DOM); chip headless guard (real Chromium, on the showcase).

Gates (both golden arms): fmt; clippy --all-targets --locked -D warnings
on a CLEAN build (exit 0); nextest (1870); coverage 98.62% (>=85); crap4rs
PASS; bdd (28); doc -D warnings; deny; heuristics ledger byte-identical;
REPORT goldens (jaffle/playground/diff-showcase) AND EXPLORE golden
(dag.html + tests.html) byte-identical; governance/enforcement/composite/
chip + explore-zero-egress headless.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@cmbays, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 1 minute and 8 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12b0acc7-054c-416d-8584-461a1c720041

📥 Commits

Reviewing files that changed from the base of the PR and between 7cd4a6c and 9e7ec94.

📒 Files selected for processing (7)
  • examples/diff-showcase-report.html
  • src/adapters/render.rs
  • src/cli/mod.rs
  • src/domain/governance.rs
  • src/domain/mod.rs
  • templates/report.html
  • tests/headless_toggle.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch governance-260-slice4-chips

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cmbays cmbays added the type:feature New capability label Jun 13, 2026
@ghost

ghost commented Jun 13, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 6 individual chapters for you:

Title
1 Define governance chip domain models
2 Implement lifecycle chip predicate logic
3 Calculate current date at CLI boundary
4 Render chips in HTML reports
5 Verify chips with domain unit tests
6 Update goldens and headless tests
Open in Stage

Chapters generated by Stage for commit 9e7ec94 on Jun 13, 2026 1:46pm UTC.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements Slice 4 of the dbt-native lifecycle chips (including public-surface-changed, ref-to-deprecated, version-bump-without-latest, group-owner-touch, and access-violation) for governance reports. It introduces the GovChip and DepDate structures, calculates the current date at the CLI boundary to keep the domain pure, updates the HTML template, and adds comprehensive unit and headless browser tests. The review feedback suggests optimizing performance by returning borrowed &str instead of allocating owned Strings for chip severity, and simplifying the Askama template syntax in report.html by using if let instead of a full match block.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/domain/governance.rs
Comment thread templates/report.html
@github-actions

github-actions Bot commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor

📄 Rendered report preview

All golden examples regenerated cleanly.

🟡 Golden examples

Committed to examples/ and byte-identity gated — the canonical reports contributors and consumers browse. Stable across PRs.

Report View Download
jaffle-shop-report.html ▶ Open ↗ ⬇ Download
diff-showcase-report.html ▶ Open ↗ ⬇ Download
playground-report.html ▶ Open ↗ ⬇ Download

🐶 Live dogfood preview

This PR doesn't touch dbt-project/, so there's no live dogfood preview.

🧭 Explore preview

The two-page cute-dbt explore explorer — dag.html (model lineage) + tests.html (unit-test viewer). Same golden/live split as the report.

🟡 Golden explore

The committed examples/explore/ playground golden (the full synthetic playground manifest). Byte-identity gated in Example report check. Stable across PRs.

Page View Download
explore/dag.html ▶ Open ↗ ⬇ Download
explore/tests.html ▶ Open ↗ ⬇ Download

🐶 Live explore

This PR doesn't touch dbt-project/, so there's no live explore preview.

▶ Open ↗ opens the report or explorer in your browser in one
click — published to this repo's GitHub Pages under
/pr-351/.
⬇ Download fetches the same self-contained HTML as a workflow
artifact (auth-gated; works fully offline). Either way the report
makes zero external resource requests.

The Pages preview may take ~1 min to update after this comment
posts. On PRs from forks the Open link is unavailable (read-only
token) — use Download.

Alternative: GitHub CLI
# gh CLI >= 2.63 extracts into ./report-preview-playground/.
gh run download 27468509484 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for 9e7ec94c58eacb8655465c6ad5f04525ab814d3d. Affordance only — never blocks merge.

@cmbays
cmbays merged commit 26951eb into main Jun 13, 2026
35 checks passed
@cmbays
cmbays deleted the governance-260-slice4-chips branch June 13, 2026 13:53
github-actions Bot added a commit that referenced this pull request Jun 13, 2026
cmbays added a commit that referenced this pull request Jun 14, 2026
…n-uncovered gate + row-5-reversal ADR

Wrap the already-Serialize-deriving Finding POD in a versioned
metadata.schema_version header (epic #261, cute-dbt#386) and emit it as
a machine-readable SIDECAR beside the HTML report — the sanctioned
reversal of ARCHITECTURE conscious-simplification row-5 ("no JSON wire
envelope"), authorized by the founder's ADR-4 amendment (2026-06-11) and
the four #261 locked decisions.

- domain (pure POD + gate): src/domain/findings_envelope.rs —
  FindingsEnvelope { metadata, findings: Vec<Finding> }; EnvelopeMetadata
  pins schema_version=1 (integer) + id_stability="unstable-v0.x" from
  constants; EnvelopeScope tags baseline | pr-diff; has_total_uncovered
  is the D3 gate predicate (Total-tier Uncovered only, not configurable).
- adapter (collect + emit): src/adapters/findings_emit.rs — mirrors the
  renderer's per-model model_findings -> apply_check_policy pipeline
  EXACTLY (parses each in-scope model's CTE graph), so the envelope's
  findings match the report's; serializes pretty JSON + writes the
  sidecar. Never touches report.html or render.rs.
- cli: --findings-out <path> (additive sidecar, NOT --format json) +
  --fail-on-uncovered (dedicated EXIT_GATE=3, distinct from usage/2 and
  fail-closed/1; the report is written BEFORE the gate trips) + a hidden
  --generated-at golden-regeneration override. generated_at is computed
  at the CLI I/O boundary (today_rfc3339_date, reusing the #260/#351
  civil_from_days machinery — std-only, NO chrono/time) and emitted as an
  RFC3339 date (YYYY-MM-DD; a finer timestamp would need a date crate the
  std-only posture forbids).
- envelope golden: examples/diff-showcase-findings.json (synthetic
  playground pr-diff combo, pinned --generated-at 2099-01-01),
  byte-identity-gated in the example-report-check diff-showcase row.
- ARCHITECTURE row-5 amended to "reversed — now present"; AGENTS.md
  conscious-simplification enumeration updated. The HTML byte-identity
  goldens are UNCHANGED (git status examples/ shows only the new JSON).

OpenLineage: fields shaped design-compatible, NO OL output (D4 deferred).
Owner fields (#256): slot reserved, not populated. SARIF: not now.

Closes #386

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant