c-ashud-asga-collector-dbahu-nqwi-af

Website source and local backups — October 22, 2026

Active task: apply the user’s clarification: GitHub is the private source repository intended to feed the website; local files are the backup. This entry supersedes the earlier backup terminology below. The application milestone remains unchanged. Website hosting connection and Supabase configuration remain deferred.

Implemented

Updated AGENTS.md, README and GITHUB_SYNC to distinguish website-source synchronization from local recovery copies. Added ignored .local-backups/, preserving dated source archives, standalone Git bundles and checksum manifests on this computer. The ACTIVE hourly automation was updated in place with the same ID/schedule: verify a local snapshot before a pull and before a push; push only completed, reviewed work with applicable verification evidence. Unfinished/unverified edits stay local. Existing Git history and private visibility are preserved.

Tested

Unverified

First unattended execution, a real incoming remote change and website hosting/deployment linkage remain unverified. Local copies cover committed project files/history; uncommitted edits remain in the working folder, and secrets, ignored runtime files, Supabase records and private media are outside the archives. Same-disk copies do not protect against loss of the computer/disk. Application checks were not rerun because application code, migrations and dependencies were unchanged.

Deferred / next remaining task

Website hosting connection, Supabase/cloud configuration, data/media backup, separate-device backup and founder-journal backfill remain separately scoped work. No automatic continuation to an application milestone. Review the first unattended local-backup/sync run.


Historical: initial GitHub upload and automatic sync — October 22, 2026

Active task: source/documentation backup and safe automatic Git synchronization. The application milestone remains the owner-profile/adaptive-quiz scope documented below. User explicitly authorized automatic pushes/pulls, confirmed the repository is private, and deferred Supabase configuration.

Implemented

Created and pushed the first source/history checkpoint, 3f0072562767b2d43540f0da754dea85262ef39d (160 files), through the existing GitHub Desktop sign-in. Retained origin, main, origin/main and local pull.ff=only. Created the ACTIVE hourly scheduled check Sync Contact Collector to GitHub (sync-contact-collector-to-github) and viewed its registered automation card. Added standing sync authorization to AGENTS.md, linked setup from README, and documented the safe hourly procedure in GITHUB_SYNC. No application code, migrations, credentials or saved data were changed by this task.

Tested

Initial candidate and staged-content scans found no known secret-pattern matches; git check-ignore .env.local node_modules/ .next/ test-results/ playwright-report/ confirmed those five exclusions. GitHub Desktop reported push complete; git rev-parse HEAD and git rev-parse refs/remotes/origin/main matched the first checkpoint. git status --short --branch was clean after the initial push. git diff --check passed for the sync documentation. Full command evidence and authentication limitations are in GITHUB_SYNC.md.

Unverified

Unattended scheduled execution and an actual incoming remote change have not yet been exercised. Command-line Git has no HTTPS login and the GitHub plugin returns 404; GitHub Desktop is the verified transport. Application tests/build/browser checks were not rerun for this Git/documentation-only change; earlier results below retain their original scope.

Deferred / next remaining task

Supabase/cloud configuration and database/media backup are deferred by the user. Founder-journal backfill, deployment and subsequent application milestones remain outside this sync task. Monitor the first scheduled sync for any access or concurrency issue.


My profile, invited-account setup and adaptive Find someone — October 22, 2026

Active scope: the latest approved owner-profile/onboarding/quiz prompt and supplied blue-button design reference, built on the completed Settings, plain-English, expanded-contact-profile and Contacts-folder work. Local production preview: http://127.0.0.1:3002, build .next-owner-quiz. Existing uncommitted files, credentials and saved libraries were preserved. No commit, push, deployment, live paid call or external integration was activated.

Implemented

Tested

All data is synthetic and account-isolated; AI regression tests use isolated fake providers only.

Command/check Result
npx supabase migration up --local Applied 018–019 without database reset
npm test 111 passed, including 25 new quiz checks
npm run typecheck Passed
npm run lint Passed, no warnings
CONTACT_RECALL_DIST_DIR=.next-owner-quiz npm run build Passed; production routes generated
npm run test:owner 10 passed, real local Auth/RLS/RPC/storage
npm run test:integration 21 passed
npm run test:profile 7 passed
npm run test:enrichment 22 passed, including final standalone confirmation
npm run test:folders 5 passed
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npm run test:e2e 31 passed in Chromium
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npx playwright test tests/browser/owner-quiz.spec.ts 3 passed after extending every binary/three-choice button to text, top-padding and bottom-padding activation checks
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npx playwright test tests/browser/owner-quiz.spec.ts -g 'approved answer rectangles' 1 passed after adding single-person recognition and two-step Prev. recovery to the complete hit-area checks
WebKit: PLAYWRIGHT_BROWSER=webkit PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npx playwright test tests/browser/owner-quiz.spec.ts --output=/tmp/collector-owner-webkit-results Could not run: installed WebKit protocol mismatch (Unknown setting: PushAPIEnabled) during page setup; remaining checks stopped
npm run benchmark Completed with synthetic 8/2,000-contact pools; pre-ranked 2,000-contact question selection median 22.65 ms, p95 33.95 ms on this machine

Initial browser runs identified outdated menu/question selectors and a test needing explicit snapshot refresh. The photo retry test now drops a successful browser response after a real upload, preserving binary file data. One enrichment run concurrent with other suites failed; the standalone rerun passed all 22. All 65 backend checks passed in the final sequential run. Run worker/queue suites sequentially because they share local infrastructure. These observations are not evidence of live provider operation.

Visual evidence inspected: test-results/adaptive-common-1440.png, adaptive-thirds-1440.png, adaptive-dark-compact-390.png, owner-profile-1440.png and owner-profile-390.png. These use fictional records/photos and are ignored test artifacts; each browser invocation regenerates its screenshots and clears earlier default output. The supplied reference was available and used for the teal question bar, dark borders, rounded rectangles and spacing.

Unverified and known limits

Deferred / next remaining task

The requested scope is implemented. Desktop and narrow dark/compact screenshots were inspected, and the full Chromium suite passes. No automatic continuation to another milestone. Public signup/OAuth, contact-only exports/account deletion infrastructure, notifications/events, live providers and hosted rollout remain separately authorized future work. Existing invitation and account-security behavior is unchanged.


Historical implementation record

Contacts folder design — October 22, 2026

Active scope: the approved Contacts folder view, creation and membership workflows, on top of the existing Settings, plain-English and expanded-profile changes. Preview: http://127.0.0.1:3002, production build .next-folders. Older preview ports, existing uncommitted work, credentials and saved libraries were preserved. No commits, pushes, resets, deployment, live paid calls or external service activation.

Implemented

Tested

All fixtures are fictional and account-isolated. AI regression tests use fake providers only.

Command/check Result
npx supabase migration up --local Applied 016, then 017 successfully; no reset or data-rewriting migration statements.
npm test 86/86 passed, eight files, 401 ms. Includes paths, overlap deduplication, independent parent/child membership, search scope and equivalence with existing smart-group predicates.
npm run test:folders 5/5 passed, real local backend, 1,069.49 ms. Covers sibling naming, cycles, cross-owner reads/writes, atomic/idempotent additions, unchanged sources, revisions, identical-email non-merging, smart-group restrictions and capacity.
npm run test:integration 21/21 passed, real local authorization/organization regressions, 1,500.95 ms.
npm run test:profile 7/7 passed, local backend profile/source/review/revision regressions, 1,149.80 ms.
npm run test:enrichment 22/22 passed, local fake-provider and Settings enforcement regressions, 2,252.21 ms.
npm run typecheck Passed, exit 0.
npm run lint Passed, exit 0.
APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-folders npm run build Passed, exit 0; homepage and ten API routes.
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npm run test:e2e Chromium 28/28 passed, 48.6 seconds against the final production build.
npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'tests/**/*.ts' Passed.
Visual checks Desktop 1440×900, narrow 390 px and dark/compact folder captures inspected. No horizontal overflow in automated narrow checks; keyboard focus and row/parent selection are tested.

The four new browser scenarios cover the requested 15 folder cases plus same-origin/account privacy and a 501-contact/501-subgroup fixture that crosses the existing 500-row paging boundary. The folder total is 501, not 502, when one person has overlapping child memberships. The last page remains searchable and direct-only filtering leaves totals intact. Existing browser suites exercise imports, cue sources, pending photos, profile edits, explicit combining/undo, Settings, recognition, failed loading and focus recovery.

Intermediate runs found obsolete grid/filter selectors, ambiguous breadcrumb/navigation accessible names, and a keyboard-focus check that had switched to pointer input. Those were corrected without weakening privacy/data assertions. Review also corrected the row explanation for a rule-based descendant and made narrow-screen heading focus avoid the adjacent photo. The first full suite passed 25/28; the next passed 27/28 with one remaining old renamed-group selector. The focused corrected group test then passed. Final results are above.

After final suite cleanup, no temporary folder/browser test accounts remained.

Screenshots are generated in ignored test-results/: folders-desktop.png, folders-narrow.png, folders-dark.png. They contain synthetic fixtures only. The source snapshot taken before editing is outside the repository at /tmp/collector-before-folders.tar.gz; it is not a database backup or substitute for production backup procedures.

Unverified / limitations

Deferred / next task

