The Tacit side

Tacit only ever sees the artifact, unless you turn send_tokenized_transcript on (below). It validates the artifact against a mirror of the contract, verifies the digest, and stores it verbatim. That is all sending does. The scenario (a fabricated identity plus one known-state item per beat) is created only when someone asks: an org admin clicking Create scenario in the web app, or the SDK’s own pull --regenerate and roundtrip commands, which call the same materialize endpoint. Regeneration is a further explicit call. Nothing derived from your data exists in Tacit until your organization asks for it. The identity Tacit fabricates (a name, an exact age, an occupation) is deterministic per token and comes from the demographic shell alone. That is the decoupling the design relies on: there is no one-to-one mapping between a synthetic consultation and a real record.

Reviewing what crossed

An org admin can open De-identified data in the platform’s Admin menu to see every artifact the organization has received: the demographic shell, the beats, the audit log, and, once created, the scenario and the regenerated consultation. The page reads the same token endpoint the SDK polls; it shows nothing the artifact does not carry. What the admin can do there:
  • Create scenario on a received artifact, choosing the conversation it is filed under, the persona’s personality, a title, and where past-medical-history beats go (their own category, revealed when asked, by default). Regenerate appears once the scenario exists.
  • Create scenarios for several artifacts at once, and put them in a new or existing cohort; the result offers a benchmark run of the new scenarios against an agent and a link to build a training dataset from them. Or tick File each scenario under its presenting category: one conversation per category ([deid-sim] Presenting Complaint, [deid-sim] Chest pain), named for the category of the first volunteered beat. That choice and a destination or a cohort exclude each other, since each of those is one conversation.
  • Delete an artifact while nothing has been derived from it. Once a scenario exists the artifact is that scenario’s provenance and stays.
  • Read the lexical fidelity card: three readings of the same metrics. beats is the artifact’s distributional_targets, which the SDK computes over the beat text, not over the transcript. real is the imported consultation’s patient turns, measured by Tacit once the transcript is imported as a session. regenerated is the persona’s turns after a regeneration. The gap is against real when it exists, else against beats. One record is a reading, not a verdict.
  • See the case mix of everything received, as counts only: age bands, sexes, and beat categories.
  • Read the tokenized transcript when the sender turned send_tokenized_transcript on; the list marks those artifacts with ”+ transcript”.
  • Import as session, from the transcript section, once the scenario exists: the transcript becomes a completed capture session on that scenario, one message per Speaker: text line. The dialog lists the speaker labels it found and the admin names which one is the operator; every other speaker is the persona, and nothing is guessed. From then on the coaching report, scoring, extraction proposals, grounding comparisons, and score leaves apply to the real consultation. An artifact imports once; the button then opens the session. The import also measures the patient’s real turns (the real column above) and, with Shape the persona’s speech ticked (the default), writes a guidance line onto the scenario persona from the measured words per turn and vocabulary, so the regeneration is told how much and how richly to speak. It reaches only a regeneration not yet started. Whether it narrows the gap is a hypothesis to read off the card, run by run, not a promise.
  • Grounding task, once the artifact has both its imported session and a completed regeneration: a blind pairwise comparison between the two, one task per expert chosen, told that one is real and one regenerated but not which. Tasks and results live on the scenario’s grounding page.
  • Accept vocabulary from beats on the list page: the beat labels across every artifact received (“Blood in stool”, “Abdominal pain, site”), counted by artifact. Ticking terms and adding them writes them to the organization glossary (category other, the definition naming the beat categories they came from) and links each to the scenarios whose artifacts carried it. A term already in the glossary is linked, never rewritten. Labels only; no beat value.
The scenario each artifact becomes also carries a briefing for the operator, built from the artifact with no model call: what the patient opens with (the volunteered beats’ labels), the history-taking role, how past medical history was placed, the demographic shell with the categories present, and one “Ask about” hint per category. No beat value appears in it, since those are what the persona is there to reveal.

Commands

All three read TACIT_API_URL and TACIT_API_KEY from --key-file (a KEY=value file) or the environment; --tacit-url overrides the URL.
roundtrip prints counts and categories only on stdout; the full verdict with values goes to --out, written owner-only. A refusal passes the oracle trivially, because nothing crossed.

Sending the tokenized transcript

Off by default. The tokenized transcript is the judge loop’s final text: every detected identifier replaced by a typed placeholder such as <NAME_1> or <DATE_2>, the sentences otherwise intact. It is more than the artifact carries, which is a structured list of beats, so it crosses only when you say so, and as its own call after the artifact, never as a field of the sealed artifact.
With it on, run writes the transcript owner-only next to the artifact (artifact.json.tokenized.txt, or --tokenized-out; a batch writes <ref>.tokenized.txt and records the path in the manifest), and roundtrip sends it after the artifact. send never reads the config: it sends the transcript only when you name the file.
Tacit stores it beside the artifact (POST /api/deid/artifacts/:token/transcript, ak_ keys only, 200,000 characters at most, a resend replaces) and shows it on the artifact’s review page. The simulation’s egress observer scans that body like any other, so a planted identifier that survived tokenization shows up in the round-trip verdict. The surrogate-filled text, with its invented names, never crosses under any setting.

Ceilings

Each org has a rolling 24-hour ceiling on artifacts received and regenerations started. The API defaults are 100 artifacts and 50 regenerations per org per day (DEID_DAILY_ARTIFACT_CEILING, DEID_DAILY_REGENERATION_CEILING on the API). Over the ceiling the API answers 429; the artifact already stored is unaffected, and a batch’s artifacts can be graded offline meanwhile.

As a library

roundtrip includes the fidelity in its summary: the artifact’s own distributional_targets beside Tacit’s reading of the regenerated consultation (the same eight lexical metrics). It is aggregate word statistics only, and one record is a reading, not a verdict. run_roundtrip(text, deps, config, client, keep=..., extra_planted=[...]) is what the command calls and returns a RoundTripReport with both hop verdicts. TacitTransportError carries the field the validator refused, which is a schema path, never patient text.