Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f5bd670
feat(telltale): scaffold the ingest Worker and its project registry
adbarc92 Aug 31, 2026
433c282
feat(telltale): validate FeedbackEvent, dropping unknown context keys
adbarc92 Aug 31, 2026
1990680
feat(telltale): scrub PII from both title and body
adbarc92 Aug 31, 2026
ac414ea
feat(telltale): fingerprint the scrubbed title for dedup
adbarc92 Aug 31, 2026
99a87ab
feat(telltale): HMAC request auth over raw bytes with a replay window
adbarc92 Aug 31, 2026
9ff9040
feat(telltale): dedup decision table, never auto-reopening
adbarc92 Aug 31, 2026
e439a25
fix(telltale): aggregate not_planned across closed duplicates, matchi…
adbarc92 Aug 31, 2026
cdd258d
feat(telltale): KV rate limits, comment throttle and stats counters
adbarc92 Aug 31, 2026
52b6d16
feat(telltale): GitHub client verifying labels on create
adbarc92 Aug 31, 2026
88c65f5
fix(telltale): exercise restClient directly, fix Content-Type, sharpe…
adbarc92 Aug 31, 2026
fa6e4a4
feat(telltale): POST /v1/events — auth, scrub, dedup, create-or-comment
adbarc92 Aug 31, 2026
16a0c2a
fix(telltale): guard TELLTALE_SENDER_SECRETS parse, record config_error
adbarc92 Aug 31, 2026
519ffed
feat(telltale): authenticated read endpoints with per-repo error isol…
adbarc92 Aug 31, 2026
b095c7d
test(telltale): cover PR exclusion in GET /v1/issues
adbarc92 Aug 31, 2026
ae884a6
ci(telltale): add the vitest job, the gated live grader and the runbook
adbarc92 Aug 31, 2026
6712547
fix(telltale): correct the tenzy target, deny an unset read token, re…
adbarc92 Aug 31, 2026
48f82fa
fix(telltale): project-scope the comment throttle, add an error bound…
adbarc92 Aug 31, 2026
ba748ea
Merge branch 'chore/remove-embargo-guard' into feat/telltale-worker
adbarc92 Aug 31, 2026
38e1d43
docs(handoff): pivot Telltale into its own repo, keep only the integr…
adbarc92 Aug 31, 2026
fdc3a12
docs(status): record the Telltale pivot and the fleetd cap race
adbarc92 Aug 31, 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
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,31 @@ jobs:
- name: Run frontend unit tests
run: npm test

telltale:
name: vitest (telltale)
runs-on: ubuntu-latest
defaults:
run:
working-directory: telltale
steps:
- uses: actions/checkout@v4

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: telltale/package-lock.json

- run: npm ci

# The live grader (test/live-grader.test.ts) self-skips without
# TELLTALE_* credentials, so it never runs here — same posture as the
# real-Docker ITs in crates/fleetd/tests/.
- run: npm test

- run: npm run check

