ThreatWatch Studio turns open-source reporting about a geopolitical flashpoint into a traceable executive brief. Sourced facts open back to their evidence. Modeled estimates carry a visible label, methodology note, and analytic confidence.
Built for the OpenAI Build Week Challenge in the Work & Productivity track.
Public demo: https://threatwatch-studio.brandon-wagener.chatgpt.site
Requirements: Node.js 22.13 or newer.
npm install
npm run devOpen http://localhost:3000. Choose any seeded flashpoint and follow the three-screen path. The default Snapshot window is deterministic and requires no API key or network access after installation.
Production check:
npm run build
npm test- Pick the Strait of Hormuz, Taiwan Strait, Gulf Coast hurricane season, or Play ransomware.
- Watch the evidence pipeline retain or discard each cached source with a stated rationale.
- Read a BLUF-format executive brief.
- Click an underlined sourced fact to open its original excerpt and link.
- Click a
MODELEDestimate to inspect the method, confidence, and probability language. - Open run provenance to inspect each live response ID, request ID, resolved model, timestamp, and token count.
- Open the assurance profile, or inspect any claim, to see its self-assessed NIST AI RMF mapping and the boundary between active and contextual guidance.
The checked-in files in demo-data/ make the judging path deterministic. They contain short, attributed excerpts and links to the original public sources.
The home screen includes a compact, editor-approved Desk Watchboard with three current items from official or primary sources. Each headline opens the same sourced-claim evidence treatment used in decision briefs: verbatim excerpt, official product date, retrieval timestamp, product note, and original-document link.
The watchboard is editorially curated by one desk editor and contains no user, crowd, popularity, or behavioral data. If a complete verified slate is unavailable, the strip does not render. It is informational only; operational and safety decisions remain with the relevant official channels.
The curation workflow is deliberately local and requires two distinct steps. A complete candidate JSON file is prepared outside the tracked product data. Review validates the schema and prints the full slate without changing the site:
npm run watchboard:review -- work/watchboard-candidates.jsonAfter every official link, excerpt, product date, retrieval time, and headline is verified, the complete slate can be approved:
npm run watchboard:approve -- work/watchboard-candidates.json --approved-by "Brandon Wagener"Approval archives the prior slate under the ignored work/ folder, stamps the current America/Phoenix date, writes the approver and timestamp into demo-data/watchboard.json, and stops. It never deploys the site or sends anything. Run npm test, inspect the diff, and commit only the approved slate. If three verified items are not ready, do not publish a partial board.
The interface shows the recorded approver and approval timestamp when one is present. The slate shipped on 2026-07-21 predates this workflow, so it displays no recorded approver rather than implying a review that was never logged.
The product's claim about traceability is enforced by tests, not by prose. npm test fails if any of the following stops being true:
- Every claim cites at least one source record, and every cited source id exists in that flashpoint's collection.
- Every brief passage that links to a claim links to a claim that exists.
- Every modeled claim carries both a methodology note and the source records that methodology was applied to.
- Every source declares an explicit
scopeofwindoworbaseline. Scope is never inferred from prose wording. - The retained-source count printed on each card equals the number of kept records in the data.
- A source record that reuses another record's URL declares
sameDocumentAs, and any URL markedrollingrecords a retrieval timestamp. - Displayed claims either match the checked-in GPT-5.6 capture exactly or the file declares an
editorialUpdatewith a real timestamp and a stated reason - and where an update is declared, claim text, type, confidence, and methodology still match the capture.
Two scope rules are worth stating explicitly because they are easy to get wrong:
- Discarded sources cannot define the evidence window.
snapshotWindowForconsiders retained, in-window records only, so a rejected item can never widen the date range a card advertises. - Baseline sources sit outside the window by design. Cards show the window range and then the count of baseline records that also support the brief, so a structural source is visible without being described as a change.
The system prompt tells the model to cite only supplied source ids and to add no facts absent from them. That is an instruction, not a control, so nothing downstream assumes it held. reconcileAnalysis checks every live response against the collection that was actually sent: unknown source ids are dropped, a claim returned as a sourced fact that resolves to no evidence is marked unsupported and rendered with a warning, and a brief passage pointing at a claim that was never produced loses its inspection link instead of opening an empty drawer. The brief screen shows a reconciliation banner whenever any of this fires.
Every brief carries a plain statement that the text is AI-generated, along with whether it was analyst-reviewed, replayed from a capture with no per-run review, or returned live with no review at all.
One limitation is recorded here deliberately: lib/text-normalization.mjs rewrites quotation marks, dashes, and ellipses on model output before it is stored and displayed. Any provenance marking embedded in the generated text by the upstream provider would not survive that step. Marking synthetic output in a machine-readable format is a provider-side obligation under Article 50(2) of Regulation (EU) 2024/1689, not a deployer obligation, but a deployer that normalizes text can still destroy the marker. No instrument currently addresses that seam.
The flashpoint screen exposes three evidence horizons with the actual dates shown in the interface:
- Last 7 days and Last 30 days use live mode. When
OPENAI_API_KEYis configured, the server re-fetches only the scenario's existing curated URLs, extracts content dated inside the chosen window, and runs the full GPT-5.6 pipeline. It does not perform open-web search or discover new sources. - Snapshot window is the default judge path. It replays the checked-in sources and displays each scenario's true source-date range.
- Structural documents such as EIA exposure shares, CRS strategic context, and operating frameworks are labeled BASELINE and remain available outside the selected window. They can support standing context and modeled judgments, but cannot be described as a new change.
Every brief now separates What changed in this window from Standing situation. A window with no verified material change says so explicitly. If live collection is unavailable or no API key is present, the product falls back to the checked-in snapshot and labels the fallback instead of implying recency.
The optional profile selector supports exactly four views:
- Analyst view (default)
- Domestic insurance
- International travel
- Logistics & shipping
The selected exposure lens changes which claims appear first, the ordering of indicators, and the recommended-action line. The brief-screen selector switches instantly among checked-in variants. All twelve non-default profile/scenario variants are checked in with their own verified GPT-5.6 provenance.
The optional live route at POST /api/analyze uses the OpenAI Responses API with the gpt-5.6 alias, which resolved to gpt-5.6-sol in the checked-in capture. It assigns GPT-5.6 five explicit roles:
- Source triage with a stated authority and relevance rationale.
- Claim extraction into structured objects.
- Sourced-versus-modeled classification.
- BLUF drafting from the structured claims.
- An estimative-language pass over the final brief.
Set OPENAI_API_KEY from .env.example to exercise the live route. The key stays server-side. The default interface replays cached snapshots so judges can inspect the complete product without credentials or network instability.
The UI reads demo-data/gpt-runs/run-status.json and labels the evidence honestly. The shipped evidence set was captured on 19 July 2026: all four scenarios have unique OpenAI response and request IDs, the requested alias, the resolved model, timestamps, and token usage. The interface therefore displays the verified-run label while replaying those checked-in outputs deterministically.
To capture the default Analyst-view evidence, create .env.local with a funded OPENAI_API_KEY, restart the local app, and run this in a second terminal:
npm run capture:gptCapture one non-default profile across all four scenarios:
npm run capture:gpt -- --profile domestic-insurance
npm run capture:gpt -- --profile international-travel
npm run capture:gpt -- --profile logistics-shippingOr capture all 12 non-default variants in one run:
npm run capture:gpt -- --all-profilesThe capture script saves base runs as demo-data/gpt-runs/<flashpoint>.json, profile variants as demo-data/gpt-runs/<flashpoint>--<profile>.json, and the variant index as profile-runs.json. Every verified variant preserves its own requested alias, resolved model, OpenAI response ID, request ID, timestamp, and usage.
- Source text is evidence, not instruction. The live prompt explicitly treats snapshots as untrusted input.
- A sourced claim cannot introduce facts absent from its cited snapshots.
- A modeled estimate must include a method and confidence.
- A modeled claim about a recurring pattern must state the relevant base rate and explain whether current indicators reinforce or depart from it.
- Hormuz modeled claims must engage ceasefire-to-escalation oscillation as the historical base rate; de-escalation alone cannot establish durable normalization.
- Probability and confidence remain separate concepts.
- The interface uses a small, consistent vocabulary of estimative probability.
- The demo is decision support, not operational, financial, or safety advice.
The competition MVP maps visible product behaviors to the free, public NIST AI Risk Management Framework 1.0 and NIST AI 600-1 Generative AI Profile. Each inspected claim explains which MAP, MEASURE, and MANAGE functions its evidence treatment supports. The assurance profile also lists CISA's voluntary Cross-Sector Cybersecurity Performance Goals as a contextual reference only when organization-facing cyber recommendations are in scope.
This is a self-assessed mapping, not a certification, endorsement, legal opinion, or determination of compliance. The interface makes that boundary visible. It links to official sources and does not embed licensed ISO content.
Brandon Wagener maintains a personal scheduled script that regenerates a daily Strait of Hormuz brief from free sources. ThreatWatch Studio is a new application built during OpenAI Build Week with Codex. The earlier script contributed domain knowledge, source-selection experience, and the sourced-versus-modeled flagging concept. No application code was imported from that project.
The majority of the core application was built in one Codex task during the challenge submission period. Codex:
- translated the tradecraft brief into the data model and three-screen product flow;
- built the responsive interaction and evidence drawer;
- created the deterministic source snapshots and claim links;
- implemented the server-side GPT-5.6 analysis route;
- added the product test, setup notes, and submission-ready evidence trail.
Brandon supplied the intelligence tradecraft, product direction, source judgment, and final editorial review. The submission includes the /feedback session ID for the main Codex build task.
Organization-scoped team boards and thresholded anonymized signals remain future work. They require multi-user identity, authorization, retention, and privacy review; this release does not mock collaboration or imply users that are not present.
The demo uses short excerpts from the International Maritime Organization, U.S. Energy Information Administration, Taiwan Ministry of National Defense, Congressional Research Service, CSIS, NOAA, U.S. Coast Guard, CISA, FBI IC3, and U.S. Geological Survey. Each source card links to the original page. New U.S. weather, cyber, and geologic sources also record the retrieval timestamp in the evidence drawer. Cached content is included only to make the demo reproducible.
The flashpoint cards use public-domain U.S. government maps hosted by Wikimedia Commons:
- Strait of Hormuz map, derived from a CIA map.
- Taiwan Strait map, produced by the CIA.
The Gulf Coast card uses the EIA federal offshore production chart. The ransomware card uses the FBI ransomware icon. Both assets were fetched from the cited federal pages and checked into public/maps/ for deterministic replay.
The interface supports current desktop and mobile browsers. The production build targets Cloudflare Workers through the bundled vinext and Sites configuration.
MIT. See LICENSE.