Skip to content

← Back to index

2. Schema

All four entities are plain dataclasses (submission/core/schema.py). They round-trip through to_dict() / from_dict() and are stored as-is, with no ORM or mapping layer, as MongoDB documents. to_dict() writes datetimes as ISO-8601 strings. from_dict() accepts ISO-8601 strings (a trailing Z is allowed here), epoch seconds, or datetime objects.

A task is stored as three documents, one per entity, that share the same social_task_id. Votes are stored separately, one document per vote.

The create request uses different key names from the stored documents. The parser maps them, as shown in the "Request key" column below and in §3.2.

2.1 SocialTaskCoreData

The task itself: who created it, who may vote, when it starts, and its current state. Collection social_task_core_data.

Field Request key Type Required Description
social_task_id — string auto Primary key, task_ plus 8 hex characters. Generated by the parser. A value in the request is ignored.
created_by_subject_id created_by_subject_id string yes Who created the task. Used as sender_subject_id on invitations.
created_by_subject_data created_by_subject_data object yes (may be {}) Free-form data about the creator.
org_ids org_ids array<string> yes (may be []) Private: the fixed list of eligible voters. Evaluation waits for a qualified vote from every entry. Public: ignored.
social_task_access_type access_type string yes "private" or "public". See §1.3. Not validated.
goal_data goal object yes (may be {}) What the vote is meant to decide. Free-form. Passed to every hook.
social_tasks_topics topics array<string> yes (may be []) Free-form topic labels. Stored only. No service filters on them.
social_task_properties properties object yes (may be {}) Free-form properties such as urgency or category.
creation_time creation_time datetime yes Supplied by the caller, not by the server.
scheduled_time scheduled_time datetime | absent needed to start When the task should start. Naive ISO-8601, interpreted as UTC. See §1.5 gap 6.
duration duration integer | absent no Public: the number of qualified votes that triggers evaluation (default 5). Not a time span.
status status string | absent needed to start "scheduled", "started", or "complete". Must be "scheduled" at creation for the task to start. See §1.4.
report_json report object auto ({}) Filled in by the evaluator job. See §2.6.
job_id — string | absent unused Reserved. Never written.
enable_live_streaming enable_live_streaming boolean no (default false) Whether the WebSocket live stream will serve this task. See §3.6.

to_dict() drops fields whose value is None, so unset optional fields are absent from the document, not null.

Example: SocialTaskCoreData document (private task, just created):

{
  "social_task_id": "task_3f9c6d2e",
  "created_by_subject_id": "planner-service",
  "created_by_subject_data": {"team": "localisation"},
  "org_ids": ["agent-reviewer-01", "agent-reviewer-02", "agent-reviewer-03"],
  "social_task_access_type": "private",
  "goal_data": {"objective": "Choose the lead translator for the Q4 handbook"},
  "social_tasks_topics": ["translation", "fr"],
  "social_task_properties": {"urgency": "high"},
  "creation_time": "2026-10-22T09:00:00",
  "scheduled_time": "2026-10-22T10:00:00",
  "status": "scheduled",
  "report_json": {},
  "enable_live_streaming": true
}

2.2 SocialChoiceSubjectSpecInput

What voters see: the topic and the options. Collection social_choice_subject_spec.

Field Request key Type Required Description
social_task_id — string auto FK to SocialTaskCoreData.social_task_id.
topic_title title string yes Short title shown to voters.
topic_description description string yes What is being voted on.
voting_options_map voting_options object yes Option ID → label. The keys double as addresses: one invitation channel per key (§5.2).
voting_option_metadata_map voting_metadata object yes (may be {}) Option ID → extra data, for example a candidate's profile.
supported_protocols supported_protocols array<string> yes (may be []) Stored only. Not read by any service.
voting_message_request_creator voting_request function spec yes (may be {}) The invitation creator. {} disables it. See §2.5 and §4.2.

Example:

{
  "social_task_id": "task_3f9c6d2e",
  "topic_title": "Lead translator, Q4 handbook",
  "topic_description": "Pick the agent that will lead the EN→FR translation of the Q4 handbook.",
  "voting_options_map": {
    "agent-translator-01": "Translator 01",
    "agent-translator-02": "Translator 02",
    "agent-translator-03": "Translator 03"
  },
  "voting_option_metadata_map": {
    "agent-translator-01": {"languages": ["en", "fr"], "past_jobs": 42},
    "agent-translator-02": {"languages": ["en", "fr", "de"], "past_jobs": 17}
  },
  "supported_protocols": ["http"],
  "voting_message_request_creator": {
    "mode": "function",
    "function_id": "voting-invite-builder:1.0-stable",
    "parameters": {}
  }
}

2.3 SocialChoiceEvaluationInput

How votes are qualified and counted. Collection social_choice_evaluation_input.

Field Request key Type Required Description
social_task_id — string auto FK to SocialTaskCoreData.social_task_id.
constraints_entry_id constraints_primary string yes (may be "") Reserved. Stored, never read.
constraints_entry_id_1 constraints_secondary string yes (may be "") Reserved. Stored, never read.
voting_pqt voting_pqt function spec yes Pre-qualification test, run on every vote. See §4.3.
choice_evaluation evaluation function spec yes Computes the winner or winners. See §4.4.
tie_breaker tie_breaker function spec yes (may be {}) Runs only when choice evaluation returns more than one winner. See §4.5.
post_awarding post_award function spec yes Runs after the winners are final. See §4.6.

Example:

