Skip to content

Expand startup ecosystem coverage with VC blogs, regional news, and unicorn tracking#27

Merged
koala73 merged 3 commits into
mainfrom
claude/improve-tech-variant-zzqdN
Jan 23, 2026
Merged

Expand startup ecosystem coverage with VC blogs, regional news, and unicorn tracking#27
koala73 merged 3 commits into
mainfrom
claude/improve-tech-variant-zzqdN

Conversation

@koala73

@koala73 koala73 commented Jan 23, 2026

Copy link
Copy Markdown
Owner

Summary

This PR significantly expands the startup and venture capital news coverage by adding four new feed categories, updating source tier classifications, and adding 10 new startup ecosystem hubs across multiple regions.

Key Changes

Feed Categories & Sources

  • New VC Blogs category: Added 9 premium venture capital and founder essay sources (Y Combinator, a16z, First Round Review, Sequoia, NFX, Paul Graham Essays, Both Sides of Table, Lenny's Newsletter, Stratechery)
  • New Regional Startups category: Added 11 regional startup news sources covering Europe (EU Startups, Tech.eu, Sifted), Asia (Tech in Asia, KrASIA, Inc42, YourStory), Africa (TechCabal, Disrupt Africa), and LATAM (LAVCA, Contxto)
  • New Unicorn Tracker category: Added 4 feeds focused on unicorn and decacorn company news and milestones
  • New Accelerators category: Added 6 feeds covering Y Combinator, Techstars, 500 Global, and demo day announcements
  • Enhanced Startups category: Added 5 additional venture-focused feeds (TechCrunch Venture, The Information, Fortune Term Sheet, PitchBook, CB Insights)

Source Tier Updates

  • Classified new premium VC sources as Tier 2 (Y Combinator Blog, a16z Blog, First Round Review, Sequoia Blog, Crunchbase News, CB Insights, PitchBook News, The Information, Paul Graham Essays, Stratechery)
  • Classified regional and specialty sources as Tier 3 (EU Startups, Tech.eu, Sifted, Tech in Asia, TechCabal, Inc42, YourStory, NFX Essays)

Startup Ecosystems

Added 10 new startup ecosystem hubs with comprehensive data:

  • US Hubs: Miami, Denver/Boulder, Chicago
  • Europe: Barcelona, Helsinki, Munich
  • Asia-Pacific: Jakarta, Ho Chi Minh City
  • Africa: Lagos, Nairobi
  • LATAM: Mexico City

Each ecosystem includes funding data, active startup counts, unicorn counts, top sectors, major VCs, notable startups, and average funding rounds.

Panel Configuration

Added 4 new panels to the tech variant configuration:

  • VC Insights & Essays
  • Global Startup News
  • Unicorn Tracker
  • Accelerators & Demo Days

Implementation Details

  • All new feeds use RSS sources with appropriate Google News search queries where direct feeds unavailable
  • Consistent tier classification based on source prestige and coverage quality
  • Ecosystem data reflects 2024 funding metrics and current market conditions
  • Changes applied to both base config and tech variant for consistency

- Add premium startup/VC feeds: The Information, PitchBook, CB Insights, Fortune Term Sheet
- Add VC blog panel with YC, a16z, First Round, Sequoia, NFX, Paul Graham essays
- Add regional startup news: EU Startups, Sifted, Tech in Asia, TechCabal, Inc42, etc.
- Add Unicorn Tracker panel with feeds tracking new unicorns and decacorns
- Add Accelerators panel with YC, Techstars, 500 Global, Demo Day news
- Expand startup ecosystems with 11 new hubs: Miami, Denver, Chicago, Barcelona,
  Helsinki, Munich, Jakarta, Lagos, Nairobi, Mexico City, Ho Chi Minh City
- Add source tier rankings for startup/VC sources

https://claude.ai/code/session_01SxRf5YSHtV92EArUY2BvaJ
@vercel

vercel Bot commented Jan 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
worldmonitor Ready Ready Preview, Comment Jan 23, 2026 9:13am
worldmonitor-startup Ready Ready Preview, Comment Jan 23, 2026 9:13am

Request Review

- Move live-news to position 2 (after map) in tech variant panels
- Prevents CSS grid overlap issue with panel-wide class
- Remove duplicate EU Startups from funding feeds (already in regionalStartups)
@koala73
koala73 merged commit ae5f9c8 into main Jan 23, 2026
1 of 3 checks passed
@koala73
koala73 deleted the claude/improve-tech-variant-zzqdN branch January 23, 2026 09:13
koala73 added a commit that referenced this pull request Jan 23, 2026
- Add vcblogs, regionalStartups, unicorns, accelerators, funding, producthunt panels
- These panels were added to config in PR #27 but not instantiated in App.ts
- Also enable layoffs panel by default in full variant
@SebastienMelki SebastienMelki added enhancement New feature or request area: feeds RSS feeds, news aggregation labels Feb 17, 2026
facusturla pushed a commit to facusturla/worldmonitor that referenced this pull request Feb 27, 2026
…nicorn tracking (koala73#27)

* Enhance tech variant as reference startup intelligence dashboard

- Add premium startup/VC feeds: The Information, PitchBook, CB Insights, Fortune Term Sheet
- Add VC blog panel with YC, a16z, First Round, Sequoia, NFX, Paul Graham essays
- Add regional startup news: EU Startups, Sifted, Tech in Asia, TechCabal, Inc42, etc.
- Add Unicorn Tracker panel with feeds tracking new unicorns and decacorns
- Add Accelerators panel with YC, Techstars, 500 Global, Demo Day news
- Expand startup ecosystems with 11 new hubs: Miami, Denver, Chicago, Barcelona,
  Helsinki, Munich, Jakarta, Lagos, Nairobi, Mexico City, Ho Chi Minh City
- Add source tier rankings for startup/VC sources

https://claude.ai/code/session_01SxRf5YSHtV92EArUY2BvaJ

* Fix panel order and remove duplicate feed

- Move live-news to position 2 (after map) in tech variant panels
- Prevents CSS grid overlap issue with panel-wide class
- Remove duplicate EU Startups from funding feeds (already in regionalStartups)

---------

Co-authored-by: Claude <[email protected]>
facusturla pushed a commit to facusturla/worldmonitor that referenced this pull request Feb 27, 2026
- Add vcblogs, regionalStartups, unicorns, accelerators, funding, producthunt panels
- These panels were added to config in PR koala73#27 but not instantiated in App.ts
- Also enable layoffs panel by default in full variant
koala73 added a commit that referenced this pull request Mar 25, 2026
Security (P1 #18):
- sanitizeForPrompt() applied to all entity/seed fields interpolated into
  Round 1 prompt (entityId, class, stance, seedId, type, timing)
- sanitizeForPrompt() applied to actorId and entityIds in Round 2 prompt
- sanitizeForPrompt() + length caps applied to all LLM array fields written
  to R2 (dominantReactions, stabilizers, invalidators, keyActors, timingMarkers)

Validation (P1 #19):
- Added validateRunId() regex guard
- Applied in enqueueSimulationTask() and processNextSimulationTask() loop

Type safety (P1 #20):
- Added isOutcomePointer() and isPackagePointer() type guards in TS handlers
- Replaced unsafe as-casts with runtime-validated guards in both handlers

Correctness (P2 #22):
- Log warning when pkgPointer.runId does not match task runId

Architecture (P2 #24):
- isMaritimeChokeEnergyCandidate() accepts both flat and nested topBucketId
- Call site simplified to pass theater directly

Performance (P2 #25):
- SIMULATION_ROUND1_MAX_TOKENS raised 1800 to 2200
- Added max 3 initialReactions instruction to Round 1 prompt

Maintainability (P2 #26):
- Simulation pointer keys exported from server/_shared/cache-keys.ts
- Both TS handlers import from shared location

Documentation (P2 #27):
- Strengthened runId no-op description in proto and OpenAPI spec
koala73 added a commit that referenced this pull request Mar 25, 2026
Security (P1 #18):
- sanitizeForPrompt() applied to all entity/seed fields interpolated into
  Round 1 prompt (entityId, class, stance, seedId, type, timing)
- sanitizeForPrompt() applied to actorId and entityIds in Round 2 prompt
- sanitizeForPrompt() + length caps applied to all LLM array fields written
  to R2 (dominantReactions, stabilizers, invalidators, keyActors, timingMarkers)

Validation (P1 #19):
- Added validateRunId() regex guard
- Applied in enqueueSimulationTask() and processNextSimulationTask() loop

Type safety (P1 #20):
- Added isOutcomePointer() and isPackagePointer() type guards in TS handlers
- Replaced unsafe as-casts with runtime-validated guards in both handlers

Correctness (P2 #22):
- Log warning when pkgPointer.runId does not match task runId

Architecture (P2 #24):
- isMaritimeChokeEnergyCandidate() accepts both flat and nested topBucketId
- Call site simplified to pass theater directly

Performance (P2 #25):
- SIMULATION_ROUND1_MAX_TOKENS raised 1800 to 2200
- Added max 3 initialReactions instruction to Round 1 prompt

Maintainability (P2 #26):
- Simulation pointer keys exported from server/_shared/cache-keys.ts
- Both TS handlers import from shared location

Documentation (P2 #27):
- Strengthened runId no-op description in proto and OpenAPI spec
koala73 added a commit that referenced this pull request Mar 25, 2026
#2220)

* feat(simulation): MiroFish Phase 2 — theater-limited simulation runner

Adds the simulation execution layer that consumes simulation-package.json
and produces simulation-outcome.json for maritime chokepoint + energy/logistics
theaters, closing the WorldMonitor → MiroFish handoff loop.

Changes:
- scripts/seed-forecasts.mjs: 2-round LLM simulation runner (prompt builders,
  JSON extractor, runTheaterSimulation, writeSimulationOutcome, task queue
  with NX dedup lock, runSimulationWorker poll loop)
- scripts/process-simulation-tasks.mjs: standalone worker entry point
- proto: GetSimulationOutcome RPC + make generate
- server/worldmonitor/forecast/v1/get-simulation-outcome.ts: RPC handler
- server/gateway.ts: slow tier for get-simulation-outcome
- api/health.js: simulationOutcomeLatest in STANDALONE + ON_DEMAND keys
- tests: 14 new tests for simulation runner functions

* fix(simulation): address P1/P2 code review findings from PR #2220

Security (P1 #18):
- sanitizeForPrompt() applied to all entity/seed fields interpolated into
  Round 1 prompt (entityId, class, stance, seedId, type, timing)
- sanitizeForPrompt() applied to actorId and entityIds in Round 2 prompt
- sanitizeForPrompt() + length caps applied to all LLM array fields written
  to R2 (dominantReactions, stabilizers, invalidators, keyActors, timingMarkers)

Validation (P1 #19):
- Added validateRunId() regex guard
- Applied in enqueueSimulationTask() and processNextSimulationTask() loop

Type safety (P1 #20):
- Added isOutcomePointer() and isPackagePointer() type guards in TS handlers
- Replaced unsafe as-casts with runtime-validated guards in both handlers

Correctness (P2 #22):
- Log warning when pkgPointer.runId does not match task runId

Architecture (P2 #24):
- isMaritimeChokeEnergyCandidate() accepts both flat and nested topBucketId
- Call site simplified to pass theater directly

Performance (P2 #25):
- SIMULATION_ROUND1_MAX_TOKENS raised 1800 to 2200
- Added max 3 initialReactions instruction to Round 1 prompt

Maintainability (P2 #26):
- Simulation pointer keys exported from server/_shared/cache-keys.ts
- Both TS handlers import from shared location

Documentation (P2 #27):
- Strengthened runId no-op description in proto and OpenAPI spec

* fix(todos): add blank lines around lists in markdown todo files

* style(api): reformat openapi yaml to match linter output

* test(simulation): add flat-shape filter test + getSimulationOutcome handler coverage

Two tests identified as missing during PR #2220 review:

1. isMaritimeChokeEnergyCandidate flat-shape tests — covers the || candidate.topBucketId
   normalization added in the P1/P2 review pass. The existing tests only used the nested
   marketContext.topBucketId shape; this adds the flat root-field shape that arrives from
   the simulation-package.json JSON (selectedTheaters entries have topBucketId at root).

2. getSimulationOutcome handler structural tests — verifies the isOutcomePointer guard,
   found:false NOT_FOUND return, found:true success path, note population on runId mismatch,
   and redis_unavailable error string. Follows the readSrc static-analysis pattern used
   elsewhere in server-handlers.test.mjs (handler imports Redis so full integration test
   would require a test Redis instance).
koala73 added a commit that referenced this pull request May 18, 2026
…C2) (#3811)

* feat(forecast): trigger-simulation endpoint + runId filter (#3734 C1+C2)

Closes #3734. Implements the C1+C2 scope of v3 plan
(docs/plans/2026-05-18-003-feat-simulation-trigger-and-runid-filter-plan.md;
also tracked as #3798):

  - POST /api/forecast/v1/trigger-simulation — PRO-gated, mirrors run-scenario
    shape (isCallerPremium → queue-depth → server-derived runId → idempotency
    pre-check → enqueue). Returns { queued, runId, pkgFingerprint, reason }.
    External reason taxonomy collapses to {'', 'no_package', 'already-handled'}
    — server logs retain the distinction between already-queued vs
    already-completed-this-cycle to avoid a cron-timing oracle (Sec4).

  - GET /api/forecast/v1/get-simulation-outcome?runId=X — filter now actually
    fires. New behavior: by-run hit → return outcome; tombstone hit → fall
    through to :latest with distinct note; queued-but-not-completed → return
    processing=true (uses listQueuedSimulationTasks; prevents queued-vs-expired
    indistinguishability from contaminating the 30-day demand signal); miss →
    fall through with expiry note.

  - Worker (writeSimulationOutcome) writes BOTH :latest (canonical, 60d TTL)
    AND :by-run:{runId} (secondary index, 24h TTL). By-run failure logs +
    attempts tombstone payload so reads can distinguish transient failure
    from true expiry (D9).

  - pkgFingerprint = sha256(pkgKey).slice(0,16) opaque token. Replaces what
    v2 had as raw R2 path (raw path leaked bucket layout to Pro callers per
    Sec7). Worker verifies task.pkgFingerprint vs current pointer fingerprint
    with truthy-guard predicate to avoid spurious package_rotated logs on
    pre-upgrade in-flight tasks (Feas-F4).

  - .mjs seeder enqueueSimulationTask backports redis_error reason code so
    the auto-trigger path can surface transport failures cleanly (Adv-F4 /
    SG-2). No documented asymmetry between TS and .mjs paths.

  - Shared shim at server/_shared/_simulation-queue-constants.mjs (with .d.ts)
    is single source of truth for queue key constants + 24h TTL +
    pkgFingerprint helper + MAX_QUEUE_DEPTH. Both the seeder and the new TS
    handler module import natively from it.

  - PREMIUM_RPC_PATHS entry added so the gateway's Pro-bearer gate fires
    before per-IP rate-limit (matches run-scenario precedent).

  - ENDPOINT_RATE_POLICIES entry: { limit: 10, window: '60 s' } per-IP,
    identical to run-scenario.

  - Proto: TriggerSimulationRequest carries an optional client_version field
    (sebuf v0.11.1 emits a typecheck-broken POST client for fully-empty
    request messages; one field works around it). Server logs but never
    branches on it.

  - Plan + tracking metadata: TODO #21 transitioned from pending → complete;
    TODO #27 work log updated noting the filter is now actually active
    (the original 2026-03-24 "complete" was docs-only).

Tests (26 total, all passing):
  - tests/simulation-queue-parity.test.mts (7) — TS ↔ .mjs parity for all
    reason codes (no documented asymmetry); structural lock on the worker's
    truthy-guard predicate
  - tests/forecast-trigger-simulation.test.mts (9) — handler test for 403 /
    429 / no_package / already-handled (both states collapse to single
    external code) / happy path with opaque fingerprint / 503 transport on
    pointer read AND enqueue / regression test that internal codes never
    leak externally
  - tests/forecast-get-simulation-outcome.test.mts (6) — all 5 read paths
    + NOT_FOUND
  - tests/simulation-outcome-by-run-write.test.mjs (4) — structural locks on
    :latest canonicality, :by-run TTL + no-NX flag, tombstone-on-failure
    pattern, return shape

Follow-up: #3809 filed for the audit-reframe docs/marketing work (surface
"simulations auto-run hourly via cron" in OpenAPI / Pro marketing / future
MCP tool descriptions). Closing #3734 in code without that docs change leaves
the audit's framing defensible to future reviewers.

* docs(simulation): operator notes for process-simulation-tasks.mjs --run-id

Inline operator notes on the script that runs the simulation worker:
  - The `--run-id=X` format must match `/^\d{13,}-[a-z0-9-]{1,64}$/i`;
    invalid IDs are silently skipped (pre-existing footgun #3734 Adv-F5).
  - Force-reprocess via `--run-id` overwrites both :latest and :by-run
    keys with no NX, resets the 24h TTL; CDN cache may serve stale for
    up to 30min (D6 trade-off documented in v3 plan).

No behavior change — comments only. Discoverable by operators reading
the script they invoke, rather than requiring knowledge of a separate
runbook file.

* fix(deps): restore platform-optional peer deps in package-lock.json

The local pre-push hook ran 'npm install --prefer-offline' (its safety net
when node_modules is missing in a worktree) and that pruned five
'[email protected]' optional peer-dep entries that exist for non-macOS
platforms. CI's 'npm ci' on Linux then refused the lockfile.

Restoring the lockfile to origin/main's version — those entries belong
there for cross-platform compatibility.

* fix(simulation): switch pkgFingerprint to Web Crypto (Edge-compat)

Vercel Edge bundler hoisted `server/_shared/_simulation-queue-constants.mjs`
into Edge function bundles (transitively via cache-keys.ts → various Edge
handlers). The shim's `import { createHash } from 'node:crypto'` is not
available in Edge runtime, breaking deploy with:

  The Edge Function "api/discord/oauth/callback" is referencing
  unsupported modules:
    - __vc__ns__/5/server/_shared/_simulation-queue-constants.mjs:
      node:crypto

Switch to `globalThis.crypto.subtle.digest('SHA-256', ...)` — the only
crypto API available in BOTH Edge runtime AND Node 19+. The seeder
(scripts/seed-forecasts.mjs) keeps working without a polyfill.

Web Crypto's subtle.digest is async-only, so pkgFingerprint() is now
async. Both call sites (handler's getSimulationPackagePointer in the TS
module + worker's currentFingerprint in the .mjs seeder) already run
inside async functions; updated to await.

Output is byte-identical to the previous Node-crypto version (16-char
sha256 hex prefix), so payloads and parity tests remain stable.

* review(pr-3811): address all 4 Greptile findings

P1 — Tombstone SET now uses NX (scripts/seed-forecasts.mjs).
A by-run primary SET that landed server-side but threw a network error
on the response would have been overwritten by the tombstone on the
catch path, corrupting the real outcome for the 24h TTL window. NX
preserves the real write when it actually landed; if Redis is fully
down the tombstone also fails and the read path falls back to :latest
with the standard "may have expired" note (acceptable).

P2 — Single source of truth for SIMULATION_OUTCOME_LATEST_KEY
(server/worldmonitor/forecast/v1/get-simulation-outcome.ts).
Was importing the key from both _simulation-queue-constants.mjs (the
designated shim) AND cache-keys.ts. Drift on a future schema-version
bump could silently break the :latest fallback path. Import only from
the shim now; cache-keys still has the const (unchanged, kept for
non-simulation consumers).

P2 — clientVersion now logged per the proto comment promise
(server/worldmonitor/forecast/v1/trigger-simulation.ts).
The proto field's doc says "Server LOGS this with the success
breadcrumb" but the handler was marking req as unused. Echoes the
field in the success log line; sanitized (truncated to 64 chars,
restricted charset) since it's a free-text caller-provided string.

P2 — User-Agent header on Upstash GET in simulation-queue.ts
(server/_shared/simulation-queue.ts).
AGENTS.md requires User-Agent on all server-side fetch calls.
redisGetThrowing was missing it.

Tests: 26/26 simulation tests still pass. Typecheck clean.

* review(pr-3811): address 2 human-review blocking findings

Fix 1 — processing=true responses can be cached for minutes (P1).
  get-simulation-outcome.ts returned {processing: true} on the by-run-miss
  + runId-queued branch without marking no-cache. The gateway's `slow`
  cache tier would cache the transient state for up to 30 min, so polling
  clients would never see the outcome land after the worker finished.
  Added markNoCacheResponse on that branch + regression test asserting
  X-No-Cache=1 on the response.

Fix 2 — enqueueSimulationTaskForServer + .mjs enqueueSimulationTask
  could return queued:true even when ZADD failed (P1, both sides).
  Worker discovers tasks EXCLUSIVELY via ZRANGE on the queue ZSET
  (scripts/seed-forecasts.mjs listQueuedSimulationTasks at line 17052,
  then processNextSimulationTask iterates queuedRunIds). A task key
  without a corresponding ZSET member is invisible to the worker until
  the 4h task TTL — silent stuck-invisible failure mode.

  Previously labeled "best-effort"; ZADD is actually load-bearing. Now:
  - Capture the ZADD result (transport throw OR non-numeric reply both
    count as failure)
  - On failure: issue compensating DEL on the task key so a future trigger
    isn't blocked by SET NX and no stale half-state lingers for the 4h TTL
  - Return {queued: false, reason: 'redis_error'}
  - EXPIRE failure stays non-fatal (TTL hint only — queue member is
    durable; logged but doesn't roll back)

  Added parity regression test covering both .mjs and .ts: simulates SET
  NX success + ZADD non-numeric reply, asserts both implementations
  surface redis_error AND issue the compensating DEL.

All 9223 tests pass; typecheck + typecheck:api green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: feeds RSS feeds, news aggregation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants