This is the spine of the page. Each card states a claim in plain language and then names the database constraint, the migration, or the shared-library symbol that decides whether it is true. The point is not that you take our word for it; the point is that you do not have to, because a claim printed beside its own constraint can be checked by anyone who can read a schema.
A stored response has no column that names a person
Checkable in the database or the shared library today
The table a response is written to has exactly four columns: an id, an owner column, the time it arrived, and a moderation state. There is no field for a name, an email address, an IP address, an account, a session, or a device fingerprint. This is worth more than a policy promise, because a column that does not exist cannot be quietly filled in by a later bug.
CheckCREATE TABLE qt_submission (id, owner_org_id, submitted_at, moderation_state) -- migration 1103_question_technology.
The response time is coarsened to the hour by the database, not by a route
Checkable in the database or the shared library today
A stored response keeps only the hour it arrived. This is not a convention that a future route could forget: it is a named CHECK constraint, so a route that tries to write a precise timestamp is rejected by the database outright. The migration comment states the intent in the same terms.
Checkck_qt_submission_submitted_at_hour_coarse CHECK (submitted_at = date_trunc('hour', submitted_at)); DEFAULT date_trunc('hour', now()).
An individual answer carries no timestamp at all, on purpose
Checkable in the database or the shared library today
The answer row deliberately has no time column of its own. If it had one, a precise per-answer timestamp would sit directly beside a deliberately coarsened submission time and quietly undo it. The migration says exactly that, which is why this is a design decision on the record rather than an omission.
Checkqt_answer has no created_at column -- migration 1103: a precise per-answer created_at would silently defeat the coarsening on the row next to it.
A flagged response is labelled, never deleted
Checkable in the database or the shared library today
Moderation state is a two-value constraint. A response that trips moderation is marked as flagged and kept; it is not silently dropped. That matters for a reporter because it means the moderation story is about labelling and review, not about disappearing responses.
Checkck_qt_submission_moderation_state CHECK (moderation_state IN ('accepted','flagged')).
Moderation runs on the server before a response is stored
Checkable in the database or the shared library today
The moderation decision is made in a server-side function on the write path, not in the browser where a determined submitter could skip it. There is one function that produces the verdict, so there is one place to read to know what the rule actually is.
CheckmoderateQtSubmission(texts) in apps/api/src/moderation/question-technology-moderation.ts.
Declared roles are self-declared and unverified, and we call them that
Checkable in the database or the shared library today
A respondent may tag themselves with roles when answering. Those tags are not checked against any roster or directory, and the schema documentation is explicit that they are a claim about a role rather than a fact about a person. We do not describe them as verified, and neither should a story about us.
Checkqt_submission_realm -- migration 1103: self-declared, NOT verified, NOT an identity; a claim about a ROLE, never about a person.
There are three answer shapes, and the database enforces the list
Checkable in the database or the shared library today
Everything the engine can ask composes from three answer shapes: open text, a numeric scale, and a single choice. The list is enforced as a database constraint rather than as application convention, and the scale bound lives in one shared constant so it cannot drift between the client and the server.
Checkqt_question.type CHECK IN ('text','scale','choice'); SCALE_RANGE in packages/shared/src/question-technology.ts is the single fallback bound.
Question sets have an enforced lifecycle, not a free-text status
Checkable in the database or the shared library today
A question set is draft, published, or archived, and the database refuses anything else. Keys and titles are shape-checked too. This is small, but it is the difference between a product with a real state machine and a screen that stores whatever it is handed.
Checkck_qt_question_set_status CHECK IN ('draft','published','archived'); ck_qt_question_key_shape; ck_qt_question_text_nonempty.
If a claim you need is not on this list, it is not because we ran out of room. Email the desk and we will either add it with its evidence line or tell you we cannot support it.