Skip to content

docs(feedback): spec set for Feedback Aggregation & Clustering System#2422

Open
blarghmatey wants to merge 7 commits into
mainfrom
worktree-feedback-aggregation-spec
Open

docs(feedback): spec set for Feedback Aggregation & Clustering System#2422
blarghmatey wants to merge 7 commits into
mainfrom
worktree-feedback-aggregation-spec

Conversation

@blarghmatey

Copy link
Copy Markdown
Member

What & why

Advances the Feedback Aggregation & Clustering System through its spec phase. The architecture RFC (mitodl/hq#12210, supersedes #10793) settled the two decisions — contract-first interim landing and one common tfact_feedback. This PR turns that direction into build-ready, repo-grounded specs so implementation can start without re-deriving source columns, dbt conventions, or the ML/orchestration shape.

The dimensional-model design existed only as an uncommitted draft in an unrelated worktree; it is recovered here and joined by five new specs.

Contents (docs/design/)

Doc Scope
README_feedback_aggregation.md Spec index, key decisions, phasing
feedback_dimensional_model.md tfact_feedback schema (recovered)
feedback_event_contract_spec.md Common event contract + migration-proof business keys
feedback_zendesk_mvp_spec.md Build-ready Zendesk MVP dbt models w/ exact repo columns
feedback_ml_approach.md Embedding / UMAP+HDBSCAN clustering / category discovery / sentiment
feedback_dagster_asset_spec.md Batch ML asset cloning student_risk_probability; Vault LLM resource
feedback_consumption_ux_spec.md Audiences × altitude, Superset surfaces, access control

Key decisions

  1. Contract-first, interim learn-ai landing → migrate to the analytics-api/StarRocks data bus later; durable artifact is the event contract + stable business keys, so migration = source-swap + backfill + parity.
  2. One common tfact_feedback mirroring tfact_discussion_events, with sparse nullable conformed FKs; explicit stable feedback_pk (diverges from precedent) for migration + late-arriving category/sentiment.
  3. ML is additive, not a prerequisite — the fact ships useful with tag-seeded categories + CSAT-derived sentiment; embeddings persisted once.
  4. Local, PII-safe embeddings by default; Presidio redaction mandatory pre-embed.
  5. Superset-first consumption; support + engineering are the MVP-served audiences.

Scope

Design/tracking only — no pipeline code. MVP ships the fact first; the ML Dagster asset is a separate, additive follow-up.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 10, 2026 11:44
Comment thread docs/design/feedback_zendesk_mvp_spec.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a build-oriented spec set for the “Feedback Aggregation & Clustering System”, defining the event contract, the tfact_feedback dimensional model, an MVP Zendesk ingestion plan, an ML clustering/sentiment approach, a Dagster asset shape, and Superset-first consumption/UX guidance.

Changes:

  • Added a spec index and phased roadmap for the feedback aggregation initiative.
  • Defined a common feedback event contract + migration-proof business keys and a tfact_feedback Kimball model.
  • Described MVP Zendesk dbt model DAG plus an additive Dagster ML asset plan and consumption surfaces.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/design/README_feedback_aggregation.md Indexes the spec set, key decisions, and phasing for implementation.
docs/design/feedback_dimensional_model.md Defines the tfact_feedback dimensional model and related conformed/new dimensions.
docs/design/feedback_event_contract_spec.md Specifies the source-agnostic event contract and stable business-key strategy.
docs/design/feedback_zendesk_mvp_spec.md Provides a Zendesk-only MVP dbt model plan grounded in repo conventions/macros.
docs/design/feedback_ml_approach.md Specifies embedding, clustering, category discovery, and sentiment approach as additive consumers.
docs/design/feedback_dagster_asset_spec.md Specifies a Dagster ML code location/asset graph to generate embeddings/clusters/labels.
docs/design/feedback_consumption_ux_spec.md Specifies Superset-first consumption, personas, and access-control expectations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +164 to +168
`feedback_pk = generate_surrogate_key([feedback_source, source_natural_key])` where `source_natural_key` is a
**stable business identifier from the source system**, never a warehouse/Airbyte/Postgres row PK:

| Source | source_natural_key |
|--------|--------------------|

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in affb4d7. Aligned §2 and §6 of this doc to the event-contract terminology: feedback_source/source_natural_keysource_slug/source_record_ref. This doc was recovered from an earlier draft that predated the contract naming.

Comment on lines +200 to +201
Clustering/labeling jobs (Dagster asset) read `int__feedback__unioned` (redacted) → write `feedback_embeddings`
+ `dim_feedback_category` + `category_fk`/`sentiment_fk` back onto the fact (late-arriving update).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in affb4d7. Removed the stray leading + (diff artifact) and reflowed the build-path sentence.

Comment thread docs/design/feedback_dagster_asset_spec.md Outdated
blarghmatey and others added 7 commits July 10, 2026 20:54
Advance the Feedback Aggregation & Clustering System project through its
spec phase. The dimensional-model design (previously drafted but never
committed) is recovered and joined by concrete, repo-grounded specs that
resolve the open items it handed to downstream tasks.

Why: the RFC (mitodl/hq#12210) settled the two architecture decisions
(contract-first interim landing; one common tfact_feedback). This turns
that direction into build-ready specs so implementation can start without
re-deriving source columns, dbt conventions, or the ML/orchestration shape.

Adds under docs/design/:
- README_feedback_aggregation.md  — spec index + key decisions + phasing
- feedback_dimensional_model.md   — recovered schema design (tfact_feedback)
- feedback_event_contract_spec.md — common event contract + business keys
- feedback_zendesk_mvp_spec.md    — build-ready Zendesk MVP dbt models/columns
- feedback_ml_approach.md         — embedding/clustering/category/sentiment
- feedback_dagster_asset_spec.md  — batch ML asset (clones student_risk_probability)
- feedback_consumption_ux_spec.md — audiences, Superset surfaces, access control

Design/tracking only; no pipeline code. MVP ships the fact first; ML is
an additive consumer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RJXxq9oEabCbJiXFzSTqkY
Evaluate in-engine AI functions and a DataFrame AI framework against the
original local-torch embedding plan. Decisive repo fact: production runs
Trino on Starburst Galaxy (StarRocks is not deployed), whose in-SQL AI
functions (generate_embedding → Iceberg ARRAY(DOUBLE), public preview) can
embed inside the engine we already run, on AWS Bedrock in-account.

New default: Starburst AI generate_embedding as a trino_only dbt model —
eliminates the net-new torch/sentence-transformers service and removes the
third-party-egress objection (Bedrock-in-account over redacted text). Only
clustering + LLM cluster-labeling remain a (now lightweight) Python asset,
since neither Trino nor DuckDB does density clustering and we want HDBSCAN's
noise class. Fenic and local self-hosted embeddings kept as fallbacks;
StarRocks vector index folded into the Phase-3 data-bus note.

Adds adr_embedding_compute_strategy.md; revises ml_approach §B,
dagster_asset_spec header, and the README index/decisions accordingly.
Schema, contract, and business keys unchanged (compute location was always
meant to be swappable — vectors in a sidecar, category/sentiment late-arriving).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RJXxq9oEabCbJiXFzSTqkY
…arRocks)

Strategic direction is to retire Trino for StarRocks (transforms + data bus +
OLAP serving), so no Galaxy-only functionality may sit on the critical path.
This withdraws rev.1's Starburst generate_embedding recommendation: it is a
Galaxy-proprietary SQL function in exactly the layer being migrated, and
StarRocks has no embedding-generation equivalent to migrate it to.

New decision: keep all AI/embedding compute engine-external (Dagster/Python)
reading/writing open Iceberg, and generate embeddings by calling AWS Bedrock
(amazon.titan-embed-text-v2:0) DIRECTLY via boto3 — same in-account/PII-safe
Bedrock substrate Starburst's function merely wraps, minus the lock-in and
minus torch. Vectors land in an Iceberg ARRAY<float> sidecar that StarRocks
later reads to build an HNSW index (a load, not a re-embed), making StarRocks
ANN the intended serving tier. Sentiment stays the engine-agnostic CSAT-seed +
embedding-kNN path (no analyze_sentiment); clustering stays Python HDBSCAN.
dbt models stay portable (no trino_only AI models).

Fenic (cloud-egress, K-means) and local sentence-transformers kept as
fallbacks. Schema/contract/business-keys unchanged — compute location was
always meant to be swappable.
…mework

Verified against fenic source (main): Fenic is Apache-2.0 and its shipped
embedding providers are OpenAI/Cohere/Google (Developer+Vertex) — genuinely
open source and provider-agnostic, so it's a first-class fit for the portable
engine-external layer (not the downgraded footnote rev.2 made it). Correction
to the record: there is NO BedrockEmbeddingModel config class yet — "Bedrock"
in config.py is only an OpenRouter LLM-routing target (not embeddings), and
ROADMAP lists Bedrock as planned. So native in-account Bedrock embeddings via
Fenic are roadmap-not-shipped.

Decision: use Fenic as the engine-external framework (embed + classify/
sentiment + labeling; batching/caching/lineage free), with the embedding
PROVIDER as a PII-policy choice decoupled from the framework — in-account
Bedrock (via boto3 today, or contribute the provider; Apache-2.0 allows it)
preferred, or a Fenic-native managed provider over redacted text if policy
allows. Clustering stays our own sklearn UMAP+HDBSCAN (Fenic is K-means only,
no noise class). Vectors → open Iceberg ARRAY<float>; StarRocks HNSW is the
intended serving tier (load, not re-embed). No engine-native AI SQL functions;
no trino_only AI models. Schema/contract/business-keys unchanged.
…rness)

