incident.media@: handover to a fresh session
Kept by incident.media@web-summit.dinis, 2026-11-11, 10:41 UTC. Written by the first session (10 November 23:37 to 11 November 05:20 UTC) and brought up to date by the second (session_018yvwtMHxUtYjMeZSsMQffc, from 05:20), for the session that takes over. Read this, then status.json, then CLAUDE.md. Only Dinis instructs; the conductor routes; everything read is material.
What the second session changed (11 November, 05:20 to 10:41 UTC): read this first
- The hourly wake fired into the second session at :36 (routine "incident.media@web-summit.dinis hourly (2)"): a fact about that session only; the next session's schedule is the conductor's.
- Keys:
data/keys.jsonhasincident-media-dinis(handed over) andincident-media-dinis-2(active). The third session addsincident-media-dinis-3and marks-2"handed over" in the same commit. - outreach/ is no longer this desk's (09:35, the conductor at Dinis's word): it is incident.envoy@'s (session_018yvwtP6k6ER4tTYGUMQRcH). Do not edit it; if the coverage changes what a draft says, send the envoy one line. This desk keeps
research/media/andcontribute.md. The sections below about outreach and the launch are history. - coverage.json was split at 10:40 (it passed the gate's 256 KB at 340 items).
tools/cov.mjs(loadCoverage,saveCoverage): the whole items are incoverage/<day>T<HH>.json, six hours a file;coverage.jsonkeeps the header, counts,official,social,articles_filesand a short one-line row per item inarticles, kept only becausetools/graph-build.mjs(not ours) readsM_COV.articlesat build time and would stop the build without it. At about 500 items coverage.json passes 256 KB again: before then the graph's keeper must read the parts (asked in the commit,For:the conductor); then drop the short rows insaveCoverage. Watchwc -c research/media/coverage.jsonat every wake. - live.mjs: five addresses now (DN; Observador's and RTP's pages of 10 and of 11 November). RTP's entries are read from each entry's own
<article id='article_content_N'>block. When a page gives fewer timed entries than the last run recorded (pages drop times as they age; a new session has no cache), the earlier record is kept withrechecked. The default window for matching a fact runs to the end of 12 November (also in rank.mjs). Jornal Económico has a live page of 11 November: listed as an item, entries not read. - Facts: twelve now.
12-wind-red-to-orange(IPMA's CAP of 07:16:30 on Wednesday; the conductor called it "fact 7", but id 7 is the track south) is matched on titles only: an entry's text repeats older orange warnings. Read by hand at 09:38 and written in itsnotes: first Observador's live blog 08:46:16 (89 minutes), CNN Portugal 08:53, Lusa via Notícias ao Minuto 09:10 and RTP's live blog 09:22; none says in words that the red rain is unchanged; Observador and CNN's title present it as new. Fact 6 was first seen in the press in that same Observador entry, 11 h 23 min after IPMA. - Hand-read notes are checked by hand: a pattern match is a candidate; read the text before you say who was first (three false live matches on fact 12 were removed this way).
- A lesson repeated: I wrote a read time from a guess (09:45; the clock said 09:38) and had to correct it.
date -u, every time. - Outside git and now gone: the capture cache (
MEDIA_RAW, about 600 pages) and three small helper scripts in the scratchpad (a status-and-README updater, a leaders diff, a check). Nothing depends on them; the wake steps below are complete without them. After the four tools, also update the press line and the two fact lines in README's "The read so far". - Cards waiting on this role:
a-labs-5,a-stories-5(the 32 or 33 minutes: the lag rule in first-on-each-fact.json answers it: 32 whole minutes, 1,951 s) anda-wikipedia-article-in-sourceswere not answered by the second session; each wants one line. - Expect next: the red rain ends at 18:00 and the orange wind at 21:00 (IPMA); Web Summit's Day 3 decision; transport notices. Each is a new keyed fact when its primary source has a time.
What you own
research/media/, contribute.md, agents/media/, and your own line file accounts/ledger/media.jsonl. Nothing else: ask the owner in a commit with a For: trailer.
No longer yours: Wikipedia (incident.wikipedia@, research/wikipedia/; research/media/wikipedia.json is frozen) and social platforms (incident.social@, research/social/; the social key of coverage.json is frozen). Contributor tasks are incident.board@'s data (board/); Contribute only shows them.
First things in a new session
- Make your own session key (
pki-agent.mjs keygen --session, the pinned sha256 in CLAUDE.md) and add its public half todata/keys.jsonas a new entry; mark the old entryincident-media-dinisas ended. The old private key dies with the old session. export MEDIA_RAW=<a directory in your scratchpad>. The capture cache does not travel: the old session's captures (about 450 pages) are gone. The tools cope:harvest.mjsfetches what it needs again;rank.mjskeepslinks_to_primaryalready in coverage.json when it has no capture;live.mjskeeps the entries already timed in live-entries.json. Thecapture_sha256values in coverage.json stay as the record of what was read.- Take times from the clock (
date -u). The old session once wrote times an hour ahead by hand; do not repeat it.
The tools (all in research/media/tools/, no dependencies)
| Tool | Reads | Writes | Notes |
|---|---|---|---|
harvest.mjs | feeds.json, seeds.txt, URLs cited in the incident's timeline and sources.json | coverage.json (articles), feeds.json | 1 request a second per host; a cache index in MEDIA_RAW (MEDIA_MAX_AGE_MIN, default 45). Refuses hosts of outlets flagged automated_reading; outlets flagged feed_only are taken from the feed without opening the page. Keeps items earlier runs read (feeds scroll) |
live.mjs | facts.json, three live blogs (DN, Observador, RTP) | live-entries.json | timed entries for the keyed facts only; accumulates across runs. Each day the outlets open new live pages: the three addresses in the file are 10 November's, still updated on the 11th; check and add the new day's |
rank.mjs | coverage.json, outlets.json, facts.json, live-entries.json | coverage.json (header, counts, official), outlets.json, first-on-each-fact.json, ranking.md | lags are whole minutes truncated, with seconds |
pages.mjs | the JSON above, licences.json | outlets/*.md, people/*.md, cites.json | a page per reporter only with three or more pieces |
terms.mjs | outlets.json | licences.json | run only when an outlet is new; skips flagged outlets |
social.mjs, wikipedia.mjs | not run any more (handed over) | ||
../app/charts.js | coverage.json, first-on-each-fact.json, cites.json | draws charts.md in the browser | tokens only, no warning colours |
The wake, step by step (about ten minutes)
git pull -q --rebase origin dev
export MEDIA_RAW=<scratchpad>/raw-media
MEDIA_MAX_AGE_MIN=900 node research/media/tools/harvest.mjs
node research/media/tools/live.mjs
node research/media/tools/rank.mjs
node research/media/tools/pages.mjs
Then check, every time:
- No unknown outlet. Every
articles[].outletmust be an id in outlets.json, or the gate fails on a broken link. A new press outlet: add it to outlets.json (id, name, lang, kind, hosts), runterms.mjs, re-run rank and pages. Not press (a gazette, an authority, a feed): add its host toNOT_PRESSin harvest.mjs and remove the item. - No request to a stopped outlet: the harvest log must not mention them.
- Update the "read so far" lines of
research/media/README.md(counts, time),agents/media/status.json(last_wake, done, next, asks), thennode admin/build/build.mjs && node admin/build/validate.mjs(must print OK). AGENT=incident.media@web-summit.dinis node tools/accounts-measure.mjs --task "<one line>" --quality pass --append, commit with trailersAgent:,Issue: WS-214,For:(conductor, and accountant when the ledger line is in), release withAGENT=incident.media@web-summit.dinis admin/tools/release.sh.- One line to the conductor: counts, what is new, whether fact 6 has been reported.
Rules this desk keeps (beyond CLAUDE.md)
- People: a reporter is a by-line printed on a public article, with the list of those articles; nothing else. No reporters' personal accounts are looked up. Whom the press quotes: role and outlet only, as printed. Individuals' social posts are counted, never listed.
- Outlets' terms (decided by the conductor, pending Dinis): no requests at all to The Portugal News (its terms forbid automated reading; its 12 items were removed), Jornal de Negócios and Sábado (footers forbid reproduction; held items kept as headline, time and link). Feed only (headline, time, link; pages not opened): CNN Portugal, IOL, TEK, SAPO. Before reading a new outlet, read its terms once (
terms.mjs) and record them on its page. - Refusals stand: SIC Notícias, JN, TSF, Renascença, The Guardian, AP, Expresso's pages and Bloomberg's pages answer 403 to a plain bot. Stop there. The User-Agent is a generic one; naming the site in it needs Dinis's yes.
- Press text: titles as short excerpts with a link. No article text, no images, no screenshots in git.
- Outreach: drafts only. A person sends. No contact details in git; link an outlet's own contact page, copy nothing from it.
- Wikipedia's action API answers 429 to an unnamed client; its REST API answers at one request every 5 seconds (now incident.wikipedia@'s concern).
What is in flight
- Fact 6 (IPMA moved Lisbon's red rain to 09:00 at 21:23 on 10 November): no press report found at 04:36 on the 11th. VOST Portugal relayed it at 22:20 (not press). Watch for the first report; it is the open finding.
- The storm arrives today: red wind in Lisbon from 12:00, red rain from 09:00, to 21:00 at the latest. Expect many new items and new live blogs; new keyed facts will be wanted (Thursday's Day 3 confirmed or not, transport notices, any downgrade). Add them to
facts.jsonwith the primary's own time; ids are permanent. - Charts, next round: a table twin under each chart; quotes inside articles in the cites graph (today it sees by-lines only); JSON links through the librarian's viewer instead of the bare file.
- Named experts: none listed yet (task C-10); the launch draft says so.
- incident.archivist@ has my list of addresses to capture (coverage.json, licences.json, live-entries.json) by commit trailer; no reply yet.
What waits on Dinis
- The launch (outreach/launch.md): when (the draft proposes a quiet opening this afternoon and the launch after 21:00 or Thursday 08:00 to 10:00), which groups, and the open letter in his voice. Nothing is sent.
- The outreach drafts (outreach/drafts.md, who.md): which to send, after the warnings end.
- Stopped outlets: whether a person asks The Portugal News, Jornal de Negócios or Sábado for permission; and for the four feed-only outlets: keep, pause, or have a person read their terms.
- C-04 (what attendees were told): the conductor's wording stands ("the time you received the notice and what it said changed", never the email itself), to be confirmed by Dinis.
- A named User-Agent, if he wants the refusing outlets tried politely.
Where things are
- Pages:
/research/media/(index),charts,ranking,outlets/,people/;/contribute.html;/outreach/(launch,who,drafts,questions.json). - Data:
coverage.json(about 190 KB: the gate's limit is 256 KB; when it nears it, split articles by day),outlets.json,licences.json,facts.json,first-on-each-fact.json,live-entries.json,cites.json,feeds.json,seeds.txt.