Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions .claude/board/ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,34 @@
> Open blockers and cross-repo follow-ups. Append new entries at the top;
> change only the `Status` line of an existing entry.

## ISS-SPEAR-DOCUMENT-CONTRACTS — spear has a content store but no document record, reference or authorization

- **Status:** OPEN (found 2026-10-21 verifying D-DOC-1; upstream asks for the operator, not filed on spear)
- **Where:** spear `main` `c69cacb`: `src/content/mod.rs` (implemented), `src/sharepoint/{intent,drive_scope}.rs` (types only), `src/sharepoint/transport/mod.rs` (stub), `.claude/plans/onedrive-delivery-v1.md` (nothing built).
- **What HubSPO-rs needs from spear, and must not build itself:**
1. A document record over the content store: tenant, content hash, name, media type, size, folder, provenance, version. The content store is a bare hash → bytes map written for message bodies.
2. A document reference a consumer holds instead of a copy, resolved by spear.
3. Document authorization: who may read, replace or link a document. spear's IAM plug (`mail::iam`) covers `email` only.
4. Folders, if HubSpot folder operations are to be served; otherwise D-DOC-1 refuses them.
5. Delivery: D-DELIVER-2..6 (`DeliveryIntent`, user drives, Entra resolution, delivery RBAC, transport, receipts) and `activity` / `send_receipts` (D-HUB-4/5, D-CONFIRM-1). Planned in spear, not built.
- **Until then:** D-DOC-1 is Blocked; no Files API operation is reported as served.

## ISS-SURFACE-COVERAGE-SEMANTICS — "mapped to a deliverable" read as "covered"

- **Status:** RESOLVED 2026-10-21 — `surface_map.tsv` has a `coverage` column: planned / implemented / deferred / out-of-scope / unclassified. `implemented` is accepted only for a D-id that is Shipped on STATUS_BOARD (`surface::check_board`); today no family is implemented, because no HubSpot-compatible endpoint is served yet. The committed-map test requires every one of the 140 families to carry a class that agrees with its deliverable (`UNPLANNED` ⇔ unclassified, `NONE` ⇔ out-of-scope, a D-id for planned or deferred), and pins the function split: planned 1,161, deferred 329, out of scope 16. A class says whether work is planned, never that it is implemented; implementation is the D-id's status on STATUS_BOARD.
- **Where:** `hubspo-harvest::surface::{Coverage, parse_map, by_coverage}`; `deliverables` command.
- **What:** the deliverable map assigned every family to a D-id or `UNPLANNED`, so a report of "families assigned" could be read as coverage. Deferred families (CMS, app platform, telephony) and out-of-scope ones were indistinguishable from planned ones.

## ISS-SURFACE-UNPLANNED — 134 documented HubSpot functions belong to no deliverable

