@terreno/mcp 57.8.0 → 57.10.1
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/dist/docs/upgrades/57.10.1.md +54 -0
- package/dist/docs/upgrades/57.9.0.md +28 -0
- package/dist/docs/versioned/next/README.md +1 -0
- package/dist/docs/versioned/next/explanation/README.md +4 -0
- package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +2 -2
- package/dist/docs/versioned/next/explanation/agent-ui-asks.md +299 -0
- package/dist/docs/versioned/next/explanation/agent-ui-blocks.md +67 -0
- package/dist/docs/versioned/next/explanation/ai-observability.md +101 -0
- package/dist/docs/versioned/next/explanation/charts.md +12 -0
- package/dist/docs/versioned/next/explanation/durable-agent-harness.md +531 -0
- package/dist/docs/versioned/next/explanation/example-coverage.md +4 -2
- package/dist/docs/versioned/next/explanation/loop-engineering.md +1 -1
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +49 -1
- package/dist/docs/versioned/next/explanation/typescript-configuration.md +1 -1
- package/dist/docs/versioned/next/explanation/versioning-policy.md +1 -1
- package/dist/docs/versioned/next/how-to/README.md +7 -1
- package/dist/docs/versioned/next/how-to/admin-import-prebuilt.md +1 -1
- package/dist/docs/versioned/next/how-to/agent-ui-asks.md +730 -0
- package/dist/docs/versioned/next/how-to/agent-ui-blocks.md +104 -0
- package/dist/docs/versioned/next/how-to/ai-feature-development.md +156 -0
- package/dist/docs/versioned/next/how-to/build-a-durable-workflow.md +232 -0
- package/dist/docs/versioned/next/how-to/charts-and-dashboards.md +7 -0
- package/dist/docs/versioned/next/how-to/circleci.md +9 -6
- package/dist/docs/versioned/next/how-to/compare-chart-rendered-snapshots.md +8 -0
- package/dist/docs/versioned/next/how-to/install-agent-skills.md +1 -1
- package/dist/docs/versioned/next/how-to/observe-llm-calls.md +197 -0
- package/dist/docs/versioned/next/how-to/run-tests-locally.md +2 -1
- package/dist/docs/versioned/next/how-to/ship-a-new-task-version.md +76 -0
- package/dist/docs/versioned/next/how-to/upgrade-terreno.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/agent-ui-asks.md +688 -0
- package/dist/docs/versioned/next/implementationPlans/agent-ui-blocks.md +10 -6
- package/dist/docs/versioned/next/implementationPlans/ai-observability.md +475 -157
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/charts-and-dashboards.md +3 -2
- package/dist/docs/versioned/next/implementationPlans/dashboard-chart-parity.md +275 -0
- package/dist/docs/versioned/next/implementationPlans/durable-agent-harness.md +340 -0
- package/dist/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -1
- package/dist/docs/versioned/next/reference/README.md +3 -0
- package/dist/docs/versioned/next/reference/admin-config.md +2 -0
- package/dist/docs/versioned/next/reference/admin-frontend.md +216 -0
- package/dist/docs/versioned/next/reference/agent-ui-asks.md +1059 -0
- package/dist/docs/versioned/next/reference/ai-harness.md +1881 -0
- package/dist/docs/versioned/next/reference/ai.md +283 -28
- package/dist/docs/versioned/next/reference/api.md +46 -0
- package/dist/docs/versioned/next/reference/blocks.md +178 -0
- package/dist/docs/versioned/next/reference/environment-variables.md +2 -1
- package/dist/docs/versioned/next/reference/feature-flags.md +1 -1
- package/dist/docs/versioned/next/reference/mcp-server.md +17 -0
- package/dist/docs/versioned/next/reference/test.md +11 -2
- package/dist/docs/versioned/next/reference/ui.md +418 -11
- package/dist/docs/versioned/next/tasks/agent-ui-asks.md +213 -0
- package/dist/docs/versioned/next/tasks/agent-ui-blocks.md +2 -1
- package/dist/docs/versioned/next/tasks/ai-observability.md +233 -104
- package/dist/docs/versioned/next/tasks/dashboard-chart-parity.md +145 -0
- package/dist/docs/versioned/next/tasks/durable-agent-harness.md +183 -0
- package/dist/tools.d.ts +4 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +37 -0
- package/dist/tools.js.map +1 -1
- package/package.json +3 -2
- package/src/docs/upgrades/57.10.1.md +54 -0
- package/src/docs/upgrades/57.9.0.md +28 -0
- package/src/docs/versioned/next/README.md +1 -0
- package/src/docs/versioned/next/explanation/README.md +4 -0
- package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +2 -2
- package/src/docs/versioned/next/explanation/agent-ui-asks.md +299 -0
- package/src/docs/versioned/next/explanation/agent-ui-blocks.md +67 -0
- package/src/docs/versioned/next/explanation/ai-observability.md +101 -0
- package/src/docs/versioned/next/explanation/charts.md +12 -0
- package/src/docs/versioned/next/explanation/durable-agent-harness.md +531 -0
- package/src/docs/versioned/next/explanation/example-coverage.md +4 -2
- package/src/docs/versioned/next/explanation/loop-engineering.md +1 -1
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +49 -1
- package/src/docs/versioned/next/explanation/typescript-configuration.md +1 -1
- package/src/docs/versioned/next/explanation/versioning-policy.md +1 -1
- package/src/docs/versioned/next/how-to/README.md +7 -1
- package/src/docs/versioned/next/how-to/admin-import-prebuilt.md +1 -1
- package/src/docs/versioned/next/how-to/agent-ui-asks.md +730 -0
- package/src/docs/versioned/next/how-to/agent-ui-blocks.md +104 -0
- package/src/docs/versioned/next/how-to/ai-feature-development.md +156 -0
- package/src/docs/versioned/next/how-to/build-a-durable-workflow.md +232 -0
- package/src/docs/versioned/next/how-to/charts-and-dashboards.md +7 -0
- package/src/docs/versioned/next/how-to/circleci.md +9 -6
- package/src/docs/versioned/next/how-to/compare-chart-rendered-snapshots.md +8 -0
- package/src/docs/versioned/next/how-to/install-agent-skills.md +1 -1
- package/src/docs/versioned/next/how-to/observe-llm-calls.md +197 -0
- package/src/docs/versioned/next/how-to/run-tests-locally.md +2 -1
- package/src/docs/versioned/next/how-to/ship-a-new-task-version.md +76 -0
- package/src/docs/versioned/next/how-to/upgrade-terreno.md +1 -1
- package/src/docs/versioned/next/implementationPlans/agent-ui-asks.md +688 -0
- package/src/docs/versioned/next/implementationPlans/agent-ui-blocks.md +10 -6
- package/src/docs/versioned/next/implementationPlans/ai-observability.md +475 -157
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/src/docs/versioned/next/implementationPlans/charts-and-dashboards.md +3 -2
- package/src/docs/versioned/next/implementationPlans/dashboard-chart-parity.md +275 -0
- package/src/docs/versioned/next/implementationPlans/durable-agent-harness.md +340 -0
- package/src/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -1
- package/src/docs/versioned/next/reference/README.md +3 -0
- package/src/docs/versioned/next/reference/admin-config.md +2 -0
- package/src/docs/versioned/next/reference/admin-frontend.md +216 -0
- package/src/docs/versioned/next/reference/agent-ui-asks.md +1059 -0
- package/src/docs/versioned/next/reference/ai-harness.md +1881 -0
- package/src/docs/versioned/next/reference/ai.md +283 -28
- package/src/docs/versioned/next/reference/api.md +46 -0
- package/src/docs/versioned/next/reference/blocks.md +178 -0
- package/src/docs/versioned/next/reference/environment-variables.md +2 -1
- package/src/docs/versioned/next/reference/feature-flags.md +1 -1
- package/src/docs/versioned/next/reference/mcp-server.md +17 -0
- package/src/docs/versioned/next/reference/test.md +11 -2
- package/src/docs/versioned/next/reference/ui.md +418 -11
- package/src/docs/versioned/next/tasks/agent-ui-asks.md +213 -0
- package/src/docs/versioned/next/tasks/agent-ui-blocks.md +2 -1
- package/src/docs/versioned/next/tasks/ai-observability.md +233 -104
- package/src/docs/versioned/next/tasks/dashboard-chart-parity.md +145 -0
- package/src/docs/versioned/next/tasks/durable-agent-harness.md +183 -0
|
@@ -1,134 +1,263 @@
|
|
|
1
|
-
# Tasks: AI observability (Langfuse
|
|
1
|
+
# Tasks: AI observability (Langfuse replacement)
|
|
2
2
|
|
|
3
3
|
IP: [ai-observability](../implementationPlans/ai-observability.md)
|
|
4
|
+
Design: [AI Observability Prototype](https://claude.ai/design/p/36eec001-f2f0-4161-b60d-20dace4d0a9c?file=AI+Observability+Prototype.dc.html)
|
|
4
5
|
|
|
5
6
|
Supporting skills (every task as applicable): `mongoose-schema-safety`, `terreno-backend-api`, `backend-test-env`, `ai-prompt-governance`, `update-docs`, `generate-sdk`, `verify-ui-changes`, `terreno-ui`, `terreno-data-fetching`, `building-terreno-apps`.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
---
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
# Phase 1 — MVP: prompt library, tracing, review queue
|
|
11
|
+
|
|
12
|
+
Ships design screens: Prompts, Prompt editor (+ Playground), Traces, Trace detail, Review queue, Review item.
|
|
13
|
+
|
|
14
|
+
## 1A — Contracts and tracer
|
|
15
|
+
|
|
16
|
+
- [x] **Task 1.1**: Observability types + `ObservabilityApp` config validation
|
|
17
|
+
- Delivers: `ObservabilityPlugin` / `TraceSink` / `ScoreSink` / `PromptRegistry` / `ReviewQueue` interfaces; `ObservabilityControlConfig`; boot throws on `experiments.primary !== datasets.primary`, on `reviewQueue !== "local"`, and on a primary whose plugin is missing
|
|
11
18
|
- Files: `ai/src/observability/types.ts`, `ai/src/observability/observabilityApp.ts`, `ai/src/observability/observabilityApp.test.ts`, `ai/src/index.ts`
|
|
12
19
|
- Blocked by: none
|
|
13
|
-
- Docs:
|
|
14
|
-
- Acceptance: unit tests for
|
|
20
|
+
- Docs: `docs/explanation/ai-observability.md` (two planes + config errors)
|
|
21
|
+
- Acceptance: unit tests for local-only valid config, illegal mix, langfuse review queue, missing plugin for a primary
|
|
15
22
|
|
|
16
|
-
- [
|
|
17
|
-
- Delivers: every `generate*` exports a trace unless `skipTrace`; sink failures logged not thrown; `AIRequest` still written; `userId
|
|
23
|
+
- [x] **Task 1.2**: In-memory sinks + `AIService` emit + production prompt resolve
|
|
24
|
+
- Delivers: `promptName` + `promptLabel` resolves via `PromptRegistry` **before the model call**, even when `skipTrace` is true or no trace sink is registered; missing registry/label/version returns 400 without a model call; resolved-version `sensitive` applies unless the generate option overrides it; every `generate*` exports a trace unless `skipTrace`; sink failures logged not thrown; `AIRequest` still written; `userId` / `sessionId` / `sensitive` / `promptRef` / `priceMap` on options; `costUsd` omitted for unpriced models
|
|
18
25
|
- Files: `ai/src/observability/memorySinks.ts`, `ai/src/service/aiService.ts`, `ai/src/types/index.ts`, `ai/src/service/aiService.test.ts`
|
|
19
26
|
- Blocked by: 1.1
|
|
20
|
-
- Docs: `docs/reference/ai.md` — `skipTrace`, `
|
|
21
|
-
- Acceptance: tests
|
|
27
|
+
- Docs: `docs/reference/ai.md` — `skipTrace`, `promptName`, `promptLabel`, `sensitive`, usage/cost fields
|
|
28
|
+
- Acceptance: tests for emit, `skipTrace`, throwing sink, cost from price map, **no `costUsd` when the model is unpriced**, multi-step still logs `AIRequest`, resolved prompt body reaches the model with `skipTrace`, and missing registry/production label → 400 with no model call
|
|
22
29
|
|
|
23
|
-
- [
|
|
24
|
-
- Delivers: `/gpt/prompt` sets `userId` from `req.user
|
|
25
|
-
- Files: `ai/src/routes/gpt.ts`,
|
|
30
|
+
- [x] **Task 1.3**: GPT routes pass identity and sensitivity
|
|
31
|
+
- Delivers: `/gpt/prompt` sets `userId` from `req.user`, `sessionId` from body/header `x-ai-session-id`, and may upgrade sensitivity with request `sensitive: true`; client `false` never downgrades a sensitive prompt version. Client `promptName` / `promptLabel` selection is admin-only; app routes select production prompts server-side
|
|
32
|
+
- Files: `ai/src/routes/gpt.ts`, route tests
|
|
26
33
|
- Blocked by: 1.2
|
|
27
34
|
- Docs: `docs/reference/ai.md` GPT section
|
|
28
|
-
- Acceptance: authenticated prompt produces a memory
|
|
35
|
+
- Acceptance: an authenticated prompt produces a memory-sink trace carrying that `userId` and `sessionId`
|
|
29
36
|
|
|
30
|
-
##
|
|
37
|
+
## 1B — Local store: prompts, traces, review
|
|
31
38
|
|
|
32
|
-
- [
|
|
33
|
-
- Delivers: schemas with
|
|
34
|
-
- Files: `ai/src/observability/local/models/*.ts`, `ai/src/observability
|
|
39
|
+
- [x] **Task 1.4**: Local Mongo models — prompts, versions, labels, traces, spans, scores
|
|
40
|
+
- Delivers: schemas with a description on every field, standard plugins, the indexes in the IP; models registered only when the local plugin constructs; `ObsPromptVersion` carries `variables[]` (`key`, `required`, `label?`, `reviewerNote?`), `inputSchema`, `outputSchema`, `outputFieldNotes`, **`sensitive` (default false)**, `config`; `ObsPrompt` carries `folder` + `tags[]`; `ObsTrace` carries `sensitive`, `errorSummary`, `prompts[]`; `ObsSpan` carries `status` and optional short `error`
|
|
41
|
+
- Files: `ai/src/observability/local/models/*.ts`, `ai/src/types/observability*.ts`, model tests
|
|
35
42
|
- Blocked by: 1.1
|
|
36
43
|
- Docs: `docs/reference/ai.md` model tables
|
|
37
|
-
- Acceptance:
|
|
44
|
+
- Acceptance: version immutability; unique `(promptId, label)`; `findExactlyOne` / `findOneOrNone` only; no unique index on scores
|
|
38
45
|
|
|
39
|
-
- [
|
|
40
|
-
- Delivers: create
|
|
46
|
+
- [x] **Task 1.5**: Local `PromptRegistry` + prompt HTTP + playground
|
|
47
|
+
- Delivers: create prompt in a folder; immutable `vN+1` create; move `production` / `staging` returning the outgoing version; `{{var}}` compile; `get({name, label})`; `POST /prompts/:name/playground` runs one `AIService` call and returns compiled messages, output, latency, tokens, cost without creating a version; list supports folder filter, search, and `include=usage7d`
|
|
41
48
|
- Files: `ai/src/observability/local/promptStore.ts`, `ai/src/observability/routes/prompts.ts`, tests
|
|
42
|
-
- Blocked by:
|
|
43
|
-
- Docs: `docs/how-to/observe-llm-calls.md` — create
|
|
44
|
-
- Acceptance: v1 unchanged after v2; get production returns
|
|
49
|
+
- Blocked by: 1.4, 1.1
|
|
50
|
+
- Docs: `docs/how-to/observe-llm-calls.md` — create a prompt and pin production
|
|
51
|
+
- Acceptance: v1 unchanged after v2; `get production` returns the labelled version; playground creates no version; usage rollup returns calls/cost for the last 7 days and `—` for a prompt with no production label
|
|
45
52
|
|
|
46
|
-
- [
|
|
47
|
-
- Delivers: persist fan-in
|
|
53
|
+
- [x] **Task 1.6**: Local `TraceSink` / `ScoreSink` + trace HTTP
|
|
54
|
+
- Delivers: persist the fan-in; list with time / prompt / status / user / session / `hasScore` / `sensitive` / `flaggedForDataset` filters and pagination; detail returns the span tree with kinds, offsets, durations, per-span I/O and cost; derive `errorSummary` from the first span where `status: "error"` using its `error`; `prompts[]` length drives the `N prompts` display; `POST /traces/:id/scores`
|
|
48
55
|
- Files: `ai/src/observability/local/traceStore.ts`, `ai/src/observability/routes/traces.ts`, tests
|
|
49
|
-
- Blocked by:
|
|
56
|
+
- Blocked by: 1.4, 1.2
|
|
50
57
|
- Docs: `docs/reference/ai.md` routes
|
|
51
|
-
- Acceptance:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- [
|
|
70
|
-
- Delivers:
|
|
71
|
-
- Files: `
|
|
72
|
-
- Blocked by:
|
|
73
|
-
- Docs:
|
|
74
|
-
- Acceptance:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
|
|
58
|
+
- Acceptance: nested spans round-trip; every filter tested; a trace with two prompts reports both; unpriced model returns no `costUsd`
|
|
59
|
+
|
|
60
|
+
- [x] **Task 1.7**: Human evaluator model + templates
|
|
61
|
+
- Delivers: `ObsEvaluator` with `type`, `target`, typed `dimensions[]`, `runModes`, `instructions`, `confidenceAlertBelow`; CRUD routes; `GET /evaluators/templates` returning the seeded set; `human` + `liveSampleRate > 0` rejected on save
|
|
62
|
+
- Files: `ai/src/observability/local/evaluatorStore.ts`, `ai/src/observability/evaluatorTemplates.ts`, `ai/src/observability/routes/evaluators.ts`, tests
|
|
63
|
+
- Blocked by: 1.4
|
|
64
|
+
- Docs: `docs/how-to/ai-feature-development.md` step 4 (human half)
|
|
65
|
+
- Acceptance: numeric / boolean / categorical dimensions persist; human evaluator with live sampling is a 400; a template installs by name
|
|
66
|
+
|
|
67
|
+
- [x] **Task 1.8**: Local review queue API
|
|
68
|
+
- Delivers: `POST /traces/review` enqueues one or many traces against a human evaluator (`reason: "manual"`); `GET /review` by status with counts, oldest-first; `GET /review/:id` returns the item, its evaluator dimensions, and rendered `given` / `wrote` panels built from the prompt version's `variables[]` labels/notes and `outputSchema` + `outputFieldNotes`, falling back to raw keys; `POST /review/:id` submit / skip / assign
|
|
69
|
+
- Files: `ai/src/observability/local/reviewStore.ts`, `ai/src/observability/reviewPanels.ts`, `ai/src/observability/routes/review.ts`, tests
|
|
70
|
+
- Blocked by: 1.6, 1.7
|
|
71
|
+
- Docs: `docs/how-to/observe-llm-calls.md` — the review flow
|
|
72
|
+
- Acceptance: submit writes dimension-keyed scores through the ScoreSink fan-out and leaves pending; skip and assign move status; panels fall back cleanly for a prompt with no labels; a submitted item is absent from pending
|
|
73
|
+
|
|
74
|
+
## 1C — Admin UI and example app
|
|
75
|
+
|
|
76
|
+
- [x] **Task 1.9**: Admin chrome — nav group, breadcrumbs, status chip
|
|
77
|
+
- Delivers: one `AI Observability` sidebar group; `Admin / AI Observability / <Section> / <leaf>` breadcrumbs; status chip reading `GET /status` (local state, primaries); **Review queue hidden when the local plugin is off**; existing `AI Requests` untouched
|
|
78
|
+
- Files: `admin-frontend/src/widgets/aiObservability/shell/*.tsx`, `builtInWidgets.ts`
|
|
79
|
+
- Blocked by: 1.1
|
|
80
|
+
- Docs: `docs/reference/admin-frontend.md` screen names
|
|
81
|
+
- Acceptance: widget tests for chip states and for the hidden review entry
|
|
82
|
+
|
|
83
|
+
- [x] **Task 1.10**: Prompts list + prompt editor + playground screens
|
|
84
|
+
- Delivers: folder rail with counts and search; table with type badge, latest, production, last used, calls 7d, cost 7d and the latest-vs-production tooltips; editor with full-width version history rows (`vN`, attached labels, creation time, selected highlight), Editor/Playground tabs, system + template + variables + schema summary, temperature preset and model hint, **Save as vN+1**, **Set vN as production…** confirm modal naming the outgoing version; playground variable inputs, Run once with a running state, compiled-messages disclosure, output, latency/tokens/cost, and a **Save this run to dataset** button disabled until phase 2
|
|
85
|
+
- Files: `admin-frontend/src/widgets/aiObservability/prompts/*.tsx`
|
|
86
|
+
- Blocked by: 1.5, 1.9
|
|
87
|
+
- Docs: `docs/how-to/ai-feature-development.md` steps 3 and 6
|
|
88
|
+
- Acceptance: widget tests empty/loading/loaded; no in-place save control exists; `verify-ui-changes` walks create → save v2 → set production
|
|
89
|
+
|
|
90
|
+
- [x] **Task 1.11**: Traces list + trace detail screens
|
|
91
|
+
- Delivers: filter bar; row selection with the bulk bar (**Send to review queue**, sensitive-count warning, Clear; Add to dataset disabled until phase 2); status dot, `sensitive` badge, error line, `N prompts`, spans/tokens/cost/latency/scores columns; pagination footer; detail header with actions, left span list (kind badge, indent, duration bar), right span detail with **collapsed** sensitive I/O disclosures, and the scores panel with value + source
|
|
92
|
+
- Files: `admin-frontend/src/widgets/aiObservability/traces/*.tsx`
|
|
93
|
+
- Blocked by: 1.6, 1.8, 1.9
|
|
94
|
+
- Docs: `docs/how-to/ai-feature-development.md` steps 7–8 (observe half)
|
|
95
|
+
- Acceptance: widget tests for empty, error row, sensitive badge, and bulk bar; `verify-ui-changes` selects traces and sends them to the queue
|
|
96
|
+
|
|
97
|
+
- [x] **Task 1.12**: Review queue + review item screens
|
|
98
|
+
- Delivers: tabs Pending / In progress / Done / Skipped with counts; oldest-first table (item, what the AI did, prompt, assignee, waiting, status); **Start reviewing — oldest first**; empty state naming both intake paths; item screen with "Item N of M pending" and prev/next, read-only given/wrote panels (long fields collapsed with word count, structured output as key/value rows, per-field reviewer notes), raw JSON disclosure, dimension-driven score form (slider / Pass-Fail / pills) headed by the evaluator instructions, comment, **Submit & next** / Skip / Assign to me, and a toast reporting the remaining count
|
|
99
|
+
- Files: `admin-frontend/src/widgets/aiObservability/review/*.tsx`
|
|
100
|
+
- Blocked by: 1.8, 1.9
|
|
101
|
+
- Docs: `docs/how-to/ai-feature-development.md` — the review loop
|
|
102
|
+
- Acceptance: widget tests for each dimension control type and the empty state; `verify-ui-changes` reviews an item end to end and reaches "Queue clear"
|
|
103
|
+
|
|
104
|
+
- [x] **Task 1.13**: example-backend registration + seed + phase-1 docs
|
|
105
|
+
- Delivers: `ObservabilityApp` with the local plugin always on; `AI_OBS_PRICE_MAP_JSON` wiring; seed prompt `example-summarize` v1 labelled production in folder `examples`; seed the human evaluator template so the queue is walkable on a fresh DB; `.env.example`
|
|
106
|
+
- Files: `example-backend/src/server.ts`, seed script, `.env.example`, `docs/explanation/ai-observability.md`, `docs/how-to/observe-llm-calls.md`, `docs/how-to/ai-feature-development.md`, `docs/reference/ai.md`
|
|
107
|
+
- Blocked by: 1.10, 1.11, 1.12
|
|
108
|
+
- Docs: (this task)
|
|
109
|
+
- Acceptance: server boots local-only with no Langfuse keys; a stranger can follow the how-to to create a prompt, pin production, trace a call, and review it; `bun run --filter=@terreno/ai compile test lint` green
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# Phase 2 — Evaluation loop: evaluators, datasets, experiments
|
|
114
|
+
|
|
115
|
+
Ships design screens: Evaluators, Evaluator detail, New evaluator, Datasets, Dataset detail, Experiments, New experiment, Experiment results.
|
|
116
|
+
|
|
117
|
+
- [x] **Task 2.1**: `llm-judge` + `json-assert` evaluator types with the schema contract
|
|
118
|
+
- Delivers: judge execution via `AIService.generateJsonObject` against a registry judge prompt; `json-assert` in-process assertion (`path`, `constraint`, plus the built-in "validate against the prompt version `outputSchema`" mode); **create/save rejects a judge whose prompt output schema omits a required dimension, naming that dimension**; parse failure records an error score rather than throwing to the caller
|
|
119
|
+
- Files: `ai/src/observability/evaluate.ts`, `ai/src/observability/local/evaluatorStore.ts`, `ai/src/observability/evaluatorTemplates.ts`, tests
|
|
120
|
+
- Blocked by: 1.7, 1.5
|
|
121
|
+
- Docs: explanation — dimensions and the schema contract; how-to step 4
|
|
122
|
+
- Acceptance: mismatch rejected with the dimension key in the message; a judge writes exactly its declared keys; `confidenceAlertBelow` defaults to 0.7; templates for correctness / hallucination / helpfulness / toxicity / schema-assert install (`*-human` variants preserved for the review queue)
|
|
123
|
+
|
|
124
|
+
- [ ] **Task 2.2**: Live sampling execution
|
|
125
|
+
- Delivers: after trace export, roll each evaluator's `liveSampleRate` (capped by `AI_OBS_SAMPLE_RATE`) and enqueue the eval on the same `BackgroundTask` path experiments use; never throws from generate
|
|
126
|
+
- Files: `ai/src/observability/liveEval.ts`, `ai/src/observability/observabilityApp.ts`, tests
|
|
127
|
+
- Blocked by: 2.1, 1.2
|
|
128
|
+
- Docs: how-to — the sampling ceiling and its cost
|
|
129
|
+
- Acceptance: rate 0 → no task; rate 100 with ceiling 0 → no task; rate 100 with ceiling 100 → task created
|
|
130
|
+
|
|
131
|
+
- [x] **Task 2.3**: Datasets and items with provenance
|
|
132
|
+
- Delivers: dataset CRUD with `inputSchemaPromptName` + `expectedOutputSchema`; item CRUD with `origin`, `proofread`, `annotatedBy`, `tags`, `outcomeClass`; `POST /datasets/:id/import` (**JSON** array of bare objects or structured rows, plus **CSV** via `Content-Type: text/csv` or `{format: "csv", content}`; validates against the bound input schema); `POST /traces/add-to-dataset` single and bulk copying the I/O snapshot with `sourceTraceId`; **a `sensitive` trace always lands `proofread: false`**
|
|
133
|
+
- Files: `ai/src/observability/local/datasetStore.ts`, `ai/src/observability/routes/datasets.ts`, tests
|
|
134
|
+
- Blocked by: 1.6
|
|
135
|
+
- Docs: how-to steps 1–2 and 8
|
|
136
|
+
- Acceptance: sensitive rule enforced; item keeps `sourceTraceId`; deleting an item does not touch the trace; import rejects schema-invalid rows with the failing path
|
|
137
|
+
|
|
138
|
+
- [ ] **Task 2.4**: Synthetic dataset generation + playground save-to-dataset
|
|
139
|
+
- Delivers: `POST /datasets/:id/generate` drafting items via `AIService` and a named generator prompt, `origin: "synthetic"`, `proofread: false`; the phase-1 playground **Save this run to dataset** button wired
|
|
140
|
+
- Files: generate route, `ai/src/service/prompts.ts` generator constant, `admin-frontend/.../prompts/*`, tests
|
|
141
|
+
- Blocked by: 2.3, 1.5
|
|
142
|
+
- Docs: how-to step 1 (synthetic)
|
|
143
|
+
- Acceptance: generated items are excluded from a default experiment run; a playground run lands as an unproofread item with its input and output
|
|
144
|
+
|
|
145
|
+
- [x] **Task 2.5**: Experiment runner, gates, and gate-blocked promote
|
|
146
|
+
- Delivers: `POST /experiments/estimate` (generations, USD, wall clock); `POST /experiments` comparing 2–3 versions on a dataset with optional `modelOverride`, always via `BackgroundTask` locally; per-item results per version; aggregates vs `thresholds[]` (defaulting to `SOP_DEFAULT_THRESHOLDS`); outlier and low-confidence item ids; failed items ordered first; `POST /experiments/:id/promote` returning **409 while any gate fails**
|
|
147
|
+
- Files: `ai/src/observability/local/experimentRunner.ts`, `ai/src/observability/routes/experiments.ts`, tests
|
|
148
|
+
- Blocked by: 2.3, 2.1, 1.5
|
|
149
|
+
- Docs: how-to steps 5–6
|
|
150
|
+
- Acceptance: a 1-item dataset still uses `BackgroundTask`; gate pass/fail computed for boolean (`trueRate`) and numeric (`mean`) dimensions; promote 409s on a failing gate and moves the label when gates pass; unproofread items excluded unless `includeUnproofread`
|
|
151
|
+
|
|
152
|
+
- [ ] **Task 2.6**: Authenticated trace feedback
|
|
153
|
+
- Delivers: `POST /traces/:id/feedback` — thumbs / outcome class / flag-for-dataset; `source: "user-feedback"` score; owner (`trace.userId`) or admin; sets `flaggedForDataset`; optional review enqueue with `reason: "feedback"`
|
|
154
|
+
- Files: `ai/src/observability/routes/feedback.ts`, tests
|
|
155
|
+
- Blocked by: 1.6, 1.8
|
|
156
|
+
- Docs: how-to step 7; `docs/reference/ai.md`
|
|
157
|
+
- Acceptance: owner thumbs-down + flag succeeds; a stranger gets 403; an admin succeeds; the trace list `flaggedForDataset` filter finds it
|
|
158
|
+
|
|
159
|
+
- [ ] **Task 2.7**: Evaluator screens (list, detail, new)
|
|
160
|
+
- Delivers: list with type badge, dimension summary, target, run-mode chips and the footnote; detail with the dimensions table, type-specific panel (judge prompt link + model + schema-match check, assertion path/constraint, reviewer instructions), run modes with the live-sampling slider and cost warning, and the **Used by** list with 30-day runs and cost; new-evaluator screen with type/target pickers, dimension builder, and the **inline schema mismatch error naming the undeclared dimension**
|
|
161
|
+
- Files: `admin-frontend/src/widgets/aiObservability/evaluators/*.tsx`
|
|
162
|
+
- Blocked by: 2.1, 1.9
|
|
163
|
+
- Docs: `docs/reference/admin-frontend.md`
|
|
164
|
+
- Acceptance: widget tests for each type's panel and for the mismatch error; `verify-ui-changes` creates a judge evaluator
|
|
165
|
+
|
|
166
|
+
- [ ] **Task 2.8**: Dataset screens (list, detail)
|
|
167
|
+
- Delivers: list with the human/auto legend, provenance bar, source and updated columns; detail with human/auto counts, the input-schema binding line, Add item, Run experiment, tabs All / Human / Auto / **Needs review** (red count), and the items table with attribution lines and trace links
|
|
168
|
+
- Files: `admin-frontend/src/widgets/aiObservability/datasets/*.tsx`
|
|
169
|
+
- Blocked by: 2.3, 2.4, 1.9
|
|
170
|
+
- Docs: `docs/reference/admin-frontend.md`
|
|
171
|
+
- Acceptance: widget tests for each tab and the empty dataset; `verify-ui-changes` bulk-adds traces and sees them under Needs review
|
|
172
|
+
|
|
173
|
+
- [ ] **Task 2.9**: Experiment screens (list, wizard, results)
|
|
174
|
+
- Delivers: list with status badge, running progress bar and cost, plus the BackgroundTask/Langfuse footnote; 4-step wizard with a completed-step rail, dataset picker showing counts and schema match, version checkboxes tagged latest/production/superseded, evaluator checkboxes with per-item cost, and a Review & run step showing the estimate; results with gate tiles, "N gates failing", the **Promote blocked** state naming the failing gate, the outliers list with reason chips, the side-by-side table with failed rows floated and highlighted, and the promote confirm modal
|
|
175
|
+
- Files: `admin-frontend/src/widgets/aiObservability/experiments/*.tsx`
|
|
176
|
+
- Blocked by: 2.5, 2.8, 1.9
|
|
177
|
+
- Docs: how-to steps 5–6
|
|
178
|
+
- Acceptance: widget tests for running progress, gate-fail results, and blocked promote; `verify-ui-changes` runs an experiment and promotes a passing version
|
|
179
|
+
|
|
180
|
+
- [ ] **Task 2.10**: Phase-2 example seeds + docs
|
|
181
|
+
- Delivers: seed judge/assert evaluator templates and dataset `example-gold` with an input-schema binding; docs updated for evaluators, datasets, experiments, feedback, and `AI_OBS_SAMPLE_RATE`
|
|
182
|
+
- Files: `example-backend` seed, docs listed in the IP, `.rulesync/skills/ai-prompt-governance/SKILL.md` + `bun run skills:sync`
|
|
183
|
+
- Blocked by: 2.7, 2.8, 2.9, 2.6
|
|
184
|
+
- Docs: (this task)
|
|
185
|
+
- Acceptance: the full SOP loop is runnable from `docs/how-to/ai-feature-development.md` without Langfuse
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
# Phase 3 — Analytics and pluggable backends
|
|
190
|
+
|
|
191
|
+
Ships design screens: Sessions, Session timeline, Users, User AI profile, Costs, plus sink health and Open in Langfuse.
|
|
192
|
+
|
|
193
|
+
- [ ] **Task 3.1**: Session, user, and cost aggregates + screens
|
|
194
|
+
- Delivers: `GET /sessions`, `/sessions/:id`, `/users`, `/users/:id`, `/costs`; Sessions list with the Traces/Sessions toggle and the timeline detail; Users list subtitled "AI cost and usage per user — not the user CRUD table" and the profile with masked email, **no prompt content**, and 7d/30d/all-time rollups; Costs with the KPI row, by-model table showing **tokens only** for unpriced models plus the "no $0 lie" note, and the by-prompt table
|
|
195
|
+
- Files: `ai/src/observability/routes/analytics.ts`, `ai/src/observability/local/traceStore.ts`, `admin-frontend/src/widgets/aiObservability/analytics/*.tsx`, tests
|
|
196
|
+
- Blocked by: 1.6, 1.9
|
|
197
|
+
- Docs: `docs/reference/ai.md` routes; `docs/reference/admin-frontend.md`
|
|
198
|
+
- Acceptance: an unpriced model renders `tokens only` and never `$0`; no prompt or output text appears in any users response; widget tests for each screen
|
|
199
|
+
|
|
200
|
+
- [ ] **Task 3.2**: Langfuse `TraceSink` + `ScoreSink`
|
|
201
|
+
- Delivers: adapters wrapping the existing `getLangfuseClient()`; **no second OTel SDK**; best-effort with logged failures
|
|
202
|
+
- Files: `ai/src/observability/langfuse/traceAdapter.ts`, tests with a mocked client
|
|
97
203
|
- Blocked by: 1.2
|
|
98
|
-
- Docs: explanation — LangfuseApp vs ObservabilityApp
|
|
99
|
-
- Acceptance: generate
|
|
204
|
+
- Docs: explanation — `LangfuseApp` vs `ObservabilityApp`
|
|
205
|
+
- Acceptance: one generate dual-writes; a throwing Langfuse mock leaves the local row intact and the caller unaffected
|
|
100
206
|
|
|
101
|
-
- [ ] **Task
|
|
102
|
-
- Delivers:
|
|
207
|
+
- [ ] **Task 3.3**: Langfuse `PromptRegistry` / `DatasetStore` / `ExperimentRunner` + primaries
|
|
208
|
+
- Delivers: `AI_OBS_*_PRIMARY` env wiring; Terreno HTTP facade delegating to the existing Langfuse admin routes; **Open in Langfuse** deep-link bases on `GET /status`
|
|
103
209
|
- Files: `ai/src/observability/langfuse/*.ts`, tests
|
|
104
|
-
- Blocked by:
|
|
105
|
-
- Docs: how-to —
|
|
106
|
-
- Acceptance: prompts primary langfuse
|
|
210
|
+
- Blocked by: 3.2, 1.5, 2.5
|
|
211
|
+
- Docs: how-to — switching primaries by env
|
|
212
|
+
- Acceptance: prompts primary `langfuse` reads through the client; experiments primary `langfuse` starts no `BackgroundTask`; the illegal mixes still fail boot
|
|
107
213
|
|
|
108
|
-
- [ ] **Task
|
|
109
|
-
- Delivers: OTLP
|
|
110
|
-
- Files: `ai/src/observability/otel/otelTraceSink.ts`, tests with mock exporter
|
|
214
|
+
- [ ] **Task 3.4**: `OtelTraceSink` (OpenInference)
|
|
215
|
+
- Delivers: OTLP exporter behind `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`; `openinference.span.kind` set from the span kind; model and token attributes
|
|
216
|
+
- Files: `ai/src/observability/otel/otelTraceSink.ts`, tests with a mock exporter
|
|
111
217
|
- Blocked by: 1.2
|
|
112
|
-
- Docs: how-to — Phoenix
|
|
113
|
-
- Acceptance: mock exporter receives span with model
|
|
218
|
+
- Docs: how-to — pointing at Phoenix or a generic collector
|
|
219
|
+
- Acceptance: the mock exporter receives an `LLM` span with model and token attributes
|
|
114
220
|
|
|
115
|
-
- [ ] **Task 5
|
|
116
|
-
- Delivers:
|
|
117
|
-
- Files: `
|
|
118
|
-
- Blocked by:
|
|
119
|
-
- Docs:
|
|
120
|
-
- Acceptance: widget tests
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
-
|
|
221
|
+
- [ ] **Task 3.5**: Sink health chip, example wiring, and phase-3 docs
|
|
222
|
+
- Delivers: last-error-per-sink on `GET /status`; the chip renders Langfuse health and active primaries and shows **Open in Langfuse** only when that plugin is registered; example-backend adds the Langfuse and OTel sinks conditionally; docs and the `terreno-langfuse-integration.md` pointer finalized
|
|
223
|
+
- Files: `ai/src/observability/routes/status.ts`, `admin-frontend/.../shell/*.tsx`, `example-backend/src/server.ts`, docs
|
|
224
|
+
- Blocked by: 3.1, 3.3, 3.4
|
|
225
|
+
- Docs: (this task)
|
|
226
|
+
- Acceptance: chip states covered by widget tests; a Langfuse-less boot shows no deep link; `verify-ui-changes` evidence attached
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
# Phase 4 — Domain-neutral RBAC and prompt relationship hub
|
|
231
|
+
|
|
232
|
+
The user approved this phase on 2026-10-02. It adds no domain-specific vocabulary or
|
|
233
|
+
in-app approval workflow. Supporting skills: `building-admin-interfaces`,
|
|
234
|
+
`terreno-backend-api`, `terreno-ui`, `terreno-data-fetching`, `mongoose-schema-safety`,
|
|
235
|
+
`update-docs`, and `verify-ui-changes`.
|
|
236
|
+
|
|
237
|
+
- [x] **Task 4.1**: Observability RBAC vocabulary, compatibility grants, and route enforcement
|
|
238
|
+
- Delivers: resources `aiPrompt`, `aiTrace`, `aiReview`, `aiDataset`, `aiExperiment`, `aiEvaluator` with the actions approved in Q62/Q63; statement descriptions; full seeded Admin grants, read-only Auditor expansion, Super Admin wildcard; existing stored Admin roles gain only missing observability grants; optional `accessControl` on `ObservabilityApp`; every route maps to one resource/action while legacy admin fallback remains
|
|
239
|
+
- Files: `api/src/rbac/statements.ts`, `api/src/rbac/roleModel.ts`, `ai/src/observability/observabilityApp.ts`, `ai/src/observability/routes/*.ts`, route/RBAC tests, public exports as needed
|
|
240
|
+
- Blocked by: none
|
|
241
|
+
- Docs: `docs/reference/api.md`, `docs/reference/ai.md`, `docs/explanation/ai-observability.md`
|
|
242
|
+
- Acceptance: catalog and role tests prove exact actions; a read-only RBAC caller can GET but receives 403 for writes; denied mutations fail even when called directly; legacy admin tests remain green
|
|
243
|
+
|
|
244
|
+
- [x] **Task 4.2**: Prompt descriptions and prompt-scoped relationship APIs
|
|
245
|
+
- Delivers: optional prompt `description` in Mongo/types/create/detail/list; trace list accepts prompt version in addition to name; experiment list accepts `promptName`; prompt detail API composes bounded recent traces and experiments for the selected prompt without client-side full-list scans
|
|
246
|
+
- Files: prompt/trace/experiment models, stores, routes, types, tests
|
|
247
|
+
- Blocked by: 4.1
|
|
248
|
+
- Docs: `docs/reference/ai.md`, `docs/explanation/ai-observability.md`
|
|
249
|
+
- Acceptance: description round-trips; prompt v2 filtering excludes v1-only traces; prompt detail relationships contain only the named prompt's traces and experiments; old prompts without descriptions still load
|
|
250
|
+
|
|
251
|
+
- [x] **Task 4.3**: Caller-filtered navigation and read-only prompt hub
|
|
252
|
+
- Delivers: each custom screen declares its read/list permission; unauthorized screens disappear from `/admin/config`; prompt detail renders Overview, Versions, Traces, and Experiments with description/folder/tags; controls are hidden independently for denied `update`, `promote`, and `playground`; direct API calls remain protected by Task 4.1
|
|
253
|
+
- Files: `ai/src/observability/adminScreens.ts`, admin contribution tests, `admin-frontend/src/widgets/aiObservability/prompts/*`, permission helpers/tests
|
|
254
|
+
- Blocked by: 4.1, 4.2
|
|
255
|
+
- Docs: `docs/reference/admin-frontend.md`, `docs/how-to/ai-feature-development.md`
|
|
256
|
+
- Acceptance: admin-config tests cover mixed grants; widget tests prove a read-only prompt hub shows relationships and no write controls; an operator sees all controls; `verify-ui-changes` captures both roles
|
|
257
|
+
|
|
258
|
+
- [x] **Task 4.4**: Phase-4 integration and documentation gate
|
|
259
|
+
- Delivers: `ObservabilityApp({accessControl: access})` in example-backend; example roles demonstrating read-only and operator composition; integration tests for admin vs viewer HTTP; all architecture/reference/how-to pages aligned; generated SDK and `verify-ui-changes` walkthrough when the parent closes UI gates
|
|
260
|
+
- Files: `example-backend` access/seed files, `observabilityRbac.integration.test.ts`, docs named above, generated SDK when required
|
|
261
|
+
- Blocked by: 4.3
|
|
133
262
|
- Docs: (this task)
|
|
134
|
-
- Acceptance: a
|
|
263
|
+
- Acceptance: example boots with existing admin access intact; a consumer can configure a domain-neutral read-only role from docs; example-backend RBAC unit + integration tests, compile, and lint pass; parent runs SDK regen and mandatory UI walkthrough before checking this task complete
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Tasks: Dashboard chart parity
|
|
2
|
+
|
|
3
|
+
IP: [dashboard-chart-parity.md](../implementationPlans/dashboard-chart-parity.md)
|
|
4
|
+
**Follows:** https://github.com/TerrenoLabs/terreno/issues/1175
|
|
5
|
+
**Roadmap issue:** set after IP approval
|
|
6
|
+
|
|
7
|
+
**Feature profile:** false (full IP)
|
|
8
|
+
|
|
9
|
+
## Phase 1 — Tracer (scorecard)
|
|
10
|
+
|
|
11
|
+
- [x] **Task 1.1**: `SparklineChart` + dotted `comparisonData`
|
|
12
|
+
- Delivers: public plot-only sparkline; solid current series; dotted comparison aligned on `label`; no axes/grid/legend/tooltip row; empty input does not throw
|
|
13
|
+
- Files: `ui/src/SparklineChart.tsx`, `ui/src/SparklineChart.test.tsx`, `ui/src/charts/paths.ts` (reuse line path), `ui/src/Common.ts` (TypeDoc props), `ui/src/index.tsx` / `heavyOptionalExports.tsx`
|
|
14
|
+
- Blocked by: none
|
|
15
|
+
- Skills: `terreno-ui`, `update-docs`
|
|
16
|
+
- Docs: stub `SparklineChart` on `docs/reference/ui.md` Display list
|
|
17
|
+
- Acceptance: bun tests — N points → path present; comparison path present when `comparisonData` set; empty data shows nothing / emptyText if provided; `ui` compile green
|
|
18
|
+
|
|
19
|
+
- [x] **Task 1.2**: `Scorecard` + `ChartCard`
|
|
20
|
+
- Delivers: KPI tile with title, formatted value, optional sparkline; `ChartCard` with title, period badge, optional `onPeriodPress`, optional `filterSummary`
|
|
21
|
+
- Files: `ui/src/Scorecard.tsx`, `ui/src/Scorecard.test.tsx`, `ui/src/ChartCard.tsx`, `ui/src/ChartCard.test.tsx`, lazy exports
|
|
22
|
+
- Blocked by: 1.1
|
|
23
|
+
- Skills: `terreno-ui`, `verify-ui-changes`, `update-docs`
|
|
24
|
+
- Docs: stub both on `docs/reference/ui.md`
|
|
25
|
+
- Acceptance: bun tests — value + title render; sparkline mounts when `sparklineData` set; badge press fires; period badge has no press handler when `onPeriodPress` omitted
|
|
26
|
+
|
|
27
|
+
- [x] **Task 1.3**: Scorecard demo + first golden
|
|
28
|
+
- Delivers: demo story; gallery fixture `scorecard-sparkline-comparison` (five KPI tiles, static data); PNG golden
|
|
29
|
+
- Files: `demo/stories/Scorecard.stories.tsx`, `demo/stories/ChartCard.stories.tsx`, `demo/demoConfig.tsx`, `demo/chartVisual/fixtureCatalog.ts`, `demo/chartVisual/fixtures.tsx`, `demo/rendered-snapshots/scorecard-sparkline-comparison.png`
|
|
30
|
+
- Blocked by: 1.2
|
|
31
|
+
- Skills: `terreno-ui`, `review-chart-visuals`, `verify-ui-changes`
|
|
32
|
+
- Docs: `docs/how-to/compare-chart-rendered-snapshots.md` lists the new id
|
|
33
|
+
- Acceptance: fixture catalog test includes the id; `bun run ui:charts:compare` green for it; story registered
|
|
34
|
+
|
|
35
|
+
## Phase 2 — Cartesian additive facades
|
|
36
|
+
|
|
37
|
+
- [x] **Task 2.1**: `series` + `comparisonData` on `LineChart` / `AreaChart`
|
|
38
|
+
- Delivers: multi-series lines from `series`; single `data` still works; dotted comparison overlay; per-series legend; markers stay
|
|
39
|
+
- Files: `ui/src/LineChart.tsx`, `ui/src/AreaChart.tsx`, matching tests, `ui/src/charts/scales.ts` (shared x domain across series)
|
|
40
|
+
- Blocked by: 1.2
|
|
41
|
+
- Skills: `terreno-ui`, `update-docs`
|
|
42
|
+
- Docs: `docs/reference/ui.md` Line/Area props
|
|
43
|
+
- Acceptance: bun tests — three `series` → three paths + three legend labels; `{label,value}[]` only still draws one series; comparison path exists when set
|
|
44
|
+
|
|
45
|
+
- [x] **Task 2.2**: `xTickPolicy` + bar comparison + header shortcuts
|
|
46
|
+
- Delivers: `"auto"` rotates when labels would truncate, stays horizontal for ≤7 categories; `BarChart` accepts `series` (grouped later if >1 — this slice: first series only unless a second is comparison) and `comparisonData`; `title` / `periodLabel` / `onPeriodPress` on cartesian facades
|
|
47
|
+
- Files: `ui/src/BarChart.tsx`, `ui/src/LineChart.tsx`, `ui/src/charts/layout.ts`, `ui/src/BarChart.test.tsx`, `ui/src/LineChart.test.tsx`
|
|
48
|
+
- Blocked by: 2.1
|
|
49
|
+
- Skills: `terreno-ui`
|
|
50
|
+
- Docs: tick policy in `docs/explanation/charts.md`
|
|
51
|
+
- Acceptance: bun tests — 14 long date labels with `auto` → rotated tick style; 7 weekday labels stay horizontal; facade title renders when set and `ChartCard` is not wrapping (documented exclusive use)
|
|
52
|
+
|
|
53
|
+
- [x] **Task 2.3**: Cartesian goldens
|
|
54
|
+
- Delivers: fixtures `bar-time-rotated-ticks`, `line-three-series`, `bar-day-of-week`
|
|
55
|
+
- Files: `demo/chartVisual/**`, `demo/rendered-snapshots/*.png`
|
|
56
|
+
- Blocked by: 2.2
|
|
57
|
+
- Skills: `review-chart-visuals`, `verify-ui-changes`
|
|
58
|
+
- Docs: compare-how-to fixture table
|
|
59
|
+
- Acceptance: `bun run ui:charts:compare` green for the three ids
|
|
60
|
+
|
|
61
|
+
## Phase 3 — Donut center and share legend
|
|
62
|
+
|
|
63
|
+
- [x] **Task 3.1**: Donut hole + percent legend
|
|
64
|
+
- Delivers: `centerTitle`, `centerValue`; legend `swatch + label + formatShare` (default percent of total); 100% single-slice still draws a ring + center
|
|
65
|
+
- Files: `ui/src/DonutChart.tsx`, `ui/src/DonutChart.test.tsx`
|
|
66
|
+
- Blocked by: 1.2
|
|
67
|
+
- Skills: `terreno-ui`, `update-docs`
|
|
68
|
+
- Docs: `docs/reference/ui.md` Donut props
|
|
69
|
+
- Acceptance: bun tests — center copy present; legend includes `%`; one-slice data still has one path; existing slice color override still works
|
|
70
|
+
|
|
71
|
+
- [x] **Task 3.2**: Donut goldens
|
|
72
|
+
- Delivers: `donut-center-and-share`, `donut-single-slice`
|
|
73
|
+
- Files: `demo/chartVisual/**`, goldens
|
|
74
|
+
- Blocked by: 3.1
|
|
75
|
+
- Skills: `review-chart-visuals`
|
|
76
|
+
- Docs: compare-how-to
|
|
77
|
+
- Acceptance: compare green for both ids
|
|
78
|
+
|
|
79
|
+
## Phase 4 — Spanning grid
|
|
80
|
+
|
|
81
|
+
- [x] **Task 4.1**: `DashboardGridItem` spans
|
|
82
|
+
- Delivers: eager `DashboardGridItem` with `span` per breakpoint; default span 1; children without a wrapper keep current equal-column behavior
|
|
83
|
+
- Files: `ui/src/DashboardGrid.tsx` and/or `ui/src/DashboardGridItem.tsx`, `ui/src/DashboardGrid.test.tsx`, `ui/src/index.tsx` (eager)
|
|
84
|
+
- Blocked by: 1.2
|
|
85
|
+
- Skills: `terreno-ui`, `update-docs`
|
|
86
|
+
- Docs: `docs/reference/ui.md` Layout
|
|
87
|
+
- Acceptance: bun tests — span 2 in a 4-column row yields ~2× cell width minus gap; unwrapped children still fill 1 column
|
|
88
|
+
|
|
89
|
+
- [ ] **Task 4.2**: `hows-it-going-dashboard` chart composition
|
|
90
|
+
- Delivers: hard fixture matching the reference layout (5 scorecards, cost/conv bar, 3-line imp share, DOW bar, two donuts). Table slot may be a `ChartCard` placeholder until 5.2
|
|
91
|
+
- Files: `demo/chartVisual/fixtures.tsx`, `fixtureCatalog.ts`, golden
|
|
92
|
+
- Blocked by: 2.3, 3.2, 4.1
|
|
93
|
+
- Skills: `review-chart-visuals`, `verify-ui-changes`
|
|
94
|
+
- Docs: how-to example rewritten to this composition
|
|
95
|
+
- Acceptance: compare green; fixture uses `Scorecard` / `ChartCard` / `DashboardGridItem`, not ad-hoc `Box` widths only
|
|
96
|
+
|
|
97
|
+
## Phase 5 — Table chrome
|
|
98
|
+
|
|
99
|
+
- [ ] **Task 5.1**: Header groups, footer rows, range status, wrapLines
|
|
100
|
+
- Delivers: `headerGroups` second header row; `footerRows` sticky totals; range copy `start–end of total` with existing pagination; `wrapLines={2}` wraps cell text inside `rowHeight` (virtualization unchanged)
|
|
101
|
+
- Files: `ui/src/DataTable.tsx`, `ui/src/DataTable.test.tsx`, `ui/src/Pagination.tsx` (if range lives there), `ui/src/Common.ts`
|
|
102
|
+
- Blocked by: 4.1
|
|
103
|
+
- Skills: `terreno-ui`, `update-docs`
|
|
104
|
+
- Docs: `docs/reference/ui.md` DataTable; pointer from charts how-to
|
|
105
|
+
- Acceptance: bun tests — grouped header text visible; footer row present; range text `1–50 of 452` with page 1 size 50 total 452; pinned column scroll still syncs with groups/footer; wrapLines 2 does not change `rowHeight`
|
|
106
|
+
|
|
107
|
+
- [ ] **Task 5.2**: Table card in the hard fixture
|
|
108
|
+
- Delivers: one `ChartCard` + `DataTable` in `hows-it-going-dashboard` (Search Terms or Ad Group Check-in static rows, totals, period headers)
|
|
109
|
+
- Files: `demo/chartVisual/fixtures.tsx`, update golden
|
|
110
|
+
- Blocked by: 5.1, 4.2
|
|
111
|
+
- Skills: `review-chart-visuals`, `verify-ui-changes`
|
|
112
|
+
- Docs: how-to shows table in the same grid
|
|
113
|
+
- Acceptance: compare green after intentional golden update; wrapped first-column names visible in the PNG
|
|
114
|
+
|
|
115
|
+
## Phase 6 — Packaging and docs
|
|
116
|
+
|
|
117
|
+
- [ ] **Task 6.1**: Lazy root + import regression
|
|
118
|
+
- Delivers: `Scorecard`, `SparklineChart`, `ChartCard`, chart facades stay on `heavyOptionalExports`; `DashboardGrid` / `DashboardGridItem` eager; root import does not evaluate chart files
|
|
119
|
+
- Files: `ui/src/lazyBoundaries/heavyOptionalExports.tsx`, `ui/src/index.tsx`, `ui/src/RootImportRegression.test.tsx`, `docs/reference/ui-performance.md`
|
|
120
|
+
- Blocked by: 4.1, 5.1, 2.1, 3.1
|
|
121
|
+
- Skills: `terreno-ui`, `update-docs`
|
|
122
|
+
- Docs: performance page lists new lazy exports
|
|
123
|
+
- Acceptance: `RootImportRegression` fails if new chart files load with the root import; subpath imports work
|
|
124
|
+
|
|
125
|
+
- [ ] **Task 6.2**: Diátaxis + changelog + rules
|
|
126
|
+
- Delivers: how-to rewritten for easy-build composition; explanation covers scorecard, comparison stroke, additive facades vs grammar; reference complete; changelog fragment; ui rule export list; TypeDoc
|
|
127
|
+
- Files: `docs/how-to/charts-and-dashboards.md`, `docs/explanation/charts.md`, `docs/reference/ui.md`, `docs/how-to/README.md`, `.rulesync/rules/ui/00-ui.mdc`, `changelog/unreleased/dashboard-chart-parity.md`; `bun run website:generate` if needed
|
|
128
|
+
- Blocked by: 6.1, 5.2
|
|
129
|
+
- Skills: `update-docs`, `docs-audit`, `terreno-ui`
|
|
130
|
+
- Docs: the files listed above
|
|
131
|
+
- Acceptance: a stranger can copy the how-to into a screen that resembles the reference; explanation states grammar is not required; changelog `category: Added`; existing single-series how-to steps still valid as a subset
|
|
132
|
+
|
|
133
|
+
## Verification mapping
|
|
134
|
+
|
|
135
|
+
| Criterion | Method |
|
|
136
|
+
|-----------|--------|
|
|
137
|
+
| Scorecard + sparkline + comparison | bun tests + `scorecard-sparkline-comparison` PNG |
|
|
138
|
+
| Multi-series line | bun tests + `line-three-series` PNG |
|
|
139
|
+
| Rotated vs horizontal ticks | bun tests + `bar-time-rotated-ticks` / `bar-day-of-week` |
|
|
140
|
+
| Donut center + share | bun tests + donut goldens |
|
|
141
|
+
| Grid spans + reference layout | `hows-it-going-dashboard` PNG + grid unit tests |
|
|
142
|
+
| Table chrome | bun tests + table region of hard golden |
|
|
143
|
+
| Facade compatibility | existing `*Chart.test.tsx` stay green |
|
|
144
|
+
| Lazy charts | `RootImportRegression` |
|
|
145
|
+
| Frontend proof | `verify-ui-changes` on demo gallery; artifacts on the implementation PR |
|