Drag-and-drop, new deletion workflows, persistence of folder navigation preferences, larger-scale architecture, integrations and future product milestones remain outside scope. Other installations must apply migrations through 017 and rebuild without resetting saved data. Next task: user review of the local Contacts folder view; no automatic continuation to another milestone.


Expanded contact profile — October 22, 2026

Active scope: the approved contact-profile redesign, on top of Settings and plain-English updates. Local preview: http://127.0.0.1:3002, production build .next-profile. Earlier preview ports, existing credentials, uncommitted work and saved contact data were preserved. No commits, pushes, deployment, messages, live paid calls or external service activation.

Implemented

Tested

All fixtures are fictional and account-isolated. AI tests use isolated fake adapters; no live provider was invoked.

Command/check Result
node --env-file=.env.local --import tsx tests/profile-migration.ts seed, migration 013, then ... verify Passed original-row/column hashes and counts across 13 tables, including a rich old-schema fixture; isolated fixture and temporary snapshot removed.
npx supabase migration up --local Applied 013, 014 and 015 successfully without resets.
npm test 80/80 passed, seven files; final unit run 304 ms.
npm run test:profile 7/7 passed, local backend, 1,563.93 ms. Includes every approved choice, source preservation, direct-RPC validation, ownership/revisions and combine/undo.
npm run test:integration 21/21 passed, local authorization/organization regression suite, 1,431 ms.
npm run test:enrichment 22/22 passed, local fake-provider regression suite, 2,111.31 ms. Includes completed-job contact deletion and Settings enforcement.
npm run typecheck Passed, exit 0.
npm run lint Passed, exit 0.
APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-profile npm run build Passed, exit 0; homepage and ten API routes.
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npm run test:e2e Chromium 24/24 passed, 34.9 seconds against the final production build.
Formatting / rendered inspection Prettier check passed for app/components/lib/tests. Inspected final desktop, 390 px narrow, and dark compact screenshots; no horizontal overflow.

Intermediate verification caught dropdown/textarea test-label assumptions, an affiliation-order test assumption, an older accessory-quiz expectation, a cascade-deletion foreign-key failure, blank partial-date display, and Escape propagating from the nested editor into its parent profile. The code defects were corrected with regression coverage. No privacy, preservation or review-state assertions were removed to obtain passing results. Synthetic accounts left by the initial failed cleanup were explicitly removed by their exact test identifiers after the deletion fix.

Screenshots: test-results/profile-desktop.png, test-results/profile-narrow.png, test-results/profile-dark-compact.png (synthetic fixtures; generated by the profile browser test). The existing database remained at its pre-change aggregate counts after isolated test cleanup; original-column hash verification, not aggregate counts alone, established migration preservation.

Unverified / limitations

Deferred / next task

No new export, account-deletion UI, skills/attachments service, cover-image service, notifications, event system, OAuth/sync, social scraping, messaging or audio identification. Apply migrations through 015 and rebuild on another installation before using the new fields. The next task is user review of the local profile; no automatic continuation to another milestone.


Plain-English interface — October 22, 2026

Active scope: the approved interface wording request on top of Settings and milestone 4. The current production preview is http://127.0.0.1:3002, served from .next-plain-english. Only the prior preview on port 3002 was restarted; older ports were left alone. Existing uncommitted files, credentials, database structure and saved content were preserved. No commit, push, deployment, paid request or external integration was performed.

Implemented

Tested

All tests used fictional local accounts. AI tests use isolated test adapters/mocked transport; no live provider was called.

Command/check Final result
npm test 71/71 passed, six files, final run 304 ms. Includes separate uncertainty states, recovery/ranking, safe error text, and lost/unreadable responses.
npm run test:integration 21/21 passed against the local backend; account isolation, organization, import and combination integrity.
npm run test:enrichment 21/21 passed against the local backend; permission/budget gates, source retention, review states and isolated worker behavior.
npm run typecheck Passed, exit 0.
npm run lint Passed, exit 0.
APP_ORIGIN=http://127.0.0.1:3002 CONTACT_RECALL_DIST_DIR=.next-plain-english npm run build Passed, exit 0; production homepage and ten API routes.
PLAYWRIGHT_BASE_URL=http://127.0.0.1:3002 npm run test:e2e Chromium 21/21 passed, 30.2 seconds. Includes persistence/reload, two-account privacy, Settings failures, original notes, pending photos, combines/undo, imports, keyboard use and recovery.
npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'tests/**/*.ts' Passed after formatting the updated test selectors.
Visual inspection Inspected final desktop contact editor and Review details, plus Find someone and Settings at desktop/narrow widths. Tests assert no horizontal overflow at 390 px. Screenshots are local synthetic fixtures; the Review details error example is explicitly mocked/labeled as a test.

Initial/intermediate runs caught obsolete test text, ambiguous selectors and a display-label/value mismatch in the workplace status selector. These were corrected; the final browser suite checks the saved former value both before saving and after reopening. A subsequent unit assertion was updated for the final duplicate-context explanation. No assertions about privacy, review gates or saved content were removed to obtain a passing result.

Unverified / limitations

Deferred / setup

No database migration or new dependency is needed for this wording change. Rebuild/restart the app using the existing environment. Settings migration 012 remains the existing prerequisite. Notifications, synchronization, export, later milestones and live paid-service validation remain deferred. No Git history changes were made; the existing origin still points to the requested MonkMonay repository.

Next remaining task: user review of the local preview and any requested wording adjustments. No automatic continuation to another milestone.


Settings implementation — October 22, 2026

Active scope: dedicated Settings tab only, on top of the existing milestone-4 application. Existing uncommitted project files and architecture were preserved. No deployment, commit/push, provider activation, paid call, reset or external integration was performed.

Implemented

Inventory and relocation

Preference/control New location and status Migration/default
Theme: Light/Dark/System Settings → Appearance; functional shared tokens and live system-media changes New; Light preserves prior behavior
Compact layout Settings → Appearance; functional navigation, list, card and review spacing New; off
Show explanatory tips Settings → Appearance; functional optional Improve explainer New; on; essential warnings/errors/review labels stay visible
Automatic memory cues Settings → Automation & AI; functional server-enforced auto_notes Moved from Improve; existing value retained, otherwise true behind permission/mode/budget gates
Automatic photo analysis Settings → Automation & AI; functional server-enforced auto_photos Moved from Improve; existing value retained, otherwise true behind permission/mode/budget gates
Automatic group suggestions Settings → Automation & AI; functional deterministic suggestions in Organize groups New switch, prior behavior on; rules/manual groups unaffected
Duplicate suggestions Settings → Automation & AI; functional proactive comparisons in Improve New switch, prior behavior on; manual comparison, decisions, merge approval/undo preserved
Paid AI processing permission Settings → Automation & AI; functional existing account policy Relabeled/moved from Improve; existing value retained, new accounts off; enabling requires explicit budget consent
Automatic budget approval and usage ledger Settings → Account & Data (approval form in Automation & AI) Moved from Improve; existing budgets retained
Account details Settings → Account & Data; authenticated email Existing identity reused; sign-out stays in header
Contacts grid/list; Identify scope and answers; contact manual/assisted mode; priorities; group pins/rules; import selections; cue pins; selected bulk budget; individual review/merge decisions Contextual controls retained in Contacts/Identify/Improve and dialogs No new persistence or relocation; these are view/workflow/record-specific, not global preferences

Tested

Unverified / limitations

Deferred

Notifications & Reminders: follow-up master permission, browser/email delivery and post-event debrief prompts. Integrations: Google/Microsoft Contacts automatic two-way sync, connected accounts and upcoming-event suggestions. Account & Data: export and unsupported account-management actions. These have no functioning infrastructure in the current app and no misleading controls were added. The intended categories are recorded in PRODUCT_SPEC §18.

Next task: user review of Settings and any requested adjustments. No automatic progression to another milestone. Setup: apply migration 012 and rebuild/restart as documented in README. Local Settings preview uses http://127.0.0.1:3002; older app ports were left alone.


Build status — Contact Recall

Current scope/date: milestone 4 only, October 22, 2026. Implementation, fixes and available local validation are complete. Chromium and Firefox pass; WebKit is blocked by an installed-engine protocol incompatibility, and the dependency audit is blocked by the registry. No Prepare, practice, Follow-ups, scraping, discovery or synchronization was added. The historical milestone-1/2/3 evidence follows this current record.

Runtime and preservation

Read the pasted milestone-4 request, AGENTS, full PRODUCT_SPEC, TECHNICAL_DESIGN, MILESTONES, ACCEPTANCE_TESTS, BUILD_STATUS and prompt 04. Inspected actual source, migrations, backend and browser behavior. Git still has no tracked project baseline; no reset/discard/commit was performed.

The initial process inventory identified PID 19053 on port 3000 (.next, build Yo88ldF7ia4zGAm8S3eKn) and PID 22405 on 3001 (.next-milestone3, build ZXa8_ZVr0ems0t5gReiog). The older port-3000 process was left running. Only the identified port-3001 preview was replaced with the milestone-4 production build in .next-milestone4. Open http://127.0.0.1:3001. Final listener: PID 25237, build Sgz6GebP-EH4FywGpncdY, ready in 146 ms. lsof -nP -iTCP:3000 -sTCP:LISTEN, lsof -nP -iTCP:3001 -sTCP:LISTEN and cat .next-milestone4/BUILD_ID confirmed those processes/build; PID 19053 still serves port 3000.

