← Tutorial page  ·  All materials  ·  Markdown source

A real spec, redacted

Companion handout for the CISOSE 2026 tutorial Building and Verifying AI Systems with Agentic AI — Chia-Kai Chang, National Central University.

This is the actual specification for a production feature, not one written for a talk. It was drafted on 2026-07-06 and the first phase was implemented on 2026-07-07 — one afternoon of writing, roughly the same again of building.

The feature is a blind model-comparison arena: a student asks one question, two anonymous models answer side by side, the student votes, and only then are the two models revealed. It exists to move a student from consumer of one AI to judge of several.

Read it for the shape, not the subject. The point is which clauses had to be written down because no agent could have inferred them.


What was removed, and why

Redaction is part of the method, so it is marked rather than hidden.

Removed Reason
Full CREATE TABLE statements Internal schema detail; the fields that matter to the teaching points are summarised in §7.
Internal hostnames and GPU inventory Operational detail, no teaching value, mild disclosure risk.
Source file layout and blueprint names Specific to one codebase.
Two clauses in §3 and §5 — a roster exclusion policy, and an enumerated contested factual claim Both are specific to one jurisdiction's politics. The mechanism is kept in full; only the enumerated instance is removed. Marked [REDACTED] in place.

Nothing was added, softened, or rewritten to look better after the fact. Where the spec was vague, it is still vague.


§1 Goal and teaching claim

Core claim: a single AI reads as an oracle. Several AIs — from different origins, with different value commitments, disagreeing with each other — force a student from "accept the answer" to "judge which answer is better, and say why". That shift is itself AI literacy.

Four-philosophy roster, one model each:

Philosophy Label Origin type
commercial commercial frontier large US vendor
community community capability national university lab
sovereign national sovereignty state-funded programme
open_science open science European public research consortium

Research output: votes plus free-text reflection become AI-literacy signals; preferences on value-laden prompts become governance data. In-platform and authenticated, so it falls under the existing umbrella ethics approval rather than needing its own.

Stated red line, verbatim from the spec: the rating is student preference, not an objective capability benchmark, and it must never be described as equivalent to one.


§2 Flow

① entry (four philosophies explained + first-time research consent)
   → choose mode: free (own prompt) | curated (prompt bank)
② prompt
③ POST /battle/start
   server: draw 2 from the active roster → randomise slot (A/B) AND screen side
         → create battle(status=streaming) → return battle id + two ANONYMOUS slots
④ SSE /battle/<id>/stream
   call both models in parallel, multiplex tokens tagged by slot
   → both columns stream at once. Self-disclosure suppressed + filtered (see §4)
⑤ vote (opens only after both columns finish)
   verdict: left | right | tie | BOTH BAD, plus optional "why did you pick it"
⑥ reveal + rating update
   → front-end flips the cards: "you chose the community model; the other was commercial"
⑦ reflect / play again

§3 Roster and availability — the arena deliberately does not fall back

This is the clause most worth reading.

與一般對話不同:一般對話允許 fallback 回其他供應商;Arena 絕不 fallback——fallback 會污染「這顆模型實際表現」的比較。

Unlike ordinary chat, which is allowed to fall back to another provider, the arena never falls back. A fallback would contaminate the comparison — you would be rating a model that did not answer.

Instead of falling back, the spec requires a health gate: probe each model before the draw and exclude unhealthy ones from that round. If a locally hosted model is offline the roster simply shrinks; the arena keeps working.

If a stream fails mid-answer, that response is marked error and the student may vote "both bad" or discard the round without it counting.

[REDACTED — one clause stating a roster exclusion policy and its reasoning.]

Why this is the example: the same engineering instinct — "always degrade gracefully, always have a fallback" — is correct everywhere else in this system and produces a measurement error here. No coding agent infers that from the goal. It comes from knowing what the numbers will be used for.


§4 Blind-test integrity

Observed in testing: some models state their own name and developer unprompted. That alone destroys the blind comparison. Two layers, because an instruction is not enforcement:

  1. System-prompt suppression (primary). Every arena model is told: you are an AI assistant in an anonymous comparison; do not reveal your name, developer, model family or country of origin; answer the question directly.
  2. Stream redaction (secondary). A configurable blocklist of model and vendor names is masked in the token stream as [model name hidden].
  3. Position randomisation. Slot and screen side are randomised every round, and model identity is held server-side only — never sent to the client before the vote.

Layer 1 is a request to a system that is free to ignore it. Layer 2 is the enforcement. Writing both down is the difference between a policy and a hope.


§5 Sensitive-topic policy

Stance: present plural perspectives, and do not reproduce specific distortions.

The clause that matters architecturally:

The policy is written at the platform layer. It is not delegated to any single model's built-in alignment.

[REDACTED — the spec enumerates one specific contested factual claim that must not be presented as fact. The enumerated instance is jurisdiction-specific; the requirement that such instances be enumerated *in the spec*, rather than left to a vendor's alignment, is the transferable part.]

Prompts touching values or politics are tagged, and those rounds are retained as governance data. Framing to students is "how do AI systems with different value commitments answer this", never "which political position is correct".


§6 The maths, written out

That fourth bullet is the third un-inferrable clause. Fold "both bad" into the score and the ranking quietly stops meaning what its label says.


§7 Data model (summarised)

Five tables: the roster with current rating, one row per battle, one row per response, one vote per battle, and an append-only rating history. Conventions from the codebase standard: UTC timestamps, binary UUIDs, soft delete.

Fields worth noting because they exist for measurement rather than for the feature:

Field Why it is there
ttft_ms, latency_ms Does answer speed influence preference? Unanswerable later if not captured now.
decision_ms Time from "both ready" to vote.
reflection_text The free-text reason. Treated as sensitive; de-identified on export.
verdict = both_bad Stored distinctly so it can be excluded from the rating and counted on its own.

§8–§9 API and front-end

Endpoints for start, stream, vote, leaderboard, prompt bank, history, and two admin routes. Response envelope and rate limiting follow existing codebase conventions.

The front-end section exists for one reason: so the agent reuses the design language instead of inventing a new one. It names the brand colours, the sanitiser configuration required for rendering model-generated markdown, the loading indicator, and the responsive behaviour of the two columns. Cheap to write, and it removes an entire category of review comment.


§10 Measurement mapping

Each captured signal is mapped, in the spec, to the research construct it serves and the exact field it comes from. Doing this before implementation is what prevents the familiar situation where the analysis needs a field nobody stored.


§11 Ethics and approval


§12 Phasing

Writing down what deliberately does not ship is what stops phase 1 from quietly growing into phase 3.


The three clauses again

If you take one thing from this document, take the exercise: after writing your spec, find three clauses an agent could not have inferred.

  1. §3 — never fall back, because a fallback is a measurement error here even though it is good practice everywhere else.
  2. §4 — suppress self-identification, because it was observed happening, and enforce it in the stream rather than trusting the instruction.
  3. §6 — "both bad" does not move the rating, because it is a different kind of signal.

Three judgements about what the thing is for. That is the part that did not get cheaper.


Released with the tutorial materials. Reuse freely; attribution welcome.

CISOSE 2026 tutorial materials · Chia-Kai Chang, National Central University · uedu.tw