Voting, Polls & Outcomes

Cast argument votes, create polls, submit real-world outcomes, and retrieve decision intelligence scores with the AskVerdict SDK.

4 min read
Share

Beyond generating verdicts, AskVerdict tracks how well its AI recommendations hold up in the real world. This page covers three closely related features:

  • Voting — cast agree/disagree votes on individual argument claims
  • Polls — create audience polls tied to a debate
  • Outcomes — record what actually happened after a decision was made, and compare it to the AI verdict
  • Decision Intelligence — retrieve accuracy scores and streaks that reflect your track record

Voting on Arguments

After a debate completes, each argument published by an AI agent contains one or more claims. Users can vote "agree" or "disagree" on each claim to signal how persuasive they found it.

Get current vote tallies

typescript
import { AskVerdictClient, type VoteMap } from "@askverdict/sdk";
 
const client = new AskVerdictClient({ apiKey: process.env.ASKVERDICT_API_KEY! });
 
const votes: VoteMap = await client.getVotes("dbt_abc123");
 
// VoteMap is Record<claimId, ClaimVoteTally>
for (const [claimId, tally] of Object.entries(votes)) {
  console.log(`Claim ${claimId}:`);
  console.log(`  Agree: ${tally.agree}`);
  console.log(`  Disagree: ${tally.disagree}`);
 
  if (tally.userVote !== undefined) {
    console.log(`  Your vote: ${tally.userVote}`); // "agree" | "disagree" | "neutral"
  }
}

VoteMap shape:

KeyTypeDescription
(claimId)ClaimVoteTallyTally object for that claim

ClaimVoteTally shape:

FieldTypeDescription
agreenumberTotal agree votes
disagreenumberTotal disagree votes
userVoteVoteValue | undefinedCaller's own vote (only when authenticated)

Cast a vote

Pass "agree", "disagree", or "neutral" as the vote value. Calling castVote again with a different value updates the existing vote — each user can hold at most one vote per claim.

typescript
await client.castVote("dbt_abc123", "claim_pro_001", "agree");

Remove a vote explicitly

typescript
await client.removeVote("dbt_abc123", "claim_pro_001");
// Equivalent to castVote(..., "neutral")

Vote on every claim after a debate completes

typescript
const { verdict } = await client.getVerdict("dbt_abc123");
 
if (verdict.status !== "completed" || !verdict.verdict) {
  throw new Error("Debate is not yet complete");
}
 
// Fetch current tallies so we know which claims exist
const votes = await client.getVotes("dbt_abc123");
 
// Vote agree on all claims we haven't voted on yet
for (const [claimId, tally] of Object.entries(votes)) {
  if (tally.userVote === undefined) {
    await client.castVote("dbt_abc123", claimId, "agree");
    console.log(`Voted agree on ${claimId}`);
  }
}

Polls

Polls let the debate owner solicit structured audience input — for example, asking "Which argument was most convincing?" after a debate completes.

Get polls for a debate

typescript
import type { Poll } from "@askverdict/sdk";
 
const polls: Poll[] = await client.getPolls("dbt_abc123");
 
for (const poll of polls) {
  console.log(`\n${poll.question} [${poll.status}]`);
  console.log(`Total votes: ${poll.totalVotes}`);
 
  for (const option of poll.options) {
    const count = poll.tallies[option.id] ?? 0;
    const pct = poll.totalVotes > 0
      ? Math.round((count / poll.totalVotes) * 100)
      : 0;
    console.log(`  ${option.label}: ${count} (${pct}%)`);
  }
 
  if (poll.userVote !== null) {
    const chosen = poll.options.find((o) => o.id === poll.userVote);
    console.log(`  Your vote: ${chosen?.label ?? poll.userVote}`);
  }
}

Poll shape:

FieldTypeDescription
idstringPoll ID
debateIdstringParent debate
questionstringPoll question text
optionsPollOption[]Array of { id, label }
status"open" | "closed"Whether voting is still open
talliesRecord<string, number>Vote counts keyed by option ID
totalVotesnumberSum of all option votes
userVotestring | nullOption ID the caller voted for (null if not voted)
createdAtstringISO 8601 creation time
closedAtstring | nullISO 8601 close time, or null if still open

Create a poll

Creating a poll requires debate ownership. Provide 2–6 option labels.

typescript
const poll = await client.createPoll(
  "dbt_abc123",
  "Which argument changed your mind most?",
  [
    "The scalability argument (Pro Round 2)",
    "The cost projection (Con Round 1)",
    "Neither — I was already decided",
  ],
);
 
console.log(`Poll created: ${poll.id}`);
// poll.options[0].id → "opt_001" (server-generated IDs)

Vote on a poll

typescript
// Get the option ID to vote for
const polls = await client.getPolls("dbt_abc123");
const poll = polls[0]!;
const firstOption = poll.options[0]!;
 
await client.votePoll("dbt_abc123", poll.id, firstOption.id);
console.log(`Voted for: ${firstOption.label}`);

Close and delete polls

typescript
// Close a poll — prevents further votes, results are still visible
await client.closePoll("dbt_abc123", "poll_pqr789");
 
// Delete a poll entirely
await client.deletePoll("dbt_abc123", "poll_pqr789");

closePoll and deletePoll require debate ownership. They will throw AskVerdictError with status 403 if called by a non-owner.


Outcomes

An outcome is a record of what actually happened after a decision was made. Submitting outcomes is what powers AskVerdict's decision intelligence: over time, it tells you how accurate the AI's recommendations were.

Submit an outcome

After a real-world decision plays out, record what happened and whether the AI verdict was correct.

typescript
const outcome = await client.submitOutcome("dbt_abc123", {
  actualOutcome: "Adopted Kubernetes — deployment time down 40% after 3 months",
  verdictWasCorrect: true,
  notes: "The scalability argument proved decisive for the infrastructure team.",
});
 
console.log(`Outcome recorded: ${outcome.id}`);
console.log(`Recorded at: ${outcome.recordedAt}`);

OutcomeRecord shape:

FieldTypeDescription
idstringOutcome record ID
debateIdstringParent debate
actualOutcomestringDescription of what happened
notesstring | nullOptional notes
verdictWasCorrectboolean | nullWhether the AI verdict matched reality
recordedAtstringISO 8601 timestamp

Get an existing outcome

typescript
const outcome = await client.getOutcome("dbt_abc123");
 
if (outcome.verdictWasCorrect === true) {
  console.log("The AI verdict was correct.");
} else if (outcome.verdictWasCorrect === false) {
  console.log("The AI verdict was incorrect.");
} else {
  console.log("Verdict accuracy not yet assessed.");
}

Get pending outcomes

Debates that have completed but have no outcome recorded yet.

typescript
const pending = await client.getPendingOutcomes();
 
console.log(`${pending.length} debates awaiting outcome recording:`);
for (const p of pending) {
  console.log(`  ${p.debateId}`);
}

Get outcome history

typescript
// Most recent 50 outcomes
const history = await client.getOutcomeHistory({ limit: 50 });
 
// Filter by domain (if you tag debates by domain)
const businessHistory = await client.getOutcomeHistory({
  limit: 20,
  domain: "business",
});
 
// Paginate through history
const page2 = await client.getOutcomeHistory({ limit: 20, offset: 20 });

Decision Intelligence Scores

After recording several outcomes, you can retrieve accuracy metrics that show how well you (and the AI) have been doing.

Get your decision score

typescript
const score = await client.getScore();
 
console.log(`Overall accuracy: ${Math.round(score.overallAccuracy * 100)}%`);
console.log(`Total decisions tracked: ${score.totalDecisions}`);
console.log(`Correct predictions: ${score.correctPredictions}`);
 
if (score.brierScore !== null) {
  // Brier score: 0.0 = perfect, 1.0 = worst possible
  console.log(`Brier score: ${score.brierScore.toFixed(3)}`);
}
 
if (score.calibrationScore !== null) {
  console.log(`Calibration: ${Math.round(score.calibrationScore * 100)}%`);
}

DecisionScore shape:

FieldTypeDescription
overallAccuracynumberFraction of verdicts that proved correct (0–1)
totalDecisionsnumberTotal decisions with recorded outcomes
correctPredictionsnumberCount of correct verdicts
brierScorenumber | nullProbabilistic calibration (0 = best, 1 = worst)
calibrationScorenumber | nullNormalized calibration fraction (0–1)

Get your debate streak

typescript
const streak = await client.getStreak();
 
console.log(`Current streak: ${streak.currentStreak} days`);
console.log(`Longest streak: ${streak.longestStreak} days`);
console.log(`Total debates: ${streak.totalDebates}`);
 
for (const milestone of streak.milestones) {
  const status = milestone.reached
    ? `reached ${milestone.reachedAt ? `on ${milestone.reachedAt}` : ""}`
    : "not yet reached";
  console.log(`  ${milestone.count}-debate milestone: ${status}`);
}

End-to-End Workflow

This example shows the complete lifecycle from creating a debate, engaging with it through polls and votes, then recording the outcome and checking the impact on your score.

typescript
import { AskVerdictClient, AskVerdictError } from "@askverdict/sdk";
 
const client = new AskVerdictClient({ apiKey: process.env.ASKVERDICT_API_KEY! });
 
async function fullWorkflow() {
  // 1. Create a verdict and wait for it to complete
  console.log("Creating verdict…");
  const { id } = await client.createVerdict({
    question: "Should we expand into the European market in Q3?",
    mode: "thorough",
    context: "We have $500K budget, a 10-person team, and 80% US revenue.",
  });
 
  // 2. Stream events until complete
  console.log(`Streaming debate ${id}…`);
  for await (const event of client.streamVerdict(id)) {
    if (event.type === "agent:argument") {
      const data = event.data as { agentName: string; content: string };
      console.log(`  [${data.agentName}] ${data.content.slice(0, 80)}…`);
    }
    if (event.type === "debate:complete") break;
  }
 
  // 3. Fetch the completed verdict
  const { verdict } = await client.getVerdict(id);
 
  if (!verdict.verdict) {
    throw new Error("Verdict is not complete");
  }
 
  console.log(`\nVerdict: ${verdict.verdict.recommendation.recommendation}`);
  console.log(`Confidence: ${Math.round(verdict.verdict.confidence * 100)}%`);
  console.log("Key findings:");
  for (const finding of verdict.verdict.keyFindings) {
    console.log(`  - ${finding}`);
  }
 
  // 4. Vote on argument claims
  const votes = await client.getVotes(id);
  const claimIds = Object.keys(votes);
 
  if (claimIds.length > 0) {
    // Agree with the first claim as an example
    await client.castVote(id, claimIds[0]!, "agree");
    console.log(`\nVoted agree on claim ${claimIds[0]}`);
  }
 
  // 5. Create an audience poll
  const poll = await client.createPoll(
    id,
    "After reading the debate, what is your decision?",
    ["Expand into Europe in Q3", "Delay until Q4", "Do not expand at all"],
  );
  console.log(`\nPoll created: ${poll.id}`);
 
  // 6. Vote on the poll
  await client.votePoll(id, poll.id, poll.options[0]!.id);
  console.log(`Voted on poll: "${poll.options[0]!.label}"`);
 
  // --- Later, after the decision plays out ---
 
  // 7. Record the outcome
  const outcome = await client.submitOutcome(id, {
    actualOutcome: "Launched EU operations — $120K revenue in first month",
    verdictWasCorrect: true,
    notes: "The market timing argument proved accurate. GDPR compliance was harder than estimated.",
  });
  console.log(`\nOutcome recorded: ${outcome.id}`);
 
  // 8. Check updated decision score
  const score = await client.getScore();
  console.log(`\nUpdated score: ${Math.round(score.overallAccuracy * 100)}% accuracy`);
  console.log(`Total decisions tracked: ${score.totalDecisions}`);
}
 
fullWorkflow().catch((error) => {
  if (error instanceof AskVerdictError) {
    console.error(`[${error.code}] ${error.message}`);
  } else {
    console.error(error);
  }
  process.exit(1);
});

TypeScript Types Reference

typescript
import type {
  // Votes
  VoteValue,        // "agree" | "disagree" | "neutral"
  ClaimVoteTally,   // { agree, disagree, userVote? }
  VoteMap,          // Record<claimId, ClaimVoteTally>
 
  // Polls
  PollOption,       // { id, label }
  Poll,             // Full poll object with tallies
 
  // Outcomes
  OutcomeRecord,    // { id, debateId, actualOutcome, notes, verdictWasCorrect, recordedAt }
  SubmitOutcomeParams, // { actualOutcome, notes?, verdictWasCorrect? }
 
  // Decision intelligence
  DecisionScore,    // { overallAccuracy, totalDecisions, correctPredictions, brierScore, calibrationScore }
  StreakInfo,       // { currentStreak, longestStreak, totalDebates, milestones }
} from "@askverdict/sdk";

Was this page helpful?