Preserved migrations 001–010, existing accounts/data and .env.local. Applied only additive 202610220011_deleted_enrichment_sources.sql. No database reset, real-data test target, real invitation, deployment, paid resource, model request or provider credential change occurred. Remote processing remains disabled and no provider key is present. Temporary account cleanup is scoped to fictional accounts created by the tests.

Findings and fixes

Requirement/gap Actual behavior and evidence
C09/C10 field/phrase search Fixed negative-only Contacts/Improve search: neutral unknowns remain visible rather than being removed by a positive-score-only filter. Added explicit glasses/facial-hair/hair-color/length phrases, spelling variants, negative current affiliation and “no longer works at”. Only confirmed appearance is used; unknown/pending remain neutral. No inferred industry or open-ended language understanding.
C05–C08/C14/C15/C20 recovery Typed structured clues prevent redundant questions. Skipped/suppressed fields can be restored independently without clearing other clues, scope or rejected batches. Existing deterministic ties, full-pool question selection, six-card batch rejection, unseen candidates and mistaken-recollection recovery remain tested.
B09 source-deletion retention Reproduced a generated unedited summary surviving its note deletion in stale history. Migration 011 removes unedited/unpinned generated cues referencing that deleted note and removes photo-associated jobs/caches on photo deletion. Old worker completion cannot resurrect deleted work. Edited/pinned copies remain clearly outdated and show deleted-source text instead of dead links. A read-only audit found 0 orphan uncurated cues / 0 orphan photo caches in existing data; no historical content cleanup was needed.
B06 keyboard/focus Tabbing through an unchanged aliases input incorrectly marked the editor dirty and triggered Discard unsaved changes. No-op patches now preserve a clean draft. Browser coverage keeps focus inside the panel, dismisses it from the close control, restores the opener and retains filters/list state. The 2,000-contact test additionally verifies deep scroll preservation. Native date controls can consume Escape before the panel.
Desktop contrast/error states Darkened muted text and used the established accent for visible keyboard focus. Added Retry opening library after an initial temporary backend failure. Tested accessible textbox names, loading, retry, empty/unknown, provider-disabled and pending/review states; no redesign or future tabs. This is bounded accessibility coverage, not a complete audit.
Large-library responsiveness Improve repeatedly rescanned the library for each contact/field. Shared counts preserve the existing reasons and remove that repeated work. The initial 2,000-contact single-sample measurement was 3,245.49 ms; after change 7.99 ms, with warmed results below. Contacts cards now mount when that view is active, avoiding thousands of hidden cards in Identify. No speculative indexing service was added.
Interruption/concurrency Browser import test lets the server commit, drops the response and retries the same batch: one record remains. Simultaneous contact edits yield one 200 and one 409, preserving the winner. Existing recovery, duplicate-job prevention, old-lease rejection, cancellation and concurrent budget tests pass against real PostgreSQL with labeled test adapters.
A01–A08/D/E privacy and integrity Real Auth/Postgres/Storage suites retain cross-account denial, same-owner relations, uninvited/revoked checks, imports/groups/history, private photo paths, merge/undo reconciliation, pending facts and source links. Additional HTTP checks reject over-size/over-count imports and disguised HTML photos, render malicious-looking notes literally, and verify private no-store caching.

Exact verification record

Environment: macOS 14.4, Apple M2 arm64, Node 22.17.0, npm 10.9.2, Next 16.4.2, local Supabase PostgreSQL 17, Playwright 1.64.1. All contact fixtures are fictional. Tests use labeled fake providers or exercise the real adapter through a mocked HTTP transport; no live provider requests occur.

Status Exact command/check Observed result
Passed npx supabase migration up --local Applied additive 011 to preserved local database; no reset.
Passed npm test 65/65, 0 failures; final domain run 319 ms. Includes 24 milestone-1, 28 milestone-2, eight milestone-3 and five milestone-4 cases.
Passed npm run test:integration 21/21, 0 failed/skipped; 1,386.77 ms on preserved local stack with isolated accounts.
Passed npm run test:enrichment 19/19, 0 failed/skipped; 1,877.85 ms. Includes new source-deletion/cache regression and prior review, budget, recovery, isolation and merge/undo cases.
Passed PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:pagination 1/1, 0 failed/skipped; 814.18 ms total, all 1,005 owned review decisions returned.
Passed npm run typecheck; npm run lint Exit 0.
Passed npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'scripts/**/*.ts' 'tests/**/*.ts' '*.{ts,mjs,json}' Exit 0; all matched source/test/config files formatted.
Passed APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 npm run build Exit 0, homepage + nine dynamic API routes.
Passed APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:e2e Chromium 18/18, 0 failed/skipped, 25.5 seconds. Four milestone-4, three milestone-3, seven milestone-2 and four milestone-1 workflows, with actual backend persistence.
Passed PLAYWRIGHT_BROWSER=firefox APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:e2e -- --output test-results/firefox Firefox 18/18, 0 failed/skipped, 34.3 seconds, same workflows. Firefox 157.0, Playwright build 1555.
Blocked — engine failure PLAYWRIGHT_BROWSER=webkit APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:e2e -- --output test-results/webkit 0 passed, 1 failed, 1 interrupted, 16 unexecuted, exit 130 after stopping only the identified runner. browserContext.newPage: Protocol error (Page.overrideSetting): Unknown setting: PushAPIEnabled occurs before application interaction; the first case timed out at 60 seconds and the second repeated the same error. Installed frozen macOS-14 WebKit build 2251 is incompatible with this Playwright page initialization. No WebKit/Safari app compatibility claim.
Passed PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:scale 2,000 actual persisted contacts, four 500-row API imports, complete library retrieval, unseen target recognition, list/panel/focus/deep-scroll checks and zero page errors; measurements below. Created/deleted only its own fictional account.
Passed npm run benchmark Five warmups, 30 measured samples per case, 8/2,000 deterministic contacts and 500-row near-limit CSV; results below.
Passed Client-bundle actual-secret-value scan (command below) Final build: 29 files, 0 matches for configured server secret values, no values printed; remote enabled false, provider key present false. A bounded check, not an exhaustive secret audit.
Passed Read-only orphan audit (SQL below) Counted generated unedited/unpinned cues whose source note is absent, and cached photo results whose source photo is absent: 0 / 0 before and after regressions. No rows mutated.
Passed Final account/HTTP check (command below) 0 temporary browser/enrichment/authorization/organization/pagination/scale/signup accounts remain. Both homepages 200, both unauthenticated library APIs 401, enrichment on 3001 401.
Passed Screenshot review + browser desktop assertions Chromium/Firefox screenshots at 1440 × 900 and 1280 × 800: Identify, recognition card, Contacts, expanded profile, photo review and source-note history inspected. Visible controls, source labels/links and no horizontal overflow are covered; no complete accessibility claim.
Passed rg -n 'console\.|fetch\(|https?://' app lib scripts/enrichment-worker.ts; docker ps --format '' --filter 'name=supabase_' Source review found only sanitized worker messages and the explicit provider transport, no source-content logging or profile URL fetch. Runtime inventory shows only the original Contact_Collector stack; temporary validation containers stopped. This does not audit hosted infrastructure logs.
Blocked by registry response npm audit --json --fetch-timeout=15000 --fetch-retries=0 Exit 1, npm registry audit endpoint 400 Bad Request with retirement notice. No fresh advisory result obtained. Earlier unbounded attempt was stopped after stalling. Historical zero production / five high development-only advisories remain historical, not a new clearance.

Final read-only checks (exact commands)

These print aggregate counts/statuses only and do not mutate contacts, accounts or storage. The secret scan compares values in memory without printing them.

node --env-file=.env.local --import tsx --input-type=module <<'JS'
import { localAdmin } from './scripts/local-client.ts';
const admin = localAdmin();
let remaining = 0;
for (let page = 1; ; page++) {
  const { data, error } = await admin.auth.admin.listUsers({ page, perPage: 100 });
  if (error) throw error;
  remaining += data.users.filter(u => /^(browser-|enrichment-|authorization-|organization-|pagination-|scale-|signup-)/.test(u.email || '')).length;
  if (data.users.length < 100) break;
}
console.log({ remainingTemporaryAccounts: remaining });
if (remaining) process.exitCode = 1;
for (const [port, path, expected] of [[3000, '/', 200], [3000, '/api/library', 401], [3001, '/', 200], [3001, '/api/library', 401], [3001, '/api/enrichment', 401]]) {
  const response = await fetch(`http://127.0.0.1:${port}${path}`, { redirect: 'manual' });
  console.log({ port, path, status: response.status, expected });
  if (response.status !== expected) process.exitCode = 1;
}
JS
node --env-file=.env.local --input-type=module <<'JS'
import { readdir, readFile } from 'node:fs/promises';
const root = '.next-milestone4/static';
const paths = await readdir(root, { recursive: true, withFileTypes: true });
const secrets = ['SUPABASE_SERVICE_ROLE_KEY', 'OPENAI_API_KEY'].map(k => process.env[k]).filter(Boolean);
let scanned = 0, matches = 0;
for (const entry of paths) {
  if (!entry.isFile()) continue;
  const body = await readFile(`${entry.parentPath}/${entry.name}`, 'utf8');
  scanned++;
  if (secrets.some(value => body.includes(value))) matches++;
}
console.log(JSON.stringify({ scanned, matches, remoteEnabled: process.env.ENRICHMENT_REMOTE_ENABLED === 'true', providerKeyPresent: Boolean(process.env.OPENAI_API_KEY) }));
if (matches) process.exitCode = 1;
JS
docker exec supabase_db_Contact_Collector psql -U postgres -d postgres -At -c "select 'orphan_uncurated_cues='||count(*) from public.memory_cues c where c.origin='generated' and not c.edited and not c.pinned and exists(select 1 from jsonb_array_elements(c.source_notes) r where not exists(select 1 from public.notes n where n.owner_id=c.owner_id and n.contact_id=c.contact_id and n.id::text=r->>'id')); select 'orphan_photo_caches='||count(*) from public.enrichment_jobs j where j.kind='photo' and j.photo_result is not null and not exists(select 1 from public.photos p where p.owner_id=j.owner_id and p.contact_id=j.contact_id and p.id::text=j.input->'photo'->>'id');"

