# HANDOVER.md — Penny read-spine UI port

## Rename

**6 September 2026.** Renamed from Atlas to Penny (repository `runeditrun/feedback-penny`): a penny for your thoughts, every voice counted — a common object, the product's feeling, and an echo of Canny.

## Manifest

**7 September 2026.** `seed.json` migrated to the shared `category`/`spine`/`replaces` schema (`category: feedback`, `spine.id: feedback`, `replaces: Canny`); validates against `schema/SEED.schema.json`.

## Clean install

**8 September 2026.** `pnpm verify` now passes from a clean clone. It had only
ever passed in a checkout that still held `worker-configuration.d.ts`, the
`wrangler types` output that `.gitignore` excludes. `tsconfig.tests.json` listed
that generated file in `include` and left `@cloudflare/workers-types` out of
`types`, so after `pnpm install --frozen-lockfile` the tests project lost
`D1Database`, `Fetcher`, `R2Bucket`, `Queue` and the `cloudflare:workers`
module; `this.connection.binding` then degraded to `any` and the strict tests
project reported thirteen implicit-`any` parameters in the `read-repository`
files. The dependency itself was always declared and locked, so the fix is in
the TypeScript configuration, not the manifest: `tsconfig.tests.json` now names
`@cloudflare/workers-types` in `types` and includes only `tests/e2e/**/*.ts`,
and the committed `tests/e2e/worker/worker-environment.d.ts` derives
`Cloudflare.Env` from `AppBindings` and `Cloudflare.GlobalProps.mainModule` from
the entry module `deploy/wrangler.template.toml` names. Generated infrastructure
types are no longer an input to the typecheck. The implicit-`any` sites needed
no change: they were consequences of the lost D1 types, and the annotated
`.all<...>()` row types flow again. Proven by cloning the branch into an empty
directory and running `pnpm install --frozen-lockfile` and `pnpm verify` there.

## Current state

Penny is a **read-only UI port and D1 data spine**, not a releasable seed. One
Cloudflare Worker serves the Vite/React operator app, public portal, and Hono
read API. The initial D1 migration and sample importer are real; the curated
sample is inserted idempotently through feature services under Miniflare.

The Worker enforces the public-path allow-list, checks D1/R2/Queue bindings at
`/health`, and requires a valid allow-listed D1 session for `/app` and every
`/api/operator/*` route. It validates a session but does not issue or revoke
one. Native magic-link sign-in therefore remains a prerequisite to a usable
operator deployment.

The public portal reads published feedback, approved roadmap projections, and
published releases only. Its public DTOs never select account, evidence,
decision, commercial, or operator fields. The sample intentionally has no
published release, so the updates feed exercises the honest REL-010 empty
state. It has no submission form: the fresh unavailable screen collects no
data until requester identity and moderation are implemented.

## Required TanStack Start migration before further implementation

**8 September 2026 — owner direction.** TanStack Start is the adopted default, but the runtime described above remains Penny's current Vite/React/TanStack Router implementation. On resuming Penny, the **FIRST** step is to bring this committed main-branch note into any parked implementation worktree and convert through the accepted recipe before further product work: local evidence `/Users/zemaj/.orchestrator/evidence/runeditrun/default-seed-on-tanstack-start-with-the-migration-recipe/MIGRATION.md`; portable author reference [TanStack Start migration recipe](https://github.com/runeditrun/seed-spec/blob/main/TANSTACK-START-MIGRATION.md).

The conversion must preserve Penny's contract, D1 operator-session boundary (including its deliberately unimplemented native magic-link issuance), public DTO filtering and true missing-document behaviour, declared Hono read and health HTTP routes, D1/R2 data and migrations, and Worker Queue/Cron/event exports. Hono remains the owner of declared HTTP contract surfaces; the custom Worker entry retains events and named exports; Start takes selected React document routes and server functions only. Public React documents need SSR HTML or an explicitly allowed invariant prerender; every private server function must re-check the native session before reading data, and `/app` navigation must hydrate and stay client-side. The recipe is accepted through local workerd validation only and makes no remote-deployment claim.

## Ported interface

The following React routes are backed by explicit D1 read DTOs, not browser
state, mock data, generated markup, or a server-side feature import:

| Surface | Routes | Read boundary |
| --- | --- | --- |
| Public feedback | `/`, `/portal/feedback/:slug` | boards, published request cards, and approved comments |
| Public roadmap and updates | `/portal/roadmap`, `/portal/updates`, `/portal/updates/:slug` | approved public projections and published releases only |
| Operator overview | `/app/overview` | attention decisions, unreviewed evidence, active roadmap, recent published releases |
| Operator evidence and decisions | `/app/feedback`, `/app/decisions`, `/app/decisions/:slug` | internal evidence and comparable decision briefs |
| Operator roadmap and releases | `/app/roadmap`, `/app/releases`, `/app/releases/:slug` | internal roadmap, draft/published releases, and internal targets |
| Operator accounts | `/app/customers`, `/app/customers/:slug` | commercial context, requester addresses, evidence chronology, linked decisions |

The public portal follows the selected 12ui violet/surface/spacing language
with locally bundled Open Sans. The operator port preserves the v2 information
hierarchy—Overview, Feedback, Decisions, Roadmap, Releases, Accounts—through a
desktop rail that collapses into a real mobile menu. Public and operator routes
render loading, retryable failure, empty, missing-record, and expired-session
states from their real HTTP results.

The final browser pass launched from an empty disposable clone, applied the D1
migration without operator input, imported the sample graph, and exercised all
mounted read routes. Representative public and operator pages were checked at
390, 768, 1280, and 1536 pixels with no horizontal overflow or browser-console
errors. Captures and their authentication provenance are in `visual/README.md`.

Fresh design was needed for the unavailable public submission flow, empty/error
states, the evidence inbox, account chronology, release readiness/outcome
panels, and the responsive operator shell. Those states name what is missing;
they do not offer inert controls or invented delivery, outcome, or CRM data.

## Contract areas represented and proven boundary

`docs/read-spine.md` maps every ported route to its API and contract area. The
read spine represents HOME-001, REQ-001 and REQ-016, ROAD-003/004/006,
REL-010, DATA-002/EVID-006, and the read portion of OPS-003. This is not a
claim that every part of those clauses is finished: tests prove the customer
safe public projection, hidden/draft filtering, derived status, empty release
feed, D1-backed operator-session gate, and route guards. Mutation, timing,
search, rate-limit, notification, and accessibility obligations still require
their own behavior and contract tests.

## Research provenance

The deleted static prototype application is not shipped. Its visual evidence is
retained under `research/`, especially `research/evidence-v2/`,
`research/12ui/`, `research/12ui-responsive/`, `research/app-page-map.md`, and
`research/product-direction.md`. These files are design and product-direction
references only; their generated fixtures, external fonts/analytics, local
storage, CRM settings, counts, scores, and fake controls must never re-enter
the runtime.

## Backend and release debt

The next implementation pass must add real behavior before enabling any of
these actions:

- native magic-link issuance, sign-out, requester verification, host-signed
  identity, and rate limiting;
- request submission, duplicate handling, votes, follows, comments,
  moderation, boards, status/decline, merge/unmerge, requester controls,
  attachments, and subscriptions;
- evidence capture/review/linking/tagging, decision commitments/revisions and
  review-due scheduling, roadmap movement/approval/status updates, release
  publication/delivery/outcomes, Queue consumers, Cron, R2 attachment access,
  the mail adapter, retries, bounce/complaint handling, and audit exposure;
- global search, custom-field editing, export/import, deterministic setup and
  deploy commands, deployment workflow, deployed verification,
  accessibility checks, load tests, previous-release migration verification,
  complete baseline/product contract coverage, visual refresh, `RELEASE.json`,
  and first-release packaging.

`seed.json` deliberately identifies this as `ui-port-read-spine`. Its limits
and costs are estimates, not load-tested capacity or active rate controls. The
declared release-recipient ceiling would require Workers Paid for Queue volume;
the current read-only port dispatches no deliveries.

Do not edit `AGENTS.md`, `AGENTS.consumer.md`, or `BASELINE.md` to resolve a
product-specific issue. Change the relevant contract behavior and test before
enabling it, preserve the public/private projection boundary, and keep reads
and mutations in their feature-owned repositories and services.
