Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
db658b2
feat(ingest): auto-sniff UTF-16/TSV + coerce display-formatted measures
Jun 25, 2026
8d4d01a
feat(schema): grow planner schema + sidecar plumbing for rich dashboards
Jun 26, 2026
daef18a
feat(builder): color encoding, scatter (Circle), multi-measure KPI tiles
Jun 26, 2026
88c1868
feat(builder): dashboard title/text zones + KPI-band-over-charts 2-zo…
Jun 26, 2026
4925e88
feat(builder): filled US-state map (semantic-role + geometry + color)
Jun 26, 2026
d5a2f7a
feat(planner): rich exec plan generation (KPI strip, color, scatter, …
Jun 27, 2026
b069580
feat(propose): design_dashboard returns a confirmable proposal (propo…
Jun 29, 2026
c2e497a
fix(sidecar): align builder nested keys to model_dump snake_case + ri…
SebMontreal06 Jul 16, 2026
f17d664
fix(planner): question-aware + canonical ranking for measures, dims, …
SebMontreal06 Jul 16, 2026
2b05002
docs(acceptance): exec-dashboards Phase 1 closed — rich dashboard liv…
SebMontreal06 Jul 16, 2026
a47c78a
feat(brand): brand.yaml kit + branding module + named personas (E1-a)
SebMontreal06 Jul 16, 2026
44a51ee
feat(brand): builder applies the brand kit to generated workbooks (E1-b)
SebMontreal06 Jul 16, 2026
659181b
fix(build_from_plan): thread rich sheet fields + dashboard-level fiel…
SebMontreal06 Jul 17, 2026
0a57fbc
docs(acceptance): E1 branding live — persona=ceo branded dashboard on…
SebMontreal06 Jul 17, 2026
97ac348
feat(design): Stephen Few design-excellence layer + full persona over…
SebMontreal06 Jul 17, 2026
6876bb5
feat(rest): retry/backoff hardening + VDS field metadata + get_dataso…
SebMontreal06 Jul 17, 2026
5540b33
feat(automation): Cloud refresh schedules + webhooook tools (E2-b)
SebMontreal06 Jul 17, 2026
c72c84a
feat(connect): live Snowflake/Presto datasources + embedded credentia…
SebMontreal06 Jul 17, 2026
27f62fc
docs(acceptance): E2 shipped — local-file refresh automation proven live
SebMontreal06 Jul 17, 2026
fe29cfc
feat(pulse): Pulse metric-definition + metric tools (E3)
SebMontreal06 Jul 17, 2026
dcdd807
feat(ingest): coerce date-string columns to datetime (Pulse pre-req)
SebMontreal06 Jul 17, 2026
5dfd73c
feat(story): Tableau story workbooks + persona-aware story arcs (E4)
SebMontreal06 Jul 17, 2026
4febff2
docs(acceptance): E4 story live on Cloud; E3 code-complete pending UI…
SebMontreal06 Jul 17, 2026
0fbfc3c
fix(security): shell-quote cron-line interpolations (VB-02) + E0-E4 a…
SebMontreal06 Jul 17, 2026
425cb86
docs: vibe-BI docs refresh — 27 tools, ADRs 0006-0012, runbook (E5)
SebMontreal06 Jul 17, 2026
4838b4e
docs(acceptance): E5 close-out — verifier SOLID 100/100, 863-test gat…
SebMontreal06 Jul 17, 2026
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
15 changes: 14 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,18 @@ PAT_VALUE=replace-me-never-commit-the-real-value
# Defaults to an automatically-chosen free port; set only to pin a specific port.
# SIDECAR_PORT=8899

# Optional. Target project for `npm run demo` (must exist; not the Default project).
# Optional. Localhost host for the Python authoring sidecar. Defaults to 127.0.0.1.
# SIDECAR_HOST=127.0.0.1

# Optional. Target project for `npm run demo` / `npm run demo:dashboard` /
# `npm run demo:superstore` (must exist; not the Default project).
# DEMO_PROJECT=Sales

# Optional. Named persona (from brand.yaml) applied by `npm run demo:superstore`.
# Equivalent to passing `--persona <name>` on the command line.
# PERSONA=ceo

# NOTE on create_live_datasource (Snowflake/Presto): database credentials are NOT read from
# environment variables by this server. They are passed as tool-call parameters
# (credentials.username / credentials.password) by the calling agent, which should source them
# from its own environment — never hardcode them in a prompt, a saved plan, or this file.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ __pycache__/
tmp/
*.log

# Generated cron/launchd artifacts (contain local file paths — never commit)
scripts/cron/

# OS / editor
.DS_Store
.idea/
Expand Down
148 changes: 148 additions & 0 deletions ACCEPTANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,151 @@ Gate green: 87 TS + 114 Python = 201 tests. Also fixed this session: the stale-p
Several throwaway diagnostic workbooks were published during debugging ("Diag Single Worksheet",
"Diag Named Dashboard") and one datasource per demo run. The keeper artifacts are the demo datasource +
workbook above; the `Diag*` workbooks can be deleted from the site.

---

# E2E — Exec-Dashboards Phase 1 CLOSED: rich dashboard live on Cloud (2026-06-29)

`npm run demo:superstore` published the full Phase-1 rich vertical slice to the dev site,
accepted by Tableau Cloud on the first attempt after the E0 fixes:

| Artifact | URL |
|---|---|
| Datasource (68 cols, UTF-16/TSV auto-sniffed + coerced) | https://10ax.online.tableau.com/#/site/sebaustin/datasources/27108116 |
| Exec dashboard workbook (embedded extract) | https://10ax.online.tableau.com/#/site/sebaustin/workbooks/2519210 |

**What renders:** KPI band — Sales (Δ Sales Difference, up_good), Profit, Quantity, Discount
(down_good) — above "Sales by Category" (bar, colored by Segment) and "Sales by State"
(filled US map colored by Sales), with dashboard title and the kpi_band_over_charts layout.

**E0 fixes that landed first (offline verification caught both before any live publish):**
1. `c2e497a` — builder nested keys aligned to `model_dump()` snake_case + an integration
test over the genuine camelCase-JSON → Pydantic → builder path (TestClient 200).
2. `f17d664` — question-aware + canonical ranking (measures/dims/geo): the alphabetical
68-column file had made the plan key on "Days to Ship" and drop Sales; now the KPI band
leads with question-mentioned measures and the map honors "by state".

Gate at close: **241 TS + 258 Python = 499 tests.** The propose→confirm proposal shown in the
demo output is the exact contract an agent presents before build_from_plan publishes.

---

# E1 — Branding system live (2026-06-29)

`npm run demo:superstore -- --persona ceo` resolved the **ceo** persona from `brand.yaml`
(→ exec base, "My Company" brand), and published the branded dashboard:

| Artifact | URL |
|---|---|
| Datasource | https://10ax.online.tableau.com/#/site/sebaustin/datasources/27109700 |
| Branded exec workbook | https://10ax.online.tableau.com/#/site/sebaustin/workbooks/2519210 |

The workbook carries the brand: `<preferences><color-palette custom='true' name="My Company
Palette">`, brand-typography title/subtitle runs, and `default-format` on measures (currency/
percent/number classified by name). The proposal states the persona + brand applied.

Shipped in E1: `brand.yaml` kit (palette/typography/formats/rules + 5 named personas),
`src/branding` (zod loader + resolvePersona), `validate_brand` tool (15 tools), persona support
in `design_dashboard`, brand application in the builder (all XSD-valid; no-brand output
byte-identical), and the tool-vs-demo threading guard (`659181b` — build_from_plan now threads
kind/color/kpi/scatter/geo + title/layoutGrammar). Gate: **277 TS + 290 Python = 567 tests.**

---

# E2 — Connectivity + automated refresh (2026-07-17)

Shipped (23 tools, gate 433 TS + 308 Python = 741 tests):
- REST hardening: bounded idempotency-aware retry (429/5xx, Retry-After honored), typed
TableauApiError; VDS field-metadata client + `get_datasource_fields`.
- Scheduling/automation: `schedule_refresh` (Cloud per-task frequency XML + honest Bridge
caveat), `list/delete_refresh_schedule`, `create/list/delete_webhook` (HTTPS, admin errors).
- Live connections: `create_live_datasource` — Snowflake/Presto federated `.tds` (no creds in
the file), publish with `<connectionCredentials embed='true'>` (password never logged,
asserted); key-pair auth cleanly rejected; Presto defaults to Bridge.
- Local-file design-around: `refresh:local` + `cron:generate` (crontab + launchd templates,
generated never installed).

**Live proof (local-file path):** `npm run refresh:local` re-ingested the Superstore file and
republished (overwrite) in 4.7s → https://10ax.online.tableau.com/#/site/sebaustin/datasources/27118502
`cron:generate --daily 06:30` emits the install-ready template.

**Pending live proofs (need user resources):** Snowflake scheduled server-side refresh (needs
account creds); the four VERIFY-LIVE schedule-XML details.

---

# E4 — Stories live (2026-07-17)

A generated Tableau STORY workbook published and accepted by Tableau Cloud:

| Artifact | URL |
|---|---|
| Story workbook ("Superstore Executive Story (demo)") | https://10ax.online.tableau.com/#/site/sebaustin/workbooks/2523370 |

6-point persona-toned arc over the exec sheets (headline KPIs → Profit → Quantity → Discount →
Sales by Category → Sales by State). Structure: `<dashboard type='storyboard'>` + paired
flipboard-nav/flipboard + `<story-points captured-sheet=…>`, mirroring the real reference
workbook and XSD-validated. En route, a latent XSD violation was found and fixed (one shared
`<dashboards>` container instead of per-call sibling wrappers).

# E3 — Pulse (code-complete; live proof blocked on fixture)

All 4 Pulse tools shipped (27 tools) with the exact researched payload + VDS pre-flight. Live
attempt: datasource republished with REAL date columns (VDS: `Order Date: DATETIME` — the date-
coercion fix proven live), but `POST /api/-/pulse/definitions` returns a bare 400: the
`basic_specification` internals are specified-by-example only (Tableau's own utilities repo
clones, never constructs, this block). Pending: user creates ONE metric in the Pulse UI → we GET
it, lock the fixture, correct the client, re-prove live.

Gate at this point: **521 TS + 338 Python = 859 tests.**

---

## E5 — Hardening, docs, acceptance (vibe-BI expansion close-out)

**Date:** 2026-07-17 · **Branch:** `feat/exec-dashboards` · **Verdict: SOLID (solution-verifier, rubric 100/100)**

### Final gate (independently re-run by the verifier)

| Check | Result |
|---|---|
| `npm run build` (tsc) | clean |
| `npm run lint` (eslint) | clean |
| `vitest run` | **525 passed** (23 files) |
| `ruff check` / `mypy --strict` | clean |
| `pytest -q` | **338 passed** |
| **Total** | **863 / 863 · exit 0** |
| `npm audit --omit=dev` | 0 vulnerabilities |
| Focused/skipped tests | none (grep-verified) |

### Security close-out

- STRIDE expansion audit VB-01..VB-12 recorded in `SECURITY.md`: **0 CRITICAL · 0 HIGH · 1 MEDIUM**.
- The single MEDIUM (**VB-02**, shell injection via interpolated crontab lines) was **fixed in-branch** (`scripts/cronTemplates.ts` POSIX `shellQuote`) and locked with four adversarial tests (`$(id)`, quote-breakout, embedded single quotes, hostile repoRoot).
- Credentials discipline verified on both the success path and a 400-error path (`tests/secrets.test.ts`); live-connection `.tds` files provably never contain credentials (`test_tds_builder_live.py`).

### Deliverables confirmed real (verifier evidence, code + tests)

- **E1 branding**: brand.yaml → `<preferences><color-palette>`, branded runs, `default-format`; no-brand output byte-identical (regression-proof). Persona resolution wired into `design_dashboard`; Few rules enforced deterministically (chartDeny, KPI caps, no-pie).
- **E2 connectivity**: bounded idempotency-aware retry (chunk-append PUT never retried), Cloud extract-refresh schedules, fail-closed HTTPS webhooks, live Snowflake/Presto `.tds` with key-pair auth cleanly rejected, local-file cron design-around (VB-02-hardened).
- **E3 Pulse**: 4 tools registered, wire payload locked by deep-equal test, VDS pre-flight hard-fails on missing measure/date dimension.
- **E4 stories**: storyboard/flipboard XML XSD-validated in 6 variants, captured-sheet fail-loud at both layers, single shared `<dashboards>` container regression-guarded.
- **Docs**: 27 tools consistent across README / tool_reference / CODEBASE / DEPLOYMENT / architecture; ADRs 0006–0012; runbook. Spot-checked tool entries match zod schemas exactly.

### Live proofs (Tableau Cloud dev site) — status ledger

| Phase | Proof | Status |
|---|---|---|
| E0 | Superstore exec dashboard (embedded extract) | ✅ recorded above |
| E1 | Branded persona=ceo rebuild | ✅ recorded above |
| E2 (local path) | Local-file re-publish refresh chain | ✅ recorded above |
| E4 | Published story (storyboard) | ✅ recorded above |
| E2 (Snowflake) | Scheduled Snowflake refresh + VERIFY-LIVE schedule tokens | ⏳ **pending user**: Snowflake credentials in `.env` |
| E3 (Pulse) | Live definition + metric creation | ⏳ **pending user**: one UI-created metric on "Superstore (exec demo)" → GET fixture → correct `basic_specification` |

No live capability is claimed beyond the ✅ rows; the two ⏳ rows are code-complete and unblocked by a ~2-minute user action each.

### Non-blocking observations (verifier, no fix required)

1. The E3 phase-close record above states the gate at its point-in-time count (521 TS / 859 total); the branch-final count is 525 / 863. Historical snapshot retained as-is.
2. Webhook HTTPS fail-closed is enforced by exact-prefix check; an explicit uppercase-scheme/whitespace unit test would be a nicety.
Loading