The platform had to preserve causal validity.
An experiment platform must keep shared elements fixed while changing one mechanism by condition. Conditions 3, 5, and 6 use the same three preparation modules—what each side wants, where they agree and disagree, and how a deal could work—but vary whether the AI generates a sheet, extends a participant draft, or only pressure-tests reasoning.
Keep non-treatment elements matched
Documents, reading targets, visual grammar, timers, and evidence navigation stay matched across the active conditions.
A citation is not enough
Every passage must be verbatim, assigned to the right analytic slot, and allowed by its source provenance.
Slow models cannot corrupt logs
Streaming, parallel scans, autosave, and model responses can finish out of order; writes need monotonic revisions.
Participants cannot wait for scoring
Survey completion and LLM scoring are separate transactions with a local fallback path.
System architecture
01 / ASSIGNURL + participant ID → deterministic condition. Explicit debug conditions remain available without contaminating the randomized pool.
02 / READPredetermined files → role-visible document reader. The browser cannot upload arbitrary files; every model request receives only the materials allowed for that role.
03 / EVIDENCEParallel per-file scans → provenance validation → global clustering. Candidates remain clickable back to exact source spans.
04 / TREATMENTC3 autofill / C5 extension / C6 challenge. Separate prompts and handlers share output contracts and the visible preparation structure.
05 / STREAMServer-sent events → incremental UI state. JSON frames carry text, artifacts, and errors; local fallbacks keep the task moving.
06 / PERSISTPostgres participant stages + interaction revision. Consent, demographics, drafts, events, final survey, and scoring have explicit save semantics.
07 / INSPECTRead-only dashboard. Cohort counts, timeouts, condition summaries, interaction heatmaps, and system versions support launch checks and analysis.
Grounding required semantic contracts.
A model can return a real quote that is still invalid for the intended use. A private note from one side cannot prove shared agreement; an unverified media report cannot establish a party’s red line; a passage about an intermediary does not authorize that actor to implement a deal.
The evidence handler therefore couples a JSON schema with deterministic checks. Each item has a verbatim quote, framework, slot, one or two visible cell IDs, importance, reason, and semantic-group label. A second layer validates source context and prohibited routes. Exact text matching confirms that the quoted span really exists in the document.
function sourceContextAllowsHighlight(framework, slot, sourceContext) {
if (framework === "ioa" && slot.endsWith("-agree") &&
["role-private-document", "unverified-external-report",
"third-party-media", "third-party-advocacy"]
.includes(sourceContext)) return false;
if (framework === "paths" && slot === "boundaries" &&
!["unspecified", "role-private-document",
"two-party-meeting-record"].includes(sourceContext)) return false;
return true;
}
Cross-document deduplication also operates at the proposition level, not the keyword level. “Food distribution” can describe a constraint, a package term, or background context; those are not interchangeable evidence.
Model failure is part of the treatment environment.
Different conditions call different handlers and models, but failure behavior must not silently become another experimental manipulation. Structured-output requests use schema validation and bounded retries. Evidence ranking falls back to deterministic core/support ordering. Final scoring has a local rubric-based fallback so a participant still receives a result if the model provider is unavailable.
| Risk | System control | Why it matters |
|---|---|---|
| Malformed output | Strict JSON schemas, normalization, bounded retry | Prevents one condition from failing as an unhandled UI state. |
| Slow generation | SSE streaming and parallel evidence scans | Keeps timing visible and avoids blocking the reading workflow. |
| Ranking outage | Deterministic evidence-order fallback | Participants can continue with the same source set. |
| Scoring outage | Compute-only scoring endpoint plus local fallback | Completion codes are released after survey storage, not model success. |
Log the path to each answer.
The platform records file opens, document clicks, saved evidence, AI requests, draft state, prompt edits, condition-specific artifacts, and timing. A monotonic interaction revision prevents a slower autosave from overwriting a newer snapshot. Each cohort also carries the case-material version and the deployed commit-derived system version, so analysis can separate participants who saw different code or content.
The dashboard supports launch and validity checks. Started versus completed counts, timeout rates, missing stages, fallback-scored rows, condition summaries, and interaction sequences surface broken data before a batch becomes unusable.
Failure modes that changed the design
- Per-file evidence labels looked globally meaningful. They were replaced with a separate cross-document clustering pass and migration logic for already-saved quotes.
- Topic overlap created false “similar evidence.” The clustering contract now requires the same decision-relevant proposition, actor, authority, and implication.
- Asynchronous snapshots could arrive out of order. Interaction saves now carry increasing revisions and reject stale state.
- Version labels were manually stale. The API derives the runtime version from the deployed commit and stores it with participant rows.
- Scoring coupled to completion created a fragile exit path. The final survey commits first; scoring saves later through a separate stage.
My scope
I implemented the experimental condition logic, document reader, evidence layer, LLM handlers, schemas, SSE path, Postgres persistence, behavioral instrumentation, dashboard, model benchmarks, tests, and deployment. Research materials shown in the public system are predetermined scenarios; participant records remain in the protected study database and are never embedded here.