Skip to content
Merged
Show file tree
Hide file tree
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
67 changes: 67 additions & 0 deletions CHANGELOG/pages/scratchnode-nodebench-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,73 @@
Append-only lane for the conversion bridge from the disposable ScratchNode live-event
room into the NodeBench app. Newest entries on top.

## 2026-06-03 — Slice 1: import a published event recap into the WORKSPACE

Lets a visitor import a published ScratchNode event wiki as ONE editable
NodeBench product document under a FRESH NodeBench-origin anonymous product
identity. On later sign-in the EXISTING bootstrap merge path
(`convex/domains/product/bootstrap.ts` → `claimAnonymousProductWorkspace`)
re-owns it from `anon:<sessionId>` to `user:<id>` — no bespoke merge code.

**Backend**

- `convex/events.ts` — added `getPublishedWikiStructuredBySlug({ slug })` plus the
shared reader `loadStructuredPublishedWiki(ctx, slug)`. Returns the SAME
published snapshot as `getPublishedWikiBySlug`, but STRUCTURED
(`{ eventId, slug, eventName, roomCode, wikiVersion, answers:[{question,body}],
sources:[{title,uri,excerpt}] }`) so the importer builds editable blocks with
no HTML round-trip. PUBLISHED-only; private notes are excluded at publish time,
so there is nothing private to read here. BOUND: answers ≤ 20, sources ≤ 20.
- `convex/domains/product/scratchnodeImport.ts` (new):
- `importPublishedWiki({ slug, anonymousSessionId })` — resolves the anon (or
signed-in) product identity, reads the published structured wiki, and
materializes ONE `entity_memory` product document (title `"<eventName> —
recap"`, body = Q&A + sources blocks) plus the canonical event entity
(`entityType: "event"`, owner-private). Reuses the existing
`productDocuments`/`productDocumentBlocks`/`productDocumentSnapshots`
primitives — no parallel doc system.
- Idempotent: stable entity slug `scratchnode-event-<hash(eventId)>` maps every
re-import of the same event to the same document; a per-import key
`hash(eventId|wikiVersion|ownerKey)` makes a re-import of the SAME published
version a no-op (`alreadyImported:true`), and a NEWER published version writes
a fresh revision/snapshot on the same document (no duplicate).
- `getScratchnodeImportStatus({ slug, anonymousSessionId })` — read-only state
(`published` / `imported` / `upToDate` / `entitySlug`) for an honest UI.
- Returns `{ ok, documentId, entitySlug, created, alreadyImported }`. Honest
no-op (`ok:false, reason:"no_published_wiki"`) on draft / unpublished /
unknown slug — never a fabricated empty recap.
- No fuzzy company/person extraction (avoids fabricated entities) — deferred.

**Frontend**

- `src/features/redesign/surfaces/ScratchnodeEventsSurface.tsx` — each event row
gains an "Import this recap into NodeBench" action via the new
`ImportRecapButton`. It only renders when a PUBLISHED wiki actually exists
(gated on `getScratchnodeImportStatus.published`), imports under the FRESH
NodeBench product anon identity (`getAnonymousProductSessionId`, NOT the
cross-domain `sn_session_id`), shows real importing/done/error states, and
links to the created recap at `/entity/<entitySlug>`. The existing "Open in
ScratchNode" CTA is untouched. `(api as any)` mirrors the surface's existing
codegen-independent call style.

**Reliability (agentic_reliability 8-point)**: BOUND (all reads ≤ 25), HONEST_STATUS
(no fake success; throws on entity-create failure), BOUND_READ (dangling ids
skipped, text sliced to caps), DETERMINISTIC (FNV-1a hash, stable block ids /
entity slug / import key). No external fetch, so SSRF/TIMEOUT are N/A.

**Privacy**: PUBLIC-DATA-ONLY. The importer reads only the published wiki snapshot
via `loadStructuredPublishedWiki`; it never reads or writes `userNotes` /
`liveEventNoteAnchors`, and never writes under another user's owner key.

Covered by 11 convex-test scenarios in
`convex/domains/product/scratchnodeImport.test.ts`: happy import (editable doc +
event entity), re-import idempotency (no dup), re-publish → new revision,
unpublished / draft / unknown → honest no-op, a PRIVACY test proving a private
note marker never reaches the imported document, plus status-query and
structured-read coverage. 11/11 green; `tsc --noEmit` clean.

**Commit**: `this commit`. **Author**: Homen Shum + Claude (agent build).

## 2026-06-03 — Make the bridge REAL: a `/events/:slug/wiki` receiving route
The bridge was broken end-to-end. ScratchNode sent users to
`nodebenchai.com/events/<slug>/wiki`, but the `/events` matcher in `src/App.tsx`
Expand Down
Loading
Loading