Connect this page to a DTSF backend
This page is a static file. It can be served three ways — from the DTSF runtime itself
(GET /diplomacy-table/config), from a GitHub Pages site, or straight off disk
(file://). In all three cases it talks to a DTSF backend over plain CORS-enabled HTTP.
Everything on the Architecture, Knobs, Models, Tactics, Scenario, Delegations and Runbook tabs works
with no backend at all; only the live probes and the Bake-off runner need a connection.
Backend
/diplomacy-table suffix.
Authorization: Bearer <token>. Stored in this browser only.
Resolution order
The same four-step resolver is used by every Diplomacy Table page. First non-empty value wins.
?api=query parameter — wins over everything; ideal for handing a pre-wired link to a class or a panel.localStorage['dtsf.apiBase']— sticky per browser; what the remember checkbox writes.window.DTSF_API_BASE_DEFAULT— a one-line<script>injected at publish time, so a Pages deployment ships already pointed at the convening backend. Tested withinrather than for truthiness, so publishing it as''is a valid, explicit "no backend here" — which is what a reference-only Pages build should ship. Without it the resolver would fall through to the Pages origin and report connection errors againstgithub.io.window.location.origin— the same-origin case, i.e. the page was served by the DTSF runtime. Onfile://this yields no base and the page stays in reference-only mode.
Token resolution mirrors it: ?token= → localStorage['dtsf.token'] → none.
What the token is, and what it is not
The backend reads DTSF_AUTH_TOKEN from its environment. If that variable is unset the
instance is completely open and the token field here is ignored — which is the right posture on a
laptop and the wrong one on anything with a public hostname. When it is set, every route
requires Authorization: Bearer <token> except four deliberate exceptions.
| Path | Why it stays public |
|---|---|
/_health, /_ready |
Load balancers, uptime monitors and container orchestrators probe these without credentials. Gating them means the platform declares a healthy box dead. |
/_version |
Build identity only. Useful when someone needs to tell you what they are running before they can authenticate. |
/diplomacy-table/config |
This page. It is the thing that collects the token, so requiring the token to load it would deadlock the bootstrap. It ships no data — every call it makes is gated. |
/_health is public, a green
status pill proves only that the host is alive. It does not prove your credential works. That is why
this console probes a gated route as part of connecting, and reports
token rejected separately from unreachable.
/diplomacy-team-*. If participants need their own seats, put path rules in the reverse
proxy (see the Caddyfile in docs/diplomacy/DESIGN.md) rather than relying on this alone.
Rotation is a restart: change the environment variable and bounce the process. Shareable links from this page deliberately omit the token, so rotating does not invalidate a link — only the credential pasted alongside it.
Live status
Probe log
Deployment shapes
| Shape | Frontend | Backend | Good for | Watch out for |
|---|---|---|---|---|
| All-in-one | served by DTSF at /_app/diplomacy-table |
same process | local dev, single-laptop demo | nothing to publish; nobody outside the room can watch |
| Pages + tunnel | GitHub Pages (Ethical-Tech-Colab) | B3IQ box behind Cloudflare Tunnel / Caddy | the recommended live-convening shape | backend must stay up; needs TLS + an auth story |
| Pages + replay | GitHub Pages | none — static JSON transcript bundles | public, permanent, zero-cost archive of a completed convening | read-only; no new rounds |
| Cloud PaaS | Pages or the PaaS itself | Render / Azure Container Apps | always-on demo without owning hardware | cold starts drop in-memory state; per-token cost is on you |
Full comparison, threat model and B3IQ topology: docs/diplomacy/DESIGN.md §4.
What is actually running
Ten minutes of orientation before anyone touches a knob. This is the mental model that makes the rest of the console legible: a neutral table twin that owns procedure and the record, and N delegation twins that own only their own instructions and their own words.
The two kinds of twin
Table twin — diplomacy-table
- Owns the session: parties, rules, round counter, status.
- Owns the record: every move, every detected tactic, every debrief.
- Runs the speaking order and the quality guards.
- Is the only component that sees all delegations' private instructions. It never leaks them into another delegation's prompt.
- Has no model of its own for the negotiation turns.
Delegation twins — diplomacy-team-*
- Own a persona, goals, red lines, a BATNA and a tactic set.
- Expose one meaningful endpoint:
POST /turn. - Receive a windowed transcript plus a structured memory block; return a JSON move.
- Are told which model to use per session — the pack does not hard-code one.
- Never see another delegation's red lines, BATNA or private guidance.
One round, step by step
- Guard the call.
POST /sessions/:id/round/nextrefuses if the session is notactive, if the round cap is hit, or if a human party still owes a move. - Compute speaking order. Honours
openerPartyTwinandrotateOpener. Coalitions with a whip collapse to a single speaking slot. - Classify each slot as speaking skipped twin-already-moved human-recorded human-awaiting. Only speaking slots call a model.
- Call each delegation in sequence. Deliberately sequential: the transcript accumulates during the round, so speaker 3 answers what speakers 1 and 2 just said. A parallel version was tried and reverted — it produced round-robin monologue and a high timeout rate.
- Run the guard ladder on each returned move: stub detector → opponent-echo → self-echo. Each failure buys one anti-mirror retry; persistent failure records a flagged placeholder move and increments a degraded counter.
- Detect tactics with the rule engine and attach them to the move.
- Advance the round and persist. The table's state is snapshotted to disk on a timer.
maxInputTokens.
Request path in a Pages deployment
browser (GitHub Pages, Ethical-Tech-Colab)
| fetch(apiBase + '/diplomacy-table/...') CORS: Access-Control-Allow-Origin: *
v
edge / tunnel (Cloudflare Tunnel or Caddy on the B3IQ box)
| TLS terminates here; add auth here, not in the browser
v
DTSF runtime (single Node process, tsx)
|-- /diplomacy-table/* table twin: sessions, moves, tactics, reports
|-- /diplomacy-team-*/* delegation twins: /turn
|-- /ollama/* provider registry + OpenAI-compatible passthrough
|-- /_proxy, /_cache inbound rate-limit shield, response cache
|-- /_health, /_version liveness
v
model backends: local weights on the B3IQ GPU, and/or a hosted API
http://localhost:${PORT}. The table twin and every delegation twin must therefore live in
the same process. You scale by making the box bigger or by running independent whole
instances, not by splitting twins across nodes. This is the single largest architectural
assumption in the system.
State & durability
- Where state lives
- In-process
Mapper twin. Fast, simple, and volatile. - Durability
- Periodic snapshots to
evidence/sessions/<timestamp>/, plus a final snapshot on graceful shutdown. On boot the runtime restores the most recent readable snapshot. - What this means
- A hard kill between snapshots loses the moves since the last one. Before a graded exercise, take a manual snapshot and shorten the interval.
- Not present
- No database, no WebSocket for the negotiation feed (the console polls), no per-user accounts, no row-level authorisation.
Knobs — what to turn, and what it does to the negotiation
Every knob below is real: it exists in the session payload, in a party record, in a delegation's fixture, or as an environment variable on the runtime. Each entry says where it lives, what the default is, what it mechanically changes, and — the part that matters for teaching — what it does to the negotiation. Use the filter to build a lesson around one dimension at a time.
| Knob | Where | Default | Mechanical effect | Effect on the negotiation — teach this |
|---|
Guided experiments
Each experiment isolates one variable. Run the same scenario twice, change only the named knob, and compare the outcome scoreboard and the tactic ledger. Twenty minutes each; all of them produce a result students can argue about.
Which model for which job
The system does not have "an AI". It has four distinct model jobs with genuinely different requirements, and the most common configuration mistake is using one model for all of them. Choosing per job is the cheapest quality win available.
| Job | What it has to do | What actually matters | Guidance |
|---|---|---|---|
| Delegation turn hot path |
Read a windowed transcript, stay in character, advance a position, emit valid JSON, in under the round timeout. | Instruction adherence, JSON reliability, latency, persona stability. Raw reasoning depth is close to irrelevant. | A mid-size instruct/chat model. This is called N× per round with humans watching, so a 6 s model that is 90 % as good beats a 60 s model that is 100 %. anti-pattern reasoning models here — they burn the token budget on hidden thinking, ignore the JSON response-format hint, and blow the timeout. |
| Convener / chair | Summarise the round, name convergence and divergence, propose the next agenda item. | Long-context comprehension and neutrality. Runs once per round, off the critical path. | The largest context window you can afford. Latency tolerance here is high, so this is the right place to spend on a stronger model. |
| Tactic judge not yet wired |
Read a move and decide whether a tactic was genuinely used. | Calibration and restraint — the ability to answer "no tactic" confidently. | Today detection is 100 % rule-based (regex + sequence). A judge model is the intended upgrade; it must run asynchronously so it never delays a round. |
| Debrief / after-action | Produce per-party and convener after-action reports from the full transcript. | Long context, analytic writing, willingness to be critical. | Runs once, at the end, unobserved. Use the strongest model available; a reasoning model is appropriate here and nowhere else in the loop. |
Model classes and their token budgets
The delegation twin classifies whatever model name you give it into one of these classes, then sizes the verbatim transcript window to fit. Reserved overhead per call: ~600 tokens of system prompt, ~700 tokens of structured memory, ~400 tokens of headroom. A transcript move averages ~134 tokens.
| Class | Matches | Input cap | Max verbatim moves | Usable window | Consequence |
|---|
maxInputTokens or move it to a larger class before you touch
the prompt.
Live model catalog
| Model id | Inferred class | Reasoning? | Verbatim moves | Suggested job |
|---|---|---|---|---|
| Not loaded. | ||||
Failover ladder
When a delegation's primary model fails, the twin does not simply error. It walks a ladder:
- Primary model. Called with a window sized for its class.
- Fallback model, if the failure is retryable: payload-too-large, a 5xx, a network fault, a content-filter rejection, or a rate limit with a long retry-after. The transcript window is re-sized for the fallback's class before the retry.
- Automatic non-filtered fallback. If a hosted content filter rejected the call and no operator fallback was configured, the twin routes to a large open-weights instruct model on its own initiative.
- Stub move. Last resort: a flagged placeholder is recorded so the round can complete, and the party's degraded counter increments.
Configuration anti-patterns
Same model, both sides, same settings
Produces uncanny symmetry: parties converge on identical phrasing and the self-/opponent-echo guards fire constantly. It is also bad pedagogy — students conclude the simulation is scripted. Vary at least the persona and preferably the model.
Reasoning model on the hot path
Temperature is forced, the JSON response-format hint is suppressed, the completion budget balloons, and timeouts follow. Save reasoning models for debriefs.
Tiny model with a big transcript
Instructions get pushed out of attention by transcript. The delegation drifts
out of character around round 4. Lower maxInputTokens rather than raising it.
No fallback configured
One content-filter hit or one 503 and that party emits a placeholder in front of
the audience. Always set fallbackModel for a live demo.
Raw API keys in provider records
Provider registrations can carry a literal key, and provider state is snapshotted to disk. Use the environment-variable form so the secret never lands in an evidence bundle.
Round timeout shorter than the model
A 30 s timeout against a model whose p95 is 40 s manufactures placeholder moves that look like model failure. Measure first, then set the timeout.
Tactics, goals, and getting a better negotiated outcome
Outcome quality is mostly decided before the first round, in how goals and red lines are written. This tab covers the two halves: what the system can detect, and how to author delegations so that detection has something interesting to find.
The rule-based tactic detectors
Detection is deterministic and explainable — every detection carries a confidence and is marked as rule-sourced. That is a feature for teaching: students can read the rule and argue about whether it is right.
| Tactic | How it is detected | Conf. | What it tells the class |
|---|
Writing goals that produce a real negotiation
Structure of a delegation's objective set
- Goals — ranked, each with a priority and an explicit note about what it can be traded against.
- Red lines — small in number, absolute, and stated in terms the other side could actually violate.
- BATNA — a described alternative with an estimated value. This is what makes walking away a live option rather than a bluff.
- Tactics — the named plays this delegation is authorised to run, each with a trigger condition.
The three rules that decide whether it works
- Goals must be tradeable across parties, not within one. If A's third priority is cheap for B to concede and vice versa, you have a deal space. If both sides rank the same single issue first and nothing else exists, you have a stalemate generator.
- Red lines must not overlap the ZOPA. If A's red line sits inside the only zone where B can agree, no settlement is reachable — which is a legitimate teaching scenario, but only if you did it on purpose.
- BATNA value must be below the midpoint of the ZOPA for a party you want to settle, and above it for a party you want to walk. This single number is the most powerful outcome dial in the whole system.
Levers on the negotiated outcome, ranked by effect size
| Rank | Lever | How to move it | Observed effect |
|---|
docs/diplomacy/SCENARIO-RESEARCH.md.
Researching and building a negotiation scenario
A scenario is a researched artefact, not a writing exercise. The credibility of the whole simulation
rests on it: participants will accept a machine-generated argument if the underlying facts are
sourced, and reject the entire exercise if one date or one number is wrong. This tab is the working
checklist; the long-form method lives in docs/diplomacy/SCENARIO-RESEARCH.md.
The seven phases
Source discipline
| Tier | What counts | Use it for | Rule |
|---|---|---|---|
| Tier 1 | Treaty text, UN Security Council resolutions, official communiqués, court filings, regulatory notices, published statistics, verbatim transcripts. | Anything asserted as fact in context, history or
pastAgreements. |
Cite title, publisher and date. Required for every hard number and every date. |
| Tier 2 | Wire-service and major-outlet reporting, think-tank analysis with a named author, specialist trade press. | recentEvents, characterisation of positions, atmospherics. |
Two independent Tier-2 sources, or one Tier-2 corroborating a Tier-1, before an item is stated as fact rather than as a claim. |
| Tier 3 | Commentary, op-eds, unattributed briefings, model output, your own inference. | Only inside a party's private guidance — i.e. what that delegation
believes. |
Never appears in shared context. Must be labelled as assessment, not fact. |
Design the deal space first
Numbers to fix before writing prose
- The issue being negotiated, expressed on a single scale where possible.
- Each party's reservation value — the worst it will accept.
- The resulting ZOPA, if any: the overlap between reservation values.
- Each party's BATNA value on the same scale.
- The secondary issues that make log-rolling possible — at least two, ranked oppositely by the two sides.
Sanity tests
- ZOPA width between roughly 5 % and 25 % of the issue range. Wider is trivial, narrower is a coin flip.
- No party's red line falls inside the ZOPA unless deadlock is the lesson.
- At least one party's BATNA is close enough to its reservation value that walking away is credible.
- Every party has something the other side wants and can concede without crossing a red line.
- If you remove any one party, the deal becomes materially easier — otherwise that party is decoration.
Scenario field reference
| Field | Required | Purpose | Authoring guidance |
|---|
Live scenarios on the connected backend
Quality gate — do not run a graded exercise until every box is ticked
Authoring a delegation
A delegation twin is a persona plus an objective set plus a model configuration. The objective set is what makes it negotiate; the persona is what makes it recognisable; the model configuration is what makes it reliable. Build all three deliberately, then export the fixture below.
Builder
diplomacy-team-; becomes the pack directory name.Generated delegation fixture
Fill the form and press Generate.
Generated system-prompt override
—
The seven-part system prompt
The delegation twin assembles its system prompt from the fixture in a fixed order. Understanding the order tells you where to intervene when a party misbehaves.
- Identity and persona. Who you are, your style, your temperament.
- Goals in priority order, with tradeability annotations.
- Red lines, stated as absolutes.
- BATNA, with its estimated value — this is what licenses walking away.
- Authorised tactic ids, with triggers. Anything the model claims to have used that is not in this list is silently discarded from the record.
- Output contract. Strict JSON shape; a short move; no meta-commentary.
- Identity lock and anti-repetition. Explicit instructions not to speak for other parties and not to restate its own previous move.
Installing a new delegation
- Copy an existing
diplomacy-team-*pack directory to the new twin name. - Update the manifest name and description; update the pack's exported identity.
- Replace the fixture with the JSON generated above.
-
Reload the twin —
POST /_twins/<name>/reloadre-evaluates the pack's whole module graph in place and preserves state (RUNTIME-HOTLOAD-002). A brand-new pack directory still needs a restart, because packs are discovered at boot. - Smoke-test with a two-party session before adding it to a real convening.
/turn, not
/diplomacy-team-x/turn. The runtime strips the twin name before dispatch. Getting this
wrong yields a twin that answers direct curl calls but 404s under the test harness.
ZOPA — the zone of possible agreement
A ZOPA is not a feeling about whether two sides are "close". It is arithmetic: the overlap of the intervals each side would still sign. This tab computes what the authored data actually supports, and is explicit about what it does not — because on a teaching tool, a confident wrong overlap bar is worse than an absent one.
/batna with test data
— silently replaces the scenario design. Switch to Runtime to see what the twins
currently hold; any divergence is reported as drift below.
How to close the gap
The reservation value (L4) is the load-bearing one, and it is research, not code. Elicit it with the flip question, per delegation, per issue:
Then cross-check it twice — both checks are teachable in their own right:
- Against the BATNA. A reservation is only credible if walking away is genuinely worse. If the side with the worse BATNA also holds the tighter reservations, the scenario is internally inconsistent.
-
Against the red lines. A red line is a reservation stated in prose. If a red line
says "no enrichment above 5%" and the goal's
minimplies 20%, one of the two is an authoring bug. Cheap check; catches real errors.
priority as a proxy — they are orthogonal: an issue can be
critical and have a wide acceptable range.
(3) Ship the {min:0, target:1} placeholders — every issue overlaps
completely, every scenario reports a maximal ZOPA, and students learn the exact inverse of the
lesson.
Full rationale: docs/diplomacy/DESIGN-ZOPA-CALCULATOR.md §1.3. Authoring method:
docs/diplomacy/SCENARIO-RESEARCH.md Phase 3 step 6.
Model bake-off — find out what actually works
The teaching claim of this whole console is that model choice is a decision with measurable consequences. This tab makes that testable: build a session payload, run the same scenario under different model assignments, and record the metrics that matter. Everything here is honest about what it measures — small samples, noisy metrics, real conclusions only after several runs.
Session payload builder
Parties
| Twin name | Display | Participant | Provider | Model | Fallback | Max input tok. |
|---|
POST /diplomacy-table/sessions
Press Build payload.
Run and measure
Results
| Session | Rounds | Moves | Tactics | Placeholders | Satisfaction spread | Red lines crossed | Wall time | Models |
|---|---|---|---|---|---|---|---|---|
| No runs recorded. | ||||||||
What to measure, and what each metric is worth
| Metric | Definition | Good looks like | Caveat |
|---|
Run-time evaluation — Diplomacy Simulation Demo, Army War College
A ninety-minute block for a professional military-education audience: senior officers and civilian equivalents who will be sceptical, subject-matter expert on the scenario, and unforgiving of anything that looks like a magic trick. The goal is not to impress them with the AI. It is to show them a method for structured wargaming of a negotiation, with the machine's limits stated up front.
Preflight — T−24 hours
Run sheet
| Clock | Segment | What happens | Operator actions & risk |
|---|
Failure modes and what to say
| If this happens | Likelihood | Do this | Say this |
|---|
Evaluation instrument
Collect these from participants at the end. They are deliberately about the method, not about whether the AI was impressive.
- Name one move a delegation made that you judged militarily or diplomatically implausible, and say why.
- Name one move you judged plausible and non-obvious.
- Did the tactic ledger identify anything you would not have noticed unaided? Did it miss anything obvious?
- Where did the deal land relative to where you expected it to land? What in the configuration explains the difference?
- Which single configuration change would most improve the fidelity of this exercise?
- What is one question this tool could help a staff group answer that they cannot answer today in a comparable amount of time?
Framing language — use it verbatim
Deployment posture for the demo
- Recommended
- Backend on the local box in the room, models local, no external network dependency. Frontend served from the same box. Zero cloud, zero latency surprise, zero content-filter risk.
- Acceptable
- Backend on the B3IQ hardware reached over a tunnel; frontend on Pages. Requires a tested network path and a rehearsed fallback to the local box.
- Fallback
- A pre-recorded transcript bundle replayed by the static frontend. Prepare this regardless — it costs an hour and it is the difference between a bad day and a cancelled session.
- Not acceptable
- Live hosted-API models over conference Wi-Fi with no local fallback, for a scenario likely to trip a content filter.