Clean setup in an isolated environment

Created /var/folders/lk/jsxzndkj381fq9yy8d8rqgm80000gn/T/contact-recall-m4-gryxzzbo with the package manifest/lockfile and source. Copied Supabase config with project ID Contact_Collector_m4_validation and ports 55320–55329 instead of 54320–54329; no existing environment/volume was copied or overwritten. Commands were run in that disposable directory unless a workdir flag is shown:

npm ci --offline --no-audit --no-fund
# From the original repository, with logs captured privately (CLI output can contain local keys):
node_modules/.bin/supabase start --workdir /var/folders/lk/jsxzndkj381fq9yy8d8rqgm80000gn/T/contact-recall-m4-gryxzzbo
# Copied migration 011 when added, then:
node_modules/.bin/supabase migration up --local --workdir /var/folders/lk/jsxzndkj381fq9yy8d8rqgm80000gn/T/contact-recall-m4-gryxzzbo
# In the disposable directory:
node --import tsx scripts/local-env.ts
LOCAL_TEST_SUPABASE_PORT=55321 npm run test:integration
LOCAL_TEST_SUPABASE_PORT=55321 npm run test:enrichment
LOCAL_TEST_SUPABASE_PORT=55321 npm run seed:local
npm run build
APP_ORIGIN=http://127.0.0.1:3002 npm run start -- --port 3002
# After smoke verification, stopped only that temporary app, then from the original repo:
node_modules/.bin/supabase stop --workdir /var/folders/lk/jsxzndkj381fq9yy8d8rqgm80000gn/T/contact-recall-m4-gryxzzbo

Passed: clean npm installation of 419 packages from the existing cache (13 seconds); fresh schema replay 001–010 and additive 011; environment generation without credential output; 21/21 real backend regressions (1,587.82 ms) and 19/19 enrichment tests (2,614.48 ms); fictional seed; production build; Chromium authenticated UI + eight seeded records on port 3002/backend 55321. Temporary app and only the named validation containers were stopped; local backup/volumes were retained by Supabase. The original stack stayed running. The clean build was repeated with the editor fix; the final small color-token adjustment is verified on the main final build.

This resolves the previously unexecuted local clean-install/migration replay path on this machine. It does not establish a new OS/Docker installation, uncached network package installation or current Safari. Installing Firefox/WebKit succeeded with npx playwright install firefox webkit; Playwright explicitly warns that macOS 14.4 receives frozen WebKit. npm also warns that the pinned ESLint 9 release is no longer supported; no unreviewed major dependency upgrade was performed.

Performance observations, not guarantees

Pure benchmark: Apple M2/macOS 14.4/Node 22.17.0, deterministic repeated-name/alias/affiliation/unknown/pending fixtures, five warmups and 30 samples, no network/provider. Question timing uses a pre-ranked full pool. These measure this fixture and environment, not real-world recognition accuracy.

Operation 8 contacts median / p95 ms 2,000 contacts median / p95 ms
Historical sentence ranking 0.06 / 0.07 9.59 / 10.60
Alias + conservative typo 0.09 / 0.13 16.05 / 16.48
Negative appearance ranking 0.03 / 0.07 5.04 / 6.87
Next useful question 0.04 / 0.05 3.53 / 3.63
Improve reasons/order 0.02 / 0.04 3.60 / 3.81

UTF-8 decode + CSV parse/validation: 500 rows / 2,087,399 bytes, median 186.32 ms, p95 233.61 ms, max 235.70 ms. Actual API import in the scale check: four 500-row, ~40,862-byte files took 1,932.41 / 2,078.15 / 2,321.62 / 2,987.98 ms. Library HTTP retrieval took 2,150.22 ms; Identify initial readiness 2,366.29 ms; typing the previously unseen final contact to a visible result 25.15 ms. Panel close preserved 183,471 px scroll and opener focus, with 0 page errors. A small focused browser diagnostic overlapped part of the import run; no dedicated performance lab/load isolation is claimed. The warmed pure measurements were separate. Full initial load is not subsecond; do not turn query timings into a blanket responsiveness claim.

Failed attempts and resolution

Readiness, setup and retained limitations

Use BETA_READINESS.md for the external-tester decision and README.md for supported imports/providers. Normal local setup remains Node/npm + Docker/Supabase; no AI credential is needed for Contacts/Improve/Identify.

Assessment: no unresolved critical privacy, isolation, merge/undo or data-loss defect was found in the completed checks after the source-deletion fix. This is bounded local evidence. External invitations still require separate authorization and the dependency, hosting, provisioning, retention/restore and accessibility/browser prerequisites in BETA_READINESS; the current audit and WebKit gaps remain open.

If the current preview stops:

npm run db:start
npx supabase migration up --local
APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 npm run build
APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone4 npm run start -- --port 3001

Do not start a second app on an occupied port or reset the working library. Existing fictional demo login remains alex@recall.test / Local-Recall-Only-2026!; automation does not use that library.

Preserved unverified items: actual live-provider semantic accuracy, uncertainty/refusal behavior and billing; local vision; fresh OS/uncached npm/Docker installation; current Safari/full assistive-technology audit; long idle expiry; exhaustive request/failure races beyond the tested concurrency/interruption cases; closed-dialog import resume (a new batch is still explicit); larger/heavier/deeper libraries beyond measured fixtures; hosted retention, backups/restore, full account erasure, operational provisioning and external deployment. Current dependency audit requires a successful retry/triage before external release. Source deletion clears uncurated derivations; independently retained raw import/entry provenance and explicitly edited/pinned cue copies remain documented user content. Local Docker backups/volumes are operator-managed. Contact deletion removes storage before rows, so interruption may require retry; no hosted erasure guarantee is claimed.

Deferred: all later milestones, deployment, real invitations and live provider use. Stop after milestone 4 and this readiness report.


Historical milestone-3 record

The following text and earlier records are preserved evidence for those tasks. Their then-current wording and counts are superseded by the milestone-4 record above.

Current date: October 22, 2026 (America/New_York). Current scope: milestone 3 only — controlled enrichment and source-linked memory cues. Implementation and local verification are complete as recorded below. Milestone 4 and later features were not started. The previous milestone-2 audit/evidence follows unchanged as historical context; it was not repeated.

Milestone 3 — implemented behavior

Read AGENTS, PRODUCT_SPEC, TECHNICAL_DESIGN, MILESTONES, ACCEPTANCE_TESTS, the existing build record and prompt 03. Extended the existing Next/React/TypeScript/Supabase implementation and npm lockfile. Preserved data and migrations 001–005; applied only additive migrations 006–010. No reset, reseed, Git discard, deployment, paid resource, invitation or live model request occurred. .env.local was not modified; safe inspection reported no OpenAI key and remote processing disabled. No external contact/photo/note transmission was authorized or performed.

The original production server on http://127.0.0.1:3000 was not restarted. A separate production build/directory serves milestone 3 at http://127.0.0.1:3001 against the preserved local database. Only that new preview process was restarted when verifying fixes.

Requirement / acceptance coverage Implemented and verified behavior
Save first; B02/B10 Existing contact save remains transactional. Source/mode changes write durable outbox rows; workers can see only committed contacts. No model call runs in a save handler. Missing provider configuration leaves contacts/editing/recognition working. Existing contacts/imports default to manual; Fully manual never automatically queues work.
Durable jobs; E05/E08/E09 Owned input hashes, three-attempt limit, two-minute lease, pending/processing/completed/failed/blocked/cancelled/stale states, explicit cancellation/retry, source invalidation and old-token rejection. Undispatched crashes recover; ambiguous dispatched outcomes stop for explicit retry rather than silently repeating a potentially charged request.
E01–E04 appearance Auto-queue appropriate new assisted photos only under enabled account policy. Show exact private source photo; approve/correct/reject individual fields or Skip. Pending/rejected/stale values are excluded from confirmed observations. Revision checks stop stale browser approval from overwriting a newer edit. Optional skin tone is always uncertain, retained in review history and not a new quiz field. Unclear/multiple-person/no-person outputs require clarification or a new single-person crop/photo; no subject is guessed.
B07/B08/B09/C16 cues and sources Generated cues immediately appear as Unreviewed summary, linked to exact original note IDs/versions. Manual cues, excerpts, editing, pins, review, dismissal and More cues work. Corrections append a new note version; original bodies remain unchanged and labeled historical. Deletion invalidates output and scrubs deleted note text from durable inputs. Stale edited/pinned cues remain explicitly outdated and leave current recognition; independent manual cues remain. Source links focus inside the active profile.
E06/E07 paid consent and concurrency Account assistance is opt-in; selected bulk scope requires explicit approval and a hard budget. Worker reservation/dispatch/completion accounting is transactional. Unknown outcomes retain their conservative allowance; known token usage releases unused allowance. Concurrent workers cannot reserve beyond the cap. No local model or automatic paid fallback exists.
Reuse and prioritization Unchanged per-contact inputs deduplicate; completed identical-photo results can be reused across contacts only within the same account/provider/model and cite each new owned source. Concurrent identical photos do not dispatch together. Priority uses saved contact/group choices (including nested smart rules), same-name difficulty and missing confirmed facts, not prestige. Group priority is captured at job creation; changing priority alone never triggers processing. Sufficiently described contacts are not automatically reanalyzed.
Genuine adapter; E10–E12 Configurable OpenAI Responses adapter, supplied image bytes, strict output schema/vocabulary/source-reference validation, no tools, no remote profile fetch, bounded input/response and timeout. Credentials remain server-only. Tests inject labeled fake adapters or a mocked HTTP transport; production configuration cannot select a fake adapter.
A01–A08 isolation New tables have RLS and ordinary-user read-only grants. Guarded user RPCs check authenticated active membership/ownership; worker RPCs are service-role-only and recheck consent, owner, source, budget and lease. Private photo download paths are independently checked. Forged IDs/writes, foreign scope, unapproved accounts and revoked access are tested.
Milestone-1/2 preservation Deterministic search/quiz and profile reads remain independent of providers; original notes and affiliation/group/relationship history remain. Cues do not enter ranking/quiz facts. Existing approved merge/undo remains intact; derived edits participate in reconciliation. New processing on active merged profiles is paused until explicit undo.

New code is concentrated in lib/enrichment/, scripts/enrichment-worker.ts, /api/enrichment, cue/review components and additive database functions. The shared contactSelect query now has a direct owner/contact relationship for photo suggestions, covered by an actual nested-query regression. Imported raw provenance and the documented CSV/vCard subset are unchanged.

Milestone-3 verification results

Environment: the existing macOS arm64 workspace, Node 22.17.0, npm 10.9.2, Next 16.4.2, local Supabase PostgreSQL 17/Auth/private Storage, Playwright 1.64.1/Chromium. No dependencies or provider credentials were installed. Tests created isolated fictional accounts and used synthetic photos/notes. The browser helper labels synthetic job output TEST ADAPTER and is not selectable by the production worker.

Status Exact command/check Observed result
Passed npx supabase migration up --local Applied 006, then the additive recovery/reuse/relationship refinements 007–009 and group-priority integration 010 successfully. No earlier migration changed and no database reset.
Passed npm test 60/60, 0 failures: 24 milestone-1, 28 milestone-2 and eight milestone-3 unit/domain/transport tests. Final run 289 ms. Includes sensitive/invalid output, mocked real-adapter requests, oversized response rejection, source references and exclusion of cues/superseded notes from identification.
Passed npm run test:enrichment 18/18, 0 failed/skipped, final run 2,482.04 ms. Covers durable automatic/manual saves, exact library query, revoked access, review/correction/rejection, source deletion/correction, stale worker/browser results, protected pins/edits, concurrent budget enforcement, lease recovery, explicit ambiguous-outcome retry, timeout/retry bound, exact accounting, private cache reuse, selected bulk scope, nested/smart group priority parity and merge/undo reconciliation.
Passed npm run test:integration 21/21, 0 failed/skipped, 1,578.07 ms after all database changes. Existing milestone-1/2 persistence, real authorization/storage, import/group/hierarchy, approved merge/undo/rollback and provenance regressions.
Passed PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:pagination 1/1, 0 failed/skipped, 728.22 ms total; all 1,005 owned review decisions returned through the milestone-3 API.
Passed npm run typecheck Exit 0 (tsc --noEmit) on final types/test code.
Passed npm run lint Exit 0, no remaining warnings/errors. The isolated generated build directory is ignored.
Passed npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'scripts/**/*.ts' 'tests/**/*.ts' '*.{ts,mjs,json}' Exit 0 on final matched source/test/config files.
Passed APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone3 npm run build Exit 0; isolated webpack production build with homepage and nine dynamic API routes, including enrichment. Does not replace the running port-3000 build.
Passed APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone3 PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 npm run test:e2e 14/14, 29.9 seconds: three new milestone-3 workflows, seven milestone-2 workflows and four milestone-1 workflows. All use real local persistence and isolated accounts; no external browser requests in the enriched recognition flow. Final source-focus regression included; .last-run.json reports passed, no failed tests.
Passed — expected unavailable result npm run enrichment:worker -- --once Exit 1, with Enrichment unavailable: remote authorization, credentials, model and conservative price/token bounds are required. No requests made. This verifies disabled/missing configuration; it is not a live-provider test.
Passed Screenshot inspection test-results/enrichment-review-1440.png, generated-cue-1440.png, cue-source-history-1440.png: source-photo decisions, exact Unreviewed summary label/source notes, manual pin and outdated original/history states inspected. Existing desktop/keyboard/overflow browser assertions also passed; this is not a full accessibility audit.
Passed rg -l -e OPENAI_API_KEY -e SUPABASE_SERVICE_ROLE_KEY -e api.openai.com/v1/responses .next-milestone3/static Exit 1, no matches in the final client bundles. This bounded scan supports server/client separation; it is not an exhaustive secret audit.
Passed Read-only cleanup/HTTP command below Exit 0; 0 temporary browser/enrichment accounts remain. Both local homepages return 200, both unauthenticated library routes return 401, and milestone-3 enrichment returns 401 without authentication.
Passed APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone3 npm run start -- --port 3001 Final production build running at http://127.0.0.1:3001, ready in 128 ms. The prior port-3000 process remains running.

Read-only cleanup/HTTP check (no contact/account mutations):

node --env-file=.env.local --import tsx --input-type=module <<'JS'
import { localAdmin } from './scripts/local-client.ts';
const admin = localAdmin();
let remaining = 0;
for (let page = 1; ; page++) {
  const { data, error } = await admin.auth.admin.listUsers({ page, perPage: 100 });
  if (error) throw error;
  remaining += data.users.filter(u => /^(browser-|enrichment-)/.test(u.email || '')).length;
  if (data.users.length < 100) break;
}
console.log(`Temporary browser/enrichment accounts remaining: ${remaining}`);
let healthy = remaining === 0;
for (const port of [3000, 3001]) {
  const base = `http://127.0.0.1:${port}`;
  const home = await fetch(base);
  const library = await fetch(`${base}/api/library`);
  console.log(`Port ${port}: homepage HTTP ${home.status}; unauthenticated library HTTP ${library.status}`);
  healthy &&= home.status === 200 && library.status === 401;
}
const enrichment = await fetch('http://127.0.0.1:3001/api/enrichment');
console.log(`Unauthenticated enrichment HTTP ${enrichment.status}`);
if (!healthy || enrichment.status !== 401) process.exitCode = 1;
JS

The final integration review also connected existing group priorities to enrichment ordering and queued-job priority. Migration 010 is additive; a backend test compares nested/manual/smart-ancestor scheduling against the existing shared group predicate and checks private helper access. No milestone-2 functionality was rebuilt.

Failed or blocked attempts, then resolved

Blocked now: none for the requested local implementation/verification.

Setup, assumptions and limitations

Open the milestone-3 application at http://127.0.0.1:3001. Docker/local Supabase remains on port 54321. Existing fictional demo login: alex@recall.test / Local-Recall-Only-2026!; Blair’s separate library is also available. These accounts were not automation targets. The prior port-3000 process remains available on its earlier build.

If the milestone-3 preview stops, keep Docker running and use:

npm run db:start
npx supabase migration up --local
APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone3 npm run build
APP_ORIGIN=http://127.0.0.1:3001 CONTACT_RECALL_DIST_DIR=.next-milestone3 npm run start -- --port 3001

Do not start a second process on an occupied port. No reset, reseed or new credentials are needed for ordinary use. Normal fresh setup still defaults to port 3000/.next; README contains both paths and unchanged supported import limits.

No provider had previously been selected. The reversible default is a configurable OpenAI Responses adapter, disabled by default, with no hardcoded model. Before any separately authorized live test, securely set OPENAI_API_KEY, OPENAI_ENRICHMENT_MODEL, ENRICHMENT_REMOTE_ENABLED=true, verified ENRICHMENT_INPUT_USD_PER_MILLION, ENRICHMENT_OUTPUT_USD_PER_MILLION and ENRICHMENT_PHOTO_TOKEN_BOUND. The operator must verify the chosen model supports images/strict structured output and the conservative cost bounds. Approve only a fictional account’s scope and budget in Improve, then explicitly start npm run enrichment:worker. No local model/fallback is claimed. See README’s configuration table and linked official request-format documentation.

Operational bounds: 32,000 serialized input bytes, 100,000 response bytes, 1,200 output tokens, three attempts per unchanged job, 45-second request timeout, two-minute lease and 30-second retry delay for an explicit retryable rejection. A missing/unknown price or image-token bound is unavailable, not unlimited permission. Each approved automatic/bulk budget is capped at $100 and backed by atomic micro-USD reservation accounting. Unknown provider outcomes retain the full allowance; explicit retry may duplicate an externally processed request. Reported allowance is not a provider invoice. Actual billing correctness depends on verified model pricing/token assumptions; live billing was not exercised.

Only source-linked approved appearance observations feed the existing quiz vocabulary. Optional uncertain skin-tone review history does not add a quiz question. Unreviewed/generated cues never become separate facts. Large note collections fail visibly rather than silently dropping text. Pins and edits are preserved; source-linked obsolete cues remain labeled outdated, while their original note versions remain accessible unless explicitly deleted. Deleting a note does not erase separately retained import/raw-entry provenance or a user’s separately edited cue. Merged profiles keep existing derived history but require explicit undo before new processing; older merge fingerprints may request reconciliation after the additive schema upgrade.

Unexecuted/unverified, preserved rather than waived: live provider accuracy/uncertainty preservation, refusal behavior on actual photos, model availability, actual token charges and billing; local vision feasibility/accuracy; fresh-machine npm/Docker/Chromium installation; full new-database migration replay; Firefox/Safari; full assistive-technology audit; long idle session expiry; exhaustive network failures and multi-process stress beyond the tested concurrent worker cases; maximum-size import responsiveness, closed-dialog import recovery and 2,000-contact performance; hosted backups/retention/deployment/external-beta readiness. No fresh dependency security audit was run; earlier evidence recorded zero production advisories and five high development-only lint-chain advisories. These historical counts are not a new audit. Prompt/schema/source validation does not prove semantic truth; generated summaries remain Unreviewed until the user reviews them.

Deferred: milestone 4 hardening/performance/release operations and all external profile discovery, scraping, Prepare, memory practice, Follow-ups/reminders, synchronization and later work. Stop after milestone 3; no automatic continuation.


Historical milestone-2 completion record

The following audit, results and limitations are retained. Its active-scope/date wording describes the earlier task; the milestone-3 record above is current.

Date: October 22, 2026 (America/New_York). Active scope: milestone-2 requirements audit, completion and stabilization. Status: the audit found required functionality missing and reproduced an unsafe merge size case, so this task completed/fixed milestone 2 only. The checks below pass with no known remaining blocking defect in this bounded implementation. Milestone 3 was not started. This is local milestone software, not the completed external beta.

Current pass — milestone-2 audit and completion

Read AGENTS, PRODUCT_SPEC, TECHNICAL_DESIGN, MILESTONES, ACCEPTANCE_TESTS, the existing BUILD_STATUS and prompts 02/03. Compared requirements with the actual domain modules, components, API authorization, migrations and tests. Reused the preceding milestone-1 verification as evidence, then ran regressions on the changed application. Test counts alone did not establish completion: the earlier suite did not cover manually selected comparisons, alias/profile-link evidence, searchable group browsing or oversized affiliation merges.

Requirement comparison and implementation

Requirement Actual implementation and evidence Outcome
CSV/vCard persistence, mapping, bounds, provenance, per-row errors Existing import parser, preview UI, /api/imports and import_contact transaction retained. Domain/backend/browser tests cover mapped CSV, malformed rows, documented vCard subset, raw source, same-batch retry, repeated explicit uploads and remote PHOTO text without fetching. Retained and regression-tested; supported subset below/README.
Quick-add and manual workflow Existing quickAdd extraction and contact editor preserve raw/unparsed input, permit editable extraction and retain the draft when switching to Fully manual. Retained; domain and browser regression passed.
Hybrid onboarding and priorities Actual empty-state UI offers Import contacts and Add a person; Contacts provides Import/Add with equal prominence. Existing optional post-import contact/group priorities include Skip and do not start analysis. Retained; Skip and saved priorities exercised in browser/backend tests.
Smart/manual groups, nested subgroups and consistent filters Existing shared predicates enforce current/former/unknown rules, smart ancestor intersections, navigational manual rollups and any/all scopes. Cycle/foreign-parent guards, pins, suggestions, priority, rename/reparent and manually curated memberships retained. Existing domain/backend/browser regressions passed.
Meaningful groups prominent; smaller categories searchable (PRODUCT_SPEC §8) Previously every group was rendered without a search control. Added shared compact browsing: pins, then membership count/name; eight default groups plus additional pinned/selected entries; full-path search and Browse all in Contacts, Identify and Organize groups. Searching preserves selected scopes. Completed; pure predicate tests and persisted browser rename/nested-path/empty-scope checks passed.
Manually choose records to compare (PRODUCT_SPEC §10.3) Previously only suggested pairs could open comparison. Added Compare any two contacts using existing side-by-side review and approval/undo. Unsuggested pairs support Keep separate and Review later; deferred pairs remain visible after reload. Self/foreign comparisons are rejected by the API. Completed; domain and browser checks passed.
Duplicate evidence and retained decisions Added saved aliases and normalized HTTP(S) profile links; recorded meeting/affiliation context is shown alongside identity evidence. A shared employer/meeting alone is not an automatic identity suggestion. New review signatures track these fields; existing signatures remain supported without rewriting decisions. Completed; deterministic matching, changed-evidence reopening, URL differences, legacy suppression and private larger signatures tested.
Approved transaction, originals/history, undo and later edits Existing logical merges, source/child IDs, private photo paths, conflict choices, reconciliation and rollback retained. Reproduced a defect: two contacts with 16 affiliations could merge into a profile rejected by the editor’s 30-affiliation save bound. Added a transactional guard and matching UI/API explanation, with no truncation. Fixed; rejection leaves both revisions/affiliation sets unchanged and no merge log. Existing authorized/unauthorized merge, rollback, undo and reconciliation tests passed.
Milestone-1 privacy and recognition Persisted Contacts → Improve → Identify, original notes, historical affiliations, private media, actual saved search/quiz facts, unknown/pending handling, clue revision/Skip, None of these match and account switching remain unchanged. Four browser workflows plus 24 domain and seven backend tests passed. Ordinary recognition remains deterministic with no provider code or AI requests.

The only new database migration is 202610220005_comparison_evidence.sql, applied locally with npx supabase migration up --local. It extends the private review-signature size bound and replaces the merge function with the same ownership/revision/conflict checks plus the affiliation limit. Migrations 001–004 are unchanged. Existing contacts, original notes, review decisions, media and merge history were not rewritten, deleted or reset. Existing oversized merges, if any, are not silently altered; the existing explicit Undo/reconciliation flow remains available.

The repository still has untracked project files, so Git has no tracked baseline for these files. No Git reset/discard, seed rerun, database reset, unrelated-file removal, dependency change, deployment, real invitation or paid request occurred. Backend/browser fixtures used isolated fictional accounts; pre-existing libraries were not test targets.

Exact verification results for this pass

Environment: existing macOS arm64 workspace, Node 22.17.0/npm 10.9.2, local Supabase PostgreSQL 17/Auth/Storage, Next 16.4.2, Playwright 1.64.1/Chromium. Results below supersede historical counts later in this file.

Status Exact command/check Result
Passed npx supabase migration up --local Applied additive migration 005 successfully to the existing local database; no reset.
Passed npm test 52/52, 24 milestone-1 and 28 milestone-2 domain tests; 0 failed. Final run after deferred-manual-review changes reported 485 ms.
Passed npm run test:integration 21/21, 0 failed/skipped; real local backend; 2,253.53 ms. Includes new affiliation-limit rollback and expanded/private review-signature tests.
Passed npm run test:pagination 1/1, 0 failed/skipped; HTTP API retained all 1,005 review decisions; 823.40 ms. Library pagination code was unchanged by subsequent UI/domain fixes.
Passed npm run typecheck Exit 0 on final code (tsc --noEmit).
Passed npm run lint Exit 0 on final code.
Passed npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'scripts/**/*.ts' 'tests/**/*.ts' '*.{ts,mjs,json}' Exit 0; all matched source/test/config files formatted.
Passed npm run build Exit 0 on final code; webpack production build, homepage and eight dynamic API routes.
Passed npm run test:e2e 11/11 Chromium workflows: four milestone-1 and seven milestone-2; no skipped tests. Final test-results/.last-run.json reports passed and an empty failedTests list.
Passed Visual review of current screenshots Inspected test-results/manual-comparison-1440.png and searchable-groups-1440.png; readable side-by-side originals, visible full subgroup paths/selected filters, no observed blocking layout issue. Existing browser keyboard/overflow/regression assertions also pass.
Passed Read-only local account/HTTP check below Exit 0: Temporary browser accounts remaining: 0; Homepage HTTP 200; unauthenticated library HTTP 401.
Passed npm run start Final production build is serving at http://127.0.0.1:3000.
node --env-file=.env.local --import tsx --input-type=module <<'JS'
import { localAdmin } from './scripts/local-client.ts';
const admin = localAdmin();
let remaining = 0;
for (let page = 1; ; page++) {
  const { data, error } = await admin.auth.admin.listUsers({ page, perPage: 100 });
  if (error) throw error;
  remaining += data.users.filter(u => u.email?.startsWith('browser-')).length;
  if (data.users.length < 100) break;
}
console.log(`Temporary browser accounts remaining: ${remaining}`);
const home = await fetch('http://127.0.0.1:3000');
const library = await fetch('http://127.0.0.1:3000/api/library');
console.log(`Homepage HTTP ${home.status}; unauthenticated library HTTP ${library.status}`);
if (remaining || home.status !== 200 || library.status !== 401) process.exitCode = 1;
JS

Failed checks, then resolved:

Blocked now: none for this local milestone-2 completion pass.

Unexecuted/unverified, retained from earlier verification: fresh-machine npm ci/Docker/Chromium installation; full migration replay on a new database (005 upgrade on this existing database did pass); Firefox/Safari; complete assistive-technology audit; long idle session expiry; exhaustive network-failure and parallel-request races; maximum-size imports, multi-process concurrency and 2,000-contact performance; hosted backups/retention/deployment/external-beta readiness. A fresh dependency security audit was not run; earlier evidence recorded zero production advisories and five high development-only lint-chain advisories. The historical counts are not a new audit. No live AI provider was configured or tested; milestone 3 and provider behavior remain unimplemented/unverified, not simulated as completed enrichment.

Setup, limits and remaining work

Open the running app: http://127.0.0.1:3000. The existing local backend is on port 54321 and .env.local was preserved. Existing fictional demo login: alex@recall.test / Local-Recall-Only-2026!; Blair has a separate library. Automation provisions its own accounts and never uses these demos.

If stopped, keep Docker running and use npm run db:start, npx supabase migration up --local, npm run build, then npm run start. Stop an older app process before starting a second server. No reset, reseed or new environment variables are required for this workspace. Fresh-machine steps, supported imports and test commands are in README.md.

Supported imports remain UTF-8 CSV with headers and mapped fields / vCard 3.0–4.0 subset, at most 2 MiB / 500 records / 60,000 characters per raw record. Imported photos, legacy encodings, XLSX, provider extensions and inferred groups/appearance are unsupported; raw unsupported properties remain provenance. No remote URLs are fetched. Same-dialog retries are idempotent; reopening starts a new batch, with no durable import-resume dashboard. See README’s exact field/encoding/image table; maximum-size responsiveness and closed-dialog interruption recovery remain unverified.

Group suggestions use saved affiliation support, not invented biography. Smart rules remain an explicit organization/kind/timeframe allowlist. Compact ordering by pins/count/name and eight default entries is a reversible UI default; memberships are unchanged. Duplicate comparisons use context as supporting evidence only. New Keep separate decisions track normalized names/aliases/methods/context; legacy decisions retain their original name/email/phone suppression basis. Review later does not block imports or recognition. Merges retain the existing 30-method/alias bounds and now enforce 30 combined affiliations, with one active merge per contact. Undo explicitly reconciles later edits and may retain shared methods on both restored records.

Deferred: milestone 3 durable enrichment, provider configuration/budgets, confirmed photo suggestions and source-linked Unreviewed summary cues; milestone 4 hardening/performance and all later events/reminders/synchronization. The user’s conditional boundary selected milestone 2 because this audit found gaps. Stop here; no milestone-3 implementation in this task.


Historical verification pass — after pausing feature development

The following record is preserved as earlier evidence. Its scope, conclusions and test counts describe that earlier pass; the requirements audit and fresh results above supersede its statement that no additional milestone-2 requirement was missing.

Inspected the actual source, all four migrations, tests, manifest/lockfile, API authorization and current Git state, in addition to AGENTS, both execution prompts, PRODUCT_SPEC and the milestone/technical/acceptance/status documents. The repository still has untracked project files and no tracked diff to use as an implementation baseline. No Git reset, discard, migration application/rollback, database reset, seed rerun, or mutation of pre-existing libraries was performed during this pass. No application feature, dependency, environment setting or migration changed.

What is present

Fresh verification results

Environment: existing macOS arm64 workspace; Node 22.17.0; npm 10.9.2; Docker/local Supabase PostgreSQL 17; Next 16.4.2; Playwright 1.64.1/Chromium. Tests used temporary fictional accounts. Cleanup was scoped to account IDs created by the tests; pre-existing accounts/data were not test targets.

Status Exact command/check Result in this pass
Passed npm test 47/47: 24 milestone-1 and 23 milestone-2 domain tests, 0 failures; 231 ms reported.
Passed npm run test:integration 19/19, 0 failed/skipped; real local Auth/Postgres/Storage, 1,578 ms. Covers isolation, forged IDs, active/revoked beta access, private media, persistence, original notes, simultaneous affiliations, imports, hierarchy, merge/undo/rollback and priorities.
Passed npm run test:pagination 1/1, 0 failed/skipped; HTTP API returned all 1,005 retained review decisions, 1,253 ms.
Passed npm run typecheck Exit 0 on the final test/helper code.
Passed npm run lint Exit 0, no warnings on final code.
Passed npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'scripts/**/*.ts' 'tests/**/*.ts' '*.{ts,mjs,json}' Exit 0; all matched files formatted.
Passed npm run build Exit 0 on final code; webpack production build, homepage and eight dynamic API routes.
Passed npm run test:e2e 9/9, 0 failed/skipped; 14.9 seconds. Four milestone-1 workflows and all five existing milestone-2 workflows, using real local persistence and isolated accounts.
Passed Screenshot review Current Contacts and Improve at 1280×800, recognition card/original notes and group organization at 1440×900 inspected; readable layout and no observed blocking visual defect. Automated keyboard opening/Escape/focus return, list/filter preservation, empty-state recovery and viewport overflow checks passed.
Passed Read-only temporary-account audit (command below) Temporary browser accounts remaining: 0, exit 0, including after the interrupted intermediate run.
Passed npm run start; curl --silent --show-error --output /dev/null --write-out 'HTTP %{http_code}\n' http://127.0.0.1:3000 Production server runs locally; homepage HTTP 200.
Passed curl --silent --show-error --output /dev/null --write-out 'Unauthenticated library HTTP %{http_code}\n' http://127.0.0.1:3000/api/library HTTP 401 after the final production-server restart.

Backend authorization is exercised using actual ordinary user credentials, not mocked UI filtering. The browser flow creates a contact with a private photo and original note, reloads, saves appearance/meeting/former-employer details through Improve, finds the saved record by a historical sentence, opens original notes, returns with clues intact, reloads again, switches accounts and signs back in with all saved fields unchanged. Foreign contact/photo requests return 404. Unknown facts rank between positive and contradictory recorded facts and remain reachable after clue changes. Existing tests cover pending exclusion, Skip/suppression, uniform/sparse questions, incorrect clues, scope widening and rejection of only the displayed six candidates. Private APIs use no-store; ordinary search/quiz has no AI integration or server query path. Runtime import and recognition checks also assert zero external browser requests.

Retained browser screenshots are in ignored test-results/: contacts-1280.png, improve-1280.png, identify-1280.png, identify-1440.png, recognition-card-1440.png, profile-expanded-1440.png, import-preview-1440.png, groups-1440.png, duplicate-comparison-1440.png, undo-reconciliation-1440.png. They contain fictional test data only. They are evidence of the scoped workflows, not a full accessibility audit.

Failed attempts, resolved blocks, and unexecuted checks

Read-only cleanup audit, with no credentials or account details printed:

node --env-file=.env.local --import tsx --input-type=module <<'JS'
import { localAdmin } from './scripts/local-client.ts';
const admin = localAdmin();
let remaining = 0;
for (let page = 1; ; page++) {
  const { data, error } = await admin.auth.admin.listUsers({ page, perPage: 100 });
  if (error) throw error;
  remaining += data.users.filter(u => u.email?.startsWith('browser-')).length;
  if (data.users.length < 100) break;
}
console.log(`Temporary browser accounts remaining: ${remaining}`);
if (remaining) process.exitCode = 1;
JS

Open the existing application

Actual address: http://127.0.0.1:3000 (local production server; Docker backend on port 54321). The current workspace is already configured; .env.local was preserved and no seed was rerun. For manual exploration use the existing fictional alex@recall.test / Local-Recall-Only-2026! account, or Blair’s separate library as documented in README. Browser automation now creates its own accounts and does not use these demo logins.

If the app has been stopped, keep Docker running and run npm run db:start, then npm run build and npm run start from the repository. Do not start a second server on the same port. No reset, reseed or new credentials are needed for this configured workspace. Fresh-machine instructions and optional seed remain in README.md.

Milestone-2 limitations and unfinished verification — no new features built

No additional required milestone-2 blocker was identified by this pass. The existing bounded implementation remains: UTF-8 CSV/vCard 3.0/4.0 only; 2 MiB/500 records; no imported image decoding, remote photo fetches, legacy encodings, XLSX or inferred groups/appearance. Unsupported fields remain in raw provenance. Same-dialog retries are idempotent; closing/reopening an interrupted import starts a new batch, with no durable resume dashboard. Groups use allowlisted organization/kind/timeframe rules; merges permit one active merge per contact and retain the 30-method/alias limit. Reconciliation preserves later edits and can leave shared methods on both restored records. See README for exact supported fields and bounds.

Still unverified for milestone 2: interrupted-import recovery across a closed dialog, maximum-size imports, production concurrency and broader browser behavior. Those items were not developed during this pass. No provider calls, paid resources, real invitations or deployment occurred. Milestones 3–4 and later work remain deferred; stop here and await a separate instruction before feature development resumes.


Historical milestone-2 implementation record

The sections below preserve the earlier implementation evidence; their counts are historical. The fresh results and current scope above take precedence.

Milestone-1 prerequisite

Read the root instructions, START_HERE, PRODUCT_SPEC, milestone/acceptance/technical planning documents, prior BUILD_STATUS and prompt 02. Inspected the working application, migrations, manifest, tests and uncommitted repository. Retained Next.js/React/TypeScript, npm lockfile, local Supabase, private photo handling and deterministic recognition core. No reset, rebuild from scratch, deployment, invitation or paid provider call occurred.

Before extension: npm test 24/24, npm run typecheck, npm run lint, npm run test:integration 7/7, and npm run test:e2e 3/3 passed. No unresolved milestone-1 blocking defect was found in inspection or those checks. Original evidence and limitations are archived in MILESTONE_1_VERIFICATION.md. Existing development-only lint dependency advisories are not production runtime findings; no dependency changes were made in milestone 2.

Implemented

Files and migrations

Area Main files
UI components/{workspace,contact-editor,organization,import-contacts,duplicate-review}.tsx, existing primitives/styles
Pure logic lib/imports/parse.ts, lib/domain/{groups,duplicates,model,identify,improve}.ts
API app/api/{imports,groups,duplicates,priorities,contacts,library}/route.ts, lib/server/{api,library}.ts, lib/client-api.ts
Database 202610220003_organization.sql, 202610220004_import_retries_and_priorities.sql in supabase/migrations/
Tests tests/organization.test.ts, tests/organization.integration.test.ts, tests/browser/organization.spec.ts, tests/review-pagination.ts, CSV/vCard fixtures; original test suites retained

Migration 003 adds hierarchy/rules, priorities, raw sources, affiliation dates/change history, relationships, duplicate decisions, import receipts and merge/undo/delete functions. It extends contact saving while keeping owned RLS and same-owner composite FKs. Guarded merge/undo/delete functions use SECURITY DEFINER only after active-beta and explicit ownership checks; ordinary application requests still use the authenticated client, never the service key. Changes serialize per owner and merge/undo fingerprints include original rows and children. Migration 004 binds retries to their exact input and adds atomic revision-aware priorities. Both applied to the existing local database without resetting records.

Earlier milestone-2 verification results

Environment retained from milestone 1: macOS arm64; Node 22.17.0; npm 10.9.2; local Docker/Supabase PostgreSQL 17; Next 16.4.2; React 19.3.1; TypeScript 6.0.3; Vitest 5.0.5; Playwright 1.64.1 / Chromium. No dependencies added or upgraded.

Exact command Actual result
npx supabase migration up --local Migrations 003 and 004 applied successfully. Sandbox initially blocked the CLI settings-directory write; the authorized local retry passed. No db:reset.
npm test 47 passed, 0 failed: 24 milestone-1 regressions and 23 milestone-2 cases. Network-free pure tests.
npm run test:integration 19 passed, 0 failed, 0 skipped: original 7 plus 12 milestone-2 tests against real local Auth/Postgres/Storage. Final integration run: 1.50 seconds.
npm run test:pagination 1 passed, 0 failed: actual HTTP library API returned all 1,005 retained decisions beyond the default backend row cap, using a temporary account removed afterward. Requires the local app running.
npm run typecheck Passed, exit 0 on the final code.
npm run lint Passed, exit 0, no warnings.
npx prettier --check 'app/**/*.{ts,tsx,css}' 'components/**/*.{ts,tsx}' 'lib/**/*.ts' 'scripts/**/*.ts' 'tests/**/*.ts' '*.{ts,mjs,json}' Passed, all matched source/config/test files use Prettier style.
npm run build Passed, exit 0, webpack production build; homepage plus eight dynamic API routes.
npm run test:e2e 8 passed, 0 failed, 0 skipped: 3 milestone-1 regressions and 5 milestone-2 browser workflows against the final production build and real local backend; final run 12.0 seconds.

Implementation-time failures were resolved rather than waived: the new scope-mode default initially changed an old reducer expectation; adding the explicit default restored the original regression. Real integration tests exposed an ambiguous PostgREST relationship embedding after adding saved-contact targets; naming the source-contact FK fixed the library query. Initial lint found two unescaped apostrophes, corrected. The browser group test needed its actual accessible combobox role instead of an exact label-text selector; the corrected quick-add/group flow passed. Tests also prompted input-bound retry receipts and atomic priority revision updates. Final review fixed inherited manual memberships being copied onto the primary during an unrelated merged-profile edit; inherited controls now explain that undo is needed, and regression tests verify the memberships remain on their original record. vCard markers are recognized only as complete lines, so literal marker text inside notes is preserved. Formatting was rerun after the final added browser test. The review-history loader also pages decisions and active merge operations, so the backend row cap cannot silently lose Keep separate decisions; the extra real API test verified 1,005 retained decisions.

Coverage includes D01–D13: overlapping/descendant deduplication, any/all scope agreement, cycles/ownership, smart ancestor intersections, current→former changes without manual-membership loss, valid/invalid/repeated/sparse imports, Skip, size/encoding/unsupported-photo checks, identical-email suggestions, transactional merge rollback, pending/source/photo/history preservation, undo before/after later edits, Keep separate suppression and explicit reimport behavior. Real-backend tests additionally cover forged relationships, unavailable merge targets, revoked access, private media after merge, receipt ownership, permanent-delete cleanup and priority scope rollback. This evidence does not claim all of milestone 4’s release validation.

Browser coverage includes actual mapped CSV and vCard imports, per-record errors, unsupported/oversized/invalid-UTF-8 uploads, raw-source inspection after reload, Skip and saved priorities, repeated upload creating separate records, raw quick-add/manual draft preservation, group creation/nesting/pinning, any/all Contacts/Identify agreement, duplicate comparison, Keep separate across reload, changed-evidence review, approved merge, later-note edits and reconciliation. New API routes reject unauthenticated, cross-origin and unapproved mutations; an imported profile remains unavailable to the other account. The monitored import/vCard and milestone-1 workflows asserted zero external browser requests; monitored workflows asserted zero runtime errors. Tests clean their synthetic contacts/groups and temporary accounts.

Screenshots in ignored test-results/: import-preview-1440.png, groups-1440.png, duplicate-comparison-1440.png, undo-reconciliation-1440.png, and the existing recognition/workspace screenshots. Import preview, group organization, comparison, reconciliation and Contacts desktop captures were visually inspected. Long group labels prompted a small control-size fix so checkboxes do not shrink; reconciliation bullets were restored for readability. Existing 1280×800 / 1440×900 recognition regressions pass. Full assistive-technology validation remains unverified.

Setup and supported limits

Full instructions and precise CSV/vCard limitations are in README.md. Existing workspace upgrade:

npx supabase migration up --local
npm run build
npm run start

Fresh local setup:

npm ci
npm run db:start
npx supabase migration up --local
npx tsx scripts/local-env.ts
npm run seed:local
npm run dev

The final production build is currently running at http://127.0.0.1:3000. Use that hostname consistently. Docker must be running; local backend port is 54321. Existing .env.local remains ignored and unchanged. No additional environment settings or credentials. The seed is opt-in, fictional and preserves nonempty libraries. Public local test credentials remain documented in README. Never reset a library to apply these migrations.

Imports: UTF-8 only; 2 MiB; 500 records; 60,000-character raw record; CSV 50 columns/100-character headers; bounded field/method/note limits. No XLSX, delimiter guessing, legacy vCard 2.1/encodings, automatic photo import, remote photo fetching, group/appearance/date inference, or external sync. Unknown/unsupported fields remain in raw source and are reported. Invalid/unselected records are not stored. Imports are transactional per record, not all-or-nothing across the file; successful rows remain usable if another fails. Same-dialog retries are idempotent for exact input; uploading again starts a new batch and creates separate records. No resumable batch dashboard.

Groups use one parent and allowlisted organization/kind/timeframe rules; no arbitrary boolean expression/SQL editor. New ancestry is bounded to 32 nodes. Manual memberships are retained independently of smart predicates. A merged record must be undone before another merge; combined methods/aliases keep existing 30-entry limits and oversized merges roll back without truncation. Inherited manual memberships remain on the original retained record; undo before editing them independently. Safe reconciliation can intentionally leave shared methods on both restored contacts. Photo deletion precedes DB deletion; a subsequent DB failure may leave removed photos unavailable until retry, as in milestone 1. Local backups/volumes remain operator-controlled.

Blocked, unverified and remaining work

No paid resources, deployments, invitations, provider credentials or external integrations were created. No implementation prerequisite is currently blocked.

Unverified: fresh-machine installation from zero after milestone 2; Safari/Firefox and full assistive-technology audit; crash/network-disconnect recovery across a closed importer; multi-process production concurrency/load; maximum-size import responsiveness and 2,000-contact performance targets; hosted storage/retention/backup erasure and external-beta readiness. Browser and integration tests use real local persistence with synthetic accounts, not real address books. Dependency advisories were not re-audited in this milestone because the lockfile did not change; milestone 1 recorded zero production vulnerabilities and five high development-only lint-chain findings.

The roadmap places milestone 3 next, but it is not authorized by this verification task: durable controlled enrichment, budgets/review and source-linked summaries. It has not been started. Milestone 4 still owns broader performance/accessibility/beta hardening. Events, practice, debriefs, follow-ups, notifications and provider synchronization remain later milestones.