{
  "social_task_id": "task_3f9c6d2e",
  "constraints_entry_id": "",
  "constraints_entry_id_1": "",
  "voting_pqt": {"mode": "dsl", "workflow_id": "vote-option-is-valid:1.0"},
  "choice_evaluation": {"mode": "dsl", "workflow_id": "plurality-count:1.0"},
  "tie_breaker": {"mode": "dsl", "workflow_id": "earliest-vote-wins:1.0"},
  "post_awarding": {"mode": "dsl", "workflow_id": "assign-lead-translator:1.0"}
}

The vote-intake service and the evaluator job currently read these hooks from string fields named voting_pqt_dsl, choice_evaluation_dsl, tie_breaker_dsl, and post_awarding_dsl. Those fields hold DSL workflow IDs. See §1.5 gap 1 and §4.1.

2.4 Votes

One subject's vote on one task. Collection votes.

Field Type Required Description
vote_id string yes Primary key. Chosen by the client. The server does not generate it or check it for uniqueness. Use a UUID4.
social_task_id string yes Which task this vote is for.
submitter_subject_id string yes Who is voting. Must be in org_ids for private tasks. At most one vote per subject per task, counting disqualified votes.
vote_data object yes The ballot itself. Free-form. Its shape is a contract between the creator and the PQT and evaluation hooks, for example {"selected_option": "agent-translator-02"} or a ranking.
submission_time datetime must be present Overwritten with server time on receipt. The request must still include it (§3.4).
qualified boolean must be present Overwritten with the PQT result. The request must still include it.

Example:

{
  "vote_id": "7d0f2a9c-2b4e-4a51-9a3e-0c6f1b2d4e8a",
  "social_task_id": "task_3f9c6d2e",
  "submitter_subject_id": "agent-reviewer-01",
  "vote_data": {"selected_option": "agent-translator-02"},
  "submission_time": "2026-10-22T10:03:12.481203",
  "qualified": true
}

2.5 Function spec

Each hook is configured with a small object that says where its logic lives. The same shape is used for voting_message_request_creator, voting_pqt, choice_evaluation, tie_breaker, and post_awarding.

Field Type Required Description
mode string yes "function" (function registry) or "dsl" (DSL workflow registry).
function_id string mode: "function" function_id in the function registry, for example voting-invite-builder:1.0-stable.
parameters object no (default {}) mode: "function" only. Passed as per-call parameters when the function runs as a stateless job.
workflow_id string mode: "dsl" Workflow ID in the DSL workflow registry.
{"mode": "function", "function_id": "voting-invite-builder:1.0-stable", "parameters": {"tone": "formal"}}
{"mode": "dsl", "workflow_id": "plurality-count:1.0"}

An empty object {} disables the invitation creator and the tie-breaker. For the other hooks, {} is accepted at creation but fails when the hook runs.

2.6 report_json

Written to SocialTaskCoreData.report_json by the evaluator job when it finishes (§1.2 step 9).

Field Type Description
task object SocialTaskCoreData.to_dict() at evaluation time
subject_spec object SocialChoiceSubjectSpecInput.to_dict()
evaluation_spec object SocialChoiceEvaluationInput.to_dict()
votes array The qualified votes that were evaluated
winners array<string> Final winners, after the tie-breaker if it ran
post_award_payload object Output of the post-award hook
dsl_outputs object Raw output of each hook that ran, keyed choice_evaluation_dsl, tie_breaker_dsl (only if it ran), and post_awarding_dsl
evaluated_at string ISO-8601 UTC timestamp

Example:

{
  "task": {"social_task_id": "task_3f9c6d2e", "status": "started", "...": "..."},
  "subject_spec": {"topic_title": "Lead translator, Q4 handbook", "...": "..."},
  "evaluation_spec": {"...": "..."},
  "votes": [
    {"vote_id": "7d0f…", "submitter_subject_id": "agent-reviewer-01", "vote_data": {"selected_option": "agent-translator-02"}, "qualified": true, "...": "..."},
    {"vote_id": "c41a…", "submitter_subject_id": "agent-reviewer-02", "vote_data": {"selected_option": "agent-translator-02"}, "qualified": true, "...": "..."},
    {"vote_id": "e9b3…", "submitter_subject_id": "agent-reviewer-03", "vote_data": {"selected_option": "agent-translator-01"}, "qualified": true, "...": "..."}
  ],
  "winners": ["agent-translator-02"],
  "post_award_payload": {"assigned_to": "agent-translator-02", "start_by": "2026-10-23T09:00:00Z"},
  "dsl_outputs": {
    "choice_evaluation_dsl": {"winner": "agent-translator-02", "tally": {"agent-translator-02": 2, "agent-translator-01": 1}},
    "post_awarding_dsl": {"assigned_to": "agent-translator-02", "start_by": "2026-10-23T09:00:00Z"}
  },
  "evaluated_at": "2026-10-22T10:07:45.221000"
}

task.status in the report is "started", because the report is built before the status changes to "complete".

2.7 Storage

All entities live in MongoDB, database voting_db, one collection each.

Collection Keyed by Indexes
social_task_core_data social_task_id none created by the services
social_choice_subject_spec social_task_id none
social_choice_evaluation_input social_task_id none
votes vote_id none

get(), update(), and delete() work on the entity's own ID field, never on MongoDB's _id. update() is a $set on top-level fields. The scheduler reads the whole social_task_core_data collection on every poll, and the duplicate-vote check reads every vote for the task. Add indexes on social_task_id, status, and votes.social_task_id yourself if volumes grow.


← Previous: Concepts · Back to index · Next: APIs →