# Global prompt administration and conversation budget `CLINICAL_ASSISTANT_CONVERSATION_CHARS` is the sole conversation budget source. Missing/empty uses 120000; nonempty values must validate as an integer from 1000 through 1000000. Invalid configuration returns 503 before query rewrite, JavaScript string length (UTF-16 code units), including all history plus draft, not model tokens. The old `clinical_assistant.conversation_chars` database value is ignored and its generic config PUT is rejected. Status retains `conversationChars`/`conversationUnit` and adds `conversationEnv`, `conversationSource`, `conversationMeasure`. Admin config exposes the same metadata as top-level `conversationBudget: {limit,unit,measure,env,source}`. ## Catalogue and runtime use Authenticated admins can use `/api/admin/config/prompts`. Its finite catalogue contains 29 AI Scribe strings, `clinical_assistant.system_behavior` for clinical text answers, and `clinical_assistant.image_behavior` for both existing image routes. Each entry includes `key`, `dbKey`, `value`, `family`, `purpose`, `usedBy`, `revision`, and `editable`. Scribe defaults remain in `utils/prompts.js`; clinical defaults and image assembly are in `utils/clinicalPrompts.js`. All shipped default text is unchanged. The poster instruction follows the input and precedes the existing conditional portrait/landscape suffixes. Fixed clinical citation safeguards, retrieval and generation settings are unchanged. Memories and private user templates are not part of this catalogue. ## Revision API All endpoints below are under `/api/admin/config` and require the existing admin gate. Prompt keys for history/reset/restore accept canonical `dbKey` or a bare Scribe key. - `PUT /:dbKey` with `{value, expectedRevision?}` saves nonempty string text. - `POST /prompts/:key/reset` with `{expectedRevision?}` removes the override and records the current shipped default. - `GET /prompts/:key/history?limit=20` returns `{success,revisions,revision}`; newest first, at most 100. Metadata has `id`, `createdAt`, `createdBy`, `restoredFrom`, `wasDefault`, never prompt text. - `GET /prompts/:key/revisions/:id` returns `{success,revision}` with the recorded `value` and metadata, checking key/id association. - `POST /prompts/:key/restore` with `{revisionId,expectedRevision?}` restores the recorded effective text **as an explicit override**, even when the historical revision used a different shipped default. The new revision has `wasDefault:false` and `restoredFrom` pointing to the original. Reset again to follow shipped defaults. Mutations return `{success:true,value,revision}`. Revision is the latest numeric row id for that key, not a contiguous per-key counter; 0 means no history yet. First mutation records the previous effective baseline plus the edit. Its baseline actor is null (unknown), with capture time rather than an invented original edit time. Provided stale `expectedRevision` returns 409 without changes; legacy callers may omit it. Reload a conflicted editor before explicitly retrying. Other settings retain their existing API contracts. ## Persistence and verification Apply `1777700000000_add-prompt-revisions.js` through the existing migration runner before edits. Missing schema fails prompt operations safely, without unversioned fallback. The migration count increases from six to seven; old frozen checks that assert six need a separate reviewed update, not changes to their evidence. `prompt_revisions` stores global administrative text, not credentials or private content, matching plaintext global `app_settings` storage. A finite-key constraint, append-only update/delete trigger and same-key restore FK protect history. Actor ids are historical integers, not cascading foreign keys. One `db.pool.connect()` client holds a per-key transaction advisory lock for baseline, revision append and setting upsert/delete. Rollbacks do not publish memory changes; only committed values mutate the original shared Scribe object. Scribe's existing process-local cache model remains; this slice does not introduce multi-process invalidation. Run `node --test test/prompt-administration.test.js test/clinical-conversation.test.js` with synthetic service boundaries, and the complete `npm test` suite. Tests include actual admin middleware/routes, rollback/concurrency, missing schema, old-default restore, default byte hashes, object identity and startup races, exact UTF-16 boundaries, legacy DB ignoring, and both image routes. Migration SQL is dry-run through the installed node-pg-migrate engine, not applied to a live database. ### Fixed image output policy and context assembly Image jobs use the separately editable workflow image behavior and its immutable revision. The existing defaults/history are not rewritten. A fixed backend instruction, **output the image only; no citations, reference numbers, footnotes, bibliography or source lists in the image**, is appended last and takes precedence over conflicting editable guidance/context. Normal answers, saved transcripts, educational bodies, citations, tables, source numbers and pages are not cleaned or rewritten. The image provider receives the full original request, the tool's image description (when dispatched by a tool), workflow/canvas/layout guidance, the largest **contiguous suffix of whole preceding turns** that fits, and the fixed output policy. Selected turns are emitted oldest to newest. Selection stops at the first non-fitting recent turn; it never skips gaps, slices turns or summarizes them. All separators/instructions count toward the exact UTF-16 budget. Mandatory overflow rejects before image payment. The default 32,000 (configurable 1,000..32,000) is a conservative code-unit allowance, **not** an averaged or computed model token limit. Clinical routes bind validated current request/history outside model-controlled tool arguments. The sidebar supplies the current conversation; independent standalone requests have no implicit chat history. Learning supplies only its authorized authoring document/body, never Clinical history. API jobs and history return `context: {includedTurns,totalTurns,used,limit,unit}` and cards visibly show omission metadata; older jobs have `context:null`. Image selection does not change the separate normal-conversation ENV cap or stored/exported history. The encrypted assembled snapshot, exact counts, model and revision are immutable. Tool replays may rephrase tool descriptions, but a changed original request or prior context with the same idempotency key rejects with 409. Apply additive migration `1777900000000_image-context` after the image migration; it does not invent metadata for older jobs. ### Operational image retention limit Back up private S3 assets, PostgreSQL jobs/links and encryption keys together. Deleting an image author currently cascades job/link deletion through the user foreign key, while Learning content survives with a null author; such pages lose those generated images and the S3 objects remain orphaned. This release does not redesign account deletion or retention. Resolve archival/retention with operators before any author-account deletion. Ambiguous paid stages are reported as interrupted/unknown using PostgreSQL alone during external outages and are never automatically paid again.