fullstackgtm 0.23.1 → 0.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and the project adheres to [Semantic Versioning](https://semver.org/).
6
6
  The path to 1.0 is planned in [docs/roadmap-to-1.0.md](./docs/roadmap-to-1.0.md).
7
7
 
8
+ ## [0.23.2] — 2026-06-12
9
+
10
+ Documentation catch-up: the README, llms.txt, and docs/api.md now cover
11
+ everything that shipped 0.19–0.23. (No code changes.)
12
+
13
+ ### Fixed
14
+
15
+ - README: new "Routine maintenance as governed verbs" section (`bulk-update`,
16
+ `dedupe`, `reassign`, `fix`) and a market-map paragraph for `market overlay`
17
+ (directives from your own ground truth) and `market scale` (citable,
18
+ calibrated size estimates).
19
+ - llms.txt: governed-write-verbs invariants block; overlay/scale invariants
20
+ added to the market-map block.
21
+ - docs/api.md: CLI command list completed (write verbs, `enrich`, market
22
+ `overlay`/`scale`); new "Governed write verbs" and "Enrich" export
23
+ sections; market-map section updated for 0.16–0.23 exports incl.
24
+ `computeDirectives`/`directivesToPlan` and `computeScaleIndex`.
25
+
8
26
  ## [0.23.1] — 2026-06-12
9
27
 
10
28
  ### Fixed
package/README.md CHANGED
@@ -109,6 +109,22 @@ npx fullstackgtm report --provider hubspot --client "Acme" --out acme-health.htm
109
109
 
110
110
  `report` renders the same audit as a deliverable — severity counts up front, a prose summary, per-rule detail with example records, and next steps — as markdown or self-contained HTML (printable, emailable, no external assets).
111
111
 
112
+ ## Routine maintenance as governed verbs: bulk-update, dedupe, reassign, fix
113
+
114
+ The maintenance work RevOps actually does in bulk — backfills, book transfers, duplicate sweeps, "just fix everything that rule found" — gets first-class verbs. Each one *builds a plan*; nothing executes without the same approve → apply gauntlet as everything else.
115
+
116
+ ```bash
117
+ fullstackgtm bulk-update deal --where "stage=closedwon" --where "amount:empty" \
118
+ --set amount=from:account.annualrevenue --save # per-record derived values; empty sources skipped, never guessed
119
+ fullstackgtm dedupe account --key domain --keep richest --save # one merge_records op per duplicate group
120
+ fullstackgtm reassign --from 411 --to 902 --except-deal-stage closing --save # ownership handoff playbook
121
+ fullstackgtm fix --rule missing-deal-owner --provider hubspot --yes # audit one rule → suggest → approve → apply, one command
122
+ ```
123
+
124
+ `bulk-update` filters the snapshot (`=`, `!=`, `~` substring, `:empty`/`:notempty`, `|` any-of, relational pseudo-fields like `account.domain` or `openDealStages`) into a dry-run patch plan — and **the full filter is re-verified per record at apply time**, with mid-apply rechecks, so a record that stopped matching between audit and apply is skipped, not clobbered. Equality filters double as preconditions; `--require` adds explicit ones; `--guard` asserts cross-record conditions; `--max-operations` caps blast radius. `--set field=from:<sourceField>` derives values per record; `--archive` refuses records whose identity key (account domain, contact email) is shared with another record — that's a duplicate, and duplicates are merged with `dedupe`, not archived around.
125
+
126
+ `dedupe` finds duplicate groups by normalized identity key and emits one `merge_records` operation per group with a deterministic survivor (`richest` = most populated fields, ties to lowest id; `oldest`). Merges stay irreversible-and-therefore-low-confidence-capped on approval, exactly like merge suggestions from the audit. `reassign` is the ownership-handoff playbook: one plan per object type, extra scoping account-lifted to deals and contacts, and `--except-deal-stage` excludes both deals in that stage and every record whose account has an open deal in it. `fix` is the one-shot composite for a single rule: audit → save → suggest → approve suggestion-backed operations at the confidence bar → with `--yes`, apply and print the stage-by-stage summary; without it, stop after approval and print the apply command.
127
+
112
128
  ## The market map: the category, observed
113
129
 
114
130
  Your CRM records what happened in your own deals; nothing records the shape of the category you sell into. The **market map** does: vendors and a claim taxonomy live in a reviewable `market.config.json`, vendor pages are captured into a content-addressed cache, every vendor × claim cell gets a messaging-intensity reading (LOUD / QUIET / ABSENT — with UNOBSERVABLE for failed captures, never a fake absence), and deterministic front states fall out per claim: open, contested, owned, saturated.
@@ -126,6 +142,8 @@ The discipline matches the rest of the tool. Intensity readings are *proposals*
126
142
 
127
143
  `market axes` is for earning a strategic 2×2 instead of asserting one: PCA over the intensity matrix (PC1 = the category's own primary axis, PC2 = the most differentiating direction orthogonal to it), triangulation of your configured axes against the data, and an orthogonality screen that flags two axes that are secretly one. Axes are claim-scoring rubrics in the config; the report renders the primary pair as the strategic map. Captures and observations are profile-scoped (`~/.fullstackgtm/market/<category>`), so one client's category intel never bleeds into another's.
128
144
 
145
+ Two more derivations close the loop from map to action. `market overlay --snapshot <crm.json> [--calls <files>]` joins the observation store against your own ground truth — which claims and vendors actually come up in your deals and call transcripts (deterministic word-boundary matching, no LLM) — and emits OCCUPY / PROMOTE / URGENT / RETREAT directives, each carrying at least one observation and one CRM stat with its sample size; below the evidence thresholds the honest answer is *no directive*. `--save` turns directives into approval-gated `create_task` operations through the normal plan chain. `market scale` estimates each vendor's size from **citable** signals you record in the config (G2 review counts, LinkedIn headcount, revenue claims — each with source URL, verbatim quote, and caveat): every signal is converted into revenue space first, calibrated within the vendor set and stratified by ACV band, then combined as a weighted geometric mean with the uncertainty spread and calibration table disclosed. The report's strategic-map bubbles become area-proportional to estimated revenue share — captioned "citable but NOT audited" — and without signals, dots are uniform and the caption says size carries no meaning.
146
+
129
147
  ## Governed enrichment: a diff you approve before third-party data touches your CRM
130
148
 
131
149
  Every enrichment vendor ships fire-and-forget writeback. The **enrich layer** inverts that: declare once which fields come from which source under which conflict policy (`enrich.config.json` — sources, ordered match keys, field mappings, policy), then `enrich append` fills the gaps and `enrich refresh` keeps them current — with every write passing through the normal dry-run → approval → apply contract, and every value traceable to the source payload that produced it.
package/docs/api.md CHANGED
@@ -59,8 +59,10 @@ release.
59
59
 
60
60
  Commands: `login` / `logout`, `snapshot`, `audit`, `report`, `diff`, `merge`, `plans`,
61
61
  `apply`, `suggest`, `call` (`parse` / `score` / `link` / `plan`), `resolve`,
62
+ `bulk-update`, `dedupe`, `reassign`, `fix`,
62
63
  `market` (`init` / `capture` / `classify` / `worksheet` / `observe` / `fronts` /
63
- `axes` / `report` / `refresh`), `rules`, `profiles`, `doctor`.
64
+ `axes` / `overlay` / `scale` / `report` / `refresh`),
65
+ `enrich` (`append` / `refresh` / `ingest` / `status`), `rules`, `profiles`, `doctor`.
64
66
  Exit codes: `0` success · `1` error · `2` findings/regressions at the requested gate
65
67
  (`--fail-on`, `--fail-on-new-findings`). `--json` everywhere; JSON output shapes are stable.
66
68
 
@@ -80,19 +82,59 @@ deliverable in markdown or self-contained HTML: severity counts, prose summary,
80
82
  per-rule detail with capped examples, and next steps. `auditReportToMarkdown` /
81
83
  `auditReportToHtml` expose the same rendering programmatically.
82
84
 
85
+ ## Governed write verbs
86
+
87
+ Plan builders behind `bulk-update`, `dedupe`, and `reassign` — every one
88
+ emits a standard dry-run `PatchPlan` for the normal approve → apply chain:
89
+
90
+ - `buildBulkUpdatePlan(snapshot, options: BulkUpdateOptions)` with
91
+ `parseWhere` (filter expressions: `=`, `!=`, `~`, `!~`, `:empty`,
92
+ `:notempty`, `|` any-of, relational pseudo-fields) and
93
+ `isFilterableField`. Filters are re-verified per record at apply time;
94
+ `from:<sourceField>` values derive per record from the snapshot.
95
+ - `buildDedupePlan(snapshot, options: DedupeOptions)` with `dedupeKey` —
96
+ duplicate groups by normalized identity key, one `merge_records` per group,
97
+ deterministic survivor selection (`richest` / `oldest`).
98
+ - `buildReassignPlans(snapshot, options: ReassignOptions)` — one plan per
99
+ `ReassignObjectType`, account-lifted scoping, stage exclusions.
100
+
101
+ `fix` is CLI-only composition of existing surfaces (audit → suggest →
102
+ approve → apply for one rule).
103
+
104
+ ## Enrich
105
+
106
+ Governed third-party enrichment (spec-first; `enrich.config.json` validated
107
+ by `parseEnrichConfig` / `loadEnrichConfig`, types `EnrichConfig`,
108
+ `EnrichFieldConfig`, `EnrichSourceConfig`): `buildEnrichPlan` matches staged
109
+ or pulled source records to CRM records (`matchSourceRecord` — ordered keys,
110
+ `MatchOutcome` of matched / unmatched / ambiguous) and emits fill-blanks-only
111
+ operations. `createFileEnrichRunStore` / `EnrichRunStore` is the profile-scoped
112
+ append-only run store (resume cursor, per-record/per-field `enrichedAt`
113
+ stamps read by `latestStamps` / `selectStaleWork`). `parseCsv` is the
114
+ dependency-free CSV intake; the Apollo client (`createApolloClient`,
115
+ `pullApolloRecords`, 429-aware with `Retry-After`) is the first `api`-kind
116
+ source.
117
+
83
118
  ## Market map
84
119
 
85
- Newer surface (0.16–0.18); shapes are settling toward the 1.0 contract. A live
120
+ Newer surface (0.16–0.23); shapes are settling toward the 1.0 contract. A live
86
121
  model of the competitive category: claim taxonomy + vendor registry as a
87
122
  reviewable `market.config.json` (`MarketConfig`, `MarketClaim`, `MarketVendor`,
88
- `MarketAxis`), content-addressed page captures (`captureMarket`,
89
- `loadCaptureTexts`), append-only observations (`ObservationSet`,
90
- `MarketObservation`, `ObservationStore` / `createFileObservationStore` —
91
- profile-scoped under `<home>/market/<category>`), and deterministic
92
- derivations: `computeFrontStates` / `diffFrontStates` (front rule v1),
93
- `assessAxes` / `pcaTop2` / `axisPosition` (axis discovery), and
123
+ `MarketAxis` — axes require `negativePole`/`positivePole` labels), content-addressed
124
+ page captures (`captureMarket`, `loadCaptureTexts`), append-only observations
125
+ (`ObservationSet`, `MarketObservation`, `ObservationStore` /
126
+ `createFileObservationStore` — profile-scoped under `<home>/market/<category>`),
127
+ and deterministic derivations: `computeFrontStates` / `diffFrontStates`
128
+ (front rule v1), `assessAxes` / `pcaTop2` / `axisPosition` (axis discovery),
129
+ `computeDirectives` / `computeOverlayStats` / `directivesToPlan`
130
+ (`market overlay` — observations × CRM snapshot × call corpus →
131
+ OCCUPY/PROMOTE/URGENT/RETREAT `MarketDirective`s, convertible to an
132
+ approval-gated plan of `create_task` operations), `computeScaleIndex` /
133
+ `scaleReportToText` (`market scale` — citable `ScaleSignal`s → within-set,
134
+ ACV-band-stratified revenue estimates with disclosed uncertainty), and
94
135
  `marketMapToMarkdown` / `marketMapToHtml` (the field report; renders the
95
- primary strategic 2×2 when `axes` / `primaryAxes` are configured).
136
+ primary strategic 2×2 when `axes` / `primaryAxes` are configured, bubbles
137
+ area-proportional to estimated revenue share when scale signals exist).
96
138
 
