Building hereandmore.com

ledger · the first HERE, feature by feature

history.hereandmore.com · archive/here at e3a4a8a6 · 2026-03-10 · read 2026-09-02

Every feature of the first HERE, traced to the table

Fifty-four features across 133,000 lines: what each one was for, how it flows from screen to row, what it feeds, and whether it works. The core loop works. The quality chain the thesis rests on is severed at one stub function, the economy is columns without writers, and fourteen tables exist in no migration.

Read from the exact tree the archive serves, plus live GET probes of the running archive under the demo account. Every status cites a file and line. The archive runs the free plan with no Stripe, Anthropic, Cloudflare, provider OAuth or GPU worker, so “archive: off” marks features whose code is whole but whose keys are absent.

54featuresfive domains, 50 route files, 95 tables
0worksscreen, API and table wired end to end
0partialbuilt, one link missing
0brokena defect stops it doing what it says
0unusedcode and tables, no consumer
0live in the archiveanswers today under the demo token

Four chains, and where each breaks

Value in this app multiplies along four paths. Each node is coloured by its status; a dashed link is a place where the code stops handing value forward.

1 · the observation chain, the thesis

NoteTemplateWeightReputationVelocityAscensionConfidence
CollisionVerificationWeight

The editor never sends a template, so completeness, agreement and extraction only ever run for Garden notes. Collision detection runs on every note and then a constant is written where its result should go. Velocity is computed on the server and lost by the client. Nothing writes an ascension record. Confidence has no route.

2 · the workspace chain, the February roadmap

TeamProjectConversationTaskSessionEvaluationMemoryDigest
CreditsProject budgetTask costReward

The human loop is complete and the densest fan-out in the app is a task completing. The economy under it never closed: allocating credits does not write the project, spend has no writer, task cost is never charged, reward is a manual admin call. Digests need an Anthropic key the archive does not have.

3 · the money chain

StripeCreditsSplatsProductsListings50 / 30 / 20 splitPayout

Real money enters in one file and becomes credits. Credits are spent by three sinks. The split credits contributors internally, banks nothing for the platform, and there is no cash-out anywhere, only a policy nobody has written down. Product escrow never releases on its own.

4 · the signal chain, presence to consequence

Location updateMapTrailGeofenceNotificationWorkflowWebhook

One browser emit fans out to the map, history, geofences, alerts, workflows and developer webhooks. Leaving the map page disconnects the shared socket for the rest of the session, and the two ends of the chain leak: positions to every user, webhooks to every tenant.

No feature matches this filter.

A

The spatial core

Identity, the map, presence, trails, assets, geofences, notes, search, export, attachments, offline. The command center the login page promises. It renders and records; its quality machinery and half its privacy walls are missing.

Works

Auth and identity

routes/auth.ts (6) · routes/users.ts (11) · lib/auth.ts, lib/oauth.ts · users, sessions · authStore, LoginPage, ProfilePage

“JWT-based authentication with Google OAuth 2.0.” The frontend exchanges an httpOnly cookie for a 30-day token; a session row backs every token; platform role is “user” or “admin.”

Flow
Google with PKCE, or the dev login the archive exposes as “Enter the demo,” creates or links a user, inserts a session and signs a token stored in local storage; every request and the socket handshake verify token, session and user. Rate limits on OAuth, dev login and session exchange.
Multiplies
Every route and the socket. The user's last location, written here and by the socket, anchors the map, search bounds, live streamers, products and splats.
Evidence
Live archive: demo login lands as Alice and /auth/me answers · profile save posts to /users/me and the only route is /users/:id, which parses “me” as an invalid id and answers 400 (ProfilePage.tsx:98, users.ts:147-152) · “Delete account” has no handler · “Sign out everywhere” signs out one session · nothing can set the admin role except the database · port defaults disagree across five files · 13 auth and 17 user route tests
Needs
A /users/me route, persistence for the profile toggles, a logout-all route over the function that exists, and one place for port defaults.
Works

Map and presence

routes/map.ts (5) · lib/socket.ts · MapViewGL (1,167 lines) and ten GL layers · mapStore, useGeolocation, useSocket, useEntities

“Your map-based command center for team and asset tracking.” Viewport entity queries up to 5,000, a density heatmap, live streamers, products, nearby. “Persist to DB first, then broadcast.”

Flow
MapLibre over OpenFreeMap tiles; every move debounces a bounds query refreshed every thirty seconds and on socket events; layers for team members, agents, assets by type, notes, geofences, own trail, a client-side heatmap, live streamers, products and splats; clustering above fifty entities. Browser geolocation sends a location update when moved ten metres, the server stores it, records history past fifty metres, broadcasts to team rooms and runs geofence checks. Time-travel mode replaces positions with interpolated history. Sharing off hides your marker and stops sending.
Multiplies
The socket is the transport for every realtime feature: tasks, notifications, streaming relay, geofences. Presence anchors four other layers.
Evidence
Live archive: /map/entities answers Bob's seeded position to Alice · the socket hook is mounted by both the app shell and the map, and its cleanup disconnects the shared singleton unconditionally, so leaving the map kills realtime for the rest of the session and while both are mounted every handler fires twice (useSocket.ts:211-223, socket.ts:79-84) · the users query in entities, heatmap, nearby and the users list has no team filter, so every authenticated user sees every other user's last position, while assets in the same endpoint are own-only · sharing off never tells the server, and “set my location here” bypasses the toggle · location payloads are unvalidated · the server heatmap has no client caller · three date and owner filters in the sidebar do nothing in the GL engine · no map or socket test
Needs
Reference-count the socket and connect it once; scope user visibility to shared teams or state the policy explicitly; a server-side sharing-off; validate location updates; wire or delete the dead filters and the server heatmap.
Works

Location history and time travel

routes/locationHistory.ts (7) · location_history · TimeSlider, LocationHistoryLayerGL · three orphaned playback services

“User movement tracking.” A trail for the map, and “interpolated positions for multiple users at a target time… to show where everyone was at a specific moment.”

Flow
Points enter through the socket; the trail layer draws your own points; the time slider scrubs a window and asks the server to interpolate every team member's position at that instant, dropping anyone whose nearest record is more than thirty minutes away, and filters agents, assets, notes, geofences, products and splats by time.
Multiplies
The temporal map. Nothing else reads the table.
Evidence
Live archive: Alice's trail holds two points at 50.09° N 14.43° E recorded on 31 August, a visitor's real location in Prague · the time-range and bulk endpoints accept any team id without a membership check, so any user can replay any team's movements (locationHistory.ts:240-248,286-294) · bulk loads unbounded history per scrub · trajectory, historical playback and playback services, 1,951 lines, have zero importers; saved trajectories and playback sessions tables have no reachable writer · three history queries fire even with the trail off · no test
Needs
Membership checks and a windowed query; a decision on the three orphaned services and two dead tables.
Partial

Assets

routes/assets.ts (7) · assets, asset_changes · entitiesStore, EntityDetail, EntityPopup

“Physical or virtual assets owned by the user”: locations, people, objects, financial. An audit trail that keeps history after deletion. The login page's third promise, “Asset Tracking.”

Flow
Create, update and delete write before-and-after snapshots and dispatch webhook and workflow events; the map reads own assets for the viewport and own-plus-team assets for auto-fit. No screen creates, edits or deletes an asset: the detail panel's buttons have no handler, and the only writers are bulk import and an offline queue nothing fills.
Multiplies
Map layers, search, export and import, attachments, evaluation access, AI suggestions, the public API. The audit trail has one reader, which nothing calls.
Evidence
Live archive: three seeded assets answer on the visible endpoint · EntityDetail.tsx:180-189,256-265 inert buttons · REST changes emit no socket event, so other clients wait for the thirty-second poll · 15 route tests
Needs
An asset editor at a map point with edit and delete from the popup, a history panel, and a socket emit on REST changes.
Partial

Geofences

routes/geofences.ts (7) · lib/geofence.ts · geofences, geofence_events · GeofenceEditor, GeofenceLayerGL, GeofenceAlertToast

