feat: classification, policy, tier resolver and access log (phase b) #7

Merged
KofTwentyTwo merged 2 commits from feature/policy-and-access-log into develop 2026-10-14 01:14:57 +00:00
KofTwentyTwo commented 2026-10-14 01:04:18 +00:00 (Migrated from github.com)

Summary

Phase (b) of secured data (spec: QRun-IO/qqq docs/SECURED-DATA.md §5, §6, §7.1, §7.5, §7.6).

  • Tables: secured_data_classification, secured_data_policy, secured_data_reveal_grant, secured_data_break_glass and secured_data_access_log, with PostgreSQL DDL. The activity tables are system-written; the access log is insert-only. All are walled off from the assistant channel.
  • SecuredDataClassifications: effective classification (admin row ▸ code), versioned. Other qbits (assistant) call it.
  • SecuredDataResolver: tiers per §7.1, covering break-glass, the secured_data_full / secured_data_reveal table features, policy rows by permission, channel caps, code defaults (PII/PHI MASKED), and no implicit access for secured_data.admin. It also produces the access fingerprint.
  • Access log: a bounded asynchronous queue, written as the system. It records VIEW for PII/PHI, EXACT_MATCH_FILTER with MATCH / NO_MATCH / REFUSED, and FILTER_DENIED, plus the client channel. It never logs values.
  • Enumeration guardrails (§7.6):
    • per-user, per-field hourly rate limit;
    • consecutive-miss and distinct-value alerts through the alerts SPI;
    • minimum-entropy auto rules plus admin override.
    • Search fingerprints are truncated to 16 bits before they are stored, so they cannot confirm a guessed value.
  • Pinned QQQ RC.5: the unreleased core types are marked stand-ins, STAND-IN(core=QRun-IO/qqq#TBD, removeBy=RC.6), and the resolver reaches core through a reflective bridge. Enforcement needs RC.6.

Tests

  • RC.5 (CI): 35 passed, 2 skipped. The skips are the core-bridge integration tests.
  • Locally against the core branch build (-Dqqq.snapshot.version=4.1.0-SECUREDATA-SNAPSHOT): 37 passed, including the real-core query/get masking matrix and refusal logging.
  • Checkstyle and the coverage gates pass (86% instructions, 97% classes).

The core PR number goes into the STAND-IN markers once it's open.

🤖 Generated with Claude Code

## Summary Phase (b) of secured data (spec: QRun-IO/qqq `docs/SECURED-DATA.md` §5, §6, §7.1, §7.5, §7.6). - **Tables:** `secured_data_classification`, `secured_data_policy`, `secured_data_reveal_grant`, `secured_data_break_glass` and `secured_data_access_log`, with PostgreSQL DDL. The activity tables are system-written; the access log is insert-only. All are walled off from the assistant channel. - **`SecuredDataClassifications`:** effective classification (admin row ▸ code), versioned. Other qbits (assistant) call it. - **`SecuredDataResolver`:** tiers per §7.1, covering break-glass, the `secured_data_full` / `secured_data_reveal` table features, policy rows by permission, channel caps, code defaults (PII/PHI MASKED), and no implicit access for `secured_data.admin`. It also produces the access fingerprint. - **Access log:** a bounded asynchronous queue, written as the system. It records VIEW for PII/PHI, EXACT_MATCH_FILTER with MATCH / NO_MATCH / REFUSED, and FILTER_DENIED, plus the client channel. It never logs values. - **Enumeration guardrails (§7.6):** - per-user, per-field hourly rate limit; - consecutive-miss and distinct-value alerts through the alerts SPI; - minimum-entropy auto rules plus admin override. - Search fingerprints are truncated to 16 bits before they are stored, so they cannot confirm a guessed value. - **Pinned QQQ RC.5:** the unreleased core types are marked stand-ins, `STAND-IN(core=QRun-IO/qqq#TBD, removeBy=RC.6)`, and the resolver reaches core through a reflective bridge. Enforcement needs RC.6. ## Tests - RC.5 (CI): 35 passed, 2 skipped. The skips are the core-bridge integration tests. - Locally against the core branch build (`-Dqqq.snapshot.version=4.1.0-SECUREDATA-SNAPSHOT`): 37 passed, including the real-core query/get masking matrix and refusal logging. - Checkstyle and the coverage gates pass (86% instructions, 97% classes). The core PR number goes into the STAND-IN markers once it's open. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.