97
139
  Intensity readings are proposals: `classifyMarket` (LLM, bring-your-own-key,
98
140
  provenance-marked) or `buildWorksheet` + `market observe` (agent/human). Every
package/llms.txt CHANGED
@@ -44,9 +44,34 @@ elsewhere). Failed captures read UNOBSERVABLE, never ABSENT. `fronts --diff`
44
44
  = deterministic front states + drift between runs; `axes` = PCA axis
45
45
  discovery + orthogonality screen; `report` = self-contained HTML field
46
46
  report; `refresh` = capture → classify → drift → report in one command.
47
+ `overlay --snapshot <crm.json> [--calls <files>]` joins observations to YOUR
48
+ CRM/calls (deterministic mention matching, no LLM) and emits OCCUPY/PROMOTE/
49
+ URGENT/RETREAT directives — each needs ≥1 observation + ≥1 CRM stat with
50
+ sample size; below thresholds = no directive; `--save` = approval-gated
51
+ create_task ops. `scale` = citable scaleSignals (sourceUrl + verbatim quote
52
+ each) → revenue-space estimates calibrated within-set by acvBand, disclosed
53
+ uncertainty; report bubbles ∝ estimated share only when signals exist.
47
54
  Storage is profile-scoped under `<home>/market/<category>`. MCP:
48
55
  `fullstackgtm_market_worksheet`, `fullstackgtm_market_observe`.
49
56
 
57
+ ## Key invariants (governed write verbs)
58
+
59
+ `bulk-update <object> --where … (--set|--archive|--create-task)` filters the
60
+ snapshot into a dry-run plan; the FULL filter is re-verified per record at
61
+ apply time (plus mid-apply rechecks); equality filters double as
62
+ preconditions, `--require`/`--guard` add explicit ones, `--max-operations`
63
+ caps blast radius. `--set f=from:<source>` derives per-record values (empty
64
+ source = skip + count, never guess). `--archive` refuses records sharing an
65
+ identity key — merge with `dedupe` instead. `dedupe <object> --key
66
+ <domain|email|name>` = one merge_records op per duplicate group,
67
+ deterministic survivor (`--keep richest|oldest`); merges are irreversible and
68
+ stay low-confidence-capped at approval. `reassign --from <owner> --to
69
+ <owner>` = ownership handoff plans per object type; `--except-deal-stage`
70
+ also excludes records whose account has an open deal in that stage. `fix
71
+ --rule <id>` = audit one rule → suggest → approve at the confidence bar →
72
+ apply only with `--yes`. All four produce plans; none writes outside
73
+ approve → apply.
74
+
50
75
  ## Key invariants (enrich)
51
76
 
52
77
  `fullstackgtm enrich` is governed enrichment: `append` pulls (Apollo, BYO key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullstackgtm",
3
- "version": "0.23.1",
3
+ "version": "0.23.2",
4
4
  "description": "Open-source agentic GTM ops framework: canonical GTM data model, pluggable deterministic audits, reviewable dry-run patch plans, approval-gated write-back with conflict detection, and cross-system entity resolution. HubSpot, Salesforce, and Stripe connectors included.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Full Stack GTM",