JobForecaster-Agent / CONTRIBUTING.md
lixiaowww
Initial commit: forecaster agent with zero-cost GitHub Pages deploy.
2fc729c
|
Raw
History Blame Contribute Delete
4.5 kB
# Contributing to forecaster-agent
Thank you for contributing. This document explains the engineering standards
the project holds itself to, and why they exist.
---
## Core principle: every module earns its place on the scoreboard
No component is assumed to add value. Everything that feeds into a forecast โ€”
the evolution prior, crowd contributions, signal sources โ€” is tracked through
the Brier scoreboard. If it doesn't improve calibration over time, it gets
down-weighted or removed. Please keep this discipline when proposing additions.
---
## Engineering standards (the harness rules)
These are not style preferences. They are what makes the system self-correcting.
### 1. Nondeterminism lives behind interfaces
The LLM judge, embedder, and any future external service must be hidden behind
a Protocol interface with a deterministic stub backend. The test harness runs
entirely offline (no API key, no network). If your code can't be tested offline
via the stub, the seam is in the wrong place.
### 2. The scoring core is pure functions
`js_divergence`, `aggregate`, `novelty`, `extract_conditional_rules` โ€” these must
remain pure (no hidden state, no randomness without an explicit seed). Tests
verify mathematical properties, not just "doesn't crash".
### 3. Every test is a behavioural specification
Tests must exercise the intended failure mode:
- Wrong: `assert result is not None`
- Right: `assert d.reason == "redundant"` (the echo was rejected *because* it was
low-entropy, not for any other reason)
Add a test for every new gate decision or model behaviour.
### 4. Thresholds are configuration, not magic numbers
`tau_soundness`, `tau_novelty`, `k`, `threshold_percentile` live in `GateConfig`
and `config.yaml`. Never hardcode a threshold inside a function.
### 5. Run the full suite before opening a PR
```bash
python -m pytest tests/ # must be 0 failures, 0 warnings
```
---
## Adding historical cases to the evolution agent
The case library (`evolution.py`, `CASE_LIBRARY`) is the foundation of the
job evolution prior. Contribution rules:
- **Every numeric figure needs a citable source** in the `sources` list.
Acceptable: peer-reviewed papers, BLS/OECD/Eurostat data, books with page
numbers. Not acceptable: news articles without underlying data, LLM-generated
"facts", personal estimates presented as data.
- All 8 variables must be in range (0-1 except `diffusion_years`).
- The case must have a clear displaced occupation and a measurable outcome
(`net_job_multiplier`, `lag_years`).
- Run `python -m pytest tests/test_evolution.py` after adding โ€” the integrity test will catch
missing sources and out-of-range values.
We need more non-Western cases (Japan, South Korea, India, Brazil).
We need more cases with `net_job_multiplier < 1` โ€” the library must not
systematically over-represent the success stories.
---
## Crowd contributions
If you are adding a UI or API endpoint for human crowd forecasts, keep this rule:
**contributions must be submitted in `Prediction` schema format (falsifiable,
dated, confidence-scored, with evidence URLs) before the contributor sees the
agent's own forecast or the current aggregate.** Without that sequencing, you
are collecting anchored opinions, not independent signals.
---
## The publishing guardrail (non-negotiable)
`require_review: true` is the default and must remain so in all example configs
and documentation. Any PR that flips it to `false` in a default config will be
rejected. The README must always show the review gate as the recommended path.
Auto-publishing speculative economic forecasts at scale is a reputational and
potentially legal risk. The gate exists to protect contributors and users alike.
---
## What good PRs look like
- A new signal source โ†’ new class implementing the `Source` protocol + offline
test with a fixture feed.
- A new publishing backend โ†’ new class implementing `.publish()` + integration
test.
- A new historical case โ†’ added to `CASE_LIBRARY` with sources + passes
`test_case_library_integrity`.
- A bug fix โ†’ the test that would have caught the bug, then the fix.
---
## What we will not merge
- Components that bypass the Brier scoreboard (they become unaccountable).
- Tests that require a network connection or API key.
- Magic-number thresholds hardcoded inside functions.
- Cases in the evolution library without citable sources.
- Anything that makes `require_review: false` the default.