Skip to content

feat(worker): bulk ingest endpoint (0.0.9-alpha.0)#35

Merged
travisbreaks merged 2 commits into
mainfrom
feat/0.0.9-onmutate-adapter-hook-2026-05-20
May 20, 2026
Merged

feat(worker): bulk ingest endpoint (0.0.9-alpha.0)#35
travisbreaks merged 2 commits into
mainfrom
feat/0.0.9-onmutate-adapter-hook-2026-05-20

Conversation

@travisbreaks

Copy link
Copy Markdown
Owner

Summary

POST /annotations/bulk at the canonical worker. Bulk-insert an array of CreateInput items, one-create-per-item against the adapter, with per-item error isolation so a partial failure does not abort the batch.

API contract

POST /annotations/bulk
Authorization: Bearer <member-token>
content-type: application/json

Body:

{
  "items": [
    { "anchor": { "mode": "route", "path": "/" }, "body": "note 1" },
    { "anchor": { "mode": "route", "path": "/" }, "body": "note 2" }
  ]
}

Response:

{
  "created": [ {...}, {...} ],
  "errors":  [ { "index": 1, "error": "invalid_item" } ]
}

Constraints

  • Member-token only. Reporter (share-link) tokens get 403 bulk_member_only.
  • Volume cap: MAX_BULK_ITEMS = 200 per request (413 over).
  • Sequential per-item creates so adapter audit-log ordering stays deterministic.

Use cases unblocked

  • Brain-dump import: bulk-insert a batch of notes from a transcript / spreadsheet / call-prep doc. The pattern Pivotal used with notes 49-72 via raw SQL becomes an API every consumer can use.
  • Migration: move notes from BugHerd / Linear / Jira export into TEB without per-row POST round-trips.
  • Seeding: initialize a fresh Phase 2 LS A6 tenant with a starter set of notes from the LSD welcome packet.

Tests

apps/worker/src/handlers.test.ts adds 7 new tests:

  • Member creates multiple annotations in one call
  • Reporter (share-link) gets 403
  • 400 on missing / empty items array
  • 413 on cap exceeded
  • Partial-failure: one bad item recorded, rest persist
  • Inserted batch is queryable via the regular list endpoint

Full repo: 195 tests green. Typecheck + lint clean. Em-dash gate clean.

Versions

Skips 0.0.8 on this branch because it landed in parallel via PR #34; when #34 merges to main, the package.json conflict resolves to keep 0.0.9-alpha.0.

  • @travisbreaks/travisEATSbugs 0.0.7-alpha.0 -> 0.0.9-alpha.0
  • @travisbreaks/travisEATSbugs-cloudflare 0.0.7-alpha.0 -> 0.0.9-alpha.0
  • @travisbreaks/travisEATSbugs-http 0.0.7-alpha.0 -> 0.0.9-alpha.0

Test plan

Phase 1 of the strategic plan (second of the OSS uplift releases).

Co-Authored-By: Tadao tadao@travisfixes.com

travisbreaks and others added 2 commits May 20, 2026 02:48
`POST /annotations/bulk` at the canonical worker. Accepts an array of
CreateInput items and one-creates-per-item against the adapter.
Returns a summary with the successful annotations alongside any per-
item errors, so a partial failure does not abort the entire batch.

## API contract

```
POST /annotations/bulk
Authorization: Bearer <member-token>
content-type: application/json

{
  "items": [
    { "anchor": { "mode": "route", "path": "/" }, "body": "note 1" },
    { "anchor": { "mode": "route", "path": "/" }, "body": "note 2" }
  ]
}
```

Response:

```
200 OK
{
  "created": [ <Annotation>, <Annotation> ],
  "errors":  [ { "index": 1, "error": "invalid_item" } ]
}
```

## Constraints

- Member-token only. Reporter (share-link) tokens get 403
  (`bulk_member_only`). Bulk insert is an admin / migration operation.
- Volume capped at MAX_BULK_ITEMS = 200 per request. Larger imports
  should chunk. Cap protects Worker CPU budget per invocation.
- Sequential per-item creates so adapter audit-log ordering stays
  deterministic. Per-row error isolation: one bad item does not taint
  the rest of the batch.

## Use cases this unblocks

- Brain-dump import: bulk-insert a batch of notes from a transcript,
  spreadsheet, or call-prep doc into the inbox in one request. The
  pattern Pivotal used with notes 49-72 via raw SQL becomes an API
  every consumer can use.
- Migration: move notes from another system (BugHerd export, Linear
  export, etc.) into TEB without per-row POST round-trips.
- Seeding: initialize a fresh tenant (Phase 2 LS A6 pilot client) with
  a starter set of notes from the LSD welcome packet.

## Tests

`apps/worker/src/handlers.test.ts` adds 7 new tests:

- Member token creates multiple annotations in one call
- Rejects share-link tokens with 403 `bulk_member_only`
- 400 when body lacks `items` array
- 400 when `items` array is empty (`empty_items`)
- 413 when items exceed `MAX_BULK_ITEMS` cap
  (`too_many_items_max_200`)
- Partial-failure: one bad item recorded in `errors`, rest persist
- Inserted batch is queryable via the regular list endpoint
  afterward

Full repo: 195 tests across widget + adapter-cloudflare + adapter-http
+ worker, all green. Typecheck + lint clean. Em-dash gate clean.

## Version bumps

Bumps 0.0.7-alpha.0 -> 0.0.9-alpha.0 (skipping 0.0.8 on this branch
because it landed in parallel via PR #34; when #34 merges to main,
the package.json conflict resolves to 0.0.9-alpha.0).