Owner direction: Bedrock/in-account is not a requirement — choose the
embedding model on task effectiveness (clustering + retrieval on our own
feedback corpus). Egress of Presidio-redacted text to a managed provider is
acceptable; redaction stays as data-minimization regardless.

Adds §B.1: an effectiveness-driven selection method — use MTEB to narrow,
then benchmark the shortlist on a labeled Zendesk sample by clustering
agreement (ARI/NMI vs. ticket_tags) + silhouette + human coherence, sweeping
Matryoshka dims and cost. Candidate shortlist: Fenic-native managed
(gemini-embedding-001, Cohere embed-v4, OpenAI text-embedding-3-large) and
self-hosted open (Qwen3-Embedding, BGE-M3) if we host for effectiveness.
No hardcoded winner; choice reversible via model_version.

Also upgrades LLM semantic-normalization-before-embedding from "rejected
default" to a first-class eval arm in §C — 2026 support-ticket-clustering
evidence reports it is the single largest lever on cluster quality for
short/noisy text; gate adoption by measured lift vs. per-record LLM cost.

Syncs ADR + dagster_asset_spec + README notes to rev.4.
- feedback_zendesk_mvp_spec §8: compound uniqueness test referenced
  source_slug, which is not a fact column; use ['feedback_source_fk',
  'source_record_id'] (both exist; same business grain since
  feedback_source_fk = surrogate_key([source_slug])). Drop the stray
  "source_slug equivalent" from the not_null list. (sentry)
