feat(app-factory): P1 backend data layer + @nuncio/contracts - #1
Open
oscarlehuu wants to merge 11 commits into
Open
feat(app-factory): P1 backend data layer + @nuncio/contracts#1oscarlehuu wants to merge 11 commits into
oscarlehuu wants to merge 11 commits into
Conversation
Repo-wide bun fmt run reformatted these pre-existing files (markdown tables, HTML). No content changes. Co-authored-by: Cursor <cursoragent@cursor.com>
App Factory research-tool backend, built TDD-first: - @nuncio/contracts (new package): App Factory domain schemas, RPC inputs/results and typed errors. @synara/contracts re-exports it, so existing imports are unchanged; WS_METHODS, request-body union and RPC group registrations stay in Synara ground as the shared socket registry. - Migration 088: af_apps, af_app_revenue, af_videos, af_screens, af_watchlist, af_sync_runs, af_state + indexes. - AppFactoryRepository: catalog/revenue/media/watchlist persistence, sync-run lifecycle, state KV. json_each for large NOT-IN sets. - ScreensdesignClient: bearer auth via ServerSecretStore (screensdesign.api-token), typed error taxonomy (401/403/404/429), Retry-After-aware rate-limit backoff, lenient wire schemas with string-number coercion. - CatalogSync: full/incremental sync with cursor resume, single-flight, crash recovery; resumed full syncs skip removed-marking; 401 mid-sync ends the run as token_invalid with local data intact; refreshApp re-mirrors one app (404 -> removed flag, revenue preserved). - AppFactoryService facade + 12 WS RPCs: token lifecycle (account email/ isPro cached in af_state), status with live sync progress, list/detail, pin/note. Videos/screens mirrored lazily on first detail view, then cache-forever in SQLite. Tests: 53 scoped (contracts, repository edge cases, client error paths from real API fixtures, sync modes incl. resume/single-flight, service facade). Full server suite 2996 green. Migration tracker expectations updated for entry 88. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot review findings, each with regression coverage: - Catalog syncs wiped detail columns: list payloads lack description/ appstoreLink/storeId/categoryPrimary/latestAppobvideoId, and the upsert overwrote them with null on every run. Syncs now use upsertCatalogApp, which COALESCEs detail-only columns on conflict; refreshApp keeps the full-overwrite upsert. - getAppDetail built the response from a stale in-memory row, so the first detail view still showed null description/link after the lazy refresh wrote them. The row is re-read after refresh. - Lazy refresh keyed off "no videos" skipped apps without recordings forever. Migration 89 adds af_apps.detail_fetched_at (guarded ALTER, replay-safe); refreshApp stamps it, getAppDetail triggers on it. - Token RPCs were unauthenticated-mutation: setToken/clearToken now requireOwner like other secret-management RPCs. - getAppDetail without a token no longer errors on upstream calls: it serves the local cache (screens stay null per contract), zero fetches. - Documented the empty-catalog removal guard: an empty seen-set is a no-op so an anomalous empty upstream page can't mass-mark removals. Tracker expectations updated for migration 89. Suites: repository 14, CatalogSync 9, service 10, migrations 19, scoped total 195 green. Co-authored-by: Cursor <cursoragent@cursor.com>
The turn-resilience checkpoints landed the compaction_start handler and the extended PiSessionContext interface but lost two pieces, breaking typecheck on main (CI red since): - piCompactionTitle helper (reason-aware compaction titles), restored verbatim from checkpoint 2dab4881. - PiSessionContext construction was missing activeTurn, pendingTurnOutcome, turnWatchdog, turnActivityAt. Co-authored-by: Cursor <cursoragent@cursor.com>
Main moved to @nuncio/* identity and upstream v0.6.3 while App Factory P1 was in flight. This merge: - Folds App Factory schemas into the rebranded @nuncio/contracts (packages/contracts/src/appFactory.ts); deletes packages/nuncio-contracts. - Renumbers App Factory migrations to 089/090 (088 taken by ExternalMcpAudienceIdentity); 090 made idempotent for lineage replays. - Renames remaining @synara/contracts imports and synara/ service tags. - Fixes pre-existing main breakage that kept CI red: PiAdapter typecheck (piCompactionTitle + PiSessionContext fields), release-smoke bin expectation (ade alias), 035 test import, ACP log redactor entry names (both identities), TOML escape fixtures, 077 fresh-install audience, web store tests (vitest setup installs in-memory localStorage over Node's unbacked global). Gate: fmt/lint/typecheck/brand:check clean; full tests 8/8 workspaces. Co-authored-by: Cursor <cursoragent@cursor.com>
Node unit tests need an in-memory localStorage before zustand persist resolves storage at import time. Browser mode already has real localStorage — clear setupFiles inheritance in the browser config and only install the stub when globalThis.localStorage is undefined, so Chromium runs are not redefined by the node stub. Co-authored-by: Cursor <cursoragent@cursor.com>
Importing defineConfig from vitest/config pulled the vitest graph into the shared Vite config that browser mode merges. CI then hung for the full 20m timeout at "[optimizer] bundling dependencies...". Restore the vite import and type the test.setupFiles field via a vitest/config triple-slash reference instead. Co-authored-by: Cursor <cursoragent@cursor.com>
Fail-fast local gate matching the Ubuntu quality job order (brand → fmt → lint → typecheck → migrations → smoke → tests → optional browser/build). Use ci:local:fast while iterating, ci:local before push, ci:local:web when touching web/vite/vitest. Co-authored-by: Cursor <cursoragent@cursor.com>
Add docs/CI-LOCAL.md (tiers, GitHub step mapping, hang signals, cheat-sheet), point Living Docs + Dev Workflow + Task Completion at it, note in STATE and DECISIONS so future agents discover the pre-push gate. Co-authored-by: Cursor <cursoragent@cursor.com>
Browser tests merge vite.config and were hanging 20m at dependency optimize whenever node setupFiles lived there. Move the localStorage stub into apps/web/vitest.config.ts (unit tests only); vite.config.ts matches main again. Includes pending ci:local script + agent docs. Co-authored-by: Cursor <cursoragent@cursor.com>
brand: check flags non-exempt docs; rephrase as upstream-inherited quality gate. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
App Factory P1 backend (TDD-first): mirror the screensdesign catalog into local SQLite, keep it fresh, and expose 12 typed WS RPCs — foundation for the App Factory sidebar (web UI in P2).
@nuncio/contracts(first@nuncio/*package): App Factory domain schemas, RPC inputs/results, typed errors.@synara/contractsre-exports it — existing imports unchanged.af_apps,af_app_revenue,af_videos,af_screens,af_watchlist,af_sync_runs,af_state;detail_fetched_atfor lazy-detail tracking.refreshAppdata.ServerSecretStore, typed errors (401/403/404/429), Retry-After backoff, lenient wire schemas (string-number coercion).token_invalidwith local data intact.requireOwnerfor set/clear), status with live progress, list/detail, pin/note. Detail view lazily mirrors detail+videos+screens on first view, then cache-forever; without a token it serves local cache.Test plan
bun fmt,bun lintclean;bun typecheckat baseline (2 pre-existing PiAdapter errors)Review notes
Bugbot review run on this branch; 6 findings addressed in
002da083(2 high: detail-field wipe on sync, stale row in detail response; 4 medium: no-video lazy gap, empty-catalog guard docs, owner gate, token-less detail view).Made with Cursor