# ---------------------------------------------------------------------------
# Rust workspace tests. Fast, OS-independent gate — runs once on Linux.
# Does NOT run the `#[ignore]`d real-Docker ITs (see header note above).
Expand Down
46 changes: 46 additions & 0 deletions docs/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ the fixes that followed, closed **five** defects: **D-7** (view-plugins received
Across both runs, **`db74a47` is CONFIRMED twice** — 1,127 samples in dev and 632 in packaged, zero
unresponsive in either.

**⚠ Telltale is pivoting OUT of this repo (2026-08-30).** A feedback pipeline — authenticated bug
reports deduplicated into GitHub issues — was built as a `telltale/` subdirectory here (PR #64, 82
tests, fully reviewed). **That was the wrong repository.** Telltale becomes its own app and repo;
this repo keeps only the **integration**: a `feedback` source adapter for the Project Dashboard that
reads Telltale's `GET /v1/issues` (spec §6, **not started**). Extraction steps, PR dispositions and
the six defects found in the plan's reference code are in
[`docs/handoffs/31f0a85d-8bcc-4d27-a849-e9e950749558.md`](handoffs/31f0a85d-8bcc-4d27-a849-e9e950749558.md).
**PR #64 is to be closed, not merged.**

**⚠ Intermittent race in the fleetd spend cap, unrelated to the above.**
`server::tests::concurrent_missions_cannot_both_breach_the_cap` failed on PR #64 with **both**
concurrent missions admitted past the $20 global cap (`left: 2, right: 1`) — the condition its own
comment calls "an open race" — then passed on a re-run of the identical tree. `create_mission` holds
the store lock across check and insert, so the obvious explanation does not apply; the `.ok()` that
swallows `upsert_unit`'s error is the first thing to look at. Not investigated further.

**Vision (unchanged):** the Command Center is the operator's **one-stop shop for agentic
engineering** — dispatch work, see every project's stage, act without alt-tabbing, host the other
tools inside it, and (future) **remote-control** it from away-from-desk. **Feature-complete before
Expand Down Expand Up @@ -175,6 +191,36 @@ across from #47; close it._

## Session log

### 2026-08-30 — Built the Telltale Worker here, then pivoted it out; removed the embargo guard

**Three PRs opened.** [#62](https://github.com/adbarc92/command-center/pull/62) removes the **embargo
guard** in full — hooks, script, CI job, denylist, README section — the embargo having been lifted
2026-08-29. It was five interlocking parts, and `embargo guard` was a *required status check* on
`main`, so deleting the CI job alone would have hung every PR forever on a check that no longer
reports; branch protection was updated in the same breath. Conflicts with `main` (PR #49 landed
mid-session) resolved in `af11995`.

[#63](https://github.com/adbarc92/command-center/pull/63) carries the **Telltale spec and plan**. The
spec lost roughly half its mass across three rounds of adversarial critique: the entire crash-side
pipeline was deleted once it became clear it was **reimplementing Sentry** (whose native GitHub
integration already opens one issue per group), and fleet dispatch was cut because it would have
widened a credentialed agent's push target from one sandbox to every repo in the registry, for a
pipeline whose input is internet-authored text.

[#64](https://github.com/adbarc92/command-center/pull/64) built the **ingest Worker** — eleven TDD
tasks, each independently reviewed, plus a whole-branch review and a final fix wave. 82 tests, zero
runtime dependencies. That process found **six defects in the plan's own reference code**, including
a registry entry pointing at `adbarc92/tenzy`, which does not exist — `gh api` silently follows a
transfer redirect to `OpenBarclay/tenzy`, and the primary PAT cannot write to an org repo.

**Then the pivot.** Telltale was never meant to live in this repo — the operator's earlier "put it in
Command Center" was about the *spec*, and it was extended to the implementation without being put to
them. Telltale becomes its own app and repo; this repo keeps only the `feedback` source adapter.
**#64 is to be closed, not merged.** Full extraction plan:
[`docs/handoffs/31f0a85d-8bcc-4d27-a849-e9e950749558.md`](handoffs/31f0a85d-8bcc-4d27-a849-e9e950749558.md).

Also surfaced, unrelated: an **intermittent race in fleetd's global spend cap** (see State summary).

### 2026-08-16 — Built the smoke skill, then it found the defect that would have shipped

Two halves. First, built and merged the **`driving-interactive-smoke-tests`** skill into `claude-kit`
Expand Down
187 changes: 187 additions & 0 deletions docs/handoffs/31f0a85d-8bcc-4d27-a849-e9e950749558.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Handoff — pivot: extract Telltale into its own repo, leave only the Command Center integration behind

**Written:** 2026-08-30 · **Branch:** `feat/telltale-worker` · **Session:** `31f0a85d-8bcc-4d27-a849-e9e950749558`

## ⏳ Background operation in flight

**None.** No build, test run, or agent is running. This is a deliberate pivot handoff, not an
idle handoff. Everything below is committed and pushed; nothing is mid-flight.

CI on PR #64 is green except one **pre-existing, intermittent** `fleetd` failure — see
[Known issues](#known-issues-carried-forward). It is not caused by this work.

## Goal

**Telltale is its own app in its own repo.** Command Center keeps only the integration: a
`feedback` source adapter for the Project Dashboard that reads Telltale's `GET /v1/issues`.

The previous session built the Telltale ingest Worker as a `telltale/` **subdirectory inside the
command-center repo**. That was wrong. The operator's "put it in Command Center" answered a question
about where the *spec document* should live; it was extended to the implementation without ever being
put to them. The work itself is sound and fully reviewed — it is in the wrong repository.

## State

- **Active spec:** [`docs/superpowers/specs/2026-08-30-telltale-feedback-pipeline-design.md`](../superpowers/specs/2026-08-30-telltale-feedback-pipeline-design.md) — on branch `docs/telltale-feedback-pipeline-spec` (PR #63), **not on `main` or this branch**.
- **Active plan:** [`docs/superpowers/plans/2026-08-30-telltale-worker.md`](../superpowers/plans/2026-08-30-telltale-worker.md) — same branch.
- **SDD ledger** (28 rulings, every review verdict, all deferred findings): `.claude/worktrees/telltale-worker/.superpowers/sdd/2026-08-30-telltale-worker/progress.md` — **gitignored, lives only in that worktree. Read it before discarding the worktree.**

### Three open PRs on `adbarc92/command-center`

| PR | Branch | Disposition under the pivot |
|---|---|---|
| **#62** chore: remove the embargo guard | `chore/remove-embargo-guard` | **Unaffected — merge as-is, first.** Conflicts with `main` already resolved (`af11995`). |
| **#63** docs(spec): Telltale pipeline | `docs/telltale-feedback-pipeline-spec` | **Needs splitting** — see step 4. |
| **#64** feat(telltale): the ingest Worker (P1) | `feat/telltale-worker` | **Close after extraction.** Its content moves to the new repo. Do not merge. |

### What is in `feat/telltale-worker`

- **17 commits touching `telltale/`** — the whole TDD + review history, worth preserving.
- `telltale/` — 29 tracked files: `src/` (9 modules), `test/` (11 files), `package.json`, `tsconfig.json`, `vitest.config.ts`, `wrangler.toml`, `README.md`, `.gitignore`.
- **The only non-Telltale change this branch makes** is the `vitest (telltale)` job added to `.github/workflows/ci.yml`. Everything else in a `cb11214..HEAD` diff came from merging `origin/main` (PR #49, plugin-runtime).
- 82 tests + 1 gated integration test, `tsc --noEmit` clean, zero runtime dependencies.

## Successor's next action

Work in this order. Steps 1–3 are mechanical; step 4 has a decision in it.

### 1. Create the repo

```bash
gh repo create adbarc92/telltale --private \
--description "Authenticated bug-report intake that deduplicates into GitHub issues"
```

Default taken: **`adbarc92`, private**. Rationale in [Decisions](#live-decisions--defaults-taken).

### 2. Extract `telltale/` with its history

`git subtree split` rewrites the 17 commits with `telltale/` as the repo root, preserving each
task's TDD and review history. Run from the **main checkout**, not the worktree:

```bash
cd D:/MajorProjects/CURRENT/command-center
git subtree split --prefix=telltale feat/telltale-worker -b telltale-extracted
git clone . /tmp/telltale-new --branch telltale-extracted --single-branch
cd /tmp/telltale-new
git remote set-url origin https://github.com/adbarc92/telltale.git
git branch -m main
git push -u origin main
```

**Verify before continuing:** `npm ci && npx vitest run` in the new clone must give **82 passed,
1 skipped**, and `npm run check` must exit 0. The paths inside the code are all relative to
`telltale/`, so nothing should need editing — but confirm rather than assume. The one thing that
*will* be wrong is `README.md`'s spec link, which points at a command-center path (see step 4).

### 3. Strip Telltale out of command-center

On a fresh branch off `chore/remove-embargo-guard`:

```bash
git rm -r telltale/
```

…and revert the `vitest (telltale)` job from `.github/workflows/ci.yml`. That job is the only
command-center file this work added; with `telltale/` gone it would fail on a missing lock file.

Then **close PR #64** with a comment pointing at the new repo. Do not merge it.

### 4. Decide where the spec lives, then rework PR #63

The spec covers both halves: §1–§5 and §8–§9 are the Worker; **§6 is the Command Center adapter**;
§7 is the Halyard boundary.

**Recommended split:**
- The **spec moves to the new repo** (`docs/design.md` or equivalent) — it is Telltale's design doc.
- **command-center keeps a short spec for the `feedback` source adapter only**, reproducing §6 and
linking out to the Telltale repo for the contract it consumes.
- The **plan** ([`2026-08-30-telltale-worker.md`](../superpowers/plans/2026-08-30-telltale-worker.md)) moves with the spec — it describes P1, which is now entirely the other repo's work.

Whatever you choose, **the plan file still contains six defects execution found and fixed in code.**
Anyone following it would rebuild them. Add a "Defects found during execution" section rather than
rewriting each code block:

| # | Defect | Consequence |
|---|---|---|
| 1 | Registry placeholders, and `adbarc92/tenzy` in the corrected table | That repo does not exist — `gh api` silently follows a transfer redirect to `OpenBarclay/tenzy`. The primary PAT cannot write to an org repo, and a followed 301 turns a POST into a GET. |
| 2 | `decide()` did not aggregate `not_planned` across closed duplicates | An operator's explicit "won't fix" was silently discarded and the pipeline commented anyway. |
| 3 | GitHub POSTs had no `Content-Type: application/json` | Every test stayed green because the fake never does HTTP; it would have failed only in production. |
| 4 | `restClient` had no tests at all | The entire production HTTP path was verified only through the fake's parallel logic. |
| 5 | Unguarded `JSON.parse(env.TELLTALE_SENDER_SECRETS)` | A malformed secret crashed every request *before* any stat was recorded — the exact silent failure `/v1/stats` exists to eliminate. |
| 6 | `if (!secret) return fail(401)` ran before the registry lookup | Made the spec's required `404` on a typo'd slug unreachable. |

### 5. Then, and only then, build the integration (spec §6 / P3)

This is the part that stays in command-center, and it is **not started**. Spec §6.1 has the verified
change surface:

| File | Change |
|---|---|
| `cockpit/ui/src/lib/dashboard/model.ts` | `Source` union `+ 'feedback'` |
| `cockpit/ui/src/lib/dashboard/adapters/feedback.ts` | New adapter + `FeedbackReader` seam |
| `cockpit/ui/src/lib/dashboard/api.ts` | `tauriFeedbackReader` |
| `cockpit/ui/src/lib/dashboard/store.ts` | `pollFeedback` |
| `cockpit/ui/src/views/Dashboard.svelte` | `SOURCE_LABEL` entry + a `pollFeedback` call |
| `cockpit/ui/src/App.svelte` | Wire the reader |
| `cockpit/ui/src-tauri/src/dashboard.rs` | `feedback_issues` command + `TELLTALE_BASE_URL`/`TELLTALE_TOKEN` env |
| `cockpit/ui/src-tauri/src/lib.rs` | Register the command in `generate_handler!` |

Three things the spec settles that are easy to get wrong:
- **Cards are `Idle`, never `Build`.** `sortedCards` ranks `Build` above `Live`, so "one old bug exists" would sort above "this project is live in production."
- **`Blocked` only for an open `telltale:crash` issue with no assignee.** `blockedCount` is the board's headline "NEEDS YOU" number; a condition that never clears poisons it.
- **`family` is inert.** It is written by three adapters and read by nothing. Do not claim it clusters cards.

## Live decisions / defaults taken

Taken during this sweep, without asking — override freely:

- **Repo `adbarc92/telltale`, private.** `adbarc92` because Telltale is infrastructure, not a product,
and that account already owns the infrastructure repos. Private because every covered project is
private today; publishing is a separate call that belongs with the launch decisions in
`D:\MajorProjects\LAUNCH-SCHEDULE.md`.
- **`git subtree split`, not a fresh-start copy.** The 17 commits carry an unusually good record —
each task's RED/GREEN evidence and its review round. Worth preserving.
- **PR #64 closed, not merged.** Merging then reverting would put the Worker in command-center's
history permanently.
- **Spec moves; command-center keeps an adapter-only spec.** Recommended, not settled — step 4.

Settled earlier in the session and already reflected in the code:

- Issues land in **each project's own repo**, including public ones; the PII exposure was raised and
knowingly accepted, and the scrub covers both `title` and `body`.
- The **ingest-abuse risk** was put to the operator and accepted: HMAC bounds and attributes abuse
rather than preventing it, since a secret in a shipped binary is extractable.
- **Crashes never traverse the Worker.** Sentry's native GitHub integration owns that path.
- **Fleet dispatch is out of scope** — it would widen a credentialed agent's push target from one
sandbox to every repo in the registry, for a pipeline whose input is internet-authored text.

## Known issues carried forward

1. **`fleetd` has an intermittent race in its spend cap — unrelated to Telltale, and worth a look.**
`server::tests::concurrent_missions_cannot_both_breach_the_cap` failed on PR #64 with
`left: 2, right: 1` — **both concurrent missions admitted past the $20 global cap**, the exact
condition the test's own comment calls "an open race." It passed on a re-run of the identical
tree, so it is intermittent. `create_mission` *looks* correct (it holds the store lock across
check and insert), which makes it more interesting, not less. First thing to look at:
`s.upsert_unit(&row, now_ms()).ok()` swallows the insert error, so a failed insert would leave
committed spend stale and admit the next caller. This branch adds no Rust; `main` passed the same
test at `e2fc3ce`.
2. **Two registry repos do not exist yet:** `adbarc92/telltale-intake` (pawsport's redirect target)
and `adbarc92/telltale-probe` (the live grader's target). Until they are created,
`GET /v1/issues` carries a permanent `errors` entry for `pawsport` and the grader cannot pass.
The README's Deploy section leads with creating them.
3. **`src/registry.ts`'s `pawsport` comment says "archived on GitHub"** while its target repo is one
the README now tells the operator to create. Parked as a one-line fix; contradictory as written.
4. **Cloudflare free-tier limits for Workers + KV were never verified** (no web access in that
session). Blocks deploy, not implementation.
5. **24 further Minor findings** are triaged in the SDD ledger. All were judged ship-as-is by the
whole-branch review.

## Do not redo

- The Worker is **complete and reviewed**: eleven scoped task reviews, a whole-branch review on the
most capable model, and a final fix wave. Do not re-litigate its design; read the spec's §11
("Cut from earlier drafts") before proposing anything that looks missing.
- The plan's reference code is **known-defective** (table in step 4). Trust the committed code over
the plan wherever they disagree.
3 changes: 3 additions & 0 deletions telltale/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
dist/
.DS_Store
73 changes: 73 additions & 0 deletions telltale/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Telltale ingest Worker

Accepts authenticated bug reports from the portfolio's apps and games, scrubs
them, deduplicates by fingerprint label, and opens or comments on a GitHub issue
in that project's own repo.

Spec: [`../docs/superpowers/specs/2026-08-30-telltale-feedback-pipeline-design.md`](../docs/superpowers/specs/2026-08-30-telltale-feedback-pipeline-design.md)

Crashes do NOT go through this Worker. They go Sentry → Sentry's native GitHub
integration, with no Telltale code — see spec §3.

## Routes

| Route | Auth |
|---|---|
| `POST /v1/events` | Per-project HMAC over raw bytes |
| `GET /v1/issues` | `Authorization: Bearer $OPERATOR_READ_TOKEN` |
| `GET /v1/stats` | `Authorization: Bearer $OPERATOR_READ_TOKEN` |

## Develop

```bash
npm ci
npm test # unit suite; the live grader self-skips
npm run check # tsc --noEmit
npm run dev # wrangler dev
```

## Deploy

Two registry targets do not exist yet and must be created first, or
`GET /v1/issues` carries a permanent `errors` entry from its very first request
and the live grader can never pass:

```bash
gh repo create adbarc92/telltale-intake --private # pawsport's target
gh repo create adbarc92/telltale-probe --private # the live grader's target
```

```bash
npx wrangler kv namespace create TELLTALE_KV # paste the id into wrangler.toml
npx wrangler secret put TELLTALE_SENDER_SECRETS # {"tenzy":"...","hexy":"..."}
npx wrangler secret put GITHUB_TOKEN_PRIMARY # fine-grained PAT, Issues: read+write
npx wrangler secret put GITHUB_TOKEN_SECONDARY
npx wrangler secret put OPERATOR_READ_TOKEN
npx wrangler secret put IP_HASH_SALT
npm run deploy
```

## Adding a project

Add an explicit entry to `src/registry.ts` — there is no slug-to-repo inference
anywhere, because a wrong guess writes a user's bug report into a stranger's
repository. Then generate an HMAC secret and add it to
`TELLTALE_SENDER_SECRETS`.

`account` must name the PAT whose **resource owner actually owns the repo**: a
fine-grained PAT owned by the `adbarc92` user cannot write to an `OpenBarclay`
org repo at all, so `OpenBarclay/*` is always `secondary`. Verify the owner
against the repo's real location, not against `gh api repos/<owner>/<name>` —
that call silently follows a transfer redirect and reports the repo's NEW owner
under the OLD path, which is how a wrong entry got in once already.

## Running the live grader

Needs a throwaway repo, never a product repo:

```bash
TELLTALE_BASE_URL=https://telltale.<subdomain>.workers.dev \
TELLTALE_PROBE_SECRET=... TELLTALE_PROBE_GH_TOKEN=... \
TELLTALE_PROBE_REPO=<owner>/telltale-probe \
npx vitest run test/live-grader.test.ts
```
Loading
Loading