Circle or polygon, monitoring users, agents and assets, with entered, exited and dwell events.

Flow
Draw on the map, save to a team; every location update is tested for containment against the team's active fences and a transition records an event, emits to the team room, creates an alert notification and dispatches a workflow and webhook event. A toast opens the event history.
Multiplies
Notifications, workflows and webhooks, the map layer, the alert toast.
Evidence
Works end to end for users in the GL engine · containment state lives in process memory, so every restart re-fires “entered” for everyone · the agent and asset flags are stored and never evaluated · dwell is declared and never produced · in the default engine a fence cannot be selected, edited, toggled or deleted, the layer has no click handler · no test
Needs
Persist containment, run checks for agents and assets or drop the flags, click-to-select wired to the existing mutations, a dwell timer.
Works

Notes, the geo-observation

routes/notes.ts (10) · routes/normalization.ts (3) · lib/spatial.ts, dedupService.ts, normalizationService.ts, geocodingClient.ts, backgroundWorker.ts · notes, places, dedup_groups, normalization_jobs, view_history · NoteEditor, NotesPage, NotePopup

“Geo-tagged observations - 4D coordinates: lat, lng, altitude, time.” The unit of the thesis: the thing you draw on the map of the world.

Flow
Right-click or press N, write content, tags and up to five photos; the server resolves timezone offline, defaults altitude, inserts, links duplicates by a location-and-time hash, detects collisions, scores weight, then fires reputation, a webhook event and team memory. A worker geocodes pending notes through Nominatim into a places cache. PostGIS answers nearby queries. The notes page lists, filters and assigns to projects.
Multiplies
The most-consumed table in the codebase: collisions, weight, reputation, velocity, confidence, packages, memory, suggestions, search, the Garden.
Evidence
Live archive: zero notes, so the map opens empty · the editor never sends a template id, so completeness scoring, contradiction detection and structured agreement never engage outside the Garden · photos are uploaded against note id 0 and never re-linked, so the notes page can never show them · unknown altitude is stored as sea level · no observed-at picker · the geocode worker has no retry cap, so ten un-geocodable notes starve every later note forever · normalization routes are unscoped · the 4D migration file is not journaled, its index never exists · view history is a dead table, normalization jobs are write-only, dedup groups have no reader · no notes route test
Needs
Templates in the editor, re-link photos after create, null for unknown altitude and a date control, retry and backoff in the worker, scoped normalization routes.
Partial

Search

routes/search.ts (2) · SearchDialog (Cmd-K), SearchTab · useSearch

“Search across all entities,” with an option to filter to the visible map area, and lightweight autocomplete.

Flow
Substring match over own assets, team tasks, projects, conversations, users and visible notes, five each, with optional bounds; the sidebar tab flies the map to a result.
Multiplies
Consumes geocoded place names and last positions; feeds the viewport.
Evidence
Live archive: “survey” finds the seeded task and project · the global dialog tests and navigates to /map, a route that does not exist, so “In View” can never be enabled and asset, user and note results point at pages that do not exist (SearchDialog.tsx:25,76 vs App.tsx:130) · suggestions are fetched per keystroke and discarded · unescaped wildcard characters · no test
Needs
One route constant, real destinations for spatial results, drop or use suggestions, trigram indexes when volume matters.
Works

Export and import

routes/export.ts (4) · routes/import.ts (4) · ExportMenu, BulkImport

CSV, JSON and GeoJSON exports of assets, tasks, activity and a project report; CSV and GeoJSON asset import with preview and rollback.

Flow
Export buttons on the project data tab download with the bearer token; import parses client-side, maps columns, previews server-side, inserts row by row and remembers a batch id for rollback.
Multiplies
Imported assets appear on the map, in search and in exports immediately.
Evidence
Live archive: task export answers CSV · rollback batches live in process memory · imports skip the audit trail · the assets export ignores the project it is asked for · the notes GeoJSON export has no UI and cannot round-trip because import rejects three-element coordinates · no test
Needs
A batch table, audit rows on import, a notes export in the UI and 3-D import.
Works

Attachments and storage

routes/attachments.ts (8) · lib/storageProvider.ts (local or S3) · lib/attachmentCleanup.ts · attachments · photoUpload, FileUpload

Polymorphic files on any entity, local disk or any S3-compatible store, quota by plan.

Flow
Images are compressed client-side, posted with progress, checked for entity access, quota, size and type, stored, and served by redirect or stream. Cleanup runs on project and team delete and half-hourly for orphaned splat inputs.
Multiplies
Note photos, task and project files, products, splat inputs and outputs, recorded streams. The only place a plan touches the spatial core.
Evidence
Live archive: usage answers 0 of 100 MB · thumbnails are never generated, the thumbnail route streams the original inline and SVG is allowed, a stored script surface · because every note photo lives at note id 0 and that id is open to any user, all note photos are listable and downloadable by anyone · conversation message and splat input access checks are open · attachments of deleted notes and assets are never cleaned · no test
Needs
Re-link photos and close the id-0 read path, serve SVG as attachment only, real thumbnails or no endpoint, cascade cleanup.
Partial

Offline and mobile

offlineStore, offlineDb (Dexie), useOffline, OfflineIndicator · lib/mobileService.ts · mobile_devices, push_notifications, offline_sync_queue

“Stores cached data and pending sync queue,” auto-sync on reconnect, and “mobile app foundations” for device registration and push.

Flow
An online flag with toast and panel; dashboards write tasks, projects and teams into IndexedDB; a queue would replay note, task, asset and message actions. No page reads the cache and no component enqueues anything, so the count is always zero. The server's mobile service and three tables have no importer; push delivery is a TODO.
Multiplies
Nothing yet.
Evidence
queueAction callers = 0 · cache readers = 0 · mobileService.ts importers = 0 · service-worker registration is unverifiable, the archive copy lacks the Vite config · six store tests
Needs
A decision on the offline contract, then route note creation through the queue and serve nearby notes and entities from cache; implement push or remove the subscribe UI; delete the mobile service unless a native app is planned.
Unused

Custom domain layers

lib/layerService.ts (901 lines) · custom_layers, layer_subscriptions

Eight system domain layers, from commercial real estate to environment, each a set of observation templates; team-made custom layers with subscriptions and stats.

Flow
None. No route, no UI, no importer; the map's “layers” are fixed toggles. Because system templates are never seeded, the domain layers would resolve to nothing even if mounted.
Multiplies
Nothing reads it.
Evidence
importer grep = 0 · the only inserts are inside the service
Needs
Mount layer routes and a domain section in the layers tab that filters notes by template set, which depends on templates existing; or delete.
B

Knowledge, quality and AI

The layer the thesis rests on: observations get a weight, weights make a reputation, agreement between observers makes them true. Thirteen features; one stub function severs the chain.

Unused

Confidence scoring

lib/confidenceService.ts · confidence_cache, confidence_areas · docs/CONFIDENCE_SCORING.md

“Confidence is HERE's core value proposition. Every piece of data in the system has a transparent, multi-factor confidence score.” The doc describes a per-observation calculator with source, correlation, aggregation and morphism factors and a badge and slider in the UI.

Flow
None. The 687-line service has no importer and no route mounts it, so both tables have no reachable writer. The only live “confidence” is a column on activity events that defaults to 0.8 and is never set by any caller, rendered as a constant 80% badge. The map has no confidence filter.
Multiplies
Nothing reads it. Even inside the orphan, the “collision rate” factor derives from a verification score that is a constant, so it would be 1.0 for every populated cell.
Evidence
confidenceService.ts importer grep = 0 · index.ts:264-331 no mount · activityService.ts:30 · doc promises lib/confidence.ts which does not exist
Needs
A decision: the doc's per-observation model or the code's per-area aggregate. Then one route, a cache-refresh worker, a real verification input and a map layer with a minimum-confidence filter.
Partial

Collisions

routes/collisions.ts (7) · lib/collisionDetector.ts · observation_collisions, collision_observations

“When two observers independently report on the same location and time. This is GRF's structural quality mechanism for verified data.”

