Skip to content

Commit 2616af5

Browse files
FlyM1ssclaude
andcommitted
docs(api): document GET /api/news/items/
- api_reference: endpoints-table row + a News Items section (limit clamp, no as_of, fail-closed 404, ETag/Last-Modified variance). Notes that its `score` is the editorial score, not the [-1,1] sentiment score of the same name under /api/signals/news/. - project_structure: signals_views.py hosts both news endpoints now. - pipeline design spec: SIGNALS_MAX_FILE_MB has a second reader. Sphinx build clean (0 warnings). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 72b7607 commit 2616af5

3 files changed

Lines changed: 44 additions & 3 deletions

File tree

Docs/source/api_reference.rst

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,9 @@ the signed ``fingpt_sessionid`` cookie. Callers may pass an optional
567567
* - GET
568568
- ``/api/signals/news/``
569569
- Latest news→sentiment signals artifact
570+
* - GET
571+
- ``/api/news/items/``
572+
- Raw news stories from the newest Heartbeat batch
570573

571574
All share the ``API_RATE_LIMIT`` budget (``429 {"error": "rate_limited"}``
572575
when exceeded). The chat endpoints can also return ``503 {"error": "busy"}``
@@ -723,6 +726,44 @@ an ``ETag`` validator and ``Cache-Control: public, max-age=300``.
723726
variants are ETag-only, so conditional requests for them must use
724727
``If-None-Match``.
725728

729+
News Items
730+
~~~~~~~~~~
731+
732+
``GET /api/news/items/`` serves the **raw news stories** of the newest
733+
Heartbeat batch — the corpus the signals above are derived from, before any
734+
LLM scoring. Like ``/api/signals/news/`` it is an integration surface for
735+
external consumers; the browser extension does not call it.
736+
737+
**Query parameters:**
738+
739+
- ``limit=N`` — how many stories to return, newest first. Clamped to
740+
``[1, 200]``; defaults to ``50`` when absent. A non-integer value returns
741+
``400 {"error": "bad_limit"}``.
742+
743+
There is no ``as_of`` here: this endpoint always reads the single newest
744+
batch.
745+
746+
**Response (200):** ``{schema_version, items, count, batch}``, where ``batch``
747+
names the source file and each entry of ``items`` is
748+
``{guid, headline, url, source, published, description, tickers, score}``.
749+
``published`` is epoch seconds.
750+
751+
.. note::
752+
753+
``score`` on this endpoint is the pipeline's **editorial** score — how
754+
newsworthy the story is, the gate that decides which stories become
755+
sentiment candidates (``SIGNALS_MIN_EDITORIAL_SCORE``). It is *not* the
756+
``[-1, 1]`` sentiment score of the same name under ``/api/signals/news/``.
757+
The two fields share a name and nothing else.
758+
759+
``404 {"error": "no_items"}`` when no batch exists, or when the newest one is
760+
unreadable or validates to zero stories — the endpoint never falls back to an
761+
older batch, and never returns a ``500``. Responses carry an ``ETag`` and
762+
``Cache-Control: public, max-age=300``. ``Last-Modified`` is sent only on the
763+
default-limit variant — an explicit ``?limit`` slices the batch differently,
764+
so those variants are ETag-only and conditional requests for them must use
765+
``If-None-Match``.
766+
726767
---
727768

728769
Usage Examples

Docs/source/project_structure.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Backend Structure
3838
├── api/ # REST API layer
3939
│ ├── views.py # Main API endpoints
4040
│ ├── openai_views.py # OpenAI-compatible API endpoints
41-
│ ├── signals_views.py # News-signals endpoint (GET /api/signals/news/)
41+
│ ├── signals_views.py # News endpoints (GET /api/signals/news/, GET /api/news/items/)
4242
│ ├── middleware/ # CORS and custom middleware
4343
│ ├── utils/ # API utility functions
4444
│ ├── apps.py # Django app configuration

Docs/superpowers/specs/2026-07-06-news-to-signals-pipeline-design.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ A machine-readable JSON Schema ships at `Heartbeat/schemas/signals-v1.schema.jso
197197

198198
## 5. Configuration (the v1 tuning surface)
199199

200-
Env vars read by `news_signals.py` (module constants as defaults). This is the surface future user-facing tuning builds on:
200+
Env vars read by `news_signals.py` (module constants as defaults). This is the surface future user-facing tuning builds on. All are pipeline-only except `SIGNALS_MAX_FILE_MB`, which the Django API reads too (see its row):
201201

202202
| Var | Default | Meaning |
203203
|-----|---------|---------|
@@ -209,7 +209,7 @@ Env vars read by `news_signals.py` (module constants as defaults). This is the s
209209
| `SIGNALS_THRESHOLD` | `0.20` | ± threshold for bullish/bearish label (40/60 band, empirically backed; was 0.15) |
210210
| `SIGNALS_DAMP_CAP` | `0.7` | Max \|score\| when under-corroborated |
211211
| `SIGNALS_DAMP_MIN_ARTICLES` | `2` | Corroboration needed for \|score\| > damp cap |
212-
| `SIGNALS_MAX_FILE_MB` | `10` | Reject oversized items files |
212+
| `SIGNALS_MAX_FILE_MB` | `10` | Reject oversized items files. **Two readers as of 2026-07-14:** `news_signals.py` (via `load_config`) and the Django API (via `settings.RAW_ITEMS_MAX_FILE_MB`, which `GET /api/news/items/` enforces when validating a batch). Deliberately one operator knob — raising it for the pipeline without raising it for the API would 404 a batch the pipeline happily accepted. Set it in `.env.production` alongside the heartbeat's own env file; the two defaults are pinned together by `Heartbeat/tests/test_port_parity.py`. |
213213
| `SIGNALS_STALENESS_ALERT_H` | `20` | Canary threshold (§6-C). Tuned, not arbitrary: the daily canary check runs 2 h after the daily beat, so a single fully-missed day leaves the newest artifact ~25.5 h old at the *next* day's check — a 30 h threshold would not cross that (it silently absorbs one entire missed day, only firing after a second consecutive miss); 20 h does. |
214214

215215
## 6. Failure policy (every mode decided)

0 commit comments

Comments
 (0)