Skip to Content
PlatformHow-to guidesApprove with a signature

How to approve with a signature

Use this guide when a protocol or report is in review and you are its approver. You start with a record in status review (an agent-drafted one reads “Agent-generated draft, unsigned.”); you end with the record approved, a signature row bound to its content, and the record page reading “Signature valid”. Approving a protocol needs plans.protocols.approve; a report needs plans.reports.approve; both need a fresh re-authentication.

Approval in the console (accepting an agent proposal) is not a signature. Signatures are reserved for the approve routes of protocols and reports and for requirement-set acceptance; the meaning is derived by the server from the route, never chosen by the client.

Prerequisites

  • A protocol or report in review (moved there with POST .../transition, or an agent draft promoted from the canvas and transitioned by its author).
  • The program_lead or program_owner persona, and an identity session that can re-authenticate.

Open the record and read its provenance

Plans › Protocols, select the protocol. An agent-drafted protocol shows the footer “Agent-generated draft, unsigned.” with “Cites N sources.” and “Model configuration MC-n (recorded <date>)”, the link to its thread (“From thread T-31” or “From a private thread”), the SOP versions it was drafted against (sop_version_ids) and, when a person edited a section, a version with origin = human.

Choose Approve

Approve is shown only with plans.protocols.approve. The dialog is titled “Decision signature (non-GxP pilot)” and shows the statement you will confirm: “I, Priya N., approve protocol <title> v1 (record 9f3a…). Decision signature (non-GxP pilot).” The sixteen hex characters are the start of the record hash of {id, version, title, body_md, format, plan_id, sop_version_ids}.

Re-authenticate

Choose Re-authenticate. The dialog persists pending_signature in sessionStorage, the identity provider prompts you to sign in again, and the dialog resumes with the same statement. From an e-mail deep link the same thing happens after you land on the record.

Confirm and submit

Confirm the statement, write a rationale and submit. The web app calls POST .../plans/protocols/{protocol_id}/approve with ApproveRequest {rationale, reauth_token, statement_ack}. The API verifies the token (oid and tid equal to your session, auth_time within 300 s, single use), derives meaning = approved, recomputes the record hash, writes the signature and the audit row in one transaction, and the record reads approved with “Signature valid”.

Read what changed

  • The protocol carries signature_id; further PATCH requests answer 409 record_signed, and a change creates a new version with supersedes_id.
  • The record page reads “Agent-generated draft; approved by Priya N. on <date> (approved). Signature valid.”; if the content ever differs from the signed hash the line becomes “Record changed since signature”.
  • Setup › Audit shows protocol.approve with actor_kind = human, signature_id, your rationale as reason, and, for an agent draft, the agent_run_id of the drafting run on the earlier protocol.create row.

Carrying the protocol into the notebook

Trovensa writes nothing into the ELN. When the approved text is copied into a notebook entry, copy the provenance footer with it: a fenced JSON block {agent_id, agent_version_id, model_config_label, run_id, generated_at, citations[], statement: "agent-generated, unsigned"} plus one line of prose, so the notebook shows where the text came from and that the approval lives in Trovensa.

Troubleshooting

SymptomCauseFix
Approve is disabledyou lack plans.protocols.approve or the record is not in reviewthe scientist persona drafts but does not approve; transition the record first
401 reauth_requiredno auth_time in the token, or older than 300 sre-authenticate again
409 record_signedthe record already carries a signaturecreate a new version that supersedes it
“Record changed since signature”content differs from the signed hashinspect the audit rows after signed_at; a signed record should only change through a new version