Skip to main content
POST
Append one authoring feedback telemetry entry

Authorizations

Authorization
string
header
required

MeshQu API key passed as a bearer token: Authorization: Bearer mqu_…. Mint one in the console (Settings → API keys).

X-MeshQu-Tenant-Id
string
header
required

Tenant UUID for multi-tenant isolation. Required on all authenticated routes — validated before authentication (middleware/tenant.ts), so a missing or non-UUID header returns 400 (MISSING_TENANT_ID / INVALID_TENANT_ID) before the API key is checked.

Body

application/json

One appended telemetry observation about one model-proposed candidate. TELEMETRY, NOT GOVERNANCE EVIDENCE.

One appended telemetry observation about one model-proposed candidate. TELEMETRY, NOT GOVERNANCE EVIDENCE.

proposal_id
string
required

The STABLE candidate identity — the proposal id minted by the editor at the moment the model answered. This is the join key. Rule code is display identity and is recorded separately: a rename moves the code and would re-point every row filed under it.

Required string length: 1 - 200
Pattern: ^[A-Za-z0-9._:-]{1,200}$
subject_kind
required

Which subject the observation was made against. SEALED_SUBMISSION requires submission_id, candidate_revision and review_package_digest together (the ruling B1 currentness triple). PRE_SUBMISSION_DRAFT forbids all three AND forbids a review-record link, because a recorded human judgment exists only against a sealed subject. Absence is spelled as a value, not inferred from nulls.

Available options:
SEALED_SUBMISSION
feedback_kind
required

What the person did to the proposal: changed it (CORRECTION) or removed it (REJECTION). There is no ACCEPTED value — this store records corrections and rejections, and a row asserting acceptance would be one step from reading as an approval.

Available options:
CORRECTION
reason
required

Why the proposal was corrected or rejected, from a CLOSED vocabulary. An unknown value is refused with 400, and there is deliberately no OTHER: an open residual would make the vocabulary a suggestion and the distribution meaningless.

SOURCE_FIDELITY (the proposal misstates the source) and UNSUPPORTED_SEMANTICS (the product cannot express what the source requires) are kept distinct because one is fixed by re-reading the source and the other by changing the product.

Available options:
SOURCE_FIDELITY
model_proposal
object
required

What the model proposed, verbatim. Stored as evidence of what was said; the server never acts on it, re-runs it or checks it against anything.

candidate_rule_code
string

The rule code as it stood. Display only; never a join key.

Required string length: 1 - 200
submission_id
string<uuid>

Leg one of the sealed subject. Required when subject_kind is SEALED_SUBMISSION, forbidden otherwise.

candidate_revision
integer

Leg two of the sealed subject.

Required range: x >= 1
review_package_digest
string

Leg three of the sealed subject.

Pattern: ^[0-9a-f]{64}$
review_record_id
string<uuid>

The recorded human review (PWB-022b) this correction corresponds to. Bound by a five-column foreign key to a record written against THIS EXACT sealed subject, so a row naming a record about a different submission, revision or package digest is refused at the database as well as at the route.

review_finding_id
string

One item id inside that record's findings or corrections. It must RESOLVE: an id naming no item in that record is refused, at the route and by a database trigger, because findings are JSON array elements that no foreign key can reach.

Required string length: 1 - 200
Pattern: ^[A-Za-z0-9._:-]{1,200}$
correction_text
string

The correction or rejection text, verbatim. Optional: a rejection with no stated text is a real thing a person does, and a placeholder would put words in their mouth.

Required string length: 1 - 8000

Response

One appended telemetry row. RECORDS what a model proposed and what a person corrected or rejected. PROVES only that the observation was appended.

One appended telemetry row. RECORDS what a model proposed and what a person corrected or rejected. PROVES only that the observation was appended.

id
string<uuid>
required
tenant_id
string<uuid>
required
proposal_id
string
required
candidate_rule_code
string | null
required
subject_kind
required

Which subject the observation was made against. SEALED_SUBMISSION requires submission_id, candidate_revision and review_package_digest together (the ruling B1 currentness triple). PRE_SUBMISSION_DRAFT forbids all three AND forbids a review-record link, because a recorded human judgment exists only against a sealed subject. Absence is spelled as a value, not inferred from nulls.

Available options:
SEALED_SUBMISSION
submission_id
string<uuid> | null
required
candidate_revision
integer | null
required
review_package_digest
string | null
required
review_record_id
string<uuid> | null
required
review_finding_id
string | null
required
feedback_kind
required

What the person did to the proposal: changed it (CORRECTION) or removed it (REJECTION). There is no ACCEPTED value — this store records corrections and rejections, and a row asserting acceptance would be one step from reading as an approval.

Available options:
CORRECTION
reason
required

Why the proposal was corrected or rejected, from a CLOSED vocabulary. An unknown value is refused with 400, and there is deliberately no OTHER: an open residual would make the vocabulary a suggestion and the distribution meaningless.

SOURCE_FIDELITY (the proposal misstates the source) and UNSUPPORTED_SEMANTICS (the product cannot express what the source requires) are kept distinct because one is fixed by re-reading the source and the other by changing the product.

Available options:
SOURCE_FIDELITY
model_proposal
object
required
correction_text
string | null
required
period_at_creation_days
integer
required

The tenant retention period in force when this row was created, in DAYS. Stored so a later lengthening of the tenant period cannot extend what was collected under a shorter one. Effective expiry is created_at + min(this, the tenant's current period) and is derived, never stored.

Required range: 30 <= x <= 730
created_at
string<date-time>
required