Phase (c) of docs/DATA-ANALYSIS.md (§5), plus the §2.4 field-access seam. Stacked on #5 (it targets develop and includes #5's commits). It stays a draft until #5 merges after RC.6.
POST /qqq/v1/qbit/data-analysis/tables/{table}/pivot (extension 1.1.0):
1–3 row and 0–2 column dimensions, with date buckets (year … hour, day of week, hour of day) or nice numeric bins;
FieldAnalysisAccessResolver maps each field to FULL, EXACT_MATCH_ONLY or NONE.
It uses core FieldAccessHelper.getTier / getAccessFingerprint reflectively when present (REVEALABLE → exact-match only; MASKED, HIDDEN → none), and FieldSecurityLockHelper otherwise.
Only FULL fields are analyzable; others get 400 as unknown and never appear in drills.
Exact-run cache keys include the field-access fingerprint.
Test plan
./mvnw verify with Docker: green on memory, H2 and Postgres. JaCoCo ~98% instructions / 100% classes.
Pivot shapes 1x1, 2x1, 1x2, date x category; totals; Other and its drill; to-one join; percentile; privacy guard; drill equivalence for every count cell and total; validation errors; HTTP 200, 400 and 403
Field access: NONE fields are refused and absent from capabilities; fingerprint cache miss; the reflective core-tier path
## Summary
Phase (c) of `docs/DATA-ANALYSIS.md` (§5), plus the §2.4 field-access seam. **Stacked on #5** (it targets `develop` and includes #5's commits). It stays a draft until #5 merges after RC.6.
- **`POST /qqq/v1/qbit/data-analysis/tables/{table}/pivot`** (extension 1.1.0):
- 1–3 row and 0–2 column dimensions, with date buckets (year … hour, day of week, hour of day) or nice numeric bins;
- fields from related tables through exposed joins;
- measures: count, sum, avg, min, max, distinct, percentile;
- totals, with "Other (k groups)" for groups beyond `limitGroups` (top N per dimension, drill = NOT IN the kept values).
- Pushed down through core aggregates, as the user.
- **Drills per cell and total:** request filter AND row conditions AND column conditions.
- To-one joined fields use `joinTable.field` criteria, which core's `JoinsContext` turns into joins automatically.
- To-many joins count joined rows, so they get no drill and a warning.
- Multi-hop joins also get no drill for now: core's memory backend doesn't reproduce multi-hop implicit-join counts, which I'm reporting to core.
- **Privacy guard:** cells and groups below `min_group_size` are merged or suppressed, with no drill.
- **Field-access seam** (secured-data program, qqq#1146 §2.4):
- `FieldAnalysisAccessResolver` maps each field to FULL, EXACT_MATCH_ONLY or NONE.
- It uses core `FieldAccessHelper.getTier` / `getAccessFingerprint` reflectively when present (REVEALABLE → exact-match only; MASKED, HIDDEN → none), and `FieldSecurityLockHelper` otherwise.
- Only FULL fields are analyzable; others get 400 as unknown and never appear in drills.
- Exact-run cache keys include the field-access fingerprint.
## Test plan
- [x] `./mvnw verify` with Docker: green on memory, H2 and Postgres. JaCoCo ~98% instructions / 100% classes.
- [x] Pivot shapes 1x1, 2x1, 1x2, date x category; totals; Other and its drill; to-one join; percentile; privacy guard; drill equivalence for every count cell and total; validation errors; HTTP 200, 400 and 403
- [x] Field access: NONE fields are refused and absent from capabilities; fingerprint cache miss; the reflective core-tier path
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Phase (c) of
docs/DATA-ANALYSIS.md(§5), plus the §2.4 field-access seam. Stacked on #5 (it targetsdevelopand includes #5's commits). It stays a draft until #5 merges after RC.6.POST /qqq/v1/qbit/data-analysis/tables/{table}/pivot(extension 1.1.0):limitGroups(top N per dimension, drill = NOT IN the kept values).joinTable.fieldcriteria, which core'sJoinsContextturns into joins automatically.min_group_sizeare merged or suppressed, with no drill.FieldAnalysisAccessResolvermaps each field to FULL, EXACT_MATCH_ONLY or NONE.FieldAccessHelper.getTier/getAccessFingerprintreflectively when present (REVEALABLE → exact-match only; MASKED, HIDDEN → none), andFieldSecurityLockHelperotherwise.Test plan
./mvnw verifywith Docker: green on memory, H2 and Postgres. JaCoCo ~98% instructions / 100% classes.🤖 Generated with Claude Code