Skip to content
Merged
Changes from all commits
Commits
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
22 changes: 12 additions & 10 deletions STATUS.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
# Helpthread — Status

**Current state:** the mail engine's threading core is built and merged — an inbound reply can be parsed, its signed reply token verified, and routed to the correct conversation end-to-end. Persistence (store) and outbound (send) are next. All work lands through a guarded pipeline: every PR runs typecheck, lint, tests-with-coverage, secret scanning, and CodeQL, plus AI review (CodeRabbit) and — for security- and threading-critical code — an independent Codex pass.
**Current state:** the mail engine's core loop is closed end-to-end — an inbound reply is parsed and threaded, conversations and threads are persisted, and an outbound reply is sent with a signed reply token in its Message-ID that a future customer reply threads back on. Everything below the wire (parse → thread → store → send) exists and is tested against real in-process Postgres; what's left is a real email provider adapter, the HTTP/API surface, and a UI. All work lands through a guarded pipeline: every PR runs typecheck, lint, tests-with-coverage, secret scanning, and CodeQL, plus AI review (CodeRabbit) and — for security- and threading-critical code — an independent Codex pass.

## Now

**Phase 1 — Core engine, dogfooded.** The threading decision is complete; building outward toward a runnable, dogfoodable slice.
**Phase 1 — Core engine, dogfooded.** The full inbound→outbound threading loop is built; turning it toward a runnable, dogfoodable slice (a real send adapter + the conversation API).

## Done

**Foundation**
- Founding charter ([CHARTER.md](CHARTER.md)) — mission, principles, licensing, architecture, roadmap.
- Behavioral specs: conversation API contract (`specs/api/conversations-v1.md`), mail threading (`specs/mail/threading.md`).
- Platform provider interfaces (`src/providers/`) — queue, scheduler, blob storage, inbound email — Vercel-first, not Vercel-only.
- Behavioral specs: conversation API contract (`specs/api/conversations-v1.md`), mail threading (`specs/mail/threading.md`), outbound sending (`specs/mail/sending.md`), conversation store (`specs/store/conversations.md`).
- Platform provider interfaces (`src/providers/`) — queue, scheduler, blob storage, inbound email, and outbound email sender — Vercel-first, not Vercel-only.
- Black-box acceptance fixtures (`fixtures/mail/`).
- CI/quality foundation: TypeScript (strict, NodeNext) + Biome + Vitest (v8 coverage); CI (quality + secret scan), CodeQL, OpenSSF Scorecard; branch protection requires all checks green.

**Mail engine — threading core**
**Mail engine — the closed loop**
- **Inbound parser** (`src/mail/parse.ts`) — raw RFC 5322/MIME → a normalized `ParsedEmail` (built on postal-mime). Surfaces the threading-critical headers; captures HTML verbatim.
- **Signed reply tokens** (`src/mail/reply-token.ts`) — HMAC-SHA256 tokens minted into outbound Message-IDs and verified on reply, with key rotation. The cryptographic basis for trustworthy threading.
- **RFC 5322 message-id extractor** (`src/mail/message-id.ts`) — comment/quoted-string-aware tokenization, shared by the parser and the threading decision.
- **RFC 5322 message-id extractor** (`src/mail/message-id.ts`) — comment/quoted-string-aware tokenization, shared across the engine.
- **Threading decision** (`src/mail/thread.ts`) — the 5-rule algorithm: a verified token routes a reply to its conversation; no valid token starts a new one; subject is never used.
- **Conversation/thread store** (`src/store/`, `src/db/`) — persistence on a thin, portable raw-SQL layer over PGlite (in-process Postgres) locally, the same SQL destined for Supabase. A valid token to a closed conversation reopens it; to a deleted one, the caller starts fresh.
- **Outbound send** (`src/mail/send.ts`) — mints the reply token into the outbound Message-ID, persists the outbound thread as an outbox item (`pending`→`sent`/`failed`), and hands it to an `EmailSender`. A round-trip test proves a sent reply threads back to the right conversation.

## Next

- **Store** — persist conversations and threads (local Postgres via a portable, thin SQL layer) so the decision's `{conversationId, threadId}` lands somewhere real; handle tokens pointing at closed/deleted conversations.
- **Send** — outbound replies that mint the reply tokens the whole system depends on.
- Then: the six-operation conversation API and an agent inbox UI (API-first, per the charter).
- **A real `EmailSender` adapter** (Gmail send / Postmark / SES) — the first one that puts actual mail on the wire, with a wire-level test proving the Message-ID is transmitted verbatim.
- **Send idempotency + delivery worker** ([HT-16](https://resonantiq.atlassian.net/browse/HT-16)) — a dedup key and a worker that retries `pending`/`failed` outbound threads reusing the same Message-ID; required before `sendReply` goes behind a live retrying caller.
- **The six-operation conversation API** and an agent inbox UI (API-first, per the charter).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the defined Agents terminology.

This refers to the human-support inbox; write “an inbox UI for Agents” and reserve Assistants for AI actors.

As per coding guidelines, human support staff are Agents and AI actors are Assistants; never conflate them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@STATUS.md` at line 30, Update the six-operation conversation API bullet in
STATUS.md to say “an inbox UI for Agents,” using “Agents” for human support
staff and reserving “Assistants” for AI actors.

Source: Coding guidelines


## Not yet / deferred

- Live Vercel + Supabase deployment — deferred to the first deployable milestone; provider adapters are interfaces, not yet built.
- Live Vercel + Supabase deployment — deferred to the first deployable milestone; provider adapters are interfaces (inbound + outbound), concrete ones not yet built.
- Agent inbox UI.
- Marketplace (paid modules, license keys, module registry).

Expand Down
Loading