Spaces:
Running
Running
Commit History
22 days ago
-
docs(sprint): custom MCP demo pack entry — on test app Space 2026-10-20 Running
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>0160599 -
Merge remote-tracking branch 'hf-test/main' into claude/custom-mcp-spotter-demo-125da8
8aebc9f -
feat(demo-pack): custom MCP demo section (GitHub issues → Spotter)
After every successful run the Demo Pack now carries a "Custom MCP Demo" section: suggested repo name, 4 LLM-generated GitHub issues grounded in the deployed model's real column names, the fine-grained token recipe, the Spotter connector settings, the two Spotter prompts, and the cleanup reminder. The SE creates the repo and pastes the issues; DemoPrep holds no GitHub token. - prompts.py: new `custom_mcp_issues` stage (JSON array of issues) - chat_interface.py: custom_mcp_repo_name(), parse_custom_mcp_issues(), render_custom_mcp_demo_section(); controller methods _extract_ddl_columns(), _generate_custom_mcp_issues(), _build_custom_mcp_section(); wired into the Demo Pack block - Side fix: the Spotter Viz story's inline DDL column dedupe always returned [] (`not (seen.add(c) or c in seen)`), so stories never saw real column names. Both generators now share _extract_ddl_columns(). - tests/test_custom_mcp_demo_pack.py: 32 unit tests; one live LLM round trip verified separately…fc2b1f9
-
admin settings: SHARE_WITH is now a real key (save/load silently dropped it — App-tab builds shared with nobody)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 493663f4098c0822ba70d4ad3d770be66b1783e7)3b90e27 -
share: SHARE_WITH / MCP_SHARE_WITH accept a comma-separated list of users and groups
One principal per build left 13 of 43 boards un-exportable by the reviewing account (grader report 2026-09-21). Both paths pass the setting through as a string, so a comma list in the admin setting or the Space secret is now enough. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 196a7b73f83d78e076ad262b42faf277137dbd01)4117ee0
-
Deploy feature/golden-demo-v3 (2b65dd2826ea97ea4be1a6eb8984b9396d95af83) to the test app Space as one commit
Squashed onto hf-test/main because HF's pre-receive hook rejects binary blobs anywhere in pushed history, and the feature branch's history carries two PNGs (stripped from its tree in 2b65dd2826ea97ea4be1a6eb8984b9396d95af83). This commit's tree == the feature branch tree. Contents: golden demo v3 — 4-KPI standard w/ sparklines, state GEO_AREA, three tabs (Showcase = Muze + GRID_TABLE + heatmap + Demo Guide), blank-tile repair, humanized titles fix, grain enforcement, lab live-verification. See sprint_2026_04.md and dev_notes/DECISIONS_for_boone_2026_09_02.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>f7377ae
-
fix(scripts): stop printing trusted-auth keys; correct required var list
Two bugs in the secrets setup script. 1. It printed secret VALUES. TS_ENV_<n>_KEY_VAR normally holds the trusted-auth key itself, and the script's "points at X which is not in .env" warning echoed that key to stdout. Values are never printed now. Root cause: it assumed KEY_VAR was always a variable NAME. Per _ts_env_table() in mcp_server.py, only an "ENV:<NAME>" value is an indirection; anything else is the literal key. The check now mirrors the server. 2. The required-variable list came from README.md, which is stale. It listed MCP_OWNER_EMAIL and MCP_TS_ENV_LABEL — the server reads neither (MCP_OWNER_EMAIL appears only in tests/e2e_mcp.py, MCP_TS_ENV_LABEL only in the README). Replaced with what mcp_server.py actually reads, verified by grep: MCP_ACCESS_TOKEN, SUPABASE_URL, SUPABASE_ANON_KEY, TS_ENV_URL_DEFAULT, TS_USER_DEFAULT, plus the TS_ENV_<n> triplets. LLM key is now "at least one of ANTHROPIC/OPENAI" rather than requiring OpenAI. README.m…d733302 -
chore(scripts): add scripts/ for operational tooling
Moves whats_deployed.py and setup_test_mcp_secrets.py out of scratch/ (which is gitignored and defined as disposable) into a tracked scripts/ dir. Both are standing operational tools, not throwaways — whats_deployed.py is meant to run at the start of every session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>ae9ba39 -
docs(sprint): record what actually landed — backport scope, verified Dockerfile fix, open secrets step
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>731af14 -
docs: correct venv path + record deploy-model drift
Two factual corrections found while standing up the MCP test tier: - venv is ./.venv, not ./demoprep (that dir does not exist). Three commands in this doc would fail as written, including the "ALWAYS use the venv" rule. - Branching Strategy describes a model that is not what is deployed: hf-test/main == spike/portal-template (a spike branch is the de facto integration branch), and develop is stale — missing the current CLAUDE.md and the entire Data Quality Push sprint section. Adds a Reality-check table and the commands to verify deployed state, rather than silently rewriting the branching model. Deciding the intended model is boone's call, not a doc edit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>491d67d -
fix(logging): harden PromptLogger against unwritable log dir
Backport of the prompt_logger.py half of 4b87c36 (cherry-picked from deploy/mcp) onto the branch that feeds hf-test. 4b87c36 fixed a prod MCP outage: PromptLogger.__init__ did an unguarded mkdir on <script_dir>/logs/prompts. HF Spaces run the container as a non-root user inside a root-owned WORKDIR and logs/ is gitignored, so it raised PermissionError: '/app/logs' and failed every MCP build. prompt_logger.py is SHARED code, so the app Spaces carried the same latent bug — it just never fired there because only the MCP path constructed a PromptLogger. This closes that gap: the log dir is resolved (module dir -> temp -> memory-only) and every read/write degrades instead of raising. The mcp_server.py half of 4b87c36 is deliberately NOT taken. It guards the run-logger block added by 47edf58, which does not exist on this branch; pulling it in would import an unrelated feature through a conflict resolution. That guard stays on deploy/mcp where the code it protects lives. Regression covera…767a6ca -
docs: MCP test tier + deploy rules, outage postmortem
Adds the process guardrails that were missing when the 2026-08-25 logging change went straight to the prod MCP Space and failed every build. CLAUDE.md: - Branching Strategy never mentioned the MCP Space at all. Adds deploy/mcp to the branch table, a remotes table naming each Space and its tier, and the mandatory sequence: hf-mcp-test -> verify -> hf-mcp. - Documents that GET / returned {"status":"ok"} throughout a total build outage, so a health check is not deploy verification. - New rule: never leave a hotfix living only on a Space remote. Fixes pushed direct to hf/hf-mcp and not merged back get reverted by the next deploy. sprint_2026_04.md: - Incident section: cause (PromptLogger unguarded mkdir under the Space's non-root user), fix (4b87c36), and the process gaps that let it ship. - Corrects a stale claim that 8d28a8c was "NOT pushed / decision: boone" — it had been live in prod since 00:42 Aug 26. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>76513d3 -
docs: portal/new-vision session notes
- docs/: AgentSpot portal handoff (8/24), new-vision execution notes, temperature tuning notes (from parallel work sessions) - demo_content/legal_demo intentionally NOT tracked: it is its own git repo (would only commit as an empty gitlink) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>eaeb114 -
test(qa): overnight quality results, MCP brief replay harness, data-quality sprint tasks
- tests/mcp_brief_replay.py: replays captured mcp_intake briefs through the real MCP server (stdio or http), re-owned to the operator, incremental reports — used for the 8/25-26 Yodeck/Triumph/Tixr runs - quality_results: 8/25 test-space runs (smoke 83.5/B, full 8-board 80.9/B) + MCP replay report (3/3 PASS on unfixed code) + backfilled 8/07-8/10 runs - sprint doc: Data Quality Push section — P0 row-count parity (fixed 8d28a8c on deploy/mcp, verified 62->78 Tixr), P0 derived-measure computation, P1 gate extensions/dense panels, P2 grader trust + 4-KPI cap + harness fixes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>f65b079
-
Merge remote-tracking branch 'hf-test/main' into spike/portal-template
4d97c9f -
docs(sprint): payload logging entry + ISS-1..9 triage issue log
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>c23ae42 -
feat(logging): capture full run payload in session_logs on every run
Every run (App tab + Chat tab) now logs its complete payload to Supabase session_logs in meta.payload of the 'run started' events: - raw GO form inputs (controller._run_payload set in defined_go) - resolved company/use case/vertical/line/function/context - secret-redacted settings snapshot Attached in _create_run_loggers() (guaranteed even when a run dies before research) and again in run_research_streaming() once fully resolved. New sanitize_payload() in session_logger.py redacts key/secret/password/ token/credential/auth values and truncates >2000-char strings; 5 tests in tests/test_run_payload_logging.py. Chat-tab runs reset stale App-tab _run_source/_run_payload at initialization. Query guide in dev_notes/logging_channels.md (local docs, not tracked). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>63e8227 -
Merge remote-tracking branch 'hf-test/main' into develop
# Conflicts: # sprint_2026_04.md6bb7908 -
Move liveboard/data/triage agents to personal scope (~/.claude/agents/)
Matches how reviewer/tester/architect are installed, so all 6 subagents behave the same way (personal, available in every project) instead of three being project-scoped to this repo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>27dd4fe -
Merge branch 'claude/youthful-lederberg-e31760' into develop
# Conflicts: # chat_interface.pydc44f67 -
feat: post-load data-quality gate for zero/null measure columns
Profile every MEASURE column after each Snowflake load (both dataset-first and legacy paths) via INFORMATION_SCHEMA + per-table aggregates. Fail the run loudly, naming the columns, when any measure is entirely zero/null (recurring Yodeck/Triumph zero-measure defect). Mostly-zero and empty-table cases surface as warnings in the completion panel and session_logs meta. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>fa79ccd -
Install project subagents (liveboard, data, triage) and skills (sprint-close, grade-runs)
Adds an empty Issues section to the current sprint doc and fixes stale sprint pointers/dates in CLAUDE.md (dropped dangling sprint_2026_01.md refs, added missing sprint_2026_03.md, updated Last Updated date). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>9e15d34
-
feat(mcp): KEY_VAR ENV: indirection + scheme-less/port-tolerant host matching
Folds in what the Space-side hotfix (0b84b8a) had that the TS_ENV table didn't: techpartners support and robust URL parsing. KEY_VAR may now be ENV:<NAME> to dereference a secret that already exists under its own name (the techpartners key lives only as a Space secret), and ts_url may omit the scheme or carry a port. Unknown clusters still fail loud with the known-environment list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>e27ea87
-
refactor(mcp): resolve trusted-auth keys from the shared TS_ENV_<n> table
The MCP server had its own two-key mapping ('sebe' in url -> SEBE_SE_TA_KEY, else SE_PRIMARY_TA_KEY) — any third instance (e.g. the new pmm env) silently got the secloud key and failed auth. _resolve_ts_target now looks the build's ts_url host up in the same numbered TS_ENV_<n>_LABEL/URL/KEY_VAR table the app dropdown reads: one environment scheme for both entry points; unknown instances fail loud listing the known environments. TS_ENV_URL_DEFAULT keeps its no-URL fallback role. 4 unit tests. DEPLOY NOTE: before this reaches the MCP Space, add the TS_ENV_<n>_* secrets there (it currently has only the legacy key pair); legacy SEBE_SE_TA_KEY / SE_PRIMARY_TA_KEY become unused after that. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>5ce76f0 -
feat(liveboard): 4 KPIs per liveboard (was 2)
NUM_KPIS 2 -> 4: AI question prompt asks for 4 KPI questions, and the no-AI fallback now generates NUM_KPIS KPIs cycling measures across weekly/monthly/quarterly/yearly grains instead of two hardcoded ones. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>ac4c74f
-
test(mcp): retry brief fetch on network errors + --brief-file escape hatch
Venue WiFi/proxy flaps were killing the burn-in with SSL errors before the first build even fired. Fetch now retries 5x with backoff and fails with a clear message; --brief-file runs the same brief from a local snapshot when Supabase is unreachable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>a423344
-
test(mcp): repeatability burn-in — fire the latest brief N times, report pass rate
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>9a955a5 -
docs(sprint): record CHECKOUT sanitizer bug fix + MCP deploy
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>e7c6ebb -
fix(ddl): CHECK sanitizer no longer deletes columns named CHECKOUT_*
The chunk-level CHECK-constraint detector used prefix matching (upper.startswith("CHECK")), so any column whose name begins with CHECK — CHECKOUT_INITIATED, CHECKOUT_ATTEMPTS, CHECKOUT_CONVERSION_RATE, CHECKOUT_ABANDONMENT_RATE — was silently dropped from CREATE TABLE while the generated dataset still carried its values. The INSERT then failed on columns the table didn't have. Root cause of the "random" schema/data-mismatch build failures (Cloudscape, Atlas Freight partial, Tixr run 02ec3e7baba6) — it fired whenever the LLM blueprint author named a column CHECKOUT_*, which checkout-funnel briefs (Tixr) invite. Detector now requires the CHECK keyword followed by a parenthesized expression, and the CONSTRAINT branch uses a word-boundary match so an FK named CHECKOUT_FK survives. Inline CHECK removal already used \bCHECK\b and was safe. 4 regression tests added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>e32850b -
docs: build-time deep dive notes (root cause, verified results, next bottleneck)
Captures the 2026-08-10 research: scoped-connection root cause + evidence, what shipped and where (hf-test + MCP Space df44611, rollback 3d735c7), verified timings (e2e 655s, MCP 9.2min), API research findings, and the model-semantics phase (~5 min of sequential LLM batches) as the documented next bottleneck with optimization options — deferred, no code changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>2d09335 -
fix(e2e): remove remaining hardcoded DEMOBUILD refs in test harnesses
Follow-up to the rotating-demo-database change: the data-grading fallback, geo-scope check, and settings_test row check still pointed at DEMOBUILD. All now derive the database from the model TML (via check_snowflake_schema's new database field) or get_demo_database(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>a22a600 -
fix(e2e): resolve Snowflake database from model TML in schema check
check_snowflake_schema hardcoded DEMOBUILD; demos now live in the rotating <base>_<YYYY_MM> database, so the check reported "Object does not exist" on runs that succeeded. The database now comes from the same model-TML resolution that supplies the schema (with get_demo_database() as the session-log path's source), and the check refuses to guess when neither is available. Verified against live run ed0dfa99: DEMOBUILD_2026_08.TST_TRE_08102144_P6D_sch, 10,037 rows / 7 tables found. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>80facca -
perf(deploy): scope TS connection to demo DB + monthly-rotating database (250s -> <1s table imports)
Root cause of the ~250s-per-call table TML imports (found 2026-08-10, corrects the July "server-side, not reducible" conclusion): ThoughtSpot table import scans all external metadata VISIBLE TO THE CONNECTION. Our connections had no database property, so every import scanned ~507 Snowflake DBs. Measured on the same instance with the same trivial table: unscoped 246s, scoped to DEMOBUILD (1,003 schemas of demo debris) 33s, scoped to a fresh tiny DB 0.7s. Prod secloud showed identical ~250s unscoped — never instance-specific. - thoughtspot_deployer: create_connection_tml/create_connection_with_reconcile now REQUIRE a database and emit a `database` property in the connection TML. - snowflake_auth: get_demo_database() -> <SNOWFLAKE_DATABASE>_<YYYY_MM> (memoized per process); ensure_demo_database() creates it on connect. Session params + cdw_connector + env injection (supabase_client) all use the rotated DB so write and deploy paths agree. Admin setting stays the base name. - chat_…21ee86d -
Merge remote-tracking branch 'origin/develop_dg' into develop_dg
baf44f7
-
merge: MCP hardening (share-with-operator + relative-date tolerance) into trunk
Pulled origin/deploy/mcp's real fixes back onto trunk instead of letting them live only on the deploy shim — deploy/mcp had drifted from a pure frontmatter shim into carrying unique engine/validator/blueprint fixes: - mcp_server: every MCP build shares the created model + liveboard with the operator (MCP_SHARE_WITH, default mike.boone@thoughtspot.com) so demos are visible no matter who ran them. - engine + validator: _safe_date() tolerates a non-ISO insight window bound (e.g. an LLM-invented relative token) instead of crashing dataset generation. - blueprint.from_dict: also drop non-numeric seasonality.monthly values. Kept trunk's README (gradio/app.py) — the merge initially took deploy/mcp's docker/MCP frontmatter, which would have broken the app Space deploy; restored before this commit finalized. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>2f533a0 -
fix(mcp+pipeline): share demos with operator + harden data-quality consumers
- mcp_server: every MCP build shares the created model + liveboard with the operator (MCP_SHARE_WITH, default mike.boone@thoughtspot.com) so demos are visible no matter who ran them. Owner unchanged — the build still authenticates AS owner_email, so the caller passed in owns the objects. - blueprint.from_dict: drop non-numeric seasonal `monthly` params too (line 261) — the merged author can emit a dict there like it did for params. - engine + validator: _safe_date() tolerates a non-ISO insight window bound (e.g. the LLM token 'relative_minus_8_months') instead of crashing on date.fromisoformat — the second merge bug that failed Cloudscape. Root theme: the merged blueprint author emits richer output than the parser/engine expected; harden the consumers to tolerate it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>2eaf446 -
fix(mcp+pipeline): share demos with operator + harden data-quality consumers
- mcp_server: every MCP build shares the created model + liveboard with the operator (MCP_SHARE_WITH, default mike.boone@thoughtspot.com) so demos are visible no matter who ran them. Owner unchanged — the build still authenticates AS owner_email, so the caller passed in owns the objects. - blueprint.from_dict: drop non-numeric seasonal `monthly` params too (line 261) — the merged author can emit a dict there like it did for params. - engine + validator: _safe_date() tolerates a non-ISO insight window bound (e.g. the LLM token 'relative_minus_8_months') instead of crashing on date.fromisoformat — the second merge bug that failed Cloudscape. Root theme: the merged blueprint author emits richer output than the parser/engine expected; harden the consumers to tolerate it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>3d735c7
-
merge: origin/develop_dg (blueprint params fix) into local guard work
6435820 -
guard: catch CREATE/INSERT column mismatches before and during Snowflake load
The Gap e2e failure: FACT_CAMPAIGN_PERFORMANCE's row loader referenced CHECKOUT_INITIATED, a column CREATE TABLE never declared -> Snowflake "invalid identifier", ~10 minutes into the run, no indication of which table/column. Root mechanism wasn't pinned with certainty (DDL and the loader both derive columns from the same DatasetBundle object, so they can't diverge in the code as read) — these guards catch the failure class immediately and name the exact column, regardless of cause. - validator.py: _check_schema_consistency() — in-memory, at validate_bundle() time. Flags (a) two column names that collide after SQL-identifier normalization (duplicate column in CREATE TABLE), and (b) a generated row carrying a key no declared column covers (INSERT would reference an identifier CREATE TABLE never defined). Runs before any DDL is derived or Snowflake is touched. - dataset_writer.py: _verify_table_columns() — right before each table's INSERT, DESCRIBE TABLE and diff against th…2cc63cd -
fix(blueprint): from_dict drops non-numeric measure params (fixes float(dict) DDL crash)
The merged blueprint author occasionally emits a measure whose `params` value is a dict; DemoBlueprint.from_dict did `float(v)` on every value → TypeError → crashed every build at DDL generation (shared pipeline; hit app + MCP). params is only ever numeric distribution config (mean/sigma, low/high — per the author examples + engine), so keep numeric values and drop anything non-numeric; the engine already backfills sane defaults for missing params. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>8d8e6bc -
fix(blueprint): from_dict drops non-numeric measure params (fixes float(dict) DDL crash)
The merged blueprint author occasionally emits a measure whose `params` value is a dict; DemoBlueprint.from_dict did `float(v)` on every value → TypeError → crashed every build at DDL generation (shared pipeline; hit app + MCP). params is only ever numeric distribution config (mean/sigma, low/high — per the author examples + engine), so keep numeric values and drop anything non-numeric; the engine already backfills sane defaults for missing params. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1907a8d -
chore: check in async-TML-import investigation (repro/perf harness + handoff docs)
- tests/ts_import_sync_vs_async.py, ts_slow_import_repro.py, ts_table_perf.py: repro/perf harness behind the async TML import fix - tests/perf_results/: captured sync-vs-async timings - docs/async_tml_import_handoff.md, sre_slow_tml_import.md: investigation + SRE handoff notes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>72b93af -
deploy(mcp): MCP-server frontmatter (docker/app_port) over unified trunk
5b89665 -
merge: liveboard geo-map (a15663c) into integration
a060e36 -
liveboard: auto-build a geo map from model lat/lon (Path B)
When the model has latitude/longitude columns and the board has no geo viz, synthesize a GEO_BUBBLE so the layout places it full-width under the KPIs ("geo on almost anything, when the data supports it"). golden_layout.py: - detect_geo_columns(): find lat/lon (word-boundary match, so "Platform" isn't a false hit) + a geo attribute + a bubble measure from model columns - _build_geo_viz(): synthesize a GEO_BUBBLE answer (clone a sibling's model ref; search_query [Lat] [Lon] sum [Measure] [GeoDim]; minimal mapview client_state that auto-fits) - _maybe_build_geo_viz(): only fires when lat/lon exist and no geo viz present - build_dashboard_plan gains model_columns; apply_golden_two_tab_layout adds the synthesized viz so it lands in the Geographic View group liveboard_creator.py: _fetch_model_columns() resolves the board's model (export w/ fqn -> model TML) and passes its columns to the plan; best-effort (returns [] on failure so liveboard creation never breaks). Verified live: st…a15663c -
merge: unify MCP (async TML import + concurrency + mcp_server) into integration
- keep app README frontmatter (gradio) on trunk; MCP docker frontmatter stays on hf-mcp-deploy - build_demo.py: blueprint LLM cap/timeout reconciled to 16384 / 300s (superset of both sides) - adds mcp_server.py, tests/e2e_mcp.py, MCP deps; async-only TML import pathc3e3f8b -
merge: liveboard-quality into integration/mcp-lb
ee1ce2a -
liveboard: balance group chunks + nicer continuation names
Avoid a lone chart landing in its own numbered group ("Performance Drivers 2" with 1 tile): _balanced_chunks folds a trailing orphan into the prior chunk (4 -> 2+2). Continuation groups now read "Additional Drivers" instead of "... 2". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>26a1772 -
liveboard quality: fix flat-72 defects + Tixr-style layout
Reshape the MCP + enhance golden layout to fix the 5 structural grader defects and adopt the SE's Tixr Executive Analytics template. golden_layout.py: - note tile: full company name (was single-letter "N"/"L"), deduped; dropped by default (keep_overview_note flag) so the KPI row leads - colors: color ADVANCED_* charts by dimension via custom_chart_config "slice-with-color" (real per-category colors + legends; was all-blue, since seriesColors/chartLevelColorConfig don't drive the new engine) - per-tile tile_brand_color cycling + tile_kpi_color on KPIs - force CHART_MODE where a chart renders as a data grid - clean raw display names (Dim / Usd / Pct / doubled words) - trend detection: time-only series -> dedicated Performance Trends - geo: GEO_* -> its own full-width row right under the KPI row - asymmetric group sizing (5/4/3, 7/5) + Tixr styling (kpi L font, hidden group descriptions) liveboard_creator.py / thoughtspot_deployer.py: thread logo_url/url into build_dashboard_pla…f7f2b52 -
chore: README, e2e grader, share-permission fix, sprint + quality results
- README: chat_interface.py is the full app (App tab primary), app.py entry point; updated structure/config - tests/e2e_quality.py: date-aware grader, COMPLETENESS rubric rewrite, --ts-environment override, hard-fail on missing dropdown label - thoughtspot_deployer.py: share-permission 400 fix — notify_on_share=false + empty message to satisfy the GraphQL $message contract - sprint_2026_04.md: progress updates - tests/quality_results: run artifacts incl. 2026-07-28 82.9/B run Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>fcde472