- `@travisbreaks/travisEATSbugs` 0.0.7-alpha.0 -> 0.0.9-alpha.0
- `@travisbreaks/travisEATSbugs-cloudflare` 0.0.7-alpha.0 -> 0.0.9-alpha.0
- `@travisbreaks/travisEATSbugs-http` 0.0.7-alpha.0 -> 0.0.9-alpha.0

Phase 1 of the strategic plan
(second of the OSS uplift releases).

Co-Authored-By: Tadao <tadao@travisfixes.com>
# Conflicts:
#	packages/adapter-cloudflare/package.json
#	packages/adapter-http/package.json
#	packages/widget/package.json
@travisbreaks travisbreaks merged commit d44c4f0 into main May 20, 2026
2 checks passed
@travisbreaks travisbreaks deleted the feat/0.0.9-onmutate-adapter-hook-2026-05-20 branch May 20, 2026 07:56
travisbreaks added a commit that referenced this pull request May 20, 2026
New `apps/mcp-server/` workspace. Ships a working MCP server that
exposes feedback annotations as tools so AI agents (Claude Code,
Claude Desktop, others) can list, inspect, resolve, and reopen notes
against the canonical eats.travisfixes.com worker.

BugHerd announced "BugHerd MCP coming soon" in their 2025 wrap-up.
TEB ships a working MCP server first as a public credibility marker
per the Phase 1 strategic plan.

## Tools shipped (0.0.10)

| Tool | Description |
|---|---|
| `list_annotations` | List with optional path + state filters |
| `get_annotation` | Fetch by id |
| `resolve_annotation` | Resolve with resolvedPR + optional resolutionNote |
| `reopen_annotation` | Clear resolution, flip state to open |

Deferred for 0.0.11+:
- `bulk_create_annotations` (calls POST /annotations/bulk from 0.0.9)
- `triage_annotation` (calls POST /triage; member-only)
- `link_pr_to_annotation` (ergonomic resolve + PR link shorthand)

## Configuration

Two env vars:
- `TEB_API_TOKEN` (required): member token from worker MEMBER_TOKENS
- `TEB_API_URL` (optional): defaults to https://eats.travisfixes.com

## Transport

stdio. Wires into Claude Code via `claude mcp add teb npx
@travisbreaks/travisEATSbugs-mcp`. Claude Desktop config example in
the package README.

## Architecture

- `src/client.ts`: loads env config, builds the canonical HttpAdapter
- `src/tools.ts`: tool defs (JSON Schema) + handlers that delegate to
  the ApiAdapter contract
- `src/index.ts`: MCP server entry point with stdio transport
- `src/tools.test.ts`: smoke tests against MemoryAdapter, 12 tests

JSON Schema instead of zod to keep the bundle tight; the MCP SDK
validates against inputSchema before calling each handler.

## Tests

- +12 mcp-server tests (tool defs sanity + 4 handler smoke tests
  each)
- Full repo: 200 tests across widget + adapter-cloudflare +
  adapter-http + worker + mcp-server, all green
- Typecheck + lint clean across 6 workspaces
- Em-dash gate clean

## Dependencies added

- `@modelcontextprotocol/sdk` ^1.0.4 (the official MCP SDK)
- `@travisbreaks/travisEATSbugs-http` workspace dep (used as the
  canonical client)
- `@travisbreaks/travisEATSbugs` workspace dep (types)

Note: pnpm reports a zod peer-dep warning (SDK wants 3.25+ or 4.x;
repo has 3.22 transitively). Tests pass and tool-call validation
works; revisit when bumping zod becomes ergonomic.

## Use cases this unblocks

- An agent (e.g. Claude Code running in the Pivotal repo) can call
  `list_annotations({ state: 'open' })` to surface unresolved notes
  while you crank, and `resolve_annotation({ id, resolvedPR: 200 })`
  to close them inline as you ship fixes
- Hosts can offer their own per-team agents (e.g. LSD assigning
  client-feedback tickets) that read TEB via MCP instead of building
  a custom integration
- The MCP MCP-inspector tool can be used to verify any TEB worker
  deployment by smoke-testing the tools against it

## Versions

Stays at 0.0.7-base in package.json (this PR was branched off main
which had 0.0.8; when this lands the mcp-server is on 0.0.10 standalone).
Widget + adapter packages unchanged on this branch; 0.0.9 (bulk
ingest) lives on its own PR #35.

Phase 1 of the strategic plan (third of the OSS uplift releases).

Co-authored-by: Tadao <tadao@travisfixes.com>
travisbreaks added a commit that referenced this pull request May 20, 2026
Update the per-project thread state to reflect the full 2026-05-20
strategic sprint:

- Phase 0 COMPLETE: PRs #24 (hygiene) + #25 (tenancy ratified) +
  #26 (per-project memory dir) merged. Branch protection enabled.
  CI secret configured. CODE MEMORY.md routing updated. Injection
  log incident 122 appended.
- Phase 1 COMPLETE: PRs #34 (0.0.8 bug-button + hint-ribbon config)
  + #33 (region-screenshot doc + Pivotal reframe) + #35 (0.0.9 bulk
  ingest worker endpoint) + #36 (0.0.10 TEB MCP server) merged.
- Test growth: 175 -> 207 (+32 new across 4 PRs).
- Widget canonical: 0.0.10-alpha.0 on main.
- Hallucination audits + Dependabot triage results captured for
  future reference.
- Phase 2 entry point (LS A6 multi-tenant scaffolding) documented
  for next-session pickup.
- 6 dependabot PRs still open at EOD: 4 GH Actions safe to merge
  next session, 2 npm groups recommended HOLD per triage.

Co-authored-by: Tadao <tadao@travisfixes.com>
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.

1 participant