Skip to content

Commit 2402715

Browse files
committed
refac(pred-swarm): open verifier v1
1 parent 6a819ff commit 2402715

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4592
-1198
lines changed

.github/ci-config.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,23 @@
2525
"pr_preview": false
2626
},
2727
"prediction-swarm": {
28-
"deploys": ["swarm-twitter", "swarm-verifier", "swarm-filter"],
28+
"deploys": [
29+
"swarm-twitter",
30+
"swarm-judge",
31+
"swarm-verifier",
32+
"swarm-filter"
33+
],
2934
"pr_preview": false,
3035
"preview_domain": "predictionswarm.com"
3136
},
3237
"swarm-twitter": {
3338
"pr_preview": false,
3439
"prod_only": true
3540
},
41+
"swarm-judge": {
42+
"pr_preview": false,
43+
"prod_only": true
44+
},
3645
"swarm-verifier": {
3746
"pr_preview": false,
3847
"prod_only": true

apps/torus-wallet/next-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3-
import "./.next/dev/types/routes.d.ts";
3+
import "./.next/types/routes.d.ts";
44

55
// NOTE: This file should not be edited
66
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
-- Create "verification_claim" table
2+
CREATE TABLE "public"."verification_claim" (
3+
"id" uuid NOT NULL DEFAULT uuidv7(),
4+
"parsed_prediction_id" uuid NOT NULL DEFAULT uuidv7(),
5+
"verifier_agent_id" character varying(256) NOT NULL,
6+
"verifier_agent_signature" text NOT NULL,
7+
"claim_outcome" boolean NOT NULL,
8+
"confidence" numeric NOT NULL,
9+
"reasoning" text NOT NULL,
10+
"sources" jsonb NULL,
11+
"timeframe_start_utc" timestamptz NULL,
12+
"timeframe_end_utc" timestamptz NULL,
13+
"timeframe_precision" character varying(32) NULL,
14+
"created_at" timestamptz NOT NULL DEFAULT now(),
15+
"updated_at" timestamptz NOT NULL DEFAULT now(),
16+
"deleted_at" timestamptz NULL,
17+
PRIMARY KEY ("id"),
18+
CONSTRAINT "verification_claim_unique_verifier" UNIQUE ("parsed_prediction_id", "verifier_agent_id"),
19+
CONSTRAINT "verification_claim_parsed_prediction_id_parsed_prediction_id_fk" FOREIGN KEY ("parsed_prediction_id") REFERENCES "public"."parsed_prediction" ("id") ON UPDATE NO ACTION ON DELETE CASCADE
20+
);
21+
-- Create index "verification_claim_created_at_idx" to table: "verification_claim"
22+
CREATE INDEX "verification_claim_created_at_idx" ON "public"."verification_claim" ("created_at");
23+
-- Create index "verification_claim_parsed_prediction_id_idx" to table: "verification_claim"
24+
CREATE INDEX "verification_claim_parsed_prediction_id_idx" ON "public"."verification_claim" ("parsed_prediction_id");
25+
-- Create index "verification_claim_verifier_agent_id_idx" to table: "verification_claim"
26+
CREATE INDEX "verification_claim_verifier_agent_id_idx" ON "public"."verification_claim" ("verifier_agent_id");
27+
-- Modify "verdict" table
28+
ALTER TABLE "public"."verdict" ADD COLUMN "accepted_claim_id" uuid NULL DEFAULT uuidv7(), ADD CONSTRAINT "verdict_accepted_claim_id_verification_claim_id_fk" FOREIGN KEY ("accepted_claim_id") REFERENCES "public"."verification_claim" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION;
29+
-- Create "verifier_feedback" table
30+
CREATE TABLE "public"."verifier_feedback" (
31+
"id" uuid NOT NULL DEFAULT uuidv7(),
32+
"parsed_prediction_id" uuid NOT NULL DEFAULT uuidv7(),
33+
"verifier_agent_id" character varying(256) NOT NULL,
34+
"verifier_agent_signature" text NOT NULL,
35+
"failure_cause" "public"."failure_cause_enum" NOT NULL,
36+
"reason" text NOT NULL,
37+
"created_at" timestamptz NOT NULL DEFAULT now(),
38+
"updated_at" timestamptz NOT NULL DEFAULT now(),
39+
"deleted_at" timestamptz NULL,
40+
PRIMARY KEY ("id"),
41+
CONSTRAINT "verifier_feedback_unique" UNIQUE ("parsed_prediction_id", "verifier_agent_id"),
42+
CONSTRAINT "verifier_feedback_parsed_prediction_id_parsed_prediction_id_fk" FOREIGN KEY ("parsed_prediction_id") REFERENCES "public"."parsed_prediction" ("id") ON UPDATE NO ACTION ON DELETE CASCADE
43+
);
44+
-- Create index "verifier_feedback_agent_idx" to table: "verifier_feedback"
45+
CREATE INDEX "verifier_feedback_agent_idx" ON "public"."verifier_feedback" ("verifier_agent_id");
46+
-- Create index "verifier_feedback_failure_cause_idx" to table: "verifier_feedback"
47+
CREATE INDEX "verifier_feedback_failure_cause_idx" ON "public"."verifier_feedback" ("failure_cause");
48+
-- Create index "verifier_feedback_prediction_idx" to table: "verifier_feedback"
49+
CREATE INDEX "verifier_feedback_prediction_idx" ON "public"."verifier_feedback" ("parsed_prediction_id");
50+
-- Create "verifier_topic_registration" table
51+
CREATE TABLE "public"."verifier_topic_registration" (
52+
"id" uuid NOT NULL DEFAULT uuidv7(),
53+
"verifier_agent_id" character varying(256) NOT NULL,
54+
"topic_id" uuid NOT NULL DEFAULT uuidv7(),
55+
"created_at" timestamptz NOT NULL DEFAULT now(),
56+
"updated_at" timestamptz NOT NULL DEFAULT now(),
57+
"deleted_at" timestamptz NULL,
58+
PRIMARY KEY ("id"),
59+
CONSTRAINT "verifier_topic_unique" UNIQUE ("verifier_agent_id", "topic_id"),
60+
CONSTRAINT "verifier_topic_registration_topic_id_prediction_topic_id_fk" FOREIGN KEY ("topic_id") REFERENCES "public"."prediction_topic" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION
61+
);
62+
-- Create index "verifier_topic_agent_idx" to table: "verifier_topic_registration"
63+
CREATE INDEX "verifier_topic_agent_idx" ON "public"."verifier_topic_registration" ("verifier_agent_id");
64+
-- Create index "verifier_topic_topic_idx" to table: "verifier_topic_registration"
65+
CREATE INDEX "verifier_topic_topic_idx" ON "public"."verifier_topic_registration" ("topic_id");

atlas/migrations/prediction_swarm/atlas.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
h1:zgOElHPnrTchPb+gb2wPJygPOHJwa/MVSSghPyDnX7A=
1+
h1:8hG9KyqunMoyK3ggRLphPfYFaoH2ZAgKRy/dyvci3v4=
22
20251118085426_baseline.sql h1:yYt/F7QkBCF92mhKeZN8/T6ljcYJN+1s3M/gBNv5MxI=
33
20251120161044_rename_goal.sql h1:V0EM07MmeCsc4naTIRBXiLxYtEbHQ0AQI4GzxmkUfxU=
44
20251120161127.sql h1:27i5PAjofmV/DRHMWKybpF5ncgpQTwdaMFUay959YSg=
@@ -11,3 +11,4 @@ h1:zgOElHPnrTchPb+gb2wPJygPOHJwa/MVSSghPyDnX7A=
1111
20251126135959.sql h1:ouWxe6r2q3MV48Z18j7vX4m6hDypY8XOpv8V9/1HdpU=
1212
20251128161908.sql h1:qcYrYrusemufBSPM9Mbj/On++3GrjxfItjfTwEOGOus=
1313
20251130132124.sql h1:kkYoKrMn7ITv2IuWGxrLBaCkpPC6zqt4C+ZVYw1BlA0=
14+
20260105202138.sql h1:56oSvxIQl+Ca6uecSbIpxST7pSFNNnNvhDyvPQ7/vGk=
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- Open verification: verification claims and topic registration
2+
3+
CREATE TABLE IF NOT EXISTS verification_claim (
4+
id UUID PRIMARY KEY DEFAULT uuidv7(),
5+
parsed_prediction_id UUID NOT NULL REFERENCES parsed_prediction(id) ON DELETE CASCADE,
6+
verifier_agent_id VARCHAR(256) NOT NULL,
7+
verifier_agent_signature TEXT NOT NULL,
8+
claim_outcome BOOLEAN NOT NULL,
9+
confidence DECIMAL NOT NULL,
10+
reasoning TEXT NOT NULL,
11+
sources JSONB,
12+
timeframe_start_utc TIMESTAMP WITH TIME ZONE,
13+
timeframe_end_utc TIMESTAMP WITH TIME ZONE,
14+
timeframe_precision VARCHAR(32),
15+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
16+
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
17+
deleted_at TIMESTAMP WITH TIME ZONE
18+
);
19+
20+
CREATE TABLE IF NOT EXISTS verifier_topic_registration (
21+
id UUID PRIMARY KEY DEFAULT uuidv7(),
22+
verifier_agent_id VARCHAR(256) NOT NULL,
23+
topic_id UUID NOT NULL REFERENCES prediction_topic(id),
24+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
25+
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
26+
deleted_at TIMESTAMP WITH TIME ZONE,
27+
UNIQUE(verifier_agent_id, topic_id)
28+
);
29+
30+
ALTER TABLE verdict ADD COLUMN IF NOT EXISTS accepted_claim_id UUID REFERENCES verification_claim(id);
31+
32+
CREATE INDEX IF NOT EXISTS verification_claim_parsed_prediction_id_idx ON verification_claim(parsed_prediction_id);
33+
CREATE INDEX IF NOT EXISTS verification_claim_verifier_agent_id_idx ON verification_claim(verifier_agent_id);
34+
CREATE INDEX IF NOT EXISTS verification_claim_created_at_idx ON verification_claim(created_at);
35+
CREATE INDEX IF NOT EXISTS verifier_topic_agent_idx ON verifier_topic_registration(verifier_agent_id);
36+
CREATE INDEX IF NOT EXISTS verifier_topic_topic_idx ON verifier_topic_registration(topic_id);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- Verifier feedback table for per-verifier feedback on predictions
2+
CREATE TABLE IF NOT EXISTS verifier_feedback (
3+
id UUID PRIMARY KEY DEFAULT uuidv7(),
4+
parsed_prediction_id UUID NOT NULL REFERENCES parsed_prediction(id) ON DELETE CASCADE,
5+
verifier_agent_id VARCHAR(256) NOT NULL,
6+
verifier_agent_signature TEXT NOT NULL,
7+
failure_cause failure_cause_enum NOT NULL,
8+
reason TEXT NOT NULL,
9+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
10+
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
11+
deleted_at TIMESTAMP WITH TIME ZONE,
12+
UNIQUE(parsed_prediction_id, verifier_agent_id)
13+
);
14+
15+
CREATE INDEX IF NOT EXISTS verifier_feedback_prediction_idx ON verifier_feedback(parsed_prediction_id);
16+
CREATE INDEX IF NOT EXISTS verifier_feedback_agent_idx ON verifier_feedback(verifier_agent_id);
17+
CREATE INDEX IF NOT EXISTS verifier_feedback_failure_cause_idx ON verifier_feedback(failure_cause);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- Add unique constraint to verification_claim table
2+
-- Ensures each verifier can only submit one claim per prediction
3+
ALTER TABLE verification_claim
4+
ADD CONSTRAINT verification_claim_unique_verifier
5+
UNIQUE (parsed_prediction_id, verifier_agent_id);

packages/db/src/schema/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ export * from "./memory";
77

88
export * from "./swarm-filter";
99

10+
export * from "./swarm-verifier";
11+
1012
export * from "./context-schemas";

packages/db/src/schema/memory.ts

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,77 @@ export const predictionTopicSchema = createTable(
289289
],
290290
);
291291