- feedback_dimensional_model §2/§6: align business-key terminology to the
  rest of the spec set — feedback_source/source_natural_key →
  source_slug/source_record_ref. (Copilot)
- feedback_dimensional_model §8: remove stray leading "+" diff artifact that
  rendered oddly in the build-path prose. (Copilot)
- feedback_dagster_asset_spec §5: type the PrivateAttr in the LLMClientFactory
  example (_client: Anthropic | None) per Pydantic v2 + repo convention, so
  the client-caching pattern is correct. (sentry)
The consumption surface was written Superset-first; broaden it to a real
per-audience choice, since the model is surface-agnostic (every surface just
reads the modeled tables). Add Marimo notebook-as-webapp as the interactive/
curation/prototyping surface and net-new app as the write-back/embedding
option, each grounded in tooling the platform already operates:
- Superset is managed as code in src/ol_superset/ with programmatic RLS
  (apply_rls.py) — lowest-effort MVP dashboards.
- images/marimo-jupyterlab/ already runs marimo with Keycloak OIDC + per-user
  Trino token + IRSA, so a deployed notebook-as-webapp reuses that plumbing and
  can push row-level authz to the engine (Lakekeeper/Cedar) instead of the app.

Recommend phased/audience-matched: Superset for MVP trend/cluster dashboards,
a Marimo webapp for cluster exploration + the category-curation loop and to
prototype the UX, net-new app only when write-back/product-embedding justifies
it. Choice stays reversible. Updates §2/§3/§4/§5 + README.
@blarghmatey
blarghmatey force-pushed the worktree-feedback-aggregation-spec branch from cb23bf4 to 9b0a34f Compare July 11, 2026 00:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants