Engineering & roadmap

Implementation review: PB-059, PR 605

Development documentation. This guide follows a reviewed snapshot of main and may describe capabilities not yet in Stable. Check Preview labels and release notes. Some executable names and paths remain unchanged for compatibility. Legacy names explained ↗
Field Value
Backlog item PB-059 Governance exception requests and approvals (FD-129; feature FEAT-GOV-03)
Pull request #603 (approved exceptions shown, warning before they end; merged as b9356a44) and #605 (exception requests on the platform; merged as fd4694ea). Requests moved to Data mesh > Requests in #806 (6159e507).
Package None
Reviewer Engineering quality review thread. It didn't write #603 or #605.
Date 2026-10-27
Environment Linux container, main 6159e507, Python venv for the engine, Playwright Chromium. No tenant, no Windows, no second PC.

Outcome#

Changes Required (recommended).

The work splits in two:

  • Policy exceptions (#605). These are well built on the GOV-001 registry. Someone asks for one, a platform admin approves it, it's recorded in catalog.policy_exception, the audit and the policy's history, and it ends on its date. Check now and Explain show it.
  • Project exceptions in exceptions.toml (#603). FD-129's criteria are written about these, and they are now shown with a notice before they end. They are still lines someone types into a project file. There's no request, no approval and no audit record of who asked or who approved.

Three gaps remain. FD-129's third criterion isn't met for the file it names. Policy exceptions get no warning before they end. Nobody can end a policy exception early. The fix is either code or a product decision: the owner could narrow FD-129 so that policy exceptions are the governed path and exceptions.toml stays a developer's file.

Recommended by: Engineering quality review. Decided by (product owner): pending.

Where the criteria come from#

PB-059's criterion is "As defined in FD-129". I found FD-129 in docs/product/enterprise-backlog.md:126–129:

exceptions in exceptions.toml show in the app with owner, reason, approver and expiry; expiring ones raise a notice; adding one records who asked and who approved in the audit trail (FD-125).

Line 129 (added by #603) still says: "Still open: asking for an exception in the app, and recording who asked and who approved in the audit trail." GOV-001 is the policy registry in docs/governance.md. PB-059's own capability line is "Request, approve and expire exceptions with history, aligned with the policy registry." I reviewed against both.

Acceptance criteria#

# Criterion Result Evidence
1 FD-129: exceptions in exceptions.toml show in the app with owner, reason, approver and expiry Met describe_exceptions (sidecar/fabric_desktop/meta/project.py:394) adds the table's owner, status and days left. Project.summary returns it as exception_notices (line 377). Data mesh > Quality > Exceptions (renderExceptionsTab, app/ui/meta.js:234) shows Table, Rule, Owner, Reason, Approver and Ends. "Approver" is whatever name was typed in the file, not a checked identity.
2 FD-129: expiring ones raise a notice Met for exceptions.toml; not met for policy exceptions A project exception ending within 14 days (EXCEPTION_WARN_DAYS, project.py:54), or already ended, gets a notice on the bell once a day and a banner on Data mesh (exceptionNotice, raiseExceptionNotices, exceptionBanner, meta.js:203–232). Policy exceptions just stop at their date (list_policy_exceptions(active=True), central/policy.py:488). Nothing warns the requester or the project first.
3 FD-129: adding one records who asked and who approved in the audit trail Met for policy exceptions; not met for exceptions.toml Policy exceptions: core.request writes the request row (requested_by) and audits request exception (central/core.py:1796–1853). decide_request checks that the caller is an admin, calls _approve_exception (policy.py:467; require_admin), and audits approved exception (core.py:1923–1976). _event adds exception granted to the policy's history and policy exception granted to the audit (policy.py:200–207). exceptions.toml is still edited by hand: no request, approval or audit (governance.md:227 says the two are separate).
4 PB-059: request, approve and expire with history, aligned with the policy registry Partly Request: Data mesh > Requests > New request > An exception to a policy (app/ui/platform.js:644–756). Also the policy's "Ask for one" (app/ui/governance.js:286, opens the dialog then Data mesh > Requests) and Check now's "Ask for an exception" (governance-checks.js:145). _check_exception (policy.py:435) refuses unpublished or retired policies and policies with exception_eligible = false. It also refuses an unknown domain, a date that isn't after today or is more than a year away, and a request with no reason. Approve: platform admins only, with a confirm dialog (platform.js:900). Expire: ends after its until day (_excepted, policy.py:498). History: request row, audit, policy history. Missing: ending one early, a list of ended exceptions (only active ones are shown), and the exceptions.toml side.

Checks#

Check Result Evidence or note
Scope matches the item Partly #603 and #605 each cover half of PB-059. They never meet: a save-gate exception can't be requested, and a policy exception doesn't affect the save gate.
New tests fail without the change, pass with it Met #605: in a copy of fd4694ea with the pre-#605 central/policy.py, tests/test_requests_core_four.py gave 3 failed, 2 errors, 14 passed. The 5 exception tests failed, for example no attribute '_approve_exception' and no operation 'list_policy_exceptions'. With #605's policy.py: 19 passed. #603: in a copy of b9356a44 with the pre-#603 meta/project.py, test_05e_exception_notices_name_the_owner_and_warn_before_expiry failed (1 failed, 1 passed). With it: 2 passed.
Full suites pass (pytest, UI, cargo) Partly (subset) On main: pytest tests/test_requests_core_four.py tests/test_meta.py tests/test_best_practice_checks.py: 87 passed. pytest tests/ -k "exception or governance or polic or request": 278 passed, 1 skipped. node --test app/tests/ui.test.cjs: 297 of 297 passed. Browser: requests-core-four 8 of 8, mesh-requests 3 of 3, best-practice-checks 8 of 8, platform-notices 5 of 5. No Rust change. I didn't run the full pytest suite.
Reachable where docs say; Preview behavior right Mostly Data mesh > Requests (after #806). The policy's "Exceptions in force" card is on its Where it applies tab (governance.js:360). Request notices still carry open: {view: "platform", tab: "requests"} (governance_notices.py:76, 84); #806 sends old Platform links to Data mesh. No browser test opens the Quality > Exceptions tab or the policy's Ask for one button.
OneLake data safety Met Writes only the platform catalog (catalog.request, catalog.policy_exception, catalog.policy_event, catalog.audit). The table is created on first approval or by Finish or repair. An older UDF without list_policy_exceptions shows a problem line, and the policies still load (governance_service.py:67).
Authentication and distribution Met Granting needs a platform admin, checked in the engine as well as the UI. test_an_exception_needs_admin_even_through_the_platform_directly calls _approve_exception as a developer and is refused. No new scope.
No unproven claim; Preview tags kept Met The request kinds are tagged Preview. Nothing claims tenant behavior.
Docs match the code Not met governance-guide.md:124 says "Policies don't check projects yet (GOV-002), so today an exception is a recorded, visible decision". But Check now applies exceptions to findings (checks_service.py:323, 341; governance.md:128). enterprise-backlog.md:129 still lists the request flow and audit as open with no mention of #605. FEAT-GOV-03 says "Platform > Governance > Requests" (FEATURE_INVENTORY.md:208, 1427), which is now Data mesh > Requests.
Accessibility of new controls Met (by reading) The new dialog fields have aria-labels (platform.js:730–746). The tables use th headers. No axe run here.
Inventory and backlog updated Partly FEAT-GOV-03 lists both PRs and tests. Its location and description need the #806 move (above).

Findings#

# Severity (blocking / should fix / note) Finding Where Status
1 blocking (criterion) FD-129's third criterion names exceptions.toml. Adding one there still records nobody: no request, no approval, no audit. The approver is free text in a file. Either route save-gate exceptions through the same request flow (an approved request writes the file, or the gate reads platform exceptions), or have the product owner rewrite FD-129 so policy exceptions are the governed path. meta/project.py:271, 358; enterprise-backlog.md:128–129 Open: FD-129 owner
2 should fix Policy exceptions get no warning before they end. Project exceptions get a 14-day bell notice and a banner. policy.py:488; governance_notices.py Open
3 should fix A granted policy exception can't be ended early or revoked. The only way is to edit catalog.policy_exception by hand. Ended exceptions aren't listed anywhere in the app, though the policy's history and the requests list keep the grant. policy.py (no revoke operation); governance_service.py:71 (active=True only) Open
4 should fix governance-guide.md:124 says exceptions don't yet affect checks, but Check now marks the findings they cover as excepted. FD-129's "Still open" line and FEAT-GOV-03's location are out of date. docs/governance-guide.md:124; docs/product/enterprise-backlog.md:129; FEATURE_INVENTORY.md:208, 1427 Open: docs
5 note withdraw_request writes no audit entry. The request row does keep withdrawn and who withdrew it. central/core.py:1979–1988 Open: low risk
6 note No browser test covers Data mesh > Quality > Exceptions or the policy's Ask for one button. ui.test.cjs:364 checks exceptionNotice and the tab's name only. app/tests/browser Open

Inventory and backlog changes#

  • Features changed: FEAT-GOV-03: location to Data mesh > Requests and Data mesh > Quality > Exceptions; add the limitations in findings 1–3.
  • Backlog item state: PB-059 stays In review until finding 1 is fixed or FD-129 is rewritten by the product owner.

Need a hand?

Find a fix in troubleshooting, or share a reproducible issue with the community.

Get support ↗Improve this guide on GitHub ↗

Search documentation

Start typing to search all 160 guides.

Search runs in your browser esc to close