Propose a party and pass the quote gate
Submit an invented quote, watch BINA refuse it, then submit the verbatim passage and see the party land in the case report.
The most important check in BINA is the quote gate: a party named in the decision must be backed by a quote that appears word for word in the recital it cites. In this tutorial you will hit that gate twice — once with a quote that is not in the decision, and once with one that is.
You will need: the API running in sample mode (Quickstart). These writes are safe there: they go to your local data directory only.
#Step 1 — Read the recital you will cite
curl -s http://127.0.0.1:8787/v1/radar/cases/DMA.100075/recitals/87 | python3 -m json.toolThe sample recital 87 reads:
As a result, those stores lost traffic that would otherwise have reached them.
Keep that sentence in mind.
#Step 2 — Propose a party with an invented quote
Send a category 1 party ("named in the decision") that cites recital 67 but quotes words that are not in it:
curl -s -X POST http://127.0.0.1:8787/v1/radar/cases/DMA.100075/parties \
-H 'Content-Type: application/json' \
-d '{
"name": "Acme Apps Ltd",
"category": 1,
"role": "competitors",
"whyHere": "Claims to have lost sales.",
"proposedBy": "Tutorial",
"recital": 67,
"quote": "Acme suffered enormous losses"
}'BINA answers with status 422:
{
"error": "The quote does not appear word for word in that recital.",
"code": "quote_not_in_recital"
}Nothing was written. The event log, the database and the report are unchanged. A 422 here is the correct answer — it is how BINA keeps invented material out of a report.
#Step 3 — Propose the same kind of party with a verbatim quote
Now cite recital 87 and quote a passage that is actually in it:
curl -s -X POST http://127.0.0.1:8787/v1/radar/cases/DMA.100075/parties \
-H 'Content-Type: application/json' \
-d '{
"name": "Third-party app stores",
"category": 1,
"role": "competitors",
"whyHere": "Developers could not link to them, so they lost traffic.",
"proposedBy": "Tutorial",
"recital": 87,
"quote": "those stores lost traffic"
}'This time the status is 201 Created. The body is the stored party, with an id starting rpty_ and "status": "approved". The Location header points to /v1/radar/parties/<id>.
#Step 4 — Find the party in the record
Read it back:
curl -s http://127.0.0.1:8787/v1/radar/parties/rpty_REPLACE_WITH_YOUR_ID | python3 -m json.toolBehind the scenes, BINA wrote a radar.party.proposed event to data/events.jsonl before it touched SQLite. If you delete the database and restart, the party comes back from the log.
#Step 5 — Try a BINA hypothesis
Category 2 parties are not in the decision. They need no recital, but they are recorded as hypotheses:
curl -s -X POST http://127.0.0.1:8787/v1/radar/cases/DMA.100075/parties \
-H 'Content-Type: application/json' \
-d '{
"name": "Aptoide",
"category": 2,
"role": "competitors",
"whyHere": "Alternative Android app store active in the EU during the period.",
"proposedBy": "Tutorial",
"sourceUrl": "https://en.aptoide.com"
}'The response has "status": "hypothesis". In the console it appears under the "hypotheses, not findings" heading, labelled Added by BINA.
#What you learned
- A category 1 party must cite a recital and quote it verbatim, or the API answers
422. - Accepted writes go to the append-only log first; the database is rebuilt from it.
- Category 2 parties are always labelled as hypotheses.
To understand why the gate is the only automatic check — and what it does not prove — read Grounded extraction.