Flow
Creating a note runs detection over other users' notes within 50 m and 24 h, joins or creates a collision group with centroid, template, domain and an agreement score, and stamps every member note. Seven read endpoints; the Garden's “collision stories” panel is the one UI consumer. Garden notes run the same detection.
Multiplies
A badge and a narrative, never a number: the weight calculator's verification factor ignores the collision and returns a constant 10 with a TODO, two lines after detection ran in the same route. Velocity hard-codes collision count to zero. Reputation reads only weight.
Evidence
notes.ts:578-612 detection · weightCalculator.ts:277-285 constant with “TODO: Update this when collision detection is implemented” · Garden card multiplies a 0–100 score by 100 (GardenCollisionStory.tsx:75-77) · activity type mislabelled conversation_message
Needs
Implement verification from the collision id and agreement score, re-weight every note in a group after it forms, fix the Garden ×100. One function lights up weight, reputation, velocity and confidence at once.
Works

Weight and reputation

lib/weightCalculator.ts · lib/reputationService.ts · routes/reputation.ts (4) · reputation_snapshots

“Weight is the currency of credibility. It's earned through consistently high-quality contribution. Never purchased.” Four factors of 25 points; a rolling 20-observation average becomes an A to D grade with “economic consequences.”

Flow
A note written through the notes route gets completeness, novelty, verification and recency scored and stored, then a fire-and-forget reputation update writes a snapshot, caches score, grade and trend on the user, and demotes tier to “observer” on a D. Profile, dashboard and team member lists render it. Streaming hours add up to 0.15.
Multiplies
Velocity sums weight; the marketplace reads weight tier; listings show a team's average reputation. The tier demotion is written and read by nothing that branches on it.
Evidence
notes.ts:621,627 · reputationService.ts:136-171 · live archive: /reputation/me answers tier contributor, in grace period · four other note writers skip scoring (publicApi.ts:110, facilitator.ts:355, aiFacilitator.ts:638, workflowEngine.ts:209) and their weight-0 rows count in the rolling window · tests cover the pure functions only
Needs
One after-note-written hook that every writer calls, a real verification factor, and a consequence for “observer” tier or drop the claim. Reputation leaderboard hooks exist with nothing rendering them.
Broken

Velocity

lib/velocityCalculator.ts · routes/velocity.ts (8) · velocity_snapshots · VelocityGauge

“Velocity measures the rate of high-quality observations per unit of time. Formula: V = (Noise × Weight) / Time.”

Flow
The live endpoint sums note weight over seven days and compares with the previous window. Snapshots feed history, leaderboard and ascension, but the only writer is a manual POST that any user may call for any entity, and no job calls it.
Multiplies
Ascension reads cycle snapshots. Nothing else.
Evidence
Every client hook unwraps a .data envelope the API never sends (useVelocity.ts:70-72 and siblings vs api.ts:59), so the profile always says “No velocity data yet” although /velocity/me answers 200 on the archive · velocityCalculator.ts:193-194 collision count hard-coded 0 · no test
Needs
Delete the unwrap in seven hooks, add a weekly snapshot job, scope the manual snapshot endpoint.
Partial

Ascension

lib/ascensionCalculator.ts · routes/ascension.ts (9) · ascension_records · LevelBadge

“Ascension measures sustained improvement in velocity over time. Formula: A = ΔV / ΔCycle.” Ten levels, Observer to Transcendent; the platform's “Win” is the sum of all positive accelerations.

Flow
Read path works: status, history, leaderboard, rising stars, levels. The only writer is a POST with a user-supplied cycle number that no UI calls, so every user is Observer level 1 forever.
Multiplies
Nothing reads the records outside the module.
Evidence
ascensionCalculator.ts:291-302 default · useCreateAscensionRecord no consumer · cycle lookup orders newest first and subtracts older from newer, inverting the sign for anyone improving (:192-212, :148-154) · AscensionIndicator.tsx orphaned with a second divergent LevelBadge
Needs
Time-derived cycles inside the same worker that writes velocity snapshots; drop the user-supplied cycle; fix the offset direction; keep one LevelBadge.
Broken

Edge taxonomy

lib/edgeTaxonomy.ts (server and client copies) · EdgeDeclaration · users.edge

“The edge system allows players to declare their unique combination of access, expertise, and geography that lets them see things others cannot.”

Flow
Profile's edge tab posts domains, geographies, access types and industries to a self-only PUT validated against the server taxonomy.
Multiplies
Nothing reads the declared edge for logic. Collisions derive domain from templates, not edges; suggestions, facilitator and marketplace never consult it.
Evidence
Hooks unwrap a non-existent .data (useEdge.ts:26,41): the display always says “No edge declared yet” and a successful save shows “Failed to save edge” · the client taxonomy adds eight Garden domains the server rejects with 400 (edgeTaxonomy.ts:57-105 vs users.ts:296-306)
Needs
Remove the unwraps, make the server taxonomy the single source, then give edge a reader such as a weight bonus when a note's domain matches the observer's declared edge.
Partial

AI suggestions

routes/suggestions.ts (12) · lib/aiSuggestionService.ts · ai_suggestions, ai_suggestion_feedback, ai_models

Heuristic suggestion generation, feedback collection, anomaly detection, location clustering and model management, “with a placeholder for future ML integration.”

Flow
Twelve endpoints generate up to five heuristic rows per team (asset-type mode, similar assets, tasks due within three days, popular tags, 500 m clusters), record feedback, flag anomalous days. No language model is called. The page at /suggestions is a “Coming Soon” placeholder; the built four-tab panel is imported by nothing.
Multiplies
Feedback is written and never read; the models table has no insert anywhere so its endpoints always 404.
Evidence
SuggestionsPage.tsx:18-27 · SuggestionPanel.tsx importer grep = 0 · response shapes and type vocabularies differ between panel and API · no team-membership check on generate or list · live archive: /suggestions?teamId=1 answers an empty list
Needs
Decide whether this is a product surface. If so, mount the panel, align shapes, seed models, add membership checks and a daily job. If the facilitator is the real AI, fold the useful heuristics into it and retire these tables.
Partial

Workflows and automation

routes/workflows.ts (11) · lib/workflowEngine.ts · lib/eventDispatcher.ts · workflows, workflow_executions · WorkflowBuilder

“Executes workflow definitions triggered by events, schedules, or manual invocation. Supports action steps, condition branching, and delays.”

Flow
Seven route files and the geofence socket dispatch sixteen event kinds; the engine loads every active workflow, matches the event, records an execution and walks action, condition and delay steps. Actions create tasks, notes, notifications, assignments and outbound webhook calls. Seven templates ship. The page at /workflows is “Coming Soon” and the 1,600-line builder is imported by nothing.
Multiplies
Consumes the whole app's events; its own notes re-enter nothing, since the create-note action skips weight, collision, reputation and memory.
Evidence
Trigger matching ignores tenancy (workflowEngine.ts:652-669): user A's active template fires on user B's note and renders B's content into A's notification · schedule triggers are stored and never scheduled · delay steps only log · send_email is a placeholder · no test
Needs
Scope triggers to the workflow's team before anything else, a scheduler tick, a job table for delays, and route created notes through the note pipeline. Then mount the builder.
Worksarchive: off, no key

AI facilitator for conversations

lib/aiFacilitator.ts · routes/ai.ts (10) · routes/facilitator.ts (9) · extracted_observations, suggested_tasks

“You are a facilitator helping a team capture observations through natural conversation.” Four phases: explore, crystallize, commit, complete. Crystallize extracts template-shaped observations and follow-up tasks as JSON.

Flow
With an Anthropic key the conversation page sends each message to Claude Sonnet, stores the reply as an insight message, and saves extractions and suggested tasks for a review panel where approving an extraction inserts a note and accepting a task inserts a task. Without the key the reply is a canned sentence and the status endpoint says so.
Multiplies
Approved extractions become notes and tasks, which feed memory, activity and projects. But those notes bypass weight, collision, reputation, memory and dispatch, and default to latitude 0, longitude 0 when the model gives no coordinates.
Evidence
Live archive: /ai/status answers “AI facilitation requires ANTHROPIC_API_KEY” · team lookup compares a team id to a project id (aiFacilitator.ts:185-194) · two API surfaces write the same tables, one with access checks on eight of ten routes missing (ai.ts) · extraction needs a conversation template no UI sets · no test
Needs
Keep the checked surface, persist the AI reply there, fix the team lookup, require coordinates or a place before approval, and route approvals through the same pipeline as a hand-written note.
Worksarchive: off, no key

Memory digests

lib/memoryDigestService.ts · lib/memoryDigestWorker.ts · mutual_memory_logs (source ai_digest)

“AI-powered weekly digest of team mutual memory. Synthesizes recent learnings, decisions, and observations into a concise summary.”

Flow
A worker runs every six hours and once after boot; for each team without a digest in the last seven days it sends the last hundred memory rows and the charter to Claude and stores the answer as a high-importance insight tagged weekly-digest. Owners and admins can trigger it by hand. The team memory tab lists it.
Multiplies
Feeds the memory list and the onboarding payload, whose client hook is imported by nothing.
Evidence
index.ts:418 start · memoryDigestService.ts:114-118 silent no-op without key while the worker still iterates every team · tests cover prompt building and parsing
Needs
Render the latest digest for new members, skip the loop when no key is set, and notify the team when a digest lands.
Works

Mutual memory and charter

lib/mutualMemoryService.ts · routes/teams.ts memory and charter endpoints (8) · mutual_memory_logs, teams.charter

“Auto-populates team mutual memory logs from observations, evaluations, and task completions.” The charter holds mission, values, norms and goals; “Context of a team is the management of mutual memory.”

Flow
Members add memories by hand; evaluations, completed tasks and charter edits write rows automatically; the digest worker adds a weekly synthesis. The team detail page has a memory tab with filters and a charter tab for owners and admins.
Multiplies
The digest reads it. The observation edge is dormant: it fires only for templated notes, and only the Garden sets a template, whose route does not call it.
Evidence
evaluations.ts:211, tasks.ts:692, teams.ts:890 writers · mutualMemoryService.ts:126 template guard · builder tests exist, no route test for memory or charter
Needs
Let untemplated notes create low-importance memories, or give the note editor real templates; render the onboarding payload.
Unused

Custom fields and entity types

lib/customFieldsService.ts (909 lines, 17 exports) · custom_field_definitions, custom_field_values, entity_type_definitions

“Manages custom field definitions, entity types, value storage, and validation for team-specific fields.” Fourteen field types, per-team slugs, validation rules, conditional visibility.

Flow
None. No route, no UI, no importer anywhere on either side.
Multiplies
Nothing reads it.
Evidence
importer grep = 0 · index.ts:264-331 mounts no route · the only inserts are inside the service
Needs
A route file and a field renderer inside the asset, task and note editors, or delete the service and three tables.
Partial

Observation templates

lib/templateService.ts · scripts/seedTemplates.ts · observation_templates · NoteTemplateManager

Structured, typed fields per template with an “aiPrompt” per field “for AI to extract this field.” System templates such as “Storefront Observation” for commercial real estate.

Flow
The table is read by eight modules: completeness scoring, collision agreement and domain, AI extraction, observation memory, buyer exports, packages, playback and layers. The only running writer is the Garden bootstrap at boot. The service and the seed script are orphaned, diverging copies, and the note editor's “templates” are a browser-local quick-fill that never sends a template id.
Multiplies
This is the pivot of the whole knowledge layer, and every edge that keys on it is live only for Garden notes.
Evidence
templateService.ts callers = 0 · index.ts:421 Garden template only · NoteEditor.tsx:35-46 local fill · live archive: /garden/template answers the seeded Garden Profile
Needs
A templates route over the service, seed system templates at boot beside the Garden one, delete the stray script, and let the note editor pick a server template and send id plus data. This single change activates completeness, agreement, extraction and memory for ordinary notes.
C

The workspace loop

Teams, projects, conversations, tasks, sessions, evaluations, credits. The February roadmap's “full collaborative workspace.” Most of it works; the credit budget that was meant to make it an economy is columns without writers.

Works

Permission model

lib/access.ts · team_members.role owner, admin, member · users.role user, admin

Every project, task, conversation, session and evaluation permission walks the entity to a team and reads the caller's team role. Notes and assets are user-owned.

Flow
Four helpers resolve team, project, task and polymorphic entity access. The teams route inlines the same query instead of using them.
Multiplies
Root of every check in the loop.
Evidence
access.test.ts covers all four helpers · the owner-sentinel returns team id 0 for notes and assets, which later breaks a memory insert on asset evaluations
Needs
Nothing structural. A per-project role does not exist and may be wanted later.
Works

Teams and invites

routes/teams.ts (22) · routes/invites.ts (3) · teams, team_members, team_invites

“Teams (Mutual Memory Layer).” “Teams let you collaborate with others on projects and tasks.”

Flow
Create, list, detail with members, projects, memory, charter and settings tabs; add, re-role and remove members with last-owner protection; invite by token with a seven-day expiry, copy link or WhatsApp share, public accept page, and an in-app notification carrying the token for existing users. Membership puts a user into the team's socket room, which is what delivers every live event.
Multiplies
Root of permissions, socket fan-out, mutual memory, and the webhook and workflow events for member joined and left.
Evidence
Live archive lists Alpha Team and Data Collectors · the runbook's “undefined existingMember at line 581” is refuted for this tree: line 581 dispatches with a variable declared at 544 · plan member cap is applied on direct add but bypassed by both invite acceptance paths (invites.ts:130-137, teams.ts:1351-1358) · invite e-mail is a TODO, the link is only logged (teams.ts:1231-1234) · onboarding endpoint has no consumer · 727-line route test with mocked database
Needs
Apply the cap in both accept paths, an e-mail provider behind the TODO, and a “start here” panel that renders the onboarding payload.
Partial

Projects and budgets

routes/projects.ts (8) · projects.creditsAllocated, creditsSpent · ProjectDetailPage (1,884 lines, 7 tabs)

Status lifecycle draft, planning, active, paused, completed, archived. “Projects help you organize work within a team.” A project carries a credit budget.

Flow
Dashboard tab with stats, stacked status bar, burndown, contributors and activity; overview, conversations, tasks, budget, data with uploads, notes, export and import, and settings. Creation is capped per plan per team.
Multiplies
Every permission in the loop walks through the project's team. Credit fields feed the return ceiling, export and velocity.
Evidence
Live archive shows 250 of 1,000 and 800 of 2,000 spent, from seed data · projects.creditsSpent has no writer anywhere · creditsAllocated is written only by an API-only PATCH and the return approval; the settings tab has no field although the budget tab tells you to use it (ProjectDetailPage.tsx:780) · project activity is team-wide, not project-filtered · tests cover CRUD, not stats
Needs
Pick the budget model: make allocation write the project and task completion write spend, or drop the two columns and the tab. Add the settings field or fix the copy.
Works

Conversations

routes/conversations.ts (7) · conversations, conversation_messages · ConversationPage (762 lines) · typing sockets

“Conversations (Dialog).” Message types message, observation, question, insight, decision. Phases explore, crystallize, commit, complete are the facilitator's.

Flow
Created inside a project; the page joins a socket room, relays typing with a three-second auto-stop, sends optimistically, dedupes incoming, edits extracted insights, and defaults to facilitated mode with the extraction review panel. Every post notifies every other team member with mention detection.
Multiplies
Suggested tasks link back by conversation id; evaluations may target a conversation; a phase reaching complete triggers an evaluation prompt.
Evidence
Seeded “Feature Prioritization” and “Survey Progress Update” answer on the archive · notification fan-out is awaited per member before the response returns (conversations.ts:425-442) · AI turns posted through the /ai route skip the socket emit · 685-line route test
Needs
Fire-and-forget notifications, or notify mentioned users only; route AI inserts through the room emit.
Works

Tasks

routes/tasks.ts (8) · tasks · TaskDetailPage, TaskKanban, TaskCalendar

Assignee is a user or an agent; each task carries a credit cost, a due date and an optional source conversation.

Flow
Calendar, kanban with optimistic drag and rollback, and list views; detail page with status menu, assignee select, attachments with plan quota, evaluation history and work sessions. Completion writes an activity event, a team memory row, a webhook and workflow event, a notification and a socket update: the densest fan-out in the codebase.
Multiplies
Project stats, burndown and contributors; work sessions; evaluations; integration imports from GitHub, Jira and Linear.
Evidence
Live archive lists five seeded tasks · creditsCost is stored and shown and never charged · dashboard “Add Task” links to /tasks/new, which is not a route, so it renders “Task not found” · reschedule hook never imported · agent assignment is API-only, the selector is disabled · 699-line route test
Needs
Charge the cost on completion or remove the field; fix the dead link; wire calendar drag to reschedule.
Partial

Work sessions

routes/workSessions.ts (5) · work_sessions · workSessionsStore · useEvaluationPrompt

Timed sessions on a task with notes and artifacts, whose completion asks for an evaluation.

Flow
Start flips the task to in progress and refuses a second active session; complete or abandon stamps the end and computes minutes in SQL; completing opens the evaluation prompt. Pause is a status change that never ends the row and resume starts a new one, so every pause leaves an orphan with no duration. The in-session quick notes are local state never sent.
Multiplies
Nothing outside its own route reads the table. Hours are not in project stats, velocity, export or reputation.
Evidence
workSessionsStore.ts:109-118 · TaskDetailPage.tsx:369-378 · seeded active session answers on the archive · 624-line route test; pause and resume untested
Needs
A real resume on the same row with duration across pauses, send the notes, and surface hours in project stats and velocity.
Partial

Evaluations

routes/evaluations.ts (6) · evaluation_logs · EvaluationPrompt, EvaluationsPage, EvaluationDetailPage

“Evaluation Logs (Long-term Memory).” Outcome, score, insights, hypotheses validated, and “Data produced (feeds back to HERE).”

Flow
Three entry points: session completion, a conversation reaching complete, and a manual form that asks for a raw entity id. List, detail and delete work. The one consumer is team memory, which turns each evaluation into an insight row.
Multiplies
Memory and the digest. Reputation does not read evaluations; no reward is triggered; data contributions are stored and never read.
Evidence
Live archive returns one seeded evaluation, outcome success, score 10 · GET /evaluations/search is registered after /:id and always answers 400 · the prompt's slider is 1 to 10 while API and pages treat score as 0 to 100 · asset evaluations pass team id 0 into the memory insert and the FK error is swallowed · “Edit” only closes the menu · 631-line route test
Needs
Register search before the id route, one score scale, and make evaluations feed something economic or reputational as the schema promises.
Partial

Credits

routes/credits.ts (13) · credit_balances, credit_transactions, credit_return_requests · CreditsPage (887 lines)

A balance per user with a ledger of grants, purchases, transfers, project allocations, rewards and returns. “Credits are spent when tasks are completed.”

Flow
Balance and ledger; admin grant and reward; transfer by numeric user id; allocate to a project by numeric id; return requests reviewed by owners and admins; packs bought through Stripe checkout and fulfilled by webhook. Real debits exist only in splats and the marketplace.
Multiplies
Splats and marketplace are the sinks; projects read the budget columns; trade stats aggregate flows.
Evidence
Live archive: balance 500 from a seed grant, no signup grant exists · allocation debits the user and never writes projects.creditsAllocated (credits.ts:281-340), so the returnable amount computes to zero and allocated credits are stranded · two read endpoints have no membership check · transfer and approve are non-transactional · 653-line route test, no return-request test
Needs
Allocation and ledger in one transaction that writes the project, membership checks on the two reads, and a defined spend so spent and reward mean something.
Partial

Activity feed

routes/activity.ts (1) · lib/activityService.ts · activity_events · ActivityFeed, ActivityPage

The schema lists seven core and fifteen build-in-public event types with typed metadata and a confidence column.

Flow
Insert, then a socket event to the team room; the feed refetches every minute and prepends live events with an unread counter. Seven types are actually produced: team, project and task created, task completed, stream started and ended, and a note type reusing the conversation-message label.
Multiplies
Suggestion heuristics count events; export and the public API expose them; project dashboards show a timeline.
Evidence
The feed's filter groups and icon map name twenty types that are never emitted, so the geofence, asset, note and people filters are always empty and the real types render as a generic “Event” (useActivityFeed.ts:32-39, ActivityFeed.tsx:28-180) · no test
Needs
Emit what the UI already draws, or trim the vocabulary to the seven real types.
Works

Notifications and Command Center

routes/notifications.ts (9) · notifications, notification_preferences, push_subscriptions · NotificationCenter, CommandCenterPage

In-app notifications with per-type preferences, push subscriptions, and a Command Center of notifications, messages, activity and preferences.

Flow
Task assigned and status, conversation messages with mentions, team invites with the token, team stream started, credit returns: each inserts a row, checks preferences, and emits to the user; the header bell refetches and the count polls every minute. Clicks route to the entity; invites accept inline.
Multiplies
The only user-facing signal for assignment, invites, returns and DMs.
Evidence
Browser push is a TODO although subscriptions are stored; e-mail is a stored boolean nobody reads · DM and workflow notifications insert directly, bypassing preferences and the socket · credit and DM types have no click route · no route test
Needs
Route every producer through the one create function, implement push with VAPID or remove the subscribe UI, add the missing click routes.
Partial

Messages and direct messages

routes/messages.ts (5, legacy) · routes/dms.ts (7) · messages · dm_conversations, dm_participants, direct_messages · MessagesPage, MessageButton

Two systems: a Command Center message list from February, and person-to-person threads with read receipts and typing.

Flow
Legacy messages can only be posted by a user to themself; nothing else writes them, and the socket helper for them has no callers. DMs find or create a pair thread, page messages, mark read, and count unread; the message button on team members, assignees, leaderboard rows and search opens a thread.
Multiplies
DMs dispatch a webhook and workflow event and insert a notification.
Evidence
The server emits dm:message, dm:read and dm:typing and the client registers no listener for any of them, so a recipient sees new messages only after reload · the page's user search calls /users/search, which does not exist, so it always says “No users found” · no route test for either
Needs
Subscribe to the three events and call the store handlers that already exist, add a user search route, retire the legacy table and tab.
Unused

Agents

routes/agents.ts (5) · agents · AgentsPage, AgentDetailPage, AgentSelector

An agent has an owner, status, device location, capabilities and a personality. The login page's second promise, “Agent Management.”

Flow
Owner-scoped CRUD with a 646-line test. Tasks, sessions and conversation messages accept an agent id with owner checks. The pages say “Coming Soon,” the selector is a disabled select, the store is imported by nothing, and no code reads capabilities or personality or executes anything.
Multiplies
Nothing. Execution would be an external client posting as the owner.
Evidence
AgentsPage.tsx:18-27 · AgentSelector.tsx:19-24 · live archive: two seeded agents exist and /agents answers an empty list for the demo user because they belong to another seed user
Needs
Either an agent UI plus an execution surface such as an agent token that can post sessions and messages, or hide the nav entries.
Works

Dashboard

DashboardPage.tsx · seven GET endpoints

Teams, projects, pending tasks, credit balance, stream hours, reputation, quick actions and recent activity.

Flow
Seven round-trips on load, cached for offline.
Multiplies
Reads only.
Evidence
Renders on the archive as “Good morning, Alice” with 2, 3, 0 and 500 · “Add Task” targets a route that does not exist · activity icons name types nothing emits
Needs
Fix the link; consider one summary endpoint.
Unused

Collaboration sessions and presence

lib/collaborationService.ts (560 lines) · collaboration_sessions, participants, changes · socket presence handlers

“Issue #84 - Real-time Collaboration, CRDT operations.” Sessions, cursors, versioned changes, undo, viewer presence and editing state.

Flow
None. The service is imported by nothing, so the tables are never written; the server's presence handlers and the client's presence emitters and event types exist with no callers or subscribers on either side.
Multiplies
Nothing.
Evidence
importer grep = 0 · socket.ts:289-360 handlers without callers · no test
Needs
Mount presence in the task and conversation pages, one effect away, and expose session routes; or delete the service, tables and handlers.
D

Money, marketplace and platform

Real money enters through Stripe and becomes credits; nothing converts credits back out. The data marketplace is dark by a flag. The developer surface is the app's outbound nervous system, and it leaks across tenants.

Partialarchive: off, no Stripe key

Billing and subscriptions

routes/billing.ts (7) · lib/stripe.ts · lib/subscriptionConfig.ts · middleware/subscription.ts · subscriptions, subscription_events

“Subscription Configuration — single source of truth for all plan parameters.” Free, Pro at 24 dollars, Business at 49; seven-day trial and grace; credit packs at 10, 40 and 70 dollars.

Flow
Pricing page creates a Stripe checkout session; the webhook upserts the subscription and cancels a previous one on upgrade; invoice paid and failed move status; the auth store loads the subscription on login and a feature-gate hook mirrors the limits; the middleware resolves the plan per request and gates streaming destinations, simulcast, scheduling, projects, team size, storage, scene collections and splats.
Multiplies
Seven feature areas read the limits; purchased credits are spent by listings, products and splats.
Evidence
Live archive: /billing/plans and /billing/subscription answer the free plan's limits; checkout would throw without a key · the idempotency row is inserted before handlers run, so a handler failure returns 500 and Stripe's retry hits the duplicate branch: the event is lost (billing.ts:341-358,395-398) · invoice handlers read a field the pinned 2026 API version may not carry · Pro copy says six destinations, config says four · requirePlan() is exported and never used · no test
Needs
Record the event after processing, read the subscription id with a fallback, a signed-fixture webhook test, and decide which flags beyond numeric limits the server should enforce.
Partialarchive: 503 coming soon

Data marketplace listings

routes/marketplace.ts (16) · lib/marketplaceService.ts · marketplace_listings, purchases, listing_reviews, saved_listings · MarketplacePage (948 lines)

“Package your team's observations and earn credits when others purchase.” “Revenue Distributions (50/30/20 split tracking).”

Flow
Behind a server flag and a client flag: build a package, create a listing that needs ten observations at average weight fifty, publish, buy with credits, download the observations as JSON or CSV, review after access. The listing detail shows the team's average reputation.
Multiplies
A purchase triggers the revenue split; the buyer API re-exposes listings. Saved listings are written only by a service nothing imports.
Evidence
Live archive: every listing route answers 503 “Data marketplace is coming soon” · purchase performs five writes with no transaction · the purchase row never sets its package id · three status vocabularies on one column · route tests never set the flag, so they would receive the 503 · 1,000-line service test with a mocked database
Needs
A transaction, one status enum, the flag in test setup, and the product decision the flag defers: the surface was rebuilt around products instead.
Partialarchive: 503 coming soon

Data packages

routes/packages.ts (9) · lib/packageService.ts · data_packages, package_observations · PackageBuilder

“Packaged observations for sale.” Criteria of domain, tags, geography, time range, templates, minimum weight and collisions.

Flow
Create stores criteria and refreshes the junction table from the team's notes at or above minimum weight, then computes count, average weight, a collision proxy and contributor count, with a preview of samples, weight buckets and per-day counts.
Multiplies
Listings, downloads, buyer exports and the contributor split all read the junction table.
Evidence
A team with no member rows and no other filters yields an undefined where clause and the package ingests every note in the database (packageService.ts:246-258,291-293) · rolling refresh has no caller · polygon geography is a bounding box, region is a no-op · collisions filter stored and ignored · no test
Needs
Guard the empty team, a scheduled rolling refresh, real PostGIS containment, and honour the collisions filter against the real table.
Partial

Products and escrow

routes/products.ts (14) · products, escrow_transactions · ProductCard, CreateProductPage, ProductDetailPage

“Items built in public for sale — apps, tools, UI kits, etc.” Escrow “holds funds between purchase and delivery confirmation”; linked stream sessions are “building in public proof.”

Flow
Upload a file and thumbnail, publish, buy with credits into a seven-day escrow, download while held or released, confirm receipt to pay the seller, dispute within the hold, admin resolve. Exclusive sales become sold; project transfer moves a project to the buyer's team.
Multiplies
Attachments, projects, the streaming badge, the credit ledger and a map layer. The revenue split and quality pool apply to data listings only.
Evidence
Live archive: /products answers an empty list · release time is set and read only to reject late disputes, and nothing ever releases: a buyer who never confirms leaves the seller unpaid forever while keeping download access (products.ts:664-665,829-831) · purchase is non-transactional · linked stream ids are never validated · no test
Needs
A scheduled release of held escrows past their date, a transaction around purchase, and a decision on whether products join the revenue split.
Partial

Revenue and payouts

routes/revenue.ts (7) · lib/revenueService.ts · lib/tradeService.ts · revenue_distributions, team_payouts, member_payouts, quality_pools · EarningsDashboard

“50% to producing team / 30% to platform / 20% goes to quality pool.” The pool pays the top twenty contributors by weight each month.

Flow
A listing sale writes a distribution, pays each contributor by their share of package weight, and adds to the monthly pool; an admin endpoint distributes the pool. The earnings tab shows balance and thirty and ninety day breakdowns.
Multiplies
Credit balances everywhere. Distributions and team payouts are written and read by no route.
Evidence
Live archive: /revenue/earnings answers zeros with the 500 seed credits as “lifetime earned,” which conflates bought and earned · the platform's 30% is a number on a row, no account is credited · no cash-out exists anywhere: Stripe appears in one file and has no Connect, transfer or payout · tradeService is imported by nothing and joins teams to users by id · no service test
Needs
A platform ledger account or an explicit burn, scheduled pool and escrow jobs, and a decision on cash-out or a stated non-redeemable policy. Delete or wire the trade service.
Brokenarchive: 503 coming soon

Buyer API

routes/buyerApi.ts (19) · lib/buyerApiService.ts · middleware/apiKeyAuth.ts · api_keys, api_usage_logs, webhooks

“Buyer API (institutional access).” Keys prefixed grf_live with scopes for marketplace read and purchase, data download and query, account and webhooks.

Flow
A bearer key with hourly usage limits can search and preview listings, buy with credits, download or query purchased data with bounding box, time and weight filters, and register webhooks.
Multiplies
A second door onto listings. Its webhook trigger is called by nothing, so buyer webhooks never fire.
Evidence
The router mounts at /data/v1 while every self-link it returns points at /api/v1, which belongs to the developer API with a different key format: every link 404s or 401s (buyerApi.ts:205,361,497 vs :588) · download and query never check the purchase belongs to the key's user, so any download-scoped key pulls any purchase · no test
Needs
One mount prefix, ownership on export and query, call the trigger from purchase and renewal, and merge or namespace the two key systems.
Partial

Developer portal and public API

routes/developer.ts (15) · routes/publicApi.ts (12, /api/v1) · lib/apiKeyService.ts · lib/eventDispatcher.ts · three key middlewares

“External-facing API endpoints authenticated via X-API-Key header. Mirrors key internal routes.” Webhooks are “HTTP POST with HMAC signatures.” The OpenAPI description: “HERE is a living world model that gets richer with every cycle of play.”

Flow
Portal tabs for keys, usage, webhooks, docs and examples; the public API exposes notes, assets, teams and activity; every mutating route in the app dispatches events that deliver signed webhooks and trigger workflows.
Multiplies
The outbound nervous system: notes, assets, teams, tasks, DMs, geofences and the public API all feed it.
Evidence
Live archive: /developer/docs answers the endpoint catalogue · delivery selects every active webhook subscribed to an event with no owner or team filter and posts the full payload, so any developer subscribed to note created receives every user's notes (apiKeyService.ts:536-544) · /api/v1/notes/nearby is shadowed by the id route · docs advertise a playback endpoint that does not exist · the “public docs” exception compares a full path to a short one and never matches · per-key rate limits are ignored for a hard-coded 1,000 an hour · single delivery attempt, no retry · one of the three key middlewares is imported by nothing · no test
Needs
Filter deliveries by the event's owner, fix route order, scope reads to the key owner, honour per-key limits, retries, and generate docs from the router.
Broken

Integrations

routes/integrations.ts (17) · routes/integrationAuth.ts (2) · lib/integrationsService.ts · lib/providers/* (9) · four tables · IntegrationsHub (1,274 lines)

“Manages third-party service integrations including OAuth connections, sync operations, webhook management, and provider metadata.” Slack, GitHub, Jira, Linear, Google Calendar, Google Drive, webhook, Zapier and Dialog providers.

Flow
As designed: the hub navigates to an OAuth start route carrying the session token, the server redirects to the provider, the callback exchanges the code and stores credentials, and a sync writes tasks and entity mappings from GitHub, Jira or Linear.
Multiplies
Mappings link external issues to tasks, notes and projects; syncs write tasks; Slack can send notifications.
Evidence
Live archive: /integrations/providers lists the nine providers · the authenticated router is mounted first on the same prefix and applies the session middleware to every path, so both OAuth routes answer 401 before their handlers run (index.ts:300-302, integrations.ts:71); the authors solved this for streaming with a separate prefix · incoming provider webhooks sit behind the same middleware and skip signature verification · a bare require('crypto') in an ES module throws the first time a secret-bearing webhook fires · the frontend offers Linear OAuth and the server has no Linear case · credentials are stored as plain JSON under a schema comment that says encrypted · the runbook's missing jsonwebtoken claim is false for this tree: the file imports jose, which is a dependency · no test
Needs
Mount the OAuth router under its own prefix before the authenticated one, exempt incoming webhooks and verify HMAC on the raw body, fix the require, add Linear, encrypt credentials, move OAuth state to Redis.
Partial

Security, audit and observability

lib/securityService.ts · lib/auditService.ts · audit_logs, security_events, totp_secrets, ip_allowlists, data_retention_policies · lib/metrics.ts, alerting.ts, sentry.ts · routes/health.ts (3)

“Handles two-factor authentication (TOTP), session management, IP allowlisting, and data retention policies.” “Comprehensive audit logging for all CRUD operations… Audit logs are immutable.”

Flow
What runs: request ids, metrics, security headers and CSP, CORS, a global 100-a-minute IP limiter, error capture to Sentry, health with a database probe and a deduplicated critical alert, detailed metrics behind a session. What is table-only: the whole security and audit layer.
Multiplies
Alerts and metrics are consumed by the worker, sockets and health.
Evidence
Live archive: /health ok, /health/detailed answers uptime and memory · security and audit services are imported by nothing: no 2FA route, no session revocation, no IP enforcement, no retention job, no audit trail · the limiter keys on a forwarded-for header or the string “unknown,” so direct traffic shares one bucket · TOTP secrets would be stored unencrypted · health, metrics and alerting have tests
Needs
Delete the dead layer or wire it: 2FA into login, audit calls in auth, permission, export and key routes, an allowlist check in the middleware, a retention cron, an admin audit view.
E

Media, 3D, The Garden, the CLI and operations

The build-in-public wing, the one feature that shipped clean, and the shell everything runs in. Fourteen tables exist in no migration.

Partialarchive: off, no Cloudflare

Live streaming, “Build in Public”

routes/streaming.ts (29) · lib/mediaRelay.ts, cloudflareStream.ts, platformOAuth.ts, streamCrypto.ts, vodUpload.ts · five tables · BroadcastSettings (1,782 lines), compositor, scene editor, leaderboard

“Go live to multiple platforms simultaneously.” “Browser sends WebM chunks via Socket.io… we pipe them into ffmpeg's stdin, which transcodes to H.264 and pushes out via RTMP directly to destination platforms.” Leaderboard: “Top builders ranked by hours building in public.”

Flow
Destinations by manual key or Twitch and YouTube OAuth, keys encrypted at rest; go live creates a Cloudflare input and simulcast targets and a session row, emits activity, notification and a workflow event; the browser panel records camera or a composited scene and streams chunks to an ffmpeg tee per destination with a local MP4; stop uploads the VOD with quota; clips, scheduling, history, stats, and a public watch link. Live streamers appear on the map with a time slider replay. Encoder mode hands OBS the Cloudflare ingest.
Multiplies
Reputation adds up to 0.15 for streaming hours; the dashboard shows stream hours; a VOD can become a splat input; products link sessions as proof; workflows and notifications fire on start and stop.
Evidence
Live archive: destinations CRUD answers, go-live would 503 · going live requires Cloudflare even on the direct relay that only needs ffmpeg (streaming.ts:258 vs socket.ts:386-436) · public VOD links are returned in three inconsistent forms and none resolves (index.ts:315, streaming.ts:1097, BroadcastSettings.tsx:403,1715) · the scenes API has no client caller, scenes live in local storage · the WHIP path is unreachable because the relay flag is hard-coded · without the key secret, stream keys and OAuth tokens are stored in clear · four streaming tables are in no migration · no test
Needs
Migrations, a Cloudflare gate conditional on encoder mode, one canonical watch URL, either wire scenes to the API or delete it, and a stated requirement for the key secret.
Partialarchive: off, free plan and no GPU

3D Gaussian splats

routes/splats.ts (7) · routes/worker.ts (5) · middleware/workerAuth.ts · splat_jobs · SplatsPage (815 lines), SplatViewer · splat-pipeline/hq-splat-worker/worker.py

“3D Gaussian Splat generation from video.” A GPU VM “polls HERE API for splat jobs and processes them via nerfstudio.” Queued, preprocessing, extracting frames, COLMAP, training, exporting, completed.

Flow
Upload a video up to 500 MB or pick a recorded stream, pay 75 or 200 credits into escrow, insert a queued job; the worker claims one with a locked select, downloads, extracts frames, runs COLMAP and splatfacto, exports a PLY and uploads it; progress reaches the page over a socket; the viewer renders with Spark or Reall3D and the map shows cyan markers filtered by time. Boot resets stuck jobs; failures refund.
Multiplies
Credits, attachments and storage quota, the map, streaming VODs, and a deploy safety check for active jobs.
Evidence
The two sides of the polling contract match line for line · live archive: the page shows “requires the Pro plan” and /splats answers an empty list · no GPU worker exists for the archive, and a queued job waits forever with no “worker last seen” signal and no timeout refund · the in-process placeholder worker is dead code · the table is in no migration · no test
Needs
A worker heartbeat surfaced in health and on the page, a job-age timeout that refunds, a contract test driving the worker's mock mode, and the migration.
Works

The Garden

routes/garden.ts (13) · routes/gardenPublic.ts (2) · lib/gardenService.ts (980 lines) · app/src/garden/** · no new tables

“Finding, indexing, and mapping wonderful people doing wonderful things. A Garden Profile is a note with templateId pointing to the seeded ‘Garden Profile’ observation template. No new DB tables.” “Alfia's command center.”

Flow
Quick add with browser location creates a templated note in discovered state; the workspace lists, searches and filters by domain; a profile page interviews by creating a conversation in an auto-provisioned “Garden Interviews” project, tracks publications, flips status to interviewed then published, and manages production tasks that are real task rows; hubs cluster profiles into emerging cities; collision stories narrate agreement; a public page lists published profiles for anyone.
Multiplies
Everything a note gets for free: weight, collisions, geocoded place names, gold map markers, conversations, tasks, projects, teams and reputation. The one feature that inherited the whole substrate.
Evidence
Live archive: template seeded, zero profiles, public list answers · collision story cards link to a collision id where a note id is expected, opening the wrong profile · hub links pass coordinates the map page ignores · the collision panel is empty until the map has set the template id · no ownership check on status, publication or task mutations · the complete-interview endpoint has no UI · the repo contains no retro on it · no test
Needs
Fix the two link defects, resolve the template id inside the module, add owner checks on mutations, wire complete-interview to the conversation.
Broken

HERE CLI and the build-in-public epic

packages/here-cli (1,206 lines) · BUILD_IN_PUBLIC_EPIC_SUMMARY.md and four sibling docs · migration 0002

“Broadcast your development activity in real-time. Build in public, get discovered, create value.” The epic claimed eight issues complete, an estimated value of 80 to 120 thousand dollars, and “READY TO SHIP.”

Flow
Git hooks post every commit and watched file change to an activity endpoint with a confidence score, queue on failure and retry five times.
Multiplies
Would feed the activity feed, public API and export.
Evidence
The CLI posts to POST /activity; the activity route defines only GET, so every event 404s and is discarded after five retries · the epic's morphism marketplace, aggregation tiles, broadcast config, vision capture and confidence module are absent from the tree; survivors are seven dead tables in migration 0002, a confidence column defaulting to 0.8, comments, and five documents still describing it as shipped
Needs
Add the POST or retire the package; update or delete the five documents; a forward migration dropping the dead tables.
Unused

Rust component

rust/ (46 lines)

“Performance-critical components for HERE.” The README's “Rust + Python on GPU VM (Gaussian splatting).”

Flow
Prints “HERE Core initialized.” Nothing imports, spawns or builds it; the splat worker is Python.
Multiplies
Nothing.
Evidence
rust/src/lib.rs:5-8 · only referenced by a disabled release workflow and dependabot
Needs
Delete it and the README lines, or give it a job.
Partial

Operations shell

app/server/src/index.ts · lib/backgroundWorker.ts · db/migrate.ts · drizzle/ · docker-compose.yml · scripts/deploy-gcp.sh · .github/workflows (all disabled)

One Node process: Hono API, Socket.io, in-process workers for normalization, digests, session and job recovery, graceful shutdown, migrations on boot. Deploy validates, builds images, pushes, restarts and health-checks.

Flow
Boot validates env, applies middleware in order, mounts 46 routers, bridges Node's server to the app, runs migrations, listens, then starts workers and recovery. Deploy refuses a dirty tree, lints, typechecks and builds, then pulls and restarts on the VM.
Multiplies
Everything.
Evidence
Fourteen schema tables exist in no migration, including subscriptions, so on a migration-provisioned database the subscription middleware 500s every streaming, scenes and splats request; only a manual push creates them, which the archive runbook had to discover · a stray migration file is on disk but not journaled · the Stripe customer column is in no migration · deploy runs no tests and no migration step · all CI workflows are disabled and the pre-push hook runs no tests · every request body is buffered whole in memory, including 500 MB uploads · the operations doc describes Fly.io while deploy targets GCP
Needs
Regenerate migrations from the schema and journal or delete the stray file, run tests in deploy and pre-push, stream bodies with the server adapter already in dependencies, rewrite the operations doc.
Partial

Tests

27 server files · 20 client files · vitest

Route tests over mocked database chains and mocked auth; service tests over pure functions; store tests over mocked fetch.

Flow
No test touches Postgres, a socket, or a side effect. The “integration” tests mount real routers over mocked drizzle chains.
Multiplies
Confidence in the loop's contracts: teams, projects, tasks, sessions, evaluations, credits, conversations, agents, assets, users, auth, access, marketplace routes and service.
Evidence
Zero tests for streaming, scenes, splats, worker auth, Garden, CLI, billing, integrations, developer and public API, notifications, activity, DMs, collisions, workflows, subscription gating, the boot sequence or migrations · marketplace route tests never set the flag that would gate them
Needs
A database-backed test lane, and coverage where the money and the media are.

What works, what needs a decision, what needs building

Three lists, in the order a reader would act on them. “Works definitively” means the running archive answers today under the demo account and the code path is whole.

Works definitively

answers today, wired end to end

  • Sign in, session, sign out through the demo door; the token, session row and socket handshake all verify.
  • The map: viewport queries, ten layers, clustering, presence broadcast, own trail and team time travel, while you stay on the page.
  • Notes: create on the map, nearby by PostGIS, edit, delete, geocode, list and assign to a project.
  • Teams, invites, conversations with live typing, tasks with kanban and calendar, notifications: the whole human loop, with route tests behind it.
  • Weight and reputation for notes written through the editor, shown on profile, dashboard and team lists.
  • Mutual memory and the charter, written by evaluations, task completions and hands.
  • The Garden: a profile is a note, so it inherited the map, weight, collisions, conversations and tasks for free. The one feature that shipped clean.
  • Export and import of assets, tasks, activity and project reports; attachments with plan quota; health, metrics and alerting.
  • Whole in code, dark in the archive: the AI facilitator and weekly digests (Anthropic key), Stripe checkout and webhooks, streaming destinations and the relay (Cloudflare key), the splat worker contract (GPU VM).

Needs planning

decisions the code cannot make

  1. Which confidence model is the product: the doc's per-observation calculator or the code's per-area aggregate. Neither runs.
  2. Templates as product: the whole knowledge layer keys on a template id only the Garden sets. Decide the first three system templates and the editor that asks for them.
  3. The credit loop: does allocation write the project, does task completion spend, does evaluation reward, and does anything ever cash out. Today credits enter and never leave.
  4. Listings or products: the data marketplace is dark by flag and its route tests would fail the gate; products shipped instead but bypass the revenue split.
  5. Who sees whom: every user's last position is visible to every user, and every developer webhook receives every tenant's events. Both need a stated policy before a fix.
  6. Agents: full CRUD, “Coming Soon” pages, nothing that runs one. Ship an execution surface or hide the nav.
  7. Offline and mobile: a queue nothing fills, a cache nothing reads, three server tables nothing touches.
  8. Delete or wire the nine orphaned services: confidence, custom fields, collaboration, layers, mobile, trajectory, playback, historical playback, trade, security and audit. Roughly 8,000 lines with zero importers.

Needs building

engineering, ordered by leverage

  1. Templates route and editor sending id and data. One change activates completeness, agreement, extraction and observation memory.
  2. Verification from collisions: replace the constant in calculateVerification and re-weight the group. Lights weight, reputation, velocity and confidence.
  3. One after-note-written hook for the four writers that bypass scoring: public API, both facilitator paths, workflow actions.
  4. Reference-count the socket so leaving the map does not end realtime; validate location payloads.
  5. Migrations for the fourteen unmigrated tables and the Stripe customer column; journal or delete the stray 4D file; run tests in deploy.
  6. Tenancy: filter webhook delivery by event owner, scope workflow triggers to their team, add membership checks to location history, credit reads, normalization and the buyer API.
  7. Mount order: the integrations OAuth router before the authenticated one on its own prefix; exempt incoming provider webhooks.
  8. A scheduler for escrow release, quality pool, velocity snapshots, rolling packages and workflow schedules. None of the five runs today.
  9. The one-line client fixes: the .data unwraps in velocity and edge hooks, /tasks/new, /users/me, the search dialog's /map, the Garden collision link, route order for evaluations search, notes nearby and entity mappings.
  10. Privacy plumbing: re-link note photos off id 0, serve SVG as attachment, a server-side sharing-off, and a clear-my-location endpoint. The demo's own trail holds a visitor's real Prague coordinates.

Method and limits

Five readers each traced one domain in the exact tree the archive serves, exported from the box by commit hash, and were required to cite a file and line for every status; their reports total about 1,500 lines and I read all of them and re-checked the thirteen claims that carry the most weight, including the two “deliberately unfixed” defects in the archive runbook, which turn out to describe the 03-04 tree and are absent from 03-10. In parallel I probed sixty GET endpoints of the running archive under the demo token and walked fifteen screens.

MeasureValue
Source read133,402 lines of TypeScript, 525 files, plus Python worker, Rust crate, CLI, docs
Routes, tables, pages50 route files · 95 schema tables · 42 pages · 43 hooks · 18 stores
Tests47 files; every server test mocks the database; none touch media, billing, integrations or the boot path
Live probes60 GET endpoints; all mounted routes answer as coded; AI off, marketplace 503, free plan limits
Not doneNo test suite was executed; no write was made to the public demo; the archive copy lacks the Vite config, nginx and Dockerfiles

The five domain reports behind this page are held by the author and available on request. Statuses are mine where readers disagreed with themselves; a feature that renders and answers but severs a promised edge is marked Works with the defect named, so the ledger counts what a visitor can use, not what the schema hoped.