- **Status:** OPEN (found 2026-10-20 by D-API-0's deliverable map; operator decision)
- **Status:** DECIDED 2026-10-21 (operator). New D-ids: D-MKT-5 (marketing events), D-EXT-1 (app platform, deferred; a2ui, not HubSpot's React runtime), D-DOC-1 (file manager as a façade over spear), D-OPS-1 (tenant quotas), D-DATA-1 (data-studio ingestion). D-DOC-1 is compatibility in `hubspo-docs` over spear only (plan §2.5.1, `ISS-SPEAR-DOCUMENT-CONTRACTS`). Folded: custom behavioural events → D-FLOW-2, record tags → D-ONT-7 + D-STO-3, deal splits → D-COM-1, forecast types → D-QRY-6, AEO → D-MKT-4 (deferred). Out of scope: partner program, API metadata (HubSpot origin IPs). 118 functions assigned, 16 out of scope; `surface_map.tsv` carries the class per family (`ISS-SURFACE-COVERAGE-SEMANTICS`).
- **Where:** `data/hubspot/surface_map.tsv` rows with `UNPLANNED`.
- **What:** 19 spec families (134 functions) have no D-id: marketing events (37), app platform (22: CRM cards, extensions, feature flags, uninstall hooks), file manager (19), partner program (14), custom behavioural events (12), portal limits (9), record tags (6), answer-engine optimisation (5), data-studio ingestion (4), deal splits and forecasts (4), API metadata (2).
- **Decide per group:** a new D-id, folded into an existing one (the map row changes and the test re-pins), or out of scope (the row stays `UNPLANNED` with the reason). Candidates that fit existing work: custom behavioural events as workflow triggers (D-FLOW-2) and report inputs (D-QRY-6); file manager onto spear's document hub; record tags as a ClassView property.

## ISS-PACKED-RUN-RBAC-GRAIN — a packed run is granted as a whole, and contact's holds personal attributes

- **Status:** OPEN (found 2026-10-20 by ISS-FIELD-MASK-256's resolution; input for D-IAM-3)
- **Status:** DECIDED 2026-10-21 (operator) — option (b), with (c) allowed before the first tenant data. Storage grain may be a run; authorization grain is the property. Field 0 grants the container only; packed properties are checked one by one against an inner mask keyed by stable table ordinal, independent of the 256-position `WideFieldMask`. Requirements recorded on the D-IAM-3 row of STATUS_BOARD.
- **Where:** `hubspo-harvest::positions::PACKED_GROUPS`, `hubspo-schema::HubSpoClassView` (field 0).
- **What:** a role granted field 0 of contact sees all 27 packed properties; one not granted it sees none. HubSpot's `facebook_ads_properties` group holds `date_of_birth`, `gender`, `marital_status` and `military_status` next to `school` and `seniority`, so a role cannot get the job fields without the personal ones. HubSpot itself marks all of them `non_sensitive`; DSGVO may not.
- **Options for D-IAM-3:** (a) accept the grain and grant the run only to roles that may see all of it; (b) a second, run-internal mask keyed by table position (the run already stores positions); (c) keep the personal attributes out of the run by narrowing `PACKED_GROUPS` to names, with another group packed instead. Only (c) changes stored slots, and only before the first tenant data is written.
Expand Down
44 changes: 28 additions & 16 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@

- `data/hubspot/surface_map.tsv` maps each of the 140 spec families
(`crm-contacts`, `cms-pages`, …; `surface::family` strips directory,
`.json` and version) to the D-id that owns it, or `UNPLANNED` with a
reason. `hubspo-harvest deliverables <surface.tsv> <map.tsv>` counts the
`.json` and version) to the D-id that owns it (`NONE` when out of scope, `UNPLANNED` when
undecided) and a coverage class. `hubspo-harvest deliverables <surface.tsv> <map.tsv>` counts the
functions per D-id and refuses a family with no row.
- A test pins it to the committed data: every family in the surface has a
row, no row names a family that is not there, every D-id is on
Expand All @@ -340,47 +340,59 @@
| deliverable | spec families | current | legacy only | beta only | functions |
|---|---|---|---|---|---|
| D-API-1 | 43 | 377 | 168 | 0 | 545 |
| D-MKT-4 | 21 | 208 | 77 | 0 | 285 |
| UNPLANNED | 19 | 99 | 30 | 5 | 134 |
| D-COM-1 | 10 | 39 | 3 | 28 | 70 |
| D-MKT-4 | 22 | 208 | 77 | 5 | 290 |
| D-COM-1 | 11 | 41 | 3 | 28 | 72 |
| D-MKT-2 | 7 | 27 | 32 | 0 | 59 |
| D-MAIL-5 | 3 | 22 | 25 | 0 | 47 |
| D-MKT-5 | 2 | 27 | 10 | 0 | 37 |
| D-QRY-2 | 1 | 31 | 1 | 0 | 32 |
| D-QRY-6 | 2 | 0 | 8 | 22 | 30 |
| D-QRY-6 | 3 | 2 | 8 | 22 | 32 |
| D-MKT-3 | 1 | 26 | 1 | 0 | 27 |
| D-UI-1 | 1 | 0 | 24 | 0 | 24 |
| D-EXT-1 | 4 | 18 | 4 | 0 | 22 |
| D-IAM-4 | 2 | 19 | 2 | 0 | 21 |
| D-FLOW-1 | 2 | 0 | 16 | 4 | 20 |
| D-DOC-1 | 1 | 6 | 13 | 0 | 19 |
| D-LOG-2 | 1 | 19 | 0 | 0 | 19 |
| D-API-2 | 1 | 8 | 9 | 0 | 17 |
| D-FLOW-3 | 1 | 17 | 0 | 0 | 17 |
| D-MAIL-10 | 2 | 13 | 4 | 0 | 17 |
| D-MKT-1 | 3 | 0 | 17 | 0 | 17 |
| D-API-2 | 1 | 8 | 9 | 0 | 17 |
| D-SVC-2 | 1 | 0 | 0 | 15 | 15 |
| NONE | 3 | 13 | 3 | 0 | 16 |
| D-ACT-3 | 2 | 11 | 4 | 0 | 15 |
| D-SVC-2 | 1 | 0 | 0 | 15 | 15 |
| D-MAIL-6 | 2 | 8 | 5 | 1 | 14 |
| D-FLOW-4 | 1 | 9 | 4 | 0 | 13 |
| D-FLOW-2 | 3 | 12 | 0 | 0 | 12 |
| D-ONT-7 | 2 | 12 | 0 | 0 | 12 |
| D-STO-3 | 1 | 9 | 2 | 0 | 11 |
| D-IAM-2 | 1 | 9 | 0 | 0 | 9 |
| D-OPS-1 | 1 | 9 | 0 | 0 | 9 |
| D-API-3 | 1 | 3 | 5 | 0 | 8 |
| D-INT-3 | 1 | 0 | 0 | 8 | 8 |
| D-ONT-7 | 1 | 6 | 0 | 0 | 6 |
| D-MAIL-8 | 1 | 5 | 0 | 0 | 5 |
| D-SIM-2 | 1 | 5 | 0 | 0 | 5 |
| D-ACT-2 | 2 | 3 | 1 | 0 | 4 |
| D-DATA-1 | 1 | 4 | 0 | 0 | 4 |
| D-ONT-6 | 1 | 2 | 2 | 0 | 4 |
| D-INT-4 | 1 | 0 | 0 | 3 | 3 |
| D-IAM-6 | 1 | 3 | 0 | 0 | 3 |
| D-INT-4 | 1 | 0 | 0 | 3 | 3 |
| D-IAM-5 | 1 | 1 | 0 | 0 | 1 |
| D-INT-6 | 1 | 1 | 0 | 0 | 1 |
| **total** | 140 | 980 | 440 | 86 | 1,506 |

- Unplanned, 134 functions in 11 groups (`ISS-SURFACE-UNPLANNED`):
marketing events 37, app platform 22 (cards, extensions, feature flags,
uninstalls), file manager 19, partner program 14, custom behavioural
events 12, portal limits 9, record tags 6, answer-engine optimisation 5,
data-studio ingestion 4, deal splits and forecasts 4, API metadata 2.
- 4 mapping tests; seven disable runs measured red (unmapped family,
- Coverage class per family (column 3 of the map, `ISS-SURFACE-COVERAGE-SEMANTICS`):
planned, implemented, deferred, out-of-scope, unclassified. `implemented`
needs the D-id Shipped on STATUS_BOARD (`surface::check_board`).
Measured 2026-10-21: implemented 0, planned 109 families / 1,161 functions, deferred 28 /
329 (CMS 290, app platform 22, telephony 17), out of scope 3 / 16
(partner program, API metadata). None unclassified. The class says whether
work is planned; implementation is the D-id's status, never the map.
- The 2026-10-21 rulings (`ISS-SURFACE-UNPLANNED`) moved the 134 former
`UNPLANNED` functions: new D-MKT-5 37, D-EXT-1 22 (deferred), D-DOC-1 19,
D-OPS-1 9, D-DATA-1 4; folded into D-FLOW-2 12, D-ONT-7 6, D-COM-1 2,
D-QRY-6 2, D-MKT-4 5 (deferred); out of scope 16.
- 6 mapping tests; seven disable runs measured red (unmapped family,
duplicate row, version-suffix strip, legacy-only by page slug, D-id not on
the board, missing row, stale row), plus the legacy/beta double count
(Codex on #40), red when the legacy check is removed.
Expand Down
Loading
Loading