292-
// ==== Verdicts ====
292+
// ==== Verification Claims ====
293+
294+
/**
295+
* Source evidence for verification claims
296+
*/
297+
export interface ClaimSource {
298+
url: string;
299+
title?: string;
300+
snippet?: string;
301+
retrievedAt: string;
302+
archiveUrl?: string;
303+
}
304+
305+
/**
306+
* Claims submitted by open verifiers asserting a prediction's outcome.
307+
* Each verifier can submit one claim per prediction.
308+
* The verdict system evaluates claims to produce final verdicts.
309+
*/
310+
export const verificationClaimSchema = createTable(
311+
"verification_claim",
312+
{
313+
id: uuidv7("id").primaryKey(),
314+
parsedPredictionId: uuidv7("parsed_prediction_id")
315+
.notNull()
316+
.references(() => parsedPredictionSchema.id, { onDelete: "cascade" }),
317+
verifierAgentId: ss58Address("verifier_agent_id").notNull(),
318+
verifierAgentSignature: text("verifier_agent_signature").notNull(),
319+
claimOutcome: boolean("claim_outcome").notNull(),
320+
confidence: decimal("confidence").notNull(),
321+
reasoning: text("reasoning").notNull(),
322+
sources: jsonb("sources").$type<ClaimSource[]>(),
323+
timeframeStartUtc: timestampz("timeframe_start_utc"),
324+
timeframeEndUtc: timestampz("timeframe_end_utc"),
325+
timeframePrecision: varchar("timeframe_precision", { length: 32 }),
326+
...timeFields(),
327+
},
328+
(t) => [
329+
unique("verification_claim_unique_verifier").on(
330+
t.parsedPredictionId,
331+
t.verifierAgentId,
332+
),
333+
index("verification_claim_parsed_prediction_id_idx").on(
334+
t.parsedPredictionId,
335+
),
336+
index("verification_claim_verifier_agent_id_idx").on(t.verifierAgentId),
337+
index("verification_claim_created_at_idx").on(t.createdAt),
338+
],
339+
);
340+
341+
/**
342+
* Tracks which topics a verifier has registered to verify.
343+
* Used for weighting claims from topic specialists.
344+
*/
345+
export const verifierTopicRegistrationSchema = createTable(
346+
"verifier_topic_registration",
347+
{
348+
id: uuidv7("id").primaryKey(),
349+
verifierAgentId: ss58Address("verifier_agent_id").notNull(),
350+
topicId: uuidv7("topic_id")
351+
.notNull()
352+
.references(() => predictionTopicSchema.id),
353+
...timeFields(),
354+
},
355+
(t) => [
356+
unique("verifier_topic_unique").on(t.verifierAgentId, t.topicId),
357+
index("verifier_topic_agent_idx").on(t.verifierAgentId),
358+
index("verifier_topic_topic_idx").on(t.topicId),
359+
],
360+
);
293361

