Homesonspec

repo: ~/Projects/homesonspec · 360 commits · 0 in last 24h, 0 in last 7d ·

Search the build

360 commits indexed

  1. ed938c0f 2026-09-13 Publish a fleet-health heartbeat: this poller was invisible to the rollup
  2. 471d1568 2026-09-13 Poller: notify() must never be able to fail its caller
  3. 043c09b7 2026-09-13 Apple review poller: stop disarming itself while awaiting Apple
  4. fb984ed6 2026-09-11 eas: pin production ios.image=latest (ITMS-90725 guard)
  5. 42bd9935 2026-09-11 Record verified production ValidationEvent partitioning
  6. df934fe2 2026-09-11 auto-data-snapshot: 2026-09-11T08:57:34 (9 data files) — ops/TK-11364-validationevent-approval.md ops/o3-partition-PROVEN-runbook.md verification/TK-11364/app-after.jsonl verification/TK-11364/independent-after.txt verification/TK-11364/previous-e2e-proof.json
  7. 90b58b81 2026-09-11 Rehearse and harden ValidationEvent partition conversion
  8. 36033811 2026-09-10 Reconcile TK-11364 partition state and document remaining approval gate
  9. 0200179c 2026-09-10 TK-11303: retire stale v1 apple-review launchd plist (superseded by v2 wrapper)
  10. 31581ff8 2026-09-10 TK-11364: version + golden-lock the TK-11125 guard's canonicalization contract
  11. 3e4d499f 2026-09-10 O3b: ValidationEvent partition conversion script (corrected pattern)
  12. 0f94115d 2026-09-10 O3: add grant script so future partitions inherit the app-role ACL
  13. cc0a0516 2026-09-10 O3: fix the two bugs the live run exposed (FK-before-attach stall, missing GRANTs)
  14. a15775f6 2026-09-10 O3: add prod apply script for the partition conversion
  15. d6400d4d 2026-09-10 O3: prove SourceEvidence partitioning is feasible with no rewrite and no data-model change
  16. 82fadf19 2026-09-10 ops: preflight now VALIDATES the rollback dump instead of suggesting it (TK-11364)
  17. 616032a6 2026-09-10 ops: fix preflight rollback check reporting a false "no backup" (TK-11364)
  18. 14ed1904 2026-09-10 ops: make Phase-2 preflight actually enforce the disk gate (TK-11364)
  19. 88e393b7 2026-09-10 docs: correct stale/false facts in O3 partition plan (TK-11364)
  20. 32416391 2026-09-10 Require configured slots for manual AdSense units
  21. 6c9cd93d 2026-09-09 TK-11341: add AdSense Auto-Ads loader + ads.txt (revert to remove ads)
  22. aaf2c487 2026-09-04 snapshot before restart: preserve in-flight work
  23. ba37b54c 2026-09-04 mobile: make the tracker-drift canary baseline-aware (was firing on steady state)
  24. 693125b2 2026-09-04 mobile: add tracker-drift canary guarding the 'Data Not Collected' privacy label
  25. 90ca06fc 2026-09-04 auto-data-snapshot: 2026-09-04T11:31:34 (65 data files) — apps/mobile/_recovered/hx/Payload/HomesonSpec.app/Assets.car apps/mobile/_recovered/hx/Payload/HomesonSpec.app/EXConstants.bundle/Info.plist apps/mobile/_recovered/hx/Payload/HomesonSpec.app/EXConstants.bundle/app.config apps/mobile/_recovered/hx/Payload/HomesonSpec.app/Expo.plist apps/mobile/_recovered/hx/Payload/HomesonSpec.app/ExpoApplication_privacy.bundle/Info.plist
  26. 7cf4bed8 2026-09-04 verify Apple review poller lifecycle
  27. 672b9689 2026-09-04 add App Store review completion poller
  28. a656c9b9 2026-09-04 auto-data-snapshot: 2026-09-04T10:10:38 (1 data files) — apps/mobile/_recovered/homesonspec-build2.ipa
  29. 307603c2 2026-09-04 record successful iOS review resubmission
  30. 29dc1871 2026-09-04 mobile: repair App Store Connect key path
  31. d8531bc3 2026-09-04 TK-10337: preserve final iOS device proof
  32. 46e6b219 2026-09-04 auto-data-snapshot: 2026-09-04T08:26:29 (1 data files) — apps/mobile/device-proof-evidence/homesonspec-DEVICE-journey-FINAL-mapfixed-2026-09-04T15-31-01Z.mov.privacy-reviewed.sha256
  33. 4df903f1 2026-09-04 mobile: cap rendered map markers (120, densest-first) + lower grid density — fix react-native-maps on-device OOM crash on the Map tab (TK-11155)
  34. f2de197d 2026-09-04 Homes on Spec: actually test the tracker-blocking script (TK-10387)
  35. 16d8e5af 2026-09-04 auto-data-snapshot: 2026-09-04T06:32:13 (1 data files) — apps/mobile/device-proof-evidence/homesonspec-DEVICE-journey-BUILD3-2026-09-04T13-10-12Z.mov.privacy-reviewed.sha256
  36. 2726cf35 2026-09-04 Homes on Spec: correct stale README claims that misled a downstream review (TK-10387)
  37. d98894aa 2026-09-03 Homes on Spec: route every WebView through one hardened TrackedWebView (TK-10387, DTD verdict A)
  38. 92f06c15 2026-09-03 mobile: make Alerts an inert coming-soon state — disable the toggle + stop it requesting notification permission until push is wired (App Store 2.1/5.1.1v hardening, TK-11155)
  39. 754ecba2 2026-09-03 auto-data-snapshot: 2026-09-03T15:45:08 (1 data files) — apps/mobile/device-proof-evidence/homesonspec-DEVICE-journey-FINAL-2026-09-03T22-28-13Z.mov.privacy-reviewed.sha256
  40. edbd4388 2026-09-03 web: large mobile-only brand logo leading the homepage hero (TK-11155)
  41. b233a41e 2026-09-03 web: disable the site-wide InstallPrompt PWA banner (TK-11155)
  42. e387ffba 2026-09-03 web+mobile: stable data-hos-install-prompt hook + hide banner in app WebView (TK-11155)
  43. 9b533a90 2026-09-03 mobile: regenerate splash.png as a large full-screen brand logo (TK-11155)
  44. 13331cf6 2026-09-03 snapshot before TK-11155 logo/PWA-banner sweep (pre-existing: tracker-policy extraction, debug-log cleanup, device capture evidence)
  45. febf413e 2026-09-03 auto-data-snapshot: 2026-09-03T14:29:24 (1 data files) — apps/mobile/device-proof-evidence/homesonspec-DEVICE-journey-2026-09-03T21-10-10Z.mov.privacy-reviewed.sha256
  46. e44f3a5f 2026-09-03 fix(homesonspec-mobile): add missing app/index.tsx to fix infinite splash hang on real device (TK-11155)
  47. 3a545346 2026-09-03 auto-data-snapshot: 2026-09-03T13:47:49 (2 data files) — apps/mobile/package.json pnpm-lock.yaml
  48. 6f64cefe 2026-09-03 snapshot before TK-10337 rejection debugging
  49. 9e884ed1 2026-09-03 HoS mobile: block GTM/GA4/Facebook trackers in Browse WebView (Guideline 2.1 Path B)
  50. 6a1800df 2026-09-02 TK-11125: e2e-proof evidence bundle for the payload guard (R3, scratch DB)
  51. 319168ad 2026-09-02 TK-11125: forward-only spurious-generation guard in extractStage
  52. 671fbb26 2026-09-02 TK-11125: add stableStringify + payloadHash canonical hash helper (shared)
  53. c97856c6 2026-09-01 defer SourceEvidence reindex pending bloat evidence
  54. b9a44831 2026-08-31 TK-10878: monthly SourceEvidence VACUUM/REINDEX maintenance (ready+gated) + plan PHASE 3 delivered
  55. ddb43e67 2026-08-31 TK-10878 Phase 2 drafts: fix 3 fatal + 2 hardening review findings
  56. 21b9aad6 2026-08-31 docs(homesonspec): TK-10878 Phase 2 drafts — pg_partman SourceEvidence conversion + provenance-safe retention (not applied)
  57. 7114f6a3 2026-08-31 fix(homesonspec): summit planName cuts at first '<' — no raw markup on fresh crawls (TK-10487)
  58. 8ffc6951 2026-08-30 fix(homesonspec): correct 2 more dead CPG seed termsUrls (brohn/summit /terms-of-use 404 -> claytonhomes.com/legal) (TK-10487)
  59. a0335075 2026-08-30 test(homesonspec): backfill committed selftests for brohn/oakwood/summit — all 13 CPG collectors now fixture-verified (TK-10487)
  60. 3a4b583a 2026-08-30 auto-data-snapshot: 2026-08-30T23:23:51 (5 data files) — collectors/brohn-homes/.gitignore collectors/brohn-homes/fixtures/homes/_urls.tsv collectors/oakwood-homes/.gitignore collectors/oakwood-homes/fixtures/homes/_urls.tsv collectors/summit-homes-kc/fixtures/homes/_urls.tsv
  61. 57212c91 2026-08-30 fix(homesonspec): correct dead Oakwood seed domain oakwoodhomesnc.com(000) -> live oakwoodhomesco.com (TK-10487)
  62. 7fd3d9fe 2026-08-30 docs(homesonspec): wire offload-preflight as mandatory step-0 GO/NO-GO in the runbook — toolkit now turnkey (TK-10809)
  63. c3626f01 2026-08-30 docs(homesonspec): record completed 13-brand CPG roster + corrected authoritative list (TK-10487)
  64. bab4fd97 2026-08-30 ops(homesonspec): read-only offload PREFLIGHT GO/NO-GO — dest capacity + live-crawl + DB checks before the gated 155G rsync (TK-10809)
  65. 235736eb 2026-08-30 fix(homesonspec): berkeley-building — real self-card isolation test + status docs (TK-10487 Cody gate)
  66. 6343338a 2026-08-30 test(homesonspec): wire ops/*.test.mjs into npm test — snapshot-offload safety suite now runs in regression (TK-10809)
  67. c57211a8 2026-08-30 auto-data-snapshot: 2026-08-30T20:54:26 (1 data files) — pnpm-lock.yaml
  68. 669907fb 2026-08-30 add collision-safe Florida Highland collector
  69. 78e4b4f1 2026-08-30 add Berkeley Building CPG collector
  70. 189933f6 2026-08-30 auto-data-snapshot: 2026-08-30T13:27:48 (5 data files) — collectors/berkeley-building/.gitignore collectors/berkeley-building/fixtures/homes/_urls.tsv collectors/berkeley-building/package.json collectors/berkeley-building/tsconfig.json pnpm-lock.yaml
  71. 9eb0f321 2026-08-30 wire(homesonspec): register Elite Homes (Louisville KY CPG) collector (TK-10487)
  72. d575caa2 2026-08-30 feat(homesonspec): Elite Homes (Louisville KY CPG) collector (TK-10487)
  73. c233bfe9 2026-08-30 wire(homesonspec): register Silverthorne Homes (Indianapolis CPG) collector (TK-10487)
  74. f0d509ba 2026-08-30 feat(homesonspec): Silverthorne Homes (Indianapolis CPG) collector (TK-10487)
  75. 86d5d249 2026-08-30 wire(homesonspec): register Arbor Homes (Indianapolis CPG) collector (TK-10487)
  76. 9e1cea83 2026-08-30 feat(homesonspec): Arbor Homes (Indianapolis CPG) collector — yourarborhome.com (TK-10487)
  77. 99a991d9 2026-08-30 add Legacy Alabama CPG collector
  78. ea4d4aee 2026-08-30 auto-data-snapshot: 2026-08-30T10:57:58 (3 data files) — collectors/arbor/fixtures/homes/_urls.tsv collectors/arbor/package.json collectors/arbor/tsconfig.json
  79. ab1b4f74 2026-08-30 fix(homesonspec): harris-doyle uses authoritative dataLayer, not fragile DOM (TK-10487 Cody gate)
  80. 473713d5 2026-08-30 Build and register Harris Doyle collector
  81. 73a0e94f 2026-08-30 TK-10809: snapshot-verify catches DEST symlink false-green before gated delete
  82. 915bd9c2 2026-08-30 TK-10809: add ops/OFFLOAD-RUNBOOK.md (SAFE prod offload ordering, deletion hard-blocked until legacy-abs rewrite)
  83. 66e0038c 2026-08-30 TK-10809: extract classifyForDest pure fn + hermetic verify test; offload VERIFY loop calls it (no behavior change)
  84. a7904b1e 2026-08-30 fix(homesonspec): correct fabricated CPG termsUrls in seed (TK-10487)
  85. ef253225 2026-08-30 Record TK-10809 post-commit proof
  86. cece23b9 2026-08-30 Harden snapshot offload verification boundaries (TK-10809)
  87. ca3c67b3 2026-08-30 Add Mungo and Chafin CPG collectors
  88. aff87907 2026-08-30 TK-10809: offload VERIFY — no false PASS on a sample, tally wrong --src
  89. d461d39d 2026-08-30 TK-10809: single shared snapshot-path resolver (ops/lib), kill 3-way drift
  90. 58cad18e 2026-08-30 ops: non-destructive snapshot offload+verify script + read-only integrity canary (TK-10809)
  91. 0a7e6b34 2026-08-30 snapshot store: store storagePath relative + resolver for volume-move safety (TK-10809)
  92. 7d5c17e6 2026-08-27 pm2(homesonspec): node-direct next start so pm2 owns the port-holder PID (TK-10499)
  93. 7312ce4b 2026-08-26 docs(homesonspec): STEP 1 APPLIED on prod — record actual method + 2 gotchas (owner-role DDL, deploy over-applies add_inventory_specs) + flag 24-day pending migration (TK-10878)
  94. 019ab4e8 2026-08-26 docs(homesonspec): O3 partition + add-disk plan (Steve-chosen path) — disk-first ordering, pg_partman raw-SQL migration, size canary (TK-10878)
  95. 26657d75 2026-08-26 docs(homesonspec): runbook reflects measured reality — index-drop is real STEP 1, corrected apply/verify/rollback (TK-10878)
  96. 63fa1185 2026-08-26 db(homesonspec): guard TK-10878 index-drop with lock_timeout=3s; document CONCURRENTLY-vs-Prisma-txn tradeoff + concurrent-rebuild rollback (codex review)
  97. bd19db5f 2026-08-26 db(homesonspec): drop unused ValidationEvent(ruleId,passed) index — 0 scans, ~508MB reclaim (TK-10878)
  98. 5f8d356c 2026-08-26 ops: DB reclaim runbook (TK-10878) — O1 dedup + O3 partition + revised-O2 truncate; O2-null rejected (public page renders the columns); Cody disk-abort gate
  99. 67563c20 2026-08-24 auto-data-snapshot: 2026-08-24T04:45:01 (6 data files) — collectors/chafin-communities/package.json collectors/chafin-communities/selftest-live.mts collectors/chafin-communities/tsconfig.json collectors/mungo-homes/package.json collectors/mungo-homes/tsconfig.json
  100. e1d685cb 2026-08-17 Add Summit Homes KC collector adapter (TK-10487 batch 2)
  101. d5513153 2026-08-13 HomesOnSpec search: make Table columns bidirectionally sortable (TK-10526)
  102. 1ee4dcd7 2026-08-13 HomesOnSpec search: add Grid/List/Table view modes + broadened server-side sort
  103. db6c10ce 2026-08-12 chore: HomesOnSpec safe full-web deploy runbook (build-gated + git-rollback) + v0.3.2 (TK-10488); drop superseded piecemeal script
  104. a2a0172b 2026-08-12 homesonspec: send scoped Basic auth to usre contractor API (TK-10488)
  105. 552d6aa2 2026-08-12 HomesOnSpec: date-stamp nearby-subs — per-row CSLB issue/expire dates + data-as-of provenance + status=CLEAR
  106. 86f64f40 2026-08-12 HomesOnSpec: 'Find subs near this home' — nearby licensed CA trades on the home detail page
  107. d89b21a7 2026-08-12 chore: sync pnpm-lock.yaml for new collector workspace deps (session close)
  108. ecee95ff 2026-08-12 chore(workers): v0.1.0 → v0.2.0 (session close — 5 new builder adapters integrated: mi-homes, smith-douglas, goodall, brohn, oakwood)
  109. 1b56601e 2026-08-12 auto-data-snapshot: 2026-08-12T09:25:42 (2 data files) — collectors/summit-homes-kc/package.json collectors/summit-homes-kc/tsconfig.json
  110. 4c9e0afc 2026-08-12 TK-10487: oakwood constructionStatus prefers authoritative KOVA Status (contrarian fix) with deterministic date fallback
  111. d3c30ea1 2026-08-12 TK-10487: build Goodall + Brohn + Oakwood CPG per-brand adapters (batch 1); register all 3, typecheck green
  112. e10bc5b7 2026-08-12 oakwood-homes: facts-only inventory adapter (Nuxt SSR + KOVA ERP payload)
  113. 01913195 2026-08-12 collectors/goodall-homes: facts-only inventory adapter (Clayton Properties Group brand)
  114. cfab6b8f 2026-08-12 auto-data-snapshot: 2026-08-12T08:54:38 (2 data files) — collectors/brohn-homes/package.json collectors/brohn-homes/tsconfig.json
  115. 62b2c3cb 2026-08-12 homesonspec search: drill() merges active rail filters (union multi-value st/builder/status) so a card drill narrows context instead of clobbering other selected states (TK-10482 contrarian SHOULD-FIX)
  116. 4d9cd041 2026-08-12 HomesOnSpec: property detail parcel/public-records block + href-drill atoms on listings grid (TK-10482)
  117. be9e4af2 2026-08-12 TK-10001: deploy-kamatera.sh frees :9975/:9976 from orphaned next-servers before pm2 start (fixes EADDRINUSE crash-loop that hung homesonspec.com web tier)
  118. 303b860f 2026-08-11 TK-10001 go-live: activate+ingest mi-homes(25)+smith-douglas(25) to local DB; document MI_STATE=texas footgun + deploy hardening
  119. 4ee4bf92 2026-08-11 TK-10001: pipeline/verify scripts load root .env via tsx --env-file (fixes 'DATABASE_URL not found' on manual pipeline runs)
  120. 66c7ded3 2026-08-11 TK-10001: harden deploy-kamatera.sh — pre-drop pg_dump backup (recoverable full-mirror) + WORKER_HEALTH_PORT=9966 in remote .env (worker was defaulting to 9976, colliding with admin)
  121. d4ac2fbd 2026-08-10 TK-10001: build M/I Homes + Smith Douglas adapters (national 30 fully accounted for); register mi-homes+smith-douglas, stanley-martin+clayton-properties documented-deferred; sanitize third-party public keys from mi-homes fixtures
  122. ef74e6c5 2026-08-10 stanley-martin: DEFERRED — Vite/React SPA, facts via runtime-resolved XHR only (RECON.md)
  123. 8d0fbaf1 2026-08-10 clayton-properties: DEFER recon — scope mismatch (manufactured-only + federated site-built brands)
  124. ec4d72cf 2026-08-10 collectors: add Smith Douglas Homes inventory adapter (facts-only)
  125. 03e75060 2026-08-10 auto-data-snapshot: 2026-08-10T21:49:05 (6 data files) — collectors/mi-homes/fixtures/homes/_urls.tsv collectors/mi-homes/package.json collectors/mi-homes/tsconfig.json collectors/smith-douglas/package.json collectors/smith-douglas/tsconfig.json
  126. f1fb64b6 2026-08-10 HomesOnSpec: 6.7in + 13in-iPad screenshot sets; submitted v1.0 (build 2) to App Review (Waiting for Review 2026-08-10)
  127. ecb8061c 2026-08-10 auto-data-snapshot: 2026-08-10T10:27:30 (6 data files) — apps/mobile/screenshots/ipad13/01-map.png apps/mobile/screenshots/ipad13/02-detail.png apps/mobile/screenshots/ipad13/03-browse.png apps/mobile/screenshots/ipad13/04-saved.png apps/mobile/screenshots/ipad13/05-alerts.png
  128. b4f48f59 2026-08-10 auto-data-snapshot: 2026-08-10T09:56:34 (6 data files) — apps/mobile/screenshots/final67/01-map.png apps/mobile/screenshots/final67/02-detail.png apps/mobile/screenshots/final67/03-browse.png apps/mobile/screenshots/final67/04-saved.png apps/mobile/screenshots/final67/05-alerts.png
  129. 787e39c1 2026-08-10 HomesOnSpec: generate 6 faithful App Store screenshots (1320x2868) from native screen source + real listing data
  130. 4d13307a 2026-08-10 auto-data-snapshot: 2026-08-10T08:23:29 (1 data files) — apps/mobile/scripts/vshots/raw/01-map.png
  131. e8c1a10f 2026-08-10 HomesOnSpec ASC docs: lock 17+ ship decision, © 2026 Steve Abrams, correct simulator→TestFlight screenshot note
  132. ac1caf5d 2026-08-10 chore(workers): pin WORKER_HEALTH_PORT=9966 (9976 taken on Kamatera)
  133. 7ff28c2d 2026-08-09 fix(workers): health-probe bind failure must not crash the worker (TK-10240 prod incident)
  134. 813a5a19 2026-08-09 fix: scope Ashton Woods Widen sweep to LD blocks only, fix stale test (TK-10382)
  135. 2831eee7 2026-08-08 test(workers): real-Postgres integration test for TK-10240 pg-boss resilience
  136. 44bdb168 2026-08-08 TK-10240: homesonspec worker resilience — pg-boss error-ride-out + graceful SIGINT/SIGTERM + health canary
  137. ccf602c5 2026-08-08 Add 5 web-rendered 1320x2868 device-spec App Store screenshots (map/search/home/builders/saved) for iOS submit (TK-10363)
  138. e79924d8 2026-08-07 auto-data-snapshot: 2026-08-07T11:47:33 (1 data files) — apps/mobile/DEVICE-CAPTURE.md
  139. b09e3a6e 2026-08-07 Homes on Spec: enlarge splash logo + wordmark (full-page prominence)
  140. 3a8b1ce1 2026-08-07 auto-data-snapshot: 2026-08-07T10:41:58 (1 data files) — apps/mobile/ASC-PASTE-KIT.md
  141. 9857d3db 2026-08-07 mobile: paste-ready ASC metadata (categories/keywords/URLs/review-info/privacy) — resolved App Privacy=Data-Not-Collected + age-rating finding from code
  142. f9131bf9 2026-08-07 auto-data-snapshot: 2026-08-07T09:37:33 (3 data files) — apps/mobile/screenshots/00-current-state.png apps/mobile/screenshots/01-landing.png apps/mobile/tsconfig.json
  143. 170271c8 2026-08-07 mobile: App Store screenshot shot-list (6 shots, map-led, captions mirror listing copy)
  144. c052b3e2 2026-08-07 auto-data-snapshot: 2026-08-07T09:05:06 (1 data files) — apps/mobile/scripts/build-ios-prod.exp
  145. cc61d3cf 2026-08-07 mobile(eas): capture ASC App ID 6798873898 — future eas submit now fully non-interactive
  146. ae36501c 2026-08-07 mobile(eas): link EAS project @agentabrams/homesonspec (projectId 9d110d60…)
  147. 7b3801dd 2026-08-07 mobile(eas): wire ios submit to reuse account-level ASC key 72Y2TZT54R (IDs only, .p8 referenced by path — matches nineoh-guide committed pattern)
  148. a1eab94c 2026-08-07 chore(web): v0.1.0 → v0.2.0 (PWA install + conversion tracking, session close)
  149. ac289689 2026-08-07 web(pwa): instrument install-conversion funnel — provider-agnostic track() (gtag+dataLayer+first-party /api/pwa-event sink) wired into InstallPrompt (shown/dismissed/result/installed)
  150. ae8f049d 2026-08-06 web(pwa): add smart install prompt (iOS hint + Chromium button, engagement-gated); harden SW (gated skipWaiting, cache caps); honest offline copy — Cody-reviewed
  151. d4c4e1c2 2026-08-06 deploy-web: also ship apps/web/public (PWA icons/sw/offline) + verify PWA endpoints on live https
  152. 85d96884 2026-08-06 web: make HomesOnSpec an installable PWA (manifest + service worker + icons + offline fallback)
  153. 23315d37 2026-08-06 auto-data-snapshot: 2026-08-06T16:03:07 (1 data files) — apps/web/public/icon.svg
  154. 57f4a18d 2026-08-06 homesonspec/mobile: Cycle 3 Cody fixes — enrich gates on staleness alone + always-stamps attempt (fixes never-refresh + 8MB-per-open fetch-storm for homes not in /api/map); adaptive-icon transparent bg (Android mask-safe)
  155. 24cb9a13 2026-08-06 homesonspec/mobile: Cycle 3 — enrich Saved by id from /api/map (shared cache + getHomeById, best-effort, lastEnrichedAt-guarded), status pill, close glyph X->✕, branded icon/splash (functional mark, replace with final art)
  156. 6abe8f2e 2026-08-06 homesonspec/mobile: Cycle 2 Cody fixes — homeDetailUrl /home->/homes (was 404), drop wrong-price DOM scrape (blank > confidently-wrong; Cycle 3 enriches from /api/map by id)
  157. f8ba090b 2026-08-06 DEPLOY.md: document deploy-web.sh as the sanctioned safe web-deploy path (generic deploy.sh --delete would wipe the 85G crawl cache)
  158. 572ac8f7 2026-08-06 homesonspec: Cycle 2 — map viewport-cull+grid-cluster (no 70k freeze), fix save-bridge /home->/homes URL + robust price/loc capture, add /privacy page (local; prod deploy gated)
  159. d67c56fa 2026-08-06 homesonspec/mobile: make Alerts tab honest (no fake delivery claims) + fix 4.2 defense to not cite unbuilt push (Cycle 1 Cody gate)
  160. f6ad8bc6 2026-08-06 scaffold apps/mobile Expo SDK 57 iOS app for App Store onboarding (TK-10305)
  161. adcc2318 2026-08-06 homesonspec: home detail contact ties to builder-as-firm — 📞 phone (salesPhone→builder fallback) · 🏢 builder site · 🔗 listing; outside-agent layer drafted as gated migration
  162. af17a415 2026-08-05 auto-save: 2026-08-05T15:43:31 (1 files) — ops/drain-dr-horton-night.sh
  163. b7da7ff9 2026-08-05 auto-save: 2026-08-05T14:42:56 (1 files) — ops/drain-dr-horton-night.sh
  164. 033d4dbb 2026-08-05 workers: exp_backoff_restart_delay to cap PG-outage restart storms (DTD verdict A + contrarian guardrails) — TK-10239
  165. 53ff5542 2026-08-05 prune: fail-open per-builder (|| true vs pipefail abort) + SNAP_DIR anchor guard + 30d manifest retention (verifier findings) — TK-10236
  166. 5c1b5c47 2026-08-05 ops: minute-precision retention (find -mtime +N truncates to >=N+1 days) — TK-10236
  167. eb45f0f3 2026-08-05 ops: age-based retention prune for snapshot page-cache (7d, live-crawl guard, dry-run default) — TK-10236
  168. 059c2688 2026-08-03 fix(workers): health classifier — DEGRADED on error RATE (>25%), not any nonzero errorCount
  169. d858b396 2026-08-03 feat(toll): raise recurring QMI crawl cap 400->2500 (Steve-approved) so nightly runs pull more of the ~11k inventory; contentHash dedup keeps re-runs cheap
  170. 576365d9 2026-08-03 feat(web): HomesOnSpec attribution on builder contact — 'mention you saw it on HomesOnSpec.com'
  171. 1f01a75d 2026-08-03 feat(toll): wave-2 QMI home ingestion (adapter v2.0.0) — plain-fetch sitemap /Quick-Move-In pages
  172. acd6564e 2026-08-03 docs(toll): wave-2 SOLVED — QMI homes are plain-fetch via sitemap /Quick-Move-In/<id> pages (JSON-LD + __NEXT_DATA__), no browser needed
  173. f98e35a7 2026-08-03 docs(toll): wave-2 recon — ~298 per-community fetches not 11k pages; homes load via amplify SPA XHR (browser-trace = fresh-session task)
  174. d6741529 2026-08-03 docs(specs): 6-builder batch outcome — 4 capture rich per-home specs, 3 deferred (verified thin/bot-walled)
  175. 674ccf86 2026-08-03 feat(specs): perry specs capture — discounted price, promotion, description, elevation, market
  176. 41335772 2026-08-03 feat(specs): meritage specs capture — monthly payment, was-price, move-in, floorplan, incentive, tour, MLS
  177. 1fd7b60a 2026-08-03 feat(specs): pulte specs capture — discount-off-list, monthly payment, basement, active-adult, tour
  178. 7c3609cc 2026-08-02 feat(specs): dr-horton capture proving slice — extract->validate->publish->render
  179. 26f91560 2026-08-02 feat(specs): InventoryHome.specs Json foundation — schema + migration + publisher wiring
  180. dad73003 2026-08-02 docs(specs): audit pass-2 — 14 zeros are unparsed blob shapes, fold into per-builder fan-out; capture is prod-gated
  181. d46a0ce9 2026-08-02 feat(specs): offline field auditor + fleet pass-1 results (all 28 builders)
  182. 3c8b733c 2026-08-02 auto-save: 2026-08-02T17:46:59 (1 files) — scripts/audit-fields.mjs
  183. 478e1c73 2026-08-02 docs(specs): all-specs capture audit — method + dr-horton reference (55 fields, ~10 captured)
  184. 49800740 2026-08-02 feat(web): gated Google AdSense banner slots (top + footer)
  185. 84407145 2026-08-02 fix: import-sweep PATH — add postgresql@14+homebrew bin so psql/npx resolve under launchd (silent no-op 7/31–8/2)
  186. 79ed5aa4 2026-08-02 fix: lennar-mac-refresh PATH — add /opt/homebrew/bin so npx resolves under nohup/launchd (silent all-state no-op otherwise)
  187. 4ad39125 2026-07-30 ops: nightly builder-import sweep (launchd com.steve.homesonspec-imports)
  188. 891f7980 2026-07-30 auto-save: 2026-07-30T08:46:20 (1 files) — pnpm-lock.yaml
  189. fdacc426 2026-07-30 feat(search): Amazon-style collapsed facet rail — 11 data points with live counts
  190. 41e2509b 2026-07-29 workers: register K. Hovnanian adapter (khovnanian-site)
  191. b61d7073 2026-07-29 auto-save: 2026-07-29T21:12:19 (1 files) — apps/workers/package.json
  192. 04b55704 2026-07-29 collectors: add K. Hovnanian adapter (khov.com RSC, 30th builder)
  193. 9c5e6719 2026-07-29 lennar refresh runner: source DB pw from gitignored .env (was hardcoded) + re-establish tunnel per-state
  194. 63d56d74 2026-07-29 auto-save: 2026-07-29T09:37:47 (1 files) — collectors/richmond-american/
  195. 5c09c690 2026-07-29 collectors: add Mattamy Homes — cracked the 'bucket-D' national via Sitecore JSS feed
  196. 718fc16b 2026-07-29 auto-save: 2026-07-29T09:07:36 (1 files) — collectors/mattamy/
  197. e70a69b5 2026-07-29 lennar: durable Mac-side refresh runner (keepalive tunnel + state-by-state pipeline)
  198. 0fbdefeb 2026-07-29 build-loop: add Dream Finders to the throttled sweep rotation + reactivation roster (recovered adapter)
  199. 6a68cd77 2026-07-29 lennar: Mac-side fetch->Kamatera image apply (routes around Lennar 403 IP-block)
  200. 0b79470c 2026-07-29 auto-save: 2026-07-29T07:06:42 (3 files) — collectors/dream-finders/src/index.ts apps/workers/apply-lennar-images.sh apps/workers/src/_lennar-mac-fetch.mts
  201. de09b351 2026-07-29 david-weekley: capture city-gated community MapPoint coord (yolo iter-6)
  202. 11a5e5fa 2026-07-29 pipeline: make evidence delete+create atomic (contrarian fix) — kills concurrent-reextract race
  203. ee8b7a7c 2026-07-29 geocode: shea per-home coord backfill from detail pages (yolo iter-5 prong 2)
  204. c806053d 2026-07-29 auto-save: 2026-07-29T01:34:44 (1 files) — scripts/backfill-drh-geo-refetch.sh
  205. 12220514 2026-07-29 publisher: promote lat/lon on the UPDATE branch too (contrarian critical fix)
  206. fa040b5f 2026-07-29 geocode: one-time dr-horton coord backfill from CACHED snapshots (yolo iter-4)
  207. d99677fd 2026-07-29 dr-horton: capture community coords from in-feed ld+json (yolo iter-4) — fixes 22.5k no-geo
  208. 13b17887 2026-07-28 geocode: 2k-address chunks (was 10k) so bulk backfill fits inside the timeout
  209. 0086b346 2026-07-28 geocode: contrarian FIX-FIRST — city+state gate, full provenance, fail-fast timeout
  210. 139ce339 2026-07-28 geocode: Census-batch enrichment for no-geo homes (yolo iter-3, DTD verdict B)
  211. e3c33f7b 2026-07-28 fulton: parse bed/bath RANGES correctly (contrarian fix) — recovers 36 dropped homes
  212. d9a0af8c 2026-07-28 ashton-woods: tighten image blocklist + purge residual pollution
  213. 840c359e 2026-07-28 collectors: add Fischer, Fulton, GL Homes adapters (+3 builders, yolo iter-2)
  214. 3cf38266 2026-07-28 cody-gate fixes: AW gallery pollution, DW community-photo hero, mediaRights split-brain
  215. 955307e6 2026-07-28 brookfield: drop shouldcountasquickmovein filter (contrarian fix) — recovers +101 homes
  216. 33db5031 2026-07-28 collectors: add Perry, Brookfield, Holt adapters (+3 builders, yolo iter-1)
  217. 590c9393 2026-07-28 auto-save: 2026-07-28T20:33:03 (1 files) — collectors/ashton-woods/src/index.ts
  218. 8e6635cb 2026-07-28 tri-pointe: capture per-home Cloudinary photos (h.image.raw)
  219. 7f27ee91 2026-07-28 david-weekley: capture per-home ElevationRendering photos from list cards
  220. cb83a522 2026-07-28 kb-home: capture listing photos (ThumbnailImage/GalleryPhotos are objects, not strings)
  221. d9241682 2026-07-28 collectors: add LGI, Shea, Century, Beazer, Drees adapters (+5 builders) + loop wiring; gitignore var/snapshots
  222. a867626b 2026-07-28 Add Century Communities scraper adapter (two-layer: findcommunities API + sitemap -> per-home QMI cards)
  223. 9b622394 2026-07-28 auto-save: 2026-07-28T17:01:56 (130 files) — apps/workers/var/snapshots/dr-horton-site/05beb3a14d3b6f3c4063e3ba5b1b171b55ebf2f4b2861da7c46315aa6137a2b4.html apps/workers/var/snapshots/dr-horton-site/1150ce3e873e463a3319027b8253b6f91ab854029e415293eda666ec46b110ea.html apps/workers/var/snapshots/dr-horton-site/18f9d8c17cb43d43975b3e1dc65aaddc4553724dfaaed459865532d8bcbe53fc.html apps/workers/var/snapshots/dr-horton-site/1b4991a8b58b4e688ab28e6035e0c4168cca4e22f37d9623c2cdcca526202a35.html apps/workers/var/snapshots/dr-horton-site/2428b450791da0b294f3a9485d8aed626e20f6c1b94afdc01bd0553d57352e60.html
  224. 20b71fae 2026-07-28 pulte: capture listing photos (feed stores image URL under 'path', not url/src)
  225. c28b10e8 2026-07-28 collectors: add Ryan Homes, Highland Homes, Landsea/Risewell adapters + wire into loop
  226. 0c5a3968 2026-07-28 Add Ryan Homes (NVR) collector adapter
  227. c3bf5d1d 2026-07-28 storefront: render home photos on the search grid (+ absolutize Taylor Morrison image URLs)
  228. 6515c4d4 2026-07-28 build-loop: add Meritage (national Sitecore-Discover feed) to the sweep rotation + reactivation roster
  229. aa57e14f 2026-07-28 collectors: add Meritage Homes adapter (Sitecore Discover national JSON feed)
  230. c4b894e7 2026-07-28 storefront: enable home images (BUILDER_IMAGES_ENABLED=1) — display the 33k builder photos (DRH/Lennar/TM); hotlink verified 200, Steve-approved
  231. 9d820bfe 2026-07-28 build-loop: add Discovery (Seeno-family single feed, run once/sweep) — 127 homes, 100% priced; last unfed adapter
  232. 74b6e755 2026-07-28 build-loop: fully uncapped (DRH/Lennar -> $CAP=100000) + 1h sweeps / 40 max (Steve: download ALL homes)
  233. 15ce8717 2026-07-28 admin/business: link data points to REAL homes — Real-home-listings table (rows → /homes/[id]), KPIs → /search + /builders
  234. 775ea10a 2026-07-28 build-loop: uncap CAP (download ALL homes per state) + 40 sweeps, 1h cadence — max-it
  235. 6d7e3802 2026-07-28 admin: Live site toggle (/live) — embeds the customer storefront with desktop/mobile preview + open-full
  236. f90ea4b6 2026-07-28 build-loop: Lennar + DR Horton page limit 120->300 (Cody: CAP=120 truncated big states alphabetically; adapters default to 300 for exactly this — DRH CA has ~226 communities, Lennar CA ~126)
  237. f00da2b4 2026-07-28 web/search: national-site card upgrades — urgency status badges, est. monthly payment, favorite/save heart (localStorage)
  238. ab43eec2 2026-07-28 build-loop: Lennar uses LENNAR_STATE_FILTER=slug(state) not LENNAR_STATE (adapter reads _FILTER) — was capped to ~7 alphabetical states, now all 42. DTD 5/5, verified
  239. 1f76088e 2026-07-28 KB Home: key community seen-set on name+state (Cody: cross-state name collision) + docstring
  240. c7715e27 2026-07-28 KB Home: national single-run adapter (all-states extract, per-record state) — fixes page-dedup coverage gap + kills 42x redundant 5.8MB fetch. DTD 5/5, root-cause verified
  241. 53fe5d85 2026-07-28 build-loop: add 3 missing AW metros (charleston/jacksonville/myrtle-beach, Cody-gated) + document the intentional roster re-enable
  242. c9a622d6 2026-07-28 build-loop: add Taylor Morrison (state-scoped) + Ashton Woods (metro primitive) — DTD 3/2; both were inactive-not-broken, verified 100% priced/addressed
  243. de14cc6d 2026-07-28 engine viewer: empty 'errors: []' no longer flagged red (honest signal)
  244. c3c35afe 2026-07-28 admin: live Engine viewer (/engine) — terminal-style tail of the pm2 ingest build-loop
  245. a5e1e41e 2026-07-28 admin/business: fully interactive — every data point hrefs to live feed data, real charts, sortable field tables
  246. 72e78889 2026-07-28 admin: Business Analysis page — full analysis + live metrics, accessible in admin
  247. 1a7632dd 2026-07-28 build-loop: correct the misleading 'cheap no-op' comment (unserved state = a real sitemap GET)
  248. 7c8f49be 2026-07-28 build-loop: scope David Weekley sweep to its 7 served states (Cody-gated: avoid wasted sitemap GETs / WAF-bait)
  249. d4ba9f8e 2026-07-28 build-loop: add David Weekley (100% priced, 7 states) to rotation — DTD 5/5 add
  250. de3e088d 2026-07-28 build-loop: throttle Toll (communities-only) to every 8th sweep — DTD 4/5 (Lennar stays full-rate)
  251. b9c9bbc3 2026-07-28 build-loop: add Lennar (state-iterating) + Toll Brothers (national) to ingestion rotation — keep ingesting
  252. 8873056b 2026-07-28 auto-save: 2026-07-28T09:29:05 (1 files) — apps/workers/var/
  253. 04910e04 2026-07-28 admin/ingestion: LEFT JOIN active sources — surface stale/absent sources (Cody-gated: silent-source blind spot)
  254. 80fb6776 2026-07-28 feat: HomesOnSpec data-feed API (:9799) — share the development pipeline with RENTV/partners
  255. 847b94d6 2026-07-28 admin/ingestion: honest error signal — surface per-record homes dropped (per-source), not just failed-run %
  256. 5aea7888 2026-07-28 engine: per-stream liveness — each cylinder fires only when its data stream is moving live (idle streams go dark; RPM=0 when nothing flows)
  257. 70807442 2026-07-28 feat: live V8 'engine room' dashboard (:9798) — pistons/crank/belt driven by real DB throughput
  258. c9a3fdf3 2026-07-28 admin/ingestion: guard sparkline last-value (TS strict index)
  259. 557ae658 2026-07-28 admin/ingestion: live sparkline + new-vs-refreshed + error rate + per-source health table
  260. d44d5270 2026-07-28 auto-save: 2026-07-28T08:58:52 (1 files) — apps/admin/src/app/api/ingestion-stats/route.ts
  261. 3cac9a33 2026-07-28 deploy-kamatera: :80 acme block covers admin.homesonspec.com for renewals
  262. 5064112b 2026-07-28 deploy-kamatera: admin block uses LE cert (admin now in cert SANs)
  263. de505ba8 2026-07-28 feat: LA all-permit ingest + Census permit geocoder + searchable permit viewer
  264. b0103f28 2026-07-28 admin: live ingestion dashboard (/ingestion) — auto-refreshing throughput from Kamatera DB
  265. db9700f2 2026-07-28 build-loop: source repo .env for DATABASE_URL (fixes PrismaClientInitializationError on Kamatera)
  266. 9075f7b0 2026-07-28 feat: construction-pipeline layer — building-permit ingestion + Census geocoder
  267. 89a47a02 2026-07-28 build-loop: honor injected DATABASE_URL (portable to Kamatera cron)
  268. be371282 2026-07-28 deploy-kamatera: rewrite for homesonspec self-host (correct naming, explicit PORT, pgboss grants, LE-cert vhost)
  269. e118a5bd 2026-07-28 build-loop: max-it — fan out 4 adapters in parallel (per-domain), 30rpm, bigger enrich batches
  270. 168b21d8 2026-07-28 build-loop: West Coast first + deeper per-state cap (CAP=120)
  271. 53b1804f 2026-07-28 collectors: add Ashton Woods adapter (national; JSON-LD QMI, per-home geo)
  272. da8824a3 2026-07-28 build-loop: go nationwide — sweep 42 top homebuilding states (all-50 name map)
  273. 40750c02 2026-07-28 fix: david-weekley stories/garages must be integer (1.5-story home 400'd the Houston page)
  274. b319e2f0 2026-07-28 TK-10: add finish-tk10.sh turnkey go-live driver
  275. 887b38f5 2026-07-28 auto-save: 2026-07-28T06:58:06 (2 files) — collectors/discovery/src/index.ts scripts/build-loop.sh
  276. eacead2b 2026-07-27 collectors: add David Weekley adapter (national; server-rendered homes-ready-soon)
  277. 8550e53d 2026-07-27 recon: classify 8 regional builders' plain-fetch inventory feasibility
  278. 444eee61 2026-07-27 collectors: add Discovery Homes adapter (first regional; Seeno-family feed)
  279. c6127358 2026-07-27 auto-save: 2026-07-27T20:54:34 (4 files) — apps/workers/package.json apps/workers/src/cli.ts pnpm-lock.yaml collectors/discovery/
  280. fbd5fc6c 2026-07-27 workers: register 29 Pacific-region regional builders as onboarding targets
  281. 76c1d275 2026-07-27 auto-save: 2026-07-27T20:24:23 (1 files) — scripts/build-loop.sh
  282. 48110bc7 2026-07-27 scripts: all-night autonomous build-loop (ingest x states + enrichment sweeps)
  283. 8dda3328 2026-07-27 workers: public-records nearby-enrichment stage (NCES schools + OSM places)
  284. 7677fe3a 2026-07-27 collectors: enforce robots.txt in LiveFetcher (POLICY compliance)
  285. 7782f9c4 2026-07-27 auto-save: 2026-07-27T19:54:12 (1 files) — collectors/common/src/live-fetch.ts
  286. ce2edb5a 2026-07-27 chore: v0.3.1 (session close — spechomes→homesonspec rename)
  287. 63efe789 2026-07-27 auto-save: 2026-07-27T18:53:10 (95 files) — .env.example README.md apps/admin/next.config.ts apps/admin/package.json apps/admin/src/app/api/review/route.ts
  288. ff7f5937 2026-07-27 Scrub non-owned domain spechomes.com -> homesonspec.com (Layer 1)
  289. 762fa0e5 2026-07-27 chore: v0.3.0 (session close) — honest positioning, admin fail-closed auth, secret history scrub, typecheck gate green
  290. 1c821fb0 2026-07-27 chore(TK-10): finalize secret scrub — gitignore ROLLBACK-DNS.txt, env-based admin test cred
  291. 77fbb632 2026-07-27 auto-save: 2026-07-27T17:22:24 (1 files) — deploy-kamatera.sh
  292. 89f29a3a 2026-07-27 admin: fail-closed auth + generated prod password (TK-10 security #2, partial)
  293. 2fa9a7f9 2026-07-27 auto-save: 2026-07-27T16:52:13 (3 files) — apps/workers/src/pipeline.itest.ts collectors/taylor-morrison/tsconfig.json packages/source-registry/src/
  294. ef45303a 2026-07-27 web: honest Lennar-anchored positioning (TK-10 blocker C)
  295. 0d87dcdf 2026-07-23 chore: v0.2.1 (session close) — spechomes pm2 prod + redeploy scripts
  296. 8f6d3bf8 2026-07-23 auto-save: 2026-07-23T13:51:43 (1 files) — pnpm-lock.yaml
  297. b04f2be0 2026-07-23 add pnpm redeploy scripts (build + pm2 restart) for prod web/admin
  298. 844edb3a 2026-07-23 pm2: boot spechomes-workers via node --env-file so DATABASE_URL loads
  299. ff4a50f7 2026-07-23 chore: gitignore screenrecord/ test artifacts
  300. 4acc9f10 2026-07-23 chore: v0.2.0 (session close) — Taylor Morrison adapter + national multi-state state-fixes
  301. 6612fe5a 2026-07-23 fix(dr-horton,tri-pointe): use real parsed state instead of hardcoded CA
  302. 55372bc1 2026-07-23 fix(pulte): use real state code instead of hardcoded CA (enables multi-state)
  303. ac8dff84 2026-07-23 docs(collectors): update builder status — 5 live, TM egress-blocked, Meritage needs XHR trace
  304. 2570ea05 2026-07-23 fix(workers): declare taylor-morrison collector dep so pnpm links it
  305. 86433ff4 2026-07-23 feat(collectors): add Taylor Morrison adapter (Sitecore fedmodel, CA)
  306. 08c6d176 2026-07-23 fix(collectors): raise DRH+Lennar default PAGE_LIMIT 8→300 for statewide coverage
  307. aa61dfd4 2026-07-23 fix(live-fetch): broaden Accept header so D.R. Horton WAF stops 406ing
  308. f66f9ae4 2026-07-23 Add Tri Pointe adapter (5th builder) — Next.js RSC (unescape + brace-match display_price objects), CA-scoped, WITH lat/lon; verified 3 live Corona homes + community geo/phone; registered
  309. 8456a67d 2026-07-23 Fix new-builder ingest bugs caught on real data: lat/lon optional in home schema (KB/DRH feeds lack per-home geo), TOWNHOUSE→TOWNHOME enum (KB/Pulte), Pulte builder slug pulte→pultegroup + deploy-full pnpm install step
  310. 74786960 2026-07-23 Add Pulte adapter (4th builder) — JSON API (getcommunities + qmiplans), CA-scoped, WITH lat/lon so homes map; verified 8 live Ontario homes + community geo/phone; registered
  311. ca4ba1d7 2026-07-22 CA builders: recon spec doc (collectors/BUILDERS.md) — turnkey extraction specs for Pulte/TriPointe/TaylorMorrison/Meritage; all 6 builders plain-curl/no-anti-bot/per-community-phone
  312. 65775ba2 2026-07-22 Add KB Home adapter (3rd builder) — single-feed (var allMIRs double-decode), CA-scoped, verified 58 communities + 143 live CA homes from one fetch; registered in pipeline
  313. d27cab5c 2026-07-22 Add D.R. Horton adapter (2nd builder) — Sitecore var-model blob, CA-scoped via DRHORTON_STATE, captures homes+community+salesPhone+images; verified 3 live Manteca homes; registered in pipeline
  314. 0d7bc778 2026-07-22 Listings contact: capture per-community sales-office phone from Lennar feed (verified) + Community.salesPhone column + prominent Call button on home detail; Lennar exposes no public email so listings show phone + lead form
  315. c6421408 2026-07-22 Lennar adapter: LENNAR_STATE_FILTER for targeted per-state crawls + drop promo/event non-community URLs (alphabetical full-sweep is too slow to reach late-alphabet states like TX)
  316. ef19ec03 2026-07-22 Fix broken search: when a query doesn't resolve to a location (city/state/builder name), fall back to a free-text filter (city/community/builder/state) instead of silently returning the entire national catalog
  317. 82319816 2026-07-22 Design review fix: dedupe home detail Data-provenance table to one row per field (newest) — kills the ~8x per-snapshot row bloat the visual review caught
  318. 2968a923 2026-07-22 Builder-image kill-switch: BUILDER_IMAGES_ENABLED env gates all photo render sites (default ON) — one flip to compliance pending media-rights decision (DTD panel FIX-THEN-SHIP)
  319. f5b91116 2026-07-22 Contrarian fixes: StagedRecord unique (source,snapshot,home) + upsert/delete-recreate → FORCE_REEXTRACT idempotent (no raw-row bloat); img loading=lazy + hero fetchPriority
  320. bda9b293 2026-07-22 auto-save: 2026-07-22T20:46:37 (1 files) — packages/database/prisma/schema.prisma
  321. f4b686d4 2026-07-22 Featured homes: spread price bands (value ~250-380k / mid ~480-650k / luxury 750k+) so tiers read distinctly
  322. ba86ab2a 2026-07-22 Homepage: 3 featured homes on load — Value / Mid-range / Luxury price tiers, real listings with builder photos
  323. 4be9de78 2026-07-22 deploy-full.sh: also ship collectors + publisher + schemas src (image extractor was silently missing from prod deploys)
  324. ba895b72 2026-07-22 Pipeline: FORCE_REEXTRACT env to re-extract already-snapshotted pages (backfills new fields like images onto unchanged-source homes) + durable grant note
  325. 13997e36 2026-07-22 Builder images: capture per-home photos from Lennar feed (elevationImage/plan/community, verified 58/58 homes), images[] schema+migration, thread through publisher, render in detail hero+gallery+carousel with gradient fallback
  326. 77b81ebe 2026-07-22 Home detail: branded hero header + status badge, 'more homes in this community' carousel, prominent builder-contact CTA (builders-want-to-sell), full brand reskin
  327. da530f2a 2026-07-22 Amazon-style faceted search rail: State (multi-select, 50-state overflow) + Builder/firm + Min Sq Ft facets, live counts, clear-all, sticky scroll; add state facet to API + multi-state param
  328. 008a9dea 2026-07-22 auto-save: 2026-07-22T18:15:55 (4 files) — apps/web/src/app/search/SearchClient.tsx apps/web/src/lib/parse-search.ts packages/search/src/index.ts deploy-full.sh
  329. ec6046b8 2026-07-22 Contrarian gate fixes: guard auto-pause recovery (manual disable stays down), defense-in-depth freshness!=INACTIVE on search+map, honest design-bundle README
  330. 3cb66354 2026-07-22 Stage-3 verification engine: freshness decay + relabel, source-health auto-pause (SourceRun log + counters), cross-source dedup, verify CLI + 9 unit tests, wired into pipeline runs
  331. 832a5c0b 2026-07-22 Design system iter-2: reskin /map explorer panel + /search cards & controls from tokens (brand/accent, Fraunces prices, card-interactive)
  332. 8b8126df 2026-07-22 Design system iter-1: Claude Design bundle (tokens + buttons/badges/home-card/map-legend cards w/ @dsCard markers) staged for DesignSync push
  333. 678cf48b 2026-07-22 Design system iter-1: @theme token layer (brand/accent/status ramps, Fraunces+Inter, radii/shadows), reskin app shell + hero from tokens
  334. be457643 2026-07-22 auto-save: 2026-07-22T17:15:39 (2 files) — deploy-heromap.sh deploy-web.sh
  335. bbbcbc6e 2026-07-22 Add robust map explorer (/map): 12k canvas markers, per-field on/off toggles (status/price/beds/builder), color-by + legend, localStorage-persisted
  336. 13c6b837 2026-07-22 Add live national map to homepage hero (loads on page load) + fix stale demo copy
  337. ab1a3305 2026-07-22 auto-save: 2026-07-22T14:44:58 (1 files) — cert-homesonspec.sh
  338. 1a425935 2026-07-22 rebrand SpecHomes → HomesOnSpec; add /builders directory (all 30 builders w/ coverage, website, live home counts + links)
  339. af67cea5 2026-07-22 clean-relaunch script for homesonspec.com (ship demo-filtered code + purge synthetic DB rows + rebuild + retarget nginx)
  340. f895480f 2026-07-22 HARD RULE: demo/synthetic inventory NEVER surfaces live — isDemo:false filter on search + all consumer queries, isDemo 404-guards on detail pages, banner drops demo language (real builder data only)
  341. 5c857690 2026-07-22 resilience: live adapters skip per-URL fetch failures (404/blip) instead of aborting the whole sweep — a single stale Lennar /promo/ URL killed a 4.4k-page run after 15,974 homes
  342. e8366c4a 2026-07-22 auto-save: 2026-07-22T13:14:23 (1 files) — ROLLBACK-DNS.txt
  343. 6e35e39f 2026-07-22 fix: relative import for parse-search (the @/ alias mis-resolved against inherited baseUrl under next build — never caught because prod build was never run locally)
  344. 013b8284 2026-07-22 yolo: harden go-live scripts per contrarian (self-signed origin TLS + CF Full, admin origin-only, default_server preflight, rollback capture)
  345. 030753f0 2026-07-22 go-live scripts (Kamatera deploy + CF/GoDaddy cutover), gitignored (contain infra topology); pm2 env hardening
  346. 30af0843 2026-07-22 go-live: Kamatera deploy script; start scripts respect PORT env; national-builder recon recorded (batches 3-4); dream-finders adapter
  347. 0e090e44 2026-07-22 auto-save: 2026-07-22T12:13:58 (1 files) — collectors/dream-finders/
  348. 4ba331cd 2026-07-22 source runbooks for toll-brothers + lennar live adapters
  349. 45f9ee29 2026-07-22 lennar live adapter (172 real homes from 8 pages, Apollo state extraction), streaming runPipeline for large sweeps, honest early-preview banner
  350. f0e81ad0 2026-07-22 top-30 builder registry + recon findings recorded; toll-brothers live adapter: 337 real communities ingested via sitemap-sanctioned feed, full evidence trail; positioning update (no one-stop place)
  351. 14131617 2026-07-22 polite LiveFetcher (rate-limited, never circumvents blocks) + top-10 national builder registry seed (sources PAUSED until recon + activation)
  352. 4dce3d29 2026-07-22 pm2 ecosystem config, 9 ADRs, data-rights policy, source runbook template, README
  353. 0ba88221 2026-07-22 integration tests (pipeline e2e, only-writer invariant, review-approve flow) + 7 Playwright e2e specs, all green
  354. 73a5db3e 2026-07-22 generalize pipeline: hints column on StagedRecord, publisher resolves builder/community from hints, label derives from collection method, live/fixture mode from registry
  355. 7c746ccb 2026-07-22 fix Leaflet SSR: keep MapView out of the shared-ui barrel, subpath dynamic import
  356. 6b477e66 2026-07-22 consumer web app (search/detail/community/builder/contact) + admin app (review/sources/validation/snapshots) + publisher package extraction; both apps serving
  357. 75e00bb8 2026-07-22 worker pipeline (fetch/extract/validate/publish) + CLI + synthetic seed; fixture pipeline e2e green, idempotent re-run, dup rule scoped to zip
  358. 1e9a023a 2026-07-22 collector adapter contract + meridian-homes fixture adapter with hand-authored extraction contracts (7 tests green, null-never-guessed proven)
  359. d6358033 2026-07-22 shared utilities (canonicalKey/geo/queue) + zod schemas + validation engine with 10 rules, 31 unit tests green
  360. 1aad19ce 2026-07-22 initial scaffold: pnpm monorepo, Prisma schema (published + raw pipeline sides), migrations applied

Authors

Agents used

  • secrets-manager1

Skills used

  • /mobile35
  • /claude25
  • /code25
  • /baths20
  • /sqft19
  • /homes16
  • /beds16
  • /workers15
  • /lon13
  • /package12
  • /screenshots12
  • /snapshots11
  • /tsconfig10
  • /deploy9
  • /geo8
  • /community8
  • /search8
  • /state7
  • /stories7
  • /index6
  • /legal6
  • /fixtures6
  • /garage6
  • /map6
  • /web5
  • /seed5
  • /price5
  • /plan5
  • /status5
  • /builder5

Creative ideas + design notes

Commits with substantial prose (≥120 chars) — the rationale behind each move.

ed938c0f · 2026-09-13 · Publish a fleet-health heartbeat: this poller was invisible to the rollup
Found by a red-team pass on my own changes. fleet-health-rollup globs
~/.claude/skills/*/data/latest.json and SILENTLY SKIPS a skill with no such file
(`if (!existsSync(file)) continue`). This poller wrote state only to
ops/runtime/, so it contributed ZERO signal and was unknown to
dw-canary-meta-watchdog too: if it died, the 7am panel would say nothing was
wrong — about the one app under a live Guideline 5.6 conduct citation.

Worse, my previous commit's own comment claimed "alert_delivered lands in
latest.json for fleet-health-rollup". There was no latest.json for this skill.
I asserted an integration I never tested, in the same session spent hunting
exactly that failure. Comment corrected; the integration now actually exists and
is actually tested — the rollup picks the row up (verdict=ATTENTION, status=WARN).

- heartbeatStatus(): approved/pending -> PASS, rejected -> WARN (matching
  ios-release-train's ATTENTION), and an outcome we could NOT measure ->
  NOT_MEASURED/WARN, never PASS (TK-11431 #1). A null state means ASC was
  unreachable or the row did not parse; that is not evidence all is well.
- Published AFTER the durable state write and wrapped so a heartbeat failure can
  never cost the observation.
- Never published from a --fixture run (the seam guard learned earlier today).
- Two tests lock the mapping, incl. the negative case.

TK-11155

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPS3gnB4H5MQKmWcHKvuf6
471d1568 · 2026-09-13 · Poller: notify() must never be able to fail its caller
My previous commit moved notify() BEFORE the log/state write so alert_delivered
lands in latest.json for fleet-health-rollup. That made bookkeeping able to break
the measurement: a throw in the new cncp_post shell-out would cost the observation
AND leave a stale state file, which then re-fires the same "change" next run.
_shared/alert_receipt.sh states this rule in its own header; I violated it.

Wrapped in try/catch returning false. Proven on the LIVE path with a clean runtime
dir (previousState=null forces stateChanged=true so notify actually runs):
state persisted, alert_delivered=true, real runtime dir untouched.

Noted honestly: the success path is proven; the catch is belt-and-braces, since a
missing helper makes `bash -c '. helper && …'` exit nonzero rather than throw.

Two earlier attempts at this test were vacuous and are recorded so they are not
repeated: --fixture skips notify entirely (`&& !fixturePath`), and repointing HOME
breaks ipa-status's key lookup before notify is ever reached.

TK-11155

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPS3gnB4H5MQKmWcHKvuf6
043c09b7 · 2026-09-13 · Apple review poller: stop disarming itself while awaiting Apple
The poller treated REJECTED as terminal and called launchctl remove on
every run, i.e. it tried to unschedule itself 303 times since 09-08. It
survived only because JOB_LABEL said 'com.steve.homesonspec-apple-review'
while the label actually loaded is '...-apple-review-v2', so every removal
returned status 3 (no such label). Correcting that constant alone would
have armed the self-destruct.

- shouldDisarm(): only an 'approved' outcome may stop the monitor. REJECTED
  is the state we are waiting to LEAVE while a Resolution Center reply is
  outstanding; stopping there blinds us at the moment it matters.
- JOB_LABEL corrected to the label that is actually loaded, with a comment
  that it is only safe alongside the guard above.
- Alert on state CHANGE only (was: a desktop banner every 15 minutes) and
  record alert_delivered via the shared cncp_post helper, which asserts the
  HTTP status instead of swallowing it.
- Negative tests: an attention outcome must NOT disarm, with a positive
  control so the guard cannot pass as dead code, plus a JOB_LABEL/plist
  assertion. Verified red-then-green by re-injecting the original logic;
  all 5 pre-existing tests stayed green through the injected fault, which
  is why this shipped untested.

TK-11155

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPS3gnB4H5MQKmWcHKvuf6
fb984ed6 · 2026-09-11 · eas: pin production ios.image=latest (ITMS-90725 guard)
Fleet sweep under TK-11155 found this app missing the guard that Charge & Explore
needed after sitting at 0 builds in ASC on an ITMS-90725 upload bounce. The
documented fix is exactly this line (Xcode 26 / iOS 26 SDK image), and the
chargeandexplore-release canary treats it as a HARD gate.

Cheap insurance: without it a production build can bounce on upload after the
EAS build has already been paid for.

Semantic diff confirms this adds build.production.ios.image only; nothing else
removed or changed. JSON re-validated.

Refs TK-11155.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
0200179c · 2026-09-10 · TK-11303: retire stale v1 apple-review launchd plist (superseded by v2 wrapper)
The direct-node plist (ops/com.steve.homesonspec-apple-review.plist) is the
job launchd bootstrapped once via RunAtLoad then DROPPED (no persistence),
and it ran apple-review-poller.mjs from the wrong cwd -> ENOENT mkdir /ops/runtime.
It is superseded by com.steve.homesonspec-apple-review-v2 (~/Library/LaunchAgents,
runs ~/.claude/skills/homesonspec-apple-review/run.sh, which cd's to the project
root and exec's the SAME ops/apple-review-poller.mjs). Nothing auto-bootstraps
ops/*.plist, so the file was an inert footgun. The poller .mjs + its test stay
(v2 depends on them; 5/5 tests pass). Reversible: git revert restores the file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdRDCrJcC2BcsYP7k3CxyA
31581ff8 · 2026-09-10 · TK-11364: version + golden-lock the TK-11125 guard's canonicalization contract
Document and version the spurious-generation guard's two canonicalization
primitives (codex follow-up). canonicalKey is stored + used as the guard's
lookup key, so a rule change re-mints one generation per home (drift-SENSITIVE);
payloadHash is recomputed on both sides at compare time, so a rule change is
self-consistent and mints nothing (drift-IMMUNE). Adds CANONICAL_KEY_VERSION /
PAYLOAD_HASH_VERSION, a golden-vector contract test that breaks the build on any
silent rule change (forcing a conscious version bump), CANONICALIZATION-CONTRACT.md,
and a guard-comment cross-reference. Code/docs only — no schema, no data write.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdRDCrJcC2BcsYP7k3CxyA
3e4d499f · 2026-09-10 · O3b: ValidationEvent partition conversion script (corrected pattern)
Second half of O3. Same ATTACH path as SourceEvidence but built on the
corrected pattern from today's run rather than repeating its mistakes:

- per-partition FKs, never a parent FK before ATTACH (that forced a 170M-row
  revalidation under ACCESS EXCLUSIVE and stalled the site for ~7 minutes)
- GRANTs on the parent and every partition, and the run aborts if any partition
  is left ungranted (a postgres-created table has no app-role ACL, which 500'd
  the public page with 42501)
- verification includes an app-role query in the exact shape the admin pages
  use (SET ROLE homesonspec; WHERE passed=false ORDER BY runAt DESC LIMIT 100)

runAt is timestamp(3) without time zone, so bounds use TIMESTAMP literals
rather than the ::timestamptz casts used for SourceEvidence.

Scratch-tested: rows preserved, new rows route to the correct monthly
partition, default partition stays empty, admin query shape returns rows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HpKbjp2febJ1r8BNTyZwvP
0f94115d · 2026-09-10 · O3: add grant script so future partitions inherit the app-role ACL
The inline paste kept line-wrapping in the terminal, which split 'sudo -u' from
its argument. Same file-pipe pattern as o3-apply.sh: short command, no wrapping.

Sets ALTER DEFAULT PRIVILEGES so a partition created later by postgres is
automatically granted to the app role instead of silently 42501-ing writes to
that range, backfills any partition currently missing the grant, and verifies
both the ACL and that a real home detail page still returns 200.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HpKbjp2febJ1r8BNTyZwvP
cc0a0516 · 2026-09-10 · O3: fix the two bugs the live run exposed (FK-before-attach stall, missing GRANTs)
The conversion succeeded on prod but caused two problems the 20k-row scratch
test was too small to expose. Both are now fixed in the script.

1. FK-before-ATTACH stalled the live site ~7 minutes.
   Adding the foreign key to the partitioned parent BEFORE attaching makes
   Postgres re-validate that FK against every row of the incoming partition --
   170M rows joined against StagedRecord -- while holding ACCESS EXCLUSIVE.
   Peak 33 app queries blocked, oldest waiting 396s. lock_timeout did not help
   because the lock was already acquired; the cost was in the work, not the
   wait. The legacy partition already carries its own valid FK and forward
   partitions are empty, so per-partition FKs are correct and instant.

2. Missing GRANTs 500'd the public home detail page.
   A table created by postgres has no ACL for the app role, so
   prisma.sourceEvidence.findMany() failed with 42501 'permission denied for
   table SourceEvidence' on /homes/[id]. The script now grants on the parent,
   the default partition and every forward partition, and sets ALTER DEFAULT
   PRIVILEGES so future partitions inherit the grant instead of silently
   breaking writes to a new range.

Also adds an app-health assertion to VERIFY: it fetches a real published home
detail page and aborts unless it returns 200. The original script verified the
database thoroughly and never once checked that the application still worked,
which is why a 500 reached users.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HpKbjp2febJ1r8BNTyZwvP
a15775f6 · 2026-09-10 · O3: add prod apply script for the partition conversion
One self-aborting script implementing ops/o3-partition-PROVEN-runbook.md.
Preflight hard-aborts on a stale/missing backup, <15G free disk, or row loss.
STEP 1 (VALIDATE CONSTRAINT) is online under SHARE UPDATE EXCLUSIVE; STEP 2 is
a single catalog-only transaction with lock_timeout so it aborts cleanly rather
than queueing behind a long transaction.

Adds two things the runbook did not have, both surfaced while preparing the
real run:

- a DEFAULT partition. Without it, a row whose createdAt falls outside every
  defined range raises 'no partition of relation found' and ALL ingestion
  stops. The verify step asserts it stays empty, which is also the alarm for a
  missing forward range.
- forward monthly partitions through 2027-12, so partition exhaustion cannot
  break ingestion unattended.

Mac2 is classifier-blocked from prod SSH, so this runs from Steve's shell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HpKbjp2febJ1r8BNTyZwvP
d6400d4d · 2026-09-10 · O3: prove SourceEvidence partitioning is feasible with no rewrite and no data-model change
Tested the ATTACH-based conversion end-to-end on a scratch PG 14.23 DB and
disproved the three blockers this work has assumed since 2026-08-26:

- pg_partman is NOT required (native PG14 declarative partitioning suffices)
- the conversion needs ~0 extra disk, NOT ~82GB of scratch for a rewrite
- no composite-PK / Prisma data-model change is needed, because a PK-less
  partitioned parent lets the legacy partition keep its own local PK

Verified on prod (read-only) that nothing has an incoming FK to
SourceEvidence.id, createdAt is NOT NULL, and the only constraints are the PK
and the StagedRecord FK. Verified in code that all four app call sites key on
stagedRecordId or entityType/entityId -- there is no findUnique by id anywhere,
which is also why SourceEvidence_pkey (11GB) shows 0 scans.

Scratch proof: 20k/20k rows preserved with the legacy heap unchanged (no
rewrite), insert routing correct, FK still enforcing, pruning working, both hot
indexes still used per partition, DETACH/re-ATTACH round-trips cleanly (the
payoff: cold archive without deleting history), and all four real app
operations plus cross-partition row movement pass.

Measured partition fan-out on the public-page query across 36 monthly
partitions: execution 0.4-0.6ms and planning within noise of the unpartitioned
baseline, so fan-out is not a concern at realistic partition counts.

Only real prod cost is one ~82GB sequential scan during VALIDATE CONSTRAINT,
held under SHARE UPDATE EXCLUSIVE, which does not block reads or writes.

Still deferred: feasibility is no longer the blocker, necessity is. Execute on
a TK-11363 trigger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HpKbjp2febJ1r8BNTyZwvP
82fadf19 · 2026-09-10 · ops: preflight now VALIDATES the rollback dump instead of suggesting it (TK-11364)
Checklist item 2 has always said the dump must be validated with pg_restore
--list, but that was a note a human had to remember at 3am. Nobody ever ran
it, so O3's entire rollback rested on an unverified 12.8GB file.

Preflight now does it automatically, cheaply:
  - pg_restore --list, and assert SourceEvidence/StagedRecord/ValidationEvent/
    InventoryHome are actually present in the TOC
  - read the LAST data block in the archive

The tail read is the one that matters here. A pg_dump killed by a full disk
produces a VALID TOC with a truncated tail, and the TOC sits at the FRONT of a
custom-format archive — so reading it proves nothing about the tail. That is a
live risk on this box, which is at 94% and already skipping other backups (the
BACKUP-SKIPPED flag printed right below). Reading the last block forces a seek
to near EOF and does catch it. Both checks measured ~0.04s on the real dump.

Also prints the full-archive proof command for pre-window use rather than
running ~6 min of CPU on every preflight.

Verified live against today's dump: TOC OK (30 tables), all four critical
tables present, tail read OK. Separately ran the full proof out-of-band —
pg_restore of the entire SourceEvidence data block exited 0 after 2m11s
(13GB read), so today's dump is a genuinely valid rollback.

Read-only against prod; no mutations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
616032a6 · 2026-09-10 · ops: fix preflight rollback check reporting a false "no backup" (TK-11364)
Section 7 globbed /root/backups/* which only matches the top level, so it
missed the real dumps in /root/backups/db/ and printed "no obvious dump found"
while a fresh 12.8GB homesonspec dump sat one directory down. On the rollback
check a false "none" is the worst possible answer — it either aborts a window
unnecessarily or, worse, normalizes proceeding without a verified rollback.

Now finds the actual dump, prints size + age, warns past a nightly cycle,
restates the pg_restore --list validation the checklist requires, and fails
loud with an explicit "there is no rollback" if none exists.

Also surfaces BACKUP-SKIPPED flags, which are themselves a rollback risk.
Verified live: one is present today — DW-Agents nightly skipped at 03:30 with
only 34G free, refusing to run to protect Postgres. That flag would otherwise
have sat silent while someone planned a conversion.

Verified read-only against prod; no mutations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhnABoxWtpF7mbBowoBWhb
14ed1904 · 2026-09-10 · ops: make Phase-2 preflight actually enforce the disk gate (TK-11364)
Three defects found while validating the O3 runbook against live prod.

1. The disk gate only PRINTED df and relied on a human doing the math — at
   exactly the spot where Cody's hard "abort if <75GB free" lives. Combined
   with the plan doc's (false) claim that the volume grow had happened, a
   session could read past it and start a rewrite that fills the volume and
   takes prod Postgres down. Now machine-checked, loudly reported, and the
   script exits non-zero with an ABORT banner so no wrapper can proceed on a
   skimmed report. Verified against prod: FAIL at 44GB free, exit 1.

2. Section 6 ("is import traffic quiet?") ran count(*) WHERE createdAt >
   now()-'2 min'. There is no index on createdAt, so that was a full seq scan
   of the 82GB heap on the check you re-run most often while waiting for a
   window to go quiet. Replaced with a pg_stat_user_tables n_tup_ins delta:
   instant, no heap read, and measures live insert RATE. Whole preflight now
   completes in ~80s instead of blowing a 90s budget unfinished.

3. New section 8 surfaces the index inventory and flags the material fact that
   SourceEvidence has NO index on createdAt — the column Phase 2 partitions on.
   partition_data_proc drains by createdAt range, so every batch is a seq scan
   unless an index is built first. That is a build-it-up-front-vs-accept-it
   decision, not something to discover mid-window.

Section 5 also now prints an instant reltuples estimate before the slow exact
count, with the seq-scan cost called out.

Verified read-only against prod; no mutations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhnABoxWtpF7mbBowoBWhb
88e393b7 · 2026-09-10 · docs: correct stale/false facts in O3 partition plan (TK-11364)
The plan claimed the Kamatera volume grow had happened and that it solved the
disk refill. It did not — sda is still 700G with 112d uptime; Steve deferred
Phase 1 on 2026-09-03. A future session reading this would assume Phase-2
headroom that does not exist.

Adds a status-correction banner reconciling the doc against read-only prod
measurement plus the independent homesonspec-size-canary heartbeat:
growth 16 -> 3.24 GB/wk (TK-11125 payload guard), SourceEvidence 55 -> 82GB,
free space 67 -> 44GB (preflight item 1 now FAILS), size canary already armed,
step-1 index drop already applied, and the "retention gets turned ON" pull
trigger permanently dead per Steve's keep-full-history ruling.

Body preserved as written for audit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhnABoxWtpF7mbBowoBWhb
aaf2c487 · 2026-09-04 · snapshot before restart: preserve in-flight work
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gbmuMHgCLDEPM4TpfAr4G
ba37b54c · 2026-09-04 · mobile: make the tracker-drift canary baseline-aware (was firing on steady state)
As first written the canary exited 1 whenever ANY uncovered third-party host was
present — which is permanently true, because homesonspec.com serves listing photos
from www.drhorton.com and awh.widen.net. A canary that fires on the steady state is
noise and gets ignored, which is the one failure mode that makes it worthless.

Now baseline-aware, per house canary doctrine: known-benign hosts live in
tracker-drift-baseline.json, are reported as 'accepted', and do NOT fail. Exit 1
fires only on a host that is NEW since the baseline — an actual worsening transition.
Adds --accept to fold a newly verified asset host into the baseline.

Baseline seeded with the two hosts verified 2026-09-04 by inspecting the page source:
both appear only as <img src> listing photos (D.R. Horton product catalogue, Widen
DAM CDN), so they are asset hosts, not trackers.

Verified both directions, not just the quiet one:
  steady state          -> PASS, exit 0
  simulated new host    -> FAIL, names www.drhorton.com, exit 1
  baseline restored     -> PASS, exit 0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEhnWQSSkAhSYxWXHJ3MCw
693125b2 · 2026-09-04 · mobile: add tracker-drift canary guarding the 'Data Not Collected' privacy label
The Browse WebView blocks trackers with a DENYLIST (lib/tracker-policy.ts, 7 hosts),
so the App Privacy label's truth is contingent on homesonspec.com's tag set. Add a
pixel whose host is not on that list — a new ad network, a self-hosted fbevents.js,
or a server-side-GTM first-party proxy — and it passes silently, with no app rebuild
to catch it, quietly making a filed 'Data Not Collected' label FALSE. On an account
already cited under Guideline 5.6 for a declaration that did not match a binary, that
is the drift that matters.

The canary fetches the live site, extracts every third-party host, and flags any not
covered by the denylist. Exit 1 on drift.

Current run: BLOCKED = www.googletagmanager.com + connect.facebook.net (the two real
trackers, both covered). UNCOVERED = www.drhorton.com + awh.widen.net, both verified
by inspecting the page as <img src> listing photos (builder product catalogue and the
Widen DAM CDN) — asset hosts, not trackers. So the label is accurate today.

Also confirmed while wiring this up: the blocker IS correctly applied. components/
TrackedWebView.tsx PREPENDS the block script to any caller-supplied
injectedJavaScriptBeforeContentLoaded and AND-s !isTrackerUrl() with the caller's
onShouldStartLoadWithRequest, so a caller cannot accidentally disable it — and the
existing suite enforces it architecturally ('the wrapper is the one place WebView is
imported', 'no file outside the wrapper imports WebView', 'every WebView rendered in
app/ is a TrackedWebView'). 12/12 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEhnWQSSkAhSYxWXHJ3MCw
4df903f1 · 2026-09-04 · mobile: cap rendered map markers (120, densest-first) + lower grid density — fix react-native-maps on-device OOM crash on the Map tab (TK-11155)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQi5poZk3YeUbEJbDcFRmc
f2de197d · 2026-09-04 · Homes on Spec: actually test the tracker-blocking script (TK-10387)
The App Store 'Data Not Collected' claim rests on the injected TRACKER_BLOCK script
working. Until now only isTrackerUrl() — the native-side URL filter — had tests. The
script doing most of the work (neutering gtag/fbq/dataLayer and intercepting
fetch/XHR/Image/sendBeacon inside the page) had none, so 'it looks right' was the only
evidence behind a claim we make to Apple.

- lib/tracker-block.ts now exports buildTrackerBlock(hosts) and has ZERO imports, so
  node --test can load it directly (Node's ESM resolver requires explicit extensions,
  which the TS/Metro resolver does not use). TrackedWebView composes it from the real
  TRACKER_HOSTS, so the shipped behaviour is unchanged.
- lib/tracker-block.test.mjs runs the REAL script text, built from the REAL host list,
  in a vm sandbox with a fake window/document, and asserts observable behaviour rather
  than string matching: gtag/fbq/dataLayer.push are no-ops (and dataLayer does not
  accumulate), tracker fetch short-circuits to an empty 204 while first-party fetch
  reaches the real implementation, GA4's sendBeacon transport is refused, tracker XHR
  never sends, the Facebook tr pixel never gets a real src, subdomains of tracker hosts
  are blocked, and a lookalike domain is NOT blocked so the filter cannot over-reach
  and break the site.

12/12 tests pass; tsc --noEmit clean. This verifies the MECHANISM only — the panel's
binding condition still stands: do not file 'Data Not Collected' until a full-device
proxy capture across all four tabs is clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfGYEoLBywwJD1nfrHe1on
2726cf35 · 2026-09-04 · Homes on Spec: correct stale README claims that misled a downstream review (TK-10387)
Item 4 said the EAS projectId was still the SET-AT-EAS-INIT placeholder. It is not —
app.json has carried a real projectId for some time. That stale line is what led an
earlier review pass to conclude push registration could never fire, which inverted the
actual finding: registration DOES succeed, so getExpoPushTokenAsync was handing a
device identifier to Expo for an Alerts feature that cannot deliver anything.

Item 1 now describes the PUSH_BACKEND_READY gate and states the flip must happen in
the same change that wires the backend. Item 5 marked done — /privacy returns 200,
verified today.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfGYEoLBywwJD1nfrHe1on
d98894aa · 2026-09-03 · Homes on Spec: route every WebView through one hardened TrackedWebView (TK-10387, DTD verdict A)
The Browse tab was hardened against homesonspec.com's GTM/GA4/Meta-pixel, but
saved.tsx opened a SECOND raw <WebView> to the same site with no injected tracker
block and no URL filter — so trackers ran freely there and an App Store
'Data Not Collected' label would have been FALSE.

The leak happened because hardening was a per-call-site ritual that had to be
remembered. A DTD panel ruled A (complete the blocking) 4/7, and the contrarian's
surviving objection was that A-as-scoped repeats the same failure mode. So this is
structural rather than another copy-paste:

- components/TrackedWebView.tsx is now the ONLY file importing the WebView
  component. It always applies TRACKER_BLOCK and the isTrackerUrl filter. A caller's
  injectedJavaScriptBeforeContentLoaded is APPENDED (never replaces the block), and a
  caller's onShouldStartLoadWithRequest is AND-ed (can restrict, never loosen).
- browse.tsx and saved.tsx both render <TrackedWebView>; browse keeps WebView only
  as a type import for useRef<WebView>.
- lib/webview-guard.test.mjs fails the suite if any file outside the wrapper imports
  the WebView component or renders a raw <WebView>. It caught a real miss on its
  first run.

Also stops handing a device identifier to a third party for a feature that cannot
work: getExpoPushTokenAsync() round-trips to Expo's servers, but the backend
registration POST is still commented out, so no alert can ever be delivered. Token
minting is now gated behind PUSH_BACKEND_READY (false), to be flipped in the same
change that wires the backend. Permission is still requested, so the Alerts toggle
is unchanged.

tsc --noEmit clean; 5/5 tests pass. Local only — no deploy, no submit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfGYEoLBywwJD1nfrHe1on
92f06c15 · 2026-09-03 · mobile: make Alerts an inert coming-soon state — disable the toggle + stop it requesting notification permission until push is wired (App Store 2.1/5.1.1v hardening, TK-11155)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQi5poZk3YeUbEJbDcFRmc
edbd4388 · 2026-09-03 · web: large mobile-only brand logo leading the homepage hero (TK-11155)
Add a transparent-background house-mark SVG (public/logo-mark.svg, brand
navy/orange, distinct from icon.svg's opaque app-icon variant) and render
it large (h-36 w-36, capped at 55vw) with the "Homes on Spec" wordmark
above the existing "Every new home..." headline in the hero. Scoped with
sm:hidden so desktop/tablet layout is unchanged; only mobile viewports get
the large lead logo.

Verified: pnpm --filter @homesonspec/web build succeeds (Next 16 compiles,
typechecks, and generates all routes). Not deployed.

Reversible: git revert this commit.
b233a41e · 2026-09-03 · web: disable the site-wide InstallPrompt PWA banner (TK-11155)
Comment out the import + usage of <InstallPrompt /> in layout.tsx rather
than deleting the component, so re-enabling the "Add to Home Screen" nag
later is a 2-line uncomment. The native iOS/Android app is now the install
path Homes on Spec is steering users toward.

Reversible: uncomment the two marked lines in layout.tsx, or git revert.
e387ffba · 2026-09-03 · web+mobile: stable data-hos-install-prompt hook + hide banner in app WebView (TK-11155)
- InstallPrompt.tsx: add data-hos-install-prompt to the dialog root so other
  surfaces (the mobile app's WebView CSS) can target it reliably without
  depending on Tailwind utility classes that may change.
- browse.tsx: add "[data-hos-install-prompt] { display: none !important; }"
  to the injected CSS so the site's "Add to Home Screen" banner never shows
  inside the native app's Browse WebView (the native app already IS the
  install; the web nag is redundant/confusing there).

Reversible: git revert this commit.
9b533a90 · 2026-09-03 · mobile: regenerate splash.png as a large full-screen brand logo (TK-11155)
Original splash.png was a full-screen navy canvas with a tiny centered
house-icon + wordmark glyph (content occupied only ~33% of screen height).
Regenerated the asset by extracting the icon and wordmark artwork and
upscaling/recentering them to ~88-92% of screen width so the logo reads as
large/full-screen-prominent on launch, keeping the same #1a3a6e background
and expo-splash-screen config (resizeMode: contain, no app.json change
needed since the asset itself now fills the frame).

Reversible: git revert this commit to restore the small-glyph asset.
e44f3a5f · 2026-09-03 · fix(homesonspec-mobile): add missing app/index.tsx to fix infinite splash hang on real device (TK-11155)
Root cause: expo-router had no route matching the root path ("/"), so
resolving the initial deep link (homesonspec:///) fell through to the
internal "+not-found" fallback - which has no screen actually registered
in the root Stack (app/_layout.tsx only declares the "(tabs)" group).
React Navigation's NavigationContainer never reaches a resolvable ready
state, so it renders its `fallback` (null) forever and the native splash
screen (SplashScreen.hideAsync() never gets a chance to matter) never
clears. No JS error, no crash - a silent, permanent hang confirmed via
device syslog breadcrumbs tracing execution through registerRootComponent
-> ExpoRoot -> getInitialURL -> getStateFromURL (resolved to "+not-found")
and then nothing further for 60+ seconds.

Fix: add app/index.tsx that <Redirect>s "/" to "/(tabs)/browse", giving
the router an always-resolvable initial route. Verified on a physical
iPhone (from-source Release build): app now reaches Browse tab with real
homesonspec.com content and Map tab with live Apple Maps pins.
9e884ed1 · 2026-09-03 · HoS mobile: block GTM/GA4/Facebook trackers in Browse WebView (Guideline 2.1 Path B)
Neutralizes analytics/ad trackers in the homesonspec.com WebView so the app
truthfully collects nothing: stubs gtag/dataLayer/fbq/google_tag_manager and
intercepts every WKWebView-exposed network primitive (createElement src,
Image/img pixels incl. the FB <noscript> fallback, fetch, XHR, sendBeacon) plus
a native onShouldStartLoadWithRequest host filter. Verified via WebKit network
capture: 5 tracker requests before, 0 after.

Also replaces the SET-AT-EAS-INIT push projectId placeholder with the real id
from expo-constants (token stays local; no backend POST, no new data collection).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNivxV68DdxP1rvhViBfcN
6a1800df · 2026-09-02 · TK-11125: e2e-proof evidence bundle for the payload guard (R3, scratch DB)
Verdict PASS. 5 data-boundary cases + unit tests, all green on
homesonspec_test. Records the no-migration design divergence + gates
respected (no prod write/deploy/push).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016JRL7REtkaBnRrfHk42iYm
319168ad · 2026-09-02 · TK-11125: forward-only spurious-generation guard in extractStage
Skip minting a new StagedRecord generation + SourceEvidence set when a new
raw snapshot carries byte-identical extracted property data as the latest
generation (only volatile page bytes moved). Compares a canonical payload
hash against the latest prior-snapshot generation, whose payload is already
stored verbatim in StagedRecord.payload — so NO new column and NO migration.

Preserves history: every genuine field change still mints a generation, and
a same-snapshot FORCE_REEXTRACT still updates in place (snapshotId-equality
escape). Guard can only ever skip an exact duplicate, never a real change.
Proven at the DB boundary in payload-guard.itest.ts (5 cases, all green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016JRL7REtkaBnRrfHk42iYm
671fbb26 · 2026-09-02 · TK-11125: add stableStringify + payloadHash canonical hash helper (shared)
Forward-only dedup guard support (spec TK-11125-impl-spec-2026-09-02).
Canonical key-sorted JSON hash so a payload compared across a Postgres
JSONB round-trip is order-independent; any real change yields a different
hash (guard can only ever SKIP on exact match, never suppress a change).
Pure code, no schema change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016JRL7REtkaBnRrfHk42iYm
ddb43e67 · 2026-08-31 · TK-10878 Phase 2 drafts: fix 3 fatal + 2 hardening review findings
- p_type: 'native' is invalid; default to 'range' (v5) with flagged v4
  'partman' fallback + a version preflight block (SELECT extversion)
- identifier casing: embed quotes 'public."SourceEvidence"' in every
  partman call and the retention part_config UPDATE (unquoted folds to
  lowercase and silently no-ops the provenance guard)
- backfill exit: CALL does not set ROW_COUNT; loop on count(*) of
  SourceEvidence_old instead
- rollback: replace ON CONFLICT ("id") (errors under the new
  ("id","createdAt") PK) with plain INSERT..SELECT back into _old
- import-sweep guard: abort on recent inserts + note the RENAME is the one
  genuinely-blocking step; pause the sweep first

Drafts only; not applied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
21b9aad6 · 2026-08-31 · docs(homesonspec): TK-10878 Phase 2 drafts — pg_partman SourceEvidence conversion + provenance-safe retention (not applied)
Draft-only: monthly RANGE partitions on createdAt with batched backfill and
full rollback path; retention DISABLED for SourceEvidence (provenance not
prunable) with a manual detach-to-archive review procedure. Plan file updated
with a Phase-2 preflight checklist. No prod touch, no migration run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7114f6a3 · 2026-08-31 · fix(homesonspec): summit planName cuts at first '<' — no raw markup on fresh crawls (TK-10487)
Investigating summit ingest rejects surfaced 166 historical staged records whose
planName carried raw markup (e.g. "Riverside Collection ... <div class=\"label\"
data-reac") — an INCOMPLETE tag opener that survives plainText's tag-strip when the
3000-char overview slice ends mid-element. The earlier end-anchored fix (<[^>]*$)
missed the mid-string case. Now planName is cut at the first '<' (a plan name never
contains markup), so fresh crawls emit clean plan names.

NOTE: the ingest rejects themselves are NOT this bug — they are the dup.no-active-
address integrity rule correctly rejecting re-crawls of addresses that already have
an active inventory record (summit had 816 from prior runs). The pipeline dedup gate
is working as designed. tsc 0; vitest 11/11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8ffc6951 · 2026-08-30 · fix(homesonspec): correct 2 more dead CPG seed termsUrls (brohn/summit /terms-of-use 404 -> claytonhomes.com/legal) (TK-10487)
A full seed-URL reachability sweep found brohn + summit still carried the
pattern-guessed /terms-of-use that 404s (same class as the oakwood dead-domain +
mungo/chafin fixes). Repointed both to the footer-verified Clayton parent legal
(brohn's footer explicitly delegates there). All 13 CPG seed website+termsUrl now
resolve 200. Full monorepo typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
a0335075 · 2026-08-30 · test(homesonspec): backfill committed selftests for brohn/oakwood/summit — all 13 CPG collectors now fixture-verified (TK-10487)
The 3 batch-1 CPG collectors were live-verified only (no committed fixture-backed
selftests). Backfilled to the hardened standard (12 real fixtures each, --compressed,
distinct addr+id, honest nulls asserted directly, exact-value snapshot, status
branches exercised, schema-valid; secrets scrubbed to placeholders — incl a Segment
analytics _writeKey in brohn that gitleaks correctly blocked on the first attempt):
- brohn-homes: 11 tests, 12 TX homes, MOVE_IN_READY+UNDER_CONSTRUCTION + SF/TOWNHOME.
- oakwood-homes: 13 tests, 12 Colorado homes (oakwoodhomesco.com confirmed live; the
  dead seed domain oakwoodhomesnc.com fixed separately). +export classifyStatus/toIsoDate.
- summit-homes-kc: 11 tests, 12 KS/MO homes. REAL BUG FIXED: plan-name parse swallowed
  raw markup at a 3000-char slice boundary (home-05/12) -> dangling-tag strip in
  plainText + a regression test. +export parseHome/isDetailUrl.

Whole-workspace typecheck clean. Now 13/13 CPG collectors have committed selftests.
Local build/test only; ingest/seed/deploy gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57212c91 · 2026-08-30 · fix(homesonspec): correct dead Oakwood seed domain oakwoodhomesnc.com(000) -> live oakwoodhomesco.com (TK-10487)
The seed pointed Oakwood at oakwoodhomesnc.com which is dead (HTTP 000); the live
adapter target + real CPG Oakwood site is oakwoodhomesco.com (Colorado, Clayton-
referenced). termsUrl repointed to the footer-verified Clayton parent legal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
235736eb · 2026-08-30 · fix(homesonspec): berkeley-building — real self-card isolation test + status docs (TK-10487 Cody gate)
Cody confirmed the extraction is CORRECT (exact-path self-card status does not
cross-contaminate siblings; no fabrication; garage/lot genuinely absent; ids
distinct) but flagged test-quality holes:
- The sibling-isolation test was a DECOY — it proved isolation only against a
  NONEXISTENT path. Replaced with a same-page multi-path test (home-08): each real
  sibling path resolves to its OWN card's verified label+status (2069 -> Available
  December 2026/UNDER_CONSTRUCTION vs 2079 -> Model Home/MOVE_IN_READY on the SAME
  html) — genuine exact-path isolation. Proven to FAIL when the match is loosened
  (it then grabs the first card). It also exercises the Pending->null +
  Available<Month>/Under-Construction + Quick-Move-In/Model branches END-TO-END,
  which no PRIMARY-home fixture triggers.
- Documented the "Model Home -> MOVE_IN_READY with price=null" semantic tension
  (constructionStatus claim, NOT sales-availability) so downstream never renders it
  as "for sale now".
- Documented the HomeCard__status immediate-child platform assumption (a break is a
  LOUD cov.status===n failure, not a silent mislabel).

tsc 0; vitest 11/11. Local build/test only; ingest/seed/deploy gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9eb0f321 · 2026-08-30 · wire(homesonspec): register Elite Homes (Louisville KY CPG) collector (TK-10487)
Add elite-homes-site to the worker CLI ADAPTERS map + workers deps + the CPG seed
(website elitebuilthomes.com, Kentucky/Louisville, claytonhomes.com/legal termsUrl).
workers + database typecheck exit 0. Ingest/seed-run/deploy gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d575caa2 · 2026-08-30 · feat(homesonspec): Elite Homes (Louisville KY CPG) collector (TK-10487)
Cycle-4 CPG collector for Elite Homes (Clayton Properties Group; JSON-LD
brand.name="Elite Homes"; Louisville KY metro). Source elitebuilthomes.com — same
React-SSR JSON-LD platform as arbor/silverthorne (--compressed required). 10 real
homes (all of the sitemap inventory), 10 distinct addr+id (N=10 makes the distinct
assertions genuinely bite), JSON-LD SingleFamilyResidence + HomeOverview.

Cody gate caught a REAL data-quality BLOCKER (not just test hardening): status was
read from the HomeOverview_lead marketing prose, which carries the phrase on only
2/10 homes -> 8/10 genuinely MOVE_IN_READY homes were emitted status=null, hidden
behind a toothless `<= n` assertion. Fixed: status now reads the authoritative
Carousel_h2Lead banner ("Move-In Ready"/"Quick Move-In" present on all 10),
prose as fallback. Test now asserts cov.status===n + pins status in the snapshot +
strips BOTH sources for the semantic-null proof — all proven to fail on the old bug.

Selector drift vs siblings: 3-seg detail URL, garage honest-null (Elite omits it),
status from Carousel banner. tsc 0; vitest 10/10. Local build/test only; gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c233bfe9 · 2026-08-30 · wire(homesonspec): register Silverthorne Homes (Indianapolis CPG) collector (TK-10487)
Add silverthorne-site to the worker CLI ADAPTERS map + workers deps + the CPG seed
(website silverthornehomes.com, Indiana luxury, claytonhomes.com/legal termsUrl).
workers + database typecheck exit 0. Ingest/seed-run/deploy gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f0d509ba · 2026-08-30 · feat(homesonspec): Silverthorne Homes (Indianapolis CPG) collector (TK-10487)
Cycle-3 CPG collector for Silverthorne Homes — Arbor's luxury sister company
(JSON-LD sameAs -> linkedin.com/company/yourarborhome), Indianapolis, Clayton
Properties Group. Source silverthornehomes.com (same React-SSR JSON-LD platform
as arbor; --compressed required — server gzips). Identity verified: Indiana
(McCordsville), not the Colorado town.

Source of truth = per-home JSON-LD SingleFamilyResidence/Product + HomeOverview
spec list. HONEST inventory: Silverthorne is low-volume luxury — the sitemap
lists exactly 1 available spec home; captured it, floor set to the real count (1),
NOT padded. Selector drift from arbor handled: garage IS published here (parsed,
not null'd); status derived from HomeOverview_lead prose via statusFromLead.

Cody gate: extraction confirmed correct + inventory-honest; N=1 test-quality holes
fixed — added an exact-value SNAPSHOT test pinning all 14 fields (coverage-% is
tautological at N=1; the snapshot is what actually catches a misparse — proven to
fail on a flipped value), documented the N=1 distinct-assertion limitation, and
disclosed the GTM scrub in _urls.tsv. tsc 0; vitest 10/10. Local build/test only;
wiring/ingest/seed/deploy gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
86d5d249 · 2026-08-30 · wire(homesonspec): register Arbor Homes (Indianapolis CPG) collector (TK-10487)
Add arbor-site to the worker CLI ADAPTERS map + workers deps + the CPG seed
(website yourarborhome.com, coverage IN/KY/OH, footer-verified claytonhomes.com
/legal termsUrl). workers + database typecheck exit 0. Ingest/seed-run/deploy gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9e1cea83 · 2026-08-30 · feat(homesonspec): Arbor Homes (Indianapolis CPG) collector — yourarborhome.com (TK-10487)
Cycle-2 CPG collector for the REAL Arbor Homes (the Indianapolis builder Clayton
Properties Group acquired 2018), source yourarborhome.com. A prior build against
arborhomes.com was DISCARDED — that domain is an unrelated Oregon builder (2 homes,
no CPG affiliation); research (claytonhomes.com press release) confirmed the CPG
Arbor is yourarborhome.com + its sister Silverthorne is silverthornehomes.com.

Source of truth = per-home JSON-LD SingleFamilyResidence/Product (address/geo/price
via offers[].price/community via containedIn.name/id via 24-hex productId), with
beds/baths/sqft/stories/lot from the PRIMARY home's HomeOverview list (never sibling
HomeCard blocks). 12 fixtures across IN/KY/OH, 12 distinct addr+id, schema-clean.
Honest nulls: garage (0%, no field), price (Model + coming-soon homes), status
(Model home). state/ZIP3 guard nulls a self-contradictory ZIP.

Cody gate: core parser confirmed contamination-free; test-coverage holes fixed —
added a direct semantic-null assertion on the real Model fixture + a statusFromLead
unit test exercising the PLANNED/UNDER_CONSTRUCTION branches no fixture triggers
(both proven to fail on an injected bug). tsc exit 0; vitest 8/8. Local build/test
only; wiring/ingest/seed/deploy gated. sitemap has 112 homes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ab1b4f74 · 2026-08-30 · fix(homesonspec): harris-doyle uses authoritative dataLayer, not fragile DOM (TK-10487 Cody gate)
Contrarian red-team caught the just-registered adapter shipping 3 data-quality
defects; all reproduced against the captured fixtures and fixed:
- community name: the hero community-anchor regex was DEAD (hrefs are
  entity-encoded &#x2f;, not /), silently falling back to a slug titlecaser that
  mis-cased prepositions ("Foothills At Blackridge"). Now read from the builder's
  own dataLayer ("113 | The Foothills at Blackridge") -> correct case. Slug
  fallback also fixed to keep joining words lowercase.
- status: was a hardcoded MOVE_IN_READY constant with a truthy-only "coverage"
  test (theater). Now mapped from the dataLayer pageType via statusFromPageType()
  (honest null when absent); the selftest proves it goes null on an unknown type.
- zip: the site itself publishes a wrong ZIP on some homes (AL homes tagged FL's
  32542). Added a state<->ZIP3 guard (AL/FL, extensible) that nulls a ZIP that
  can't belong to the parsed state — honest null over known-wrong data.

New selftest asserts community names are naturally cased (no mid-name title-cased
prepositions). tsc --noEmit exit 0; vitest 5/5. Facts-only; local build/test only;
ingest/seed/deploy remain gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
73a0e94f · 2026-08-30 · TK-10809: snapshot-verify catches DEST symlink false-green before gated delete
FIX1: lstatSync existence check + distinct 'symlink' verdict; never hash-follow a
DEST symlink (rsync -a preserves links; a link back to SRC would sha-match and score
'ok' right before a gated delete wipes the real file). Wired through offload-snapshots
counters/summary/slice-print/clean-check so a symlink forces clean=false.
FIX2: +2 tests — absolute-under-SRC legacy-row shape classifies 'ok'; DEST symlink
back to SRC classifies 'symlink' (not 'ok') and proves non-destructive (SRC intact).
FIX3: explicit BLOCKING breakdown line (miss/mismatch/symlink/abs-not-under-src).
FIX4: runbook — step 5 is a prerequisite for step 4 PASSING when abs-not-under-src>0.
a7904b1e · 2026-08-30 · fix(homesonspec): correct fabricated CPG termsUrls in seed (TK-10487)
Mungo /terms-of-use and Chafin /terms-of-use/ were pattern-guessed by the
batch-2 build loop and both 404. Replaced with footer-verified 200 URLs:
mungo.com/legal and the CPG-parent claytonhomes.com/legal that Chafin's own
footer links (Chafin has no standalone terms page). Facts-only; seed is not
executed (seeding stays Steve-gated).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aff87907 · 2026-08-30 · TK-10809: offload VERIFY — no false PASS on a sample, tally wrong --src
FIX1: show sampled/total + coverage% of the WHOLE store; a clean SAMPLE prints
'VERIFY PASS (SAMPLE ONLY …)' + a loud not-proof warning and, under --apply, exits
3 (distinct) so automation can't treat sample-only as a proven-clean copy. FULL+clean=0,
any dirty=1. FIX3: count abs-not-under-src rows separately (wrong --src, not a copy
failure) so the operator can tell it from an incomplete copy. Uses the shared resolver.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d461d39d · 2026-08-30 · TK-10809: single shared snapshot-path resolver (ops/lib), kill 3-way drift
Extract relTail/resolveAgainstDir/resolveAgainstDest into ops/lib/snapshot-resolve.mjs
and import it in verify-snapshots.mjs + backfill-drh-geo-from-cache.mjs. Make the TS
resolveSnapshotPath strip the same var/snapshots/ tail so it stops lying about being
the single source of truth; add the tail-strip test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

File tree

771 files tracked. Click any to browse the source at HEAD.

Other build journals

← Homebuyer Claim Helper  ·  all 4 projects  ·  Hospitalitydesignreps →

Export

commits.csv · feed.atom · project.json · commits.json

rendered in 9ms