Skip to content

Run The Cross-Repo Harness Against Rada-Weather

Use this harness when you need to verify that the HTTP contract between yaya-engine and the sibling rada-weather repository actually works end to end — not just that yaya-engine's own Pest suite passes, but that rada-weather's real ETL client can talk to a really-running yaya-engine server and get back data that round-trips correctly. This matters because the contract spans two separate codebases: yaya-engine owns the /api/v1 endpoints, rada-weather owns the client that calls them, and neither repo's own test suite alone can catch a contract drift between the two.

What it proves

harness/test_cross_repo_flow.py is a standalone script, not part of phpunit.xml/Pest — it is invoked directly with python3. It owns the entire server lifecycle itself: run migrate:fresh, seed fixture towns, boot php artisan serve in its own process group, poll /up until the server answers, run five "seams" of real HTTP requests, then tear the server down and re-poll the port to confirm it actually died [@harness-script]. The five seams are documented in the script's module docstring: forecast bulk-insert followed by a latest-per-town read (checking null-vs-zero preservation and model dedup), observation bulk-insert into forecast-accuracy scoring, a season → event → scheduled-alert → nested-history read chain, a threshold/forecast-config/dispatch-mode PUT+GET+audit round trip, and a request with no bearer token asserting a 401 [@harness-script].

Precondition: a sibling rada-weather checkout

The harness imports rada-weather's actual ETL client module directly:

sys.path.insert(0, str(RADA_DIR))
from etl.clients.yaya_engine import YayaEngineClient  # noqa: E402

[@harness-script]. RADA_DIR defaults to /Users/Koldan/Documents/atram/dev/rada-v2-worktrees/rada-weather-int and can be overridden with the RADA_WEATHER_DIR environment variable [@harness-script]. This means the harness cannot run from yaya-engine alone — you need a checked-out rada-weather repo (or worktree) on disk with etl/clients/yaya_engine.py present, and the default path is a specific developer's machine layout, so most environments will need RADA_WEATHER_DIR set explicitly.

The script also reads ADMIN_API_TOKEN out of yaya-engine's own .env file and points the client at the locally booted server via YAYA_ENGINE_API_BASE_URL / YAYA_ENGINE_ADMIN_TOKEN, so it exercises the same bearer-token auth used in production, not a test-only bypass [@harness-script].

Running it

# from the yaya-engine repo root
RADA_WEATHER_DIR=/path/to/rada-weather python3 harness/test_cross_repo_flow.py

PHP_BIN (default /opt/homebrew/opt/php@8.4/bin/php) and HARNESS_PORT (default 8011) can also be overridden if your environment needs a different PHP binary or the default port is taken [@harness-script].

Before booting the server, the harness runs migrate:fresh --force against your local database, then runs harness/seed_towns.php as a standalone bootstrap script — it loads bootstrap/app.php directly rather than going through artisan db:seed [@seed-towns]. migrate:fresh means this harness resets your local database; do not point it at anything you care about.

seed_towns.php seeds four fixed towns via Town::updateOrCreate keyed on hardcoded Supabase-issued IDs: Nairobi (500001), Mombasa (500002), Kisumu (500003), and Bogota Centro (500101), each with yellow/orange/red thresholds [@seed-towns]. Kisumu is deliberately left unreferenced by any alert the harness creates later, so it isolates the forecast-accuracy seam's scoring from the event-chain seam's alert [@seed-towns]. This file is kept out of database/seeders/ on purpose — it is fixture data whose fixed IDs the Python script's assertions hardcode, not general-purpose application seed data.

Verifying success

The script prints a [PASS]/[FAIL] line per check as it runs, then a summary block at the end:

==================== SUMMARY ====================
  N/M checks passed
  FAILED:
    - <check name>
=================================================

and exits with status 0 only if every check passed [@harness-script]. Read individual [FAIL] lines rather than just the pass count — each failing check names the exact seam and assertion that broke, which is usually enough to tell you whether the break is on the yaya-engine side (an /api/v1 response shape changed) or the rada-weather side (the client's request payload changed).

Recovery notes

If the server never comes up, the harness prints the tail of harness/server.log before failing the server booted on port check [@harness-script] — check that log first; a common cause is the configured PHP_BIN not matching an installed PHP version, or HARNESS_PORT already being in use by a leftover artisan serve process from a previous run.

The teardown() step kills the whole process group with SIGTERM, escalates to SIGKILL if needed, and then re-polls /up to confirm the port was actually released [@harness-script]. If a prior run crashed before reaching teardown(), you may find a stray artisan serve still bound to the harness port; kill it manually before re-running.

For background on why yaya-engine's own geography/alert data is moving into its own Postgres instead of staying in the separate Supabase database this harness's /api/v1 seams ultimately serve, see Rada v2 Collapse. For the exact /api/v1 endpoints the harness exercises, see API v1 Surface.