294-
// TODO: I don't think the JSON for the conclusion works
295-
// Some of our queries are more complicated than this allows
296-
// We shall see
362+
// ==== Verdicts ====
297363

298364
/**
299365
* Stores verdicts for predictions
@@ -307,6 +373,9 @@ export const verdictSchema = createTable(
307373
.references(() => parsedPredictionSchema.id),
308374
verdict: boolean("verdict").notNull(), // True if prediction came true, false otherwise
309375
context: jsonb("context").notNull().$type<VerdictContext>(), // Context explaining the verdict
376+
acceptedClaimId: uuidv7("accepted_claim_id").references(
377+
() => verificationClaimSchema.id,
378+
),
310379
...timeFields(),
311380
},
312381
(t) => [
@@ -429,6 +498,34 @@ export const parsedPredictionFeedbackSchema = createTable(
429498
],
430499
);
431500

501+
/**
502+
* Stores per-verifier feedback on predictions.
503+
* When a verifier submits feedback, that prediction is excluded from their claimable list.
504+
*/
505+
export const verifierFeedbackSchema = createTable(
506+
"verifier_feedback",
507+
{
508+
id: uuidv7("id").primaryKey(),
509+
parsedPredictionId: uuidv7("parsed_prediction_id")
510+
.notNull()
511+
.references(() => parsedPredictionSchema.id, { onDelete: "cascade" }),
512+
verifierAgentId: ss58Address("verifier_agent_id").notNull(),
513+
verifierAgentSignature: text("verifier_agent_signature").notNull(),
514+
failureCause: failureCauseEnum("failure_cause").notNull(),
515+
reason: text("reason").notNull(),
516+
...timeFields(),
517+
},
518+
(t) => [
519+
unique("verifier_feedback_unique").on(
520+
t.parsedPredictionId,
521+
t.verifierAgentId,
522+
),
523+
index("verifier_feedback_prediction_idx").on(t.parsedPredictionId),
524+
index("verifier_feedback_agent_idx").on(t.verifierAgentId),
525+
index("verifier_feedback_failure_cause_idx").on(t.failureCause),
526+
],
527+
);
528+
432529
// ==== Credit System ====
433530

434531
/**
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { integer, text } from "drizzle-orm/pg-core";
2+
import { createTable, ss58Address, timeFields } from "./utils";
3+
4+
/**
5+
* Tracks the last processed cursor for each verifier instance.
6+
* Prevents reprocessing the same predictions on restart.
7+
*/
8+
export const verifierCursorStateSchema = createTable("verifier_cursor_state", {
9+
verifierAgentId: ss58Address("verifier_agent_id").primaryKey(),
10+
lastCursor: text("last_cursor").notNull(),
11+
...timeFields(),
12+
});

0 commit comments

Comments
 (0)