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
7 changes: 7 additions & 0 deletions .claude/board/ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
> Open blockers and cross-repo follow-ups. Append new entries at the top;
> change only the `Status` line of an existing entry.

## 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)
- **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)
Expand Down
74 changes: 72 additions & 2 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,11 @@
changes shape in 2026-09 (`/crm/v3/objects/x` → `/crm/objects/2026-09/x`),
so the page slug, not the path, is what says it is the same function.
- Measured 2026-10-20 (`coverage data/hubspot/api_surface.tsv
.cache/harvest.json`): about **1,518 distinct functions** — 980 current,
440 legacy-only, 98 beta-only. The stable harvest holds 912 of the 980
.cache/harvest.json`): about **1,506 distinct functions** — 980 current,
440 legacy-only, 86 beta-only (corrected from 1,518 / 98 on 2026-10-21:
12 beta pages also exist in legacy and were counted twice; the area
table's "beta only" column still counts beta pages without a *current*
counterpart, 98). The stable harvest holds 912 of the 980
current ones.

| area | current (2026-09) | in stable harvest | legacy only | beta only |
Expand Down Expand Up @@ -318,6 +321,73 @@
page-slug match). A Haiku `census-counter` run confirmed the per-version
counts (AGENT_LOG 2026-10-20).

## The API surface by deliverable (D-API-0)

- `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
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
STATUS_BOARD, and the functions sum to 1,506 (a page in both legacy and
beta counts once, under legacy).
- The mapping is a judgement, recorded so it can be argued with row by row.
Object CRUD of every object type (including types with no concept, like
courses and listings) is D-API-1, which is why it holds a third of the
surface. Measured 2026-10-20:

| 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-2 | 7 | 27 | 32 | 0 | 59 |
| D-MAIL-5 | 3 | 22 | 25 | 0 | 47 |
| D-QRY-2 | 1 | 31 | 1 | 0 | 32 |
| D-QRY-6 | 2 | 0 | 8 | 22 | 30 |
| D-MKT-3 | 1 | 26 | 1 | 0 | 27 |
| D-UI-1 | 1 | 0 | 24 | 0 | 24 |
| D-IAM-4 | 2 | 19 | 2 | 0 | 21 |
| D-FLOW-1 | 2 | 0 | 16 | 4 | 20 |
| D-LOG-2 | 1 | 19 | 0 | 0 | 19 |
| 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 |
| D-ACT-3 | 2 | 11 | 4 | 0 | 15 |
| D-MAIL-6 | 2 | 8 | 5 | 1 | 14 |
| D-FLOW-4 | 1 | 9 | 4 | 0 | 13 |
| D-STO-3 | 1 | 9 | 2 | 0 | 11 |
| D-IAM-2 | 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-ONT-6 | 1 | 2 | 2 | 0 | 4 |
| D-INT-4 | 1 | 0 | 0 | 3 | 3 |
| D-IAM-6 | 1 | 3 | 0 | 0 | 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,
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.
- D-ids with no surface functions are internal (store, simulation, query
engine, UI, CI) or have their API inside another D-id's families: D-SVC-1's
tickets and feedback are D-API-1 CRUD, D-IAM-1's roles have no public API.

## Probe P-QDB-1 (Quack as the database; plan H-ADR-6, D-QRY-1)

`probes/p-qdb-1`. Command:
Expand Down
4 changes: 2 additions & 2 deletions .claude/board/STATUS_BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
| D-ONT-3 | Mint dossier: per candidate concept (H-ADR-2 table) the METHOD/STORAGE/STRUCTURE evidence + OGIT source + convergence argument; submit to the 5+3 codebook council | M | Shipped | ratified v3 `.claude/plans/hubspo-concept-mint-dossier-v3.md` (5+3 council, 2026-10-10) |
| D-ONT-4 | OGAR PR: `ConceptDomain::Crm` (`0x05XX`), 15 concepts in `class_ids` + `CODEBOOK` + `ALL`, `HubSpoPort` (`0x000B`) + aliases, layout doc row; lance-graph `ogar_codebook` mirror rows + `AppPrefix` 0x0008–0x000B. `crm_actions` deferred to D-ACT-1 (dossier v3 §7) | M | Shipped | OGAR#330, lance-graph#1438 |
| D-ONT-5 | `hubspo-port`: `RbacPlug` binding; `HotPlug` over Crm ids asserted to fail `NoCapabilitiesFor` until D-ACT-1 (dossier v3 §7); deliberately-wrong-plug test proving each drift arm can fire | S | Shipped | `hubspo-port`, 13 tests (`04edf87` on main) |
| D-ONT-6 | `hubspo-schema`: ClassViews for contact, company, deal, ticket, lead, product, line item, quote, activity kinds; standard property position tables via the generator into `hubspo-generated` | L | In PR | 2026-10-20 provisional (operator: public docs): `hubspo-harvest` objdef/guide/merge/emit from HubSpot's object-definition pages and activity guides, `data/hubspot/standard_properties.tsv` (24 object types, 1,413 properties by internal name), generated tables, `hubspo-schema::HubSpoClassView` keyed by concept for 13 object types (counts pinned); contact passes the 256-position mask ceiling (`ISS-FIELD-MASK-256`); see `ISS-KB-PROPERTIES-PROVISIONAL`. Gate G1 stays open until the portal. Unblocked 2026-10-20: `ISS-CRM-KEY-CLASSVIEW` decided, CRM keys carry classview `0x0000` (`concept << 16`); ClassViews keyed by concept. Earlier: `ISS-CRM-KEY-CLASSVIEW`: no ClassView or key on the `0x000B` prefix until answered (plan H-ADR-1 note) |
| D-ONT-6 | `hubspo-schema`: ClassViews for contact, company, deal, ticket, lead, product, line item, quote, activity kinds; standard property position tables via the generator into `hubspo-generated` | L | Shipped | 2026-10-20 provisional (operator: public docs): `hubspo-harvest` objdef/guide/merge/emit from HubSpot's object-definition pages and activity guides, `data/hubspot/standard_properties.tsv` (24 object types, 1,413 properties by internal name), generated tables, `hubspo-schema::HubSpoClassView` keyed by concept for 13 object types (counts pinned); contact passes the 256-position mask ceiling (`ISS-FIELD-MASK-256`); see `ISS-KB-PROPERTIES-PROVISIONAL`. Gate G1 stays open until the portal. Unblocked 2026-10-20: `ISS-CRM-KEY-CLASSVIEW` decided, CRM keys carry classview `0x0000` (`concept << 16`); ClassViews keyed by concept. Earlier: `ISS-CRM-KEY-CLASSVIEW`: no ClassView or key on the `0x000B` prefix until answered (plan H-ADR-1 note) |
| D-ONT-7 | Custom-object/-property design (H-ADR-3) + probe P-CUSTOM-1 (lane-per-property vs packed run; fold latency at 50 / 500 / 2,000 custom properties) | M | In progress | P-CUSTOM-1 2026-10-10: lanes 0.73–1.61× std, packed 15–35×; the 33–96 s is a fresh K-column `Dataset::write`, not updates. Both measured paths are off the shipped path since #23/#25: re-probe as P-CUSTOM-2 under the resident fold |

## Wave 2 — Store, versions, history
Expand Down Expand Up @@ -144,7 +144,7 @@

| D-id | Deliverable | Size | Status | Evidence |
|---|---|---|---|---|
| D-API-0 | The documented API surface as data: every operation of legacy, 2026-09 and 2027-03-beta, with coverage per area (the map of functions to rebuild) | M | In PR | 2026-10-20: `hubspo-harvest surface`/`coverage`, `scripts/fetch-hubspot-surface.sh`, `data/hubspot/api_surface.tsv` — 2,279 endpoints (legacy 1,194, 2026-09 980, beta 105; 2,325 doc entries, generic endpoints listed by several specs); ~1,518 distinct functions (980 current + 440 legacy-only + 98 beta-only). Table in LATEST_STATE. Linear claim: EXO-50 `session_01PPcakjk7ioQsnasmNDtc5z/002` (D-API-SURFACE) |
| D-API-0 | The documented API surface as data: every operation of legacy, 2026-09 and 2027-03-beta, with coverage per area (the map of functions to rebuild) | M | Shipped | 2026-10-20: `hubspo-harvest surface`/`coverage`, `scripts/fetch-hubspot-surface.sh`, `data/hubspot/api_surface.tsv` — 2,279 endpoints (legacy 1,194, 2026-09 980, beta 105; 2,325 doc entries, generic endpoints listed by several specs); ~1,506 distinct functions (980 current + 440 legacy-only + 86 beta-only; corrected from 1,518, 12 beta pages double-counted). Table in LATEST_STATE. Linear claim: EXO-50 `session_01PPcakjk7ioQsnasmNDtc5z/002` (D-API-SURFACE). Shipped in #39. Deliverable map: `data/hubspot/surface_map.tsv` + `hubspo-harvest deliverables` (140 families → 33 D-ids, 134 functions unplanned: `ISS-SURFACE-UNPLANNED`) |
| D-API-1 | `/crm/v3/objects/*` CRUD + batch + search on the façade; association v4; properties; pipelines; owners | XL | Queued | |
| D-API-2 | Webhook subscriptions (outbound) from version deltas | M | Queued | |
| D-API-3 | OAuth apps / private app tokens mapped to RBAC actors with delegation | M | Queued | |
Expand Down
25 changes: 24 additions & 1 deletion crates/hubspo-harvest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
//! output already holds, and how many also exist under the current version:
//! `version <TAB> area <TAB> operations <TAB> harvested <TAB> in_current`.
//!
//! `hubspo-harvest deliverables <surface.tsv> <map.tsv>` — prints, per
//! deliverable in the map, the documented functions it owns:
//! `deliverable <TAB> families <TAB> current <TAB> legacy_only <TAB>
//! beta_only <TAB> functions`. A family without a map row is an error.
//!
//! `hubspo-harvest emit <table.tsv>` — prints the generated Rust for
//! `hubspo-generated/src/standard_properties.rs`.

Expand Down Expand Up @@ -194,14 +199,32 @@ fn run(args: &[String]) -> Result<(), String> {
}
Ok(())
}
[cmd, table, map] if cmd == "deliverables" => {
let ops = surface::parse_tsv(&read(table)?).map_err(|l| format!("{table}: bad line {l}"))?;
let map_rows = surface::parse_map(&read(map)?).map_err(|l| format!("{map}: bad line {l}"))?;
let counts = surface::by_deliverable(&ops, &map_rows)
.map_err(|f| format!("{map}: no row for spec family {f}"))?;
for c in counts {
println!(
"{}\t{}\t{}\t{}\t{}\t{}",
c.deliverable,
c.families,
c.current,
c.legacy_only,
c.beta_only,
c.functions()
);
}
Ok(())
}
[cmd, table] if cmd == "emit" => {
let rows = read_table(Path::new(table))?;
print!("{}", positions::emit(&rows));
Ok(())
}
_ => Err(
"usage: hubspo-harvest select <index.json> | report <cache-dir> | objdef <page.html> \
| guide <page.md> | surface <page.html>... | coverage <surface.tsv> <harvest.json> | merge <table.tsv> <object> <found.tsv> | emit <table.tsv>"
| guide <page.md> | surface <page.html>... | coverage <surface.tsv> <harvest.json> | deliverables <surface.tsv> <map.tsv> | merge <table.tsv> <object> <found.tsv> | emit <table.tsv>"
.to_string(),
),
}
Expand Down
Loading
Loading