Metadata-Version: 2.4
Name: iatro-clintrace
Version: 1.0.2
Summary: ClinTrace clinical-course compression, grounding, and longitudinal decision modeling
License-Expression: CC-BY-4.0
Project-URL: Homepage, https://github.com/iatrode/iatro-clintrace
Project-URL: Repository, https://github.com/iatrode/iatro-clintrace
Project-URL: Issues, https://github.com/iatrode/iatro-clintrace/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: iatro-base-iac>=0.0.3
Requires-Dist: huggingface_hub>=0.30
Requires-Dist: modelscope>=1.20
Requires-Dist: numpy>=2.0
Requires-Dist: orjson>=3.10
Requires-Dist: peft>=0.17
Requires-Dist: pyarrow>=18.0
Requires-Dist: safetensors>=0.5
Requires-Dist: scipy>=1.11
Requires-Dist: torch>=2.6
Requires-Dist: tqdm>=4.66
Requires-Dist: transformers>=4.57
Provides-Extra: full
Requires-Dist: accelerate>=1.10; extra == "full"
Requires-Dist: optuna>=4.0; extra == "full"
Requires-Dist: PyYAML>=6.0; extra == "full"
Requires-Dist: tensorboard>=2.16; extra == "full"
Requires-Dist: build>=1.2; extra == "full"
Requires-Dist: pytest>=8.0; extra == "full"
Requires-Dist: twine>=5.0; extra == "full"
Dynamic: license-file

# Iatro ClinTrace

[![Source](https://img.shields.io/badge/source-GitHub-181717?logo=github)](https://github.com/iatrode/iatro-hcc-clintrace) [![Hugging Face](<https://img.shields.io/badge/Hugging%20Face-gated%20model-ffcc4d?logo=huggingface&logoColor=black>)](https://huggingface.co/iwiley/iatro-clintrace) [![ModelScope](<https://img.shields.io/badge/ModelScope-gated%20model-624aff>)](https://modelscope.cn/models/iWiley/iatro-clintrace) [![PyPI](https://img.shields.io/pypi/v/iatro--clintrace)](https://pypi.org/project/iatro-clintrace/)

[EN](README.md) | [中文](docs/README.zh-CN.md)

**Gated model weights:** [Hugging Face](https://huggingface.co/iwiley/iatro-clintrace) | [ModelScope](https://modelscope.cn/models/iWiley/iatro-clintrace).
Both repositories contain the same ClinTrace model artifact; clinical assets
and patient-level outputs are not distributed.

ClinTrace is a longitudinal clinical-course model for HCC notes. Its job is to
turn free-text clinical notes into a reusable course representation that can
support treatment-pathway reasoning, evidence-grounded decision completion, and
downstream model integration.

**Research use only.** ClinTrace is not a medical device and must not be used
for clinical diagnosis, treatment selection, triage, or patient management.

The authoritative design record is
[`docs/clintrace_total_design.md`](docs/clintrace_total_design.md). This README
is the open-source entrypoint: it describes the package boundary, public command
surface, and controlled-asset contract.

## Table of Contents

- [Scientific Contract](#scientific-contract)
- [Frozen Model](#frozen-model)
- [Release Boundary](#release-boundary)
- [Installation](#installation)
- [Quickstart: Local Inference](#quickstart-local-inference)
- [Training Workflow](#training-workflow)
  - [1. Build Source IAC Assets](#1-build-source-iac-assets)
  - [2. Build or Import Compressed Text Assets](#2-build-or-import-compressed-text-assets)
  - [3. Build and Check Paired IAC Assets](#3-build-and-check-paired-iac-assets)
  - [4. Train, Select, and Export the Compressor](#4-train-select-and-export-the-compressor)
  - [5. Build Frozen Note Features](#5-build-frozen-note-features)
  - [6. Build Decision Supervision](#6-build-decision-supervision)
  - [7. Build Direct-Token and Decoder Planes](#7-build-direct-token-and-decoder-planes)
  - [8. Build History-State and Decision-Contrast Assets](#8-build-history-state-and-decision-contrast-assets)
  - [9. Train the ClinTrace Decision Expert](#9-train-the-clintrace-decision-expert)
  - [10. Evaluate and Freeze Release Candidates](#10-evaluate-and-freeze-release-candidates)
- [Configuration](#configuration)
- [Optional LLM Client Utilities](#optional-llm-client-utilities)

## Scientific Contract

ClinTrace is released as one final clinical-course model, not as separate
curriculum checkpoints. It does not consume manually supplied decision-chain
labels at inference time.

```text
input
  ordered preceding-admission documents -> H
  current clinical evidence package E

supervision and audit
  LLM-extracted E/P/X/O chains
  timeline-derived labels
  history-state summaries

output
  ranked PX decision candidates
  candidate-conditioned observed O distributions
  clinician-facing trusted source-evidence references
```

E/P/X/O labels, chain metadata and timeline-derived fields define the
supervision, evaluation, and audit assets. Completion is conditioned on `H +
E`, while demonstration callers keep each supplied evidence item linked to its
trusted source record for review.
Displayable evidence comes from controlled source spans, not token-offset
fragments chosen by the model.

ClinTrace also treats document inclusion and admission ordering as an upstream
asset contract. Users decide which notes belong in the training/release asset
before building IAC packs. The framework does not apply private note-type rules
to filter longitudinal history. Within the same admission, users must provide a
stable clinical order through admission/episode metadata, timestamps, and stable
document keys; ClinTrace consumes that order rather than correcting ambiguous
hospital-system timestamps.

The central modeling target is:

```text
history state + observed clinical evidence -> plausible P/X/O decision candidates
```

This is intentionally open-world. Missing labels in the record are treated as
unobserved, not as clinical negatives. The model is evaluated primarily by
whether documented decisions are ranked highly. Review inspects the supplied
evidence and its trusted source reference; the final model does not generate
evidence spans from a full current note.

## Frozen Model

The frozen ClinTrace model accepts ordered admission history `H` and current
evidence `E`:

```math
(H,E) \longrightarrow \mathrm{candidate}\ PX\ \mathrm{slot}
\\
(H,E,PX\ \mathrm{slot}) \longrightarrow \mathrm{observed}\ O\ \mathrm{distribution}
```

Hungarian matching uses the observed P and/or X facets available for an O
bundle to assign it to a generated candidate slot. Conditional-O metrics score
observed O labels within their native facet; unobserved labels remain unknown,
not negatives. The conditional-outcome branch does not alter
completion-ranking parameters.

The selected final checkpoint SHA-256 is
`665fcd8779fa884101edee532060bd00bca35f659647c739bad6ed9b947ff709`.
Its frozen decision-backbone source SHA-256 is
`59134e4ab5e96fb73e5c35220f8641dad1d09228acadda7b542429bfaf17873c`.
The recorded final configuration SHA-256 is
`1d6907e6f319102d8e492c1f92c3531b7d51aa807af36cb922b241619a6ea98b`.

Selection used validation conditional-O loss. Final evaluations wrote no
patient-level prediction exports.

| Split | PXO R@5 | O facet targets | O R@1 | O R@3 | O R@5 | O MRR | O observed-set NLL |
|---|---:|---:|---:|---:|---:|---:|---:|
| Validation | 0.880236 | 3,551 | 0.615883 | 0.901436 | 0.957477 | 0.763672 | 1.141718 |
| Internal test | 0.879324 | 2,365 | 0.611416 | 0.897252 | 0.957294 | 0.759065 | 1.089216 |
| External | 0.808669 | 17,608 | 0.548046 | 0.877101 | 0.946047 | 0.719123 | 1.505285 |

PXO ranking equals the frozen decision-backbone evaluation, confirming that
the conditional-outcome branch did not alter the primary completion task.

## Release Boundary

The GitHub repository contains source code, reproducible configurations,
packaged prompt contracts, tests, and documentation. The gated Hugging Face
and ModelScope repositories distribute the corresponding final model artifact.

## Installation

Default installation includes the released inference runtime, IAC tooling, and
the local LLM client utilities.

```bash
pip install iatro-clintrace
```

Install the single extension only when rebuilding, training, evaluating, or
packaging a model:

```bash
pip install "iatro-clintrace[full]"
```

Development checkout:

```bash
pip install -e .
pip install -e ".[full]"
```

## Quickstart: Local Inference

Start from a local clone so that the command-line interface and documentation
stay together:

```bash
git clone https://github.com/iatrode/iatro-hcc-clintrace.git
cd iatro-hcc-clintrace
pip install .
```

Request access to the gated release through either [Hugging
Face](https://huggingface.co/iwiley/iatro-clintrace) or
[ModelScope](https://modelscope.cn/models/iWiley/iatro-clintrace). Once access
is approved, download the complete release once:

```bash
clintrace download
```

The command chooses ModelScope for a China public IP and Hugging Face otherwise,
then reuses the selected hub's existing local login. It also uses `HF_TOKEN` or
`MODELSCOPE_API_TOKEN` when that environment variable is already configured.

If no local login or configured token is available, either authenticate with an
official client first:

```bash
hf auth login
# or
modelscope login
```

or provide the gated token for this download explicitly:

```bash
clintrace download --token "$HF_TOKEN"
# or
clintrace download --token "$MODELSCOPE_API_TOKEN"
```

For explicit tokens, ClinTrace selects the hub from the token format (`hf_` for
Hugging Face and `ms-` for ModelScope), rather than from public-IP location.

The official clients can also download the gated repository directly. In that
case pass the resulting directory explicitly with `--release-dir` when running
`clintrace infer` or `clintrace compress`. ClinTrace stores its own downloaded
bundle under `~/.cache/iatro-clintrace/releases/{hf|modelscope}/`; `infer` and
`compress` only load local weights and never initiate a download themselves.

Prepare ordered preceding-admission documents as separate UTF-8 files, and put
the current evidence package `E` in a separate UTF-8 file. The current evidence
file is not a full current note and must not contain P/X/O target annotations.
Then run:

```bash
clintrace infer \
  --history-note examples/toy/inference/prior_admission_note_01.txt \
  --history-note examples/toy/inference/prior_admission_note_02.txt \
  --evidence-note examples/toy/inference/current_evidence.txt \
  --evidence-source "toy-current-evidence" \
  --top-k 5
```

The terminal report presents ranked PX candidates and candidate-conditioned O
estimates. `--evidence-source` is displayed for review and never enters the
model. Use `--json --output result.json` only when a machine-readable result is
needed in an approved local workflow.

`examples/toy/inference/` contains the example input layout used above.

## Training Workflow

The section below documents the full reproduction path used to rebuild release
artifacts. It is not the normal runtime path for future users. Commands use the
local `data/`, `runs/`, and `artifacts/` layout. Aggregate strategy selection is
recorded in [`docs/training_strategy_record.md`](docs/training_strategy_record.md).

Before the first training command, create local configuration copies. Repository
configs use `demo_*` asset identifiers and are templates, not ready-to-run
datasets. In each local copy, replace the paths for decision samples, extracted
chains, timeline index, compressor features, direct-token features,
admission-history states, and decoder input plane. Set the local train and
external institution identifiers at the same time. The history and navigation
configurations use the `label_vocab.json` written by the completion run that
supplies their initialization checkpoint.

```bash
cp configs/decision/default.yaml configs/decision/local_grounding_completion.yaml
cp configs/decision/stage3_final_earlystop.yaml configs/decision/local_history.yaml
cp configs/decision/stage4_navigation_final.yaml configs/decision/local_navigation.yaml
```

### 1. Build Source IAC Assets

Start from a de-identified document table in JSONL, CSV, or TSV. Required
columns are:

```text
patient_id      stable de-identified patient identifier
doc_id          stable de-identified document identifier, unique within dataset
text            clinical note text
```

Optional columns are:

```text
doc_type        observable note title/type
doc_timestamp   sortable clinical timestamp string
episode_index   integer visit/admission index, -1 if unknown
encounter       optional encounter identifier
doc_category    optional source category, defaults to clinical_document
source          optional source-system label
```

Before packing, finalize the source asset scope. Remove documents that should
not be part of longitudinal history or supervision, and normalize admission or
encounter boundaries. For same-admission records, provide timestamps and stable
document identifiers that encode the intended clinical order. The source packer
performs deterministic sorting; it does not infer clinical sequence from
damaged timestamps or apply built-in note-type filtering.

Pack the table into a clinical_text IAC:

```bash
clintrace build source-iac \
  --input data/source_documents/demo_train.jsonl \
  --output data/00_source/demo_train.iac \
  --institution demo_train \
  --overwrite
```

The source pack builder sorts documents within each patient by
`episode_index`, `doc_timestamp`, and `doc_id`. This is a deterministic
serialization rule over user-supplied metadata, not a clinical reordering
algorithm. It skips rows with missing required fields, duplicate `doc_id`, or
empty text. It reports:

```text
input_rows=<input table rows>
patients=<packed patient count>
docs=<packed document count>
duplicate_doc_ids=<skipped duplicate document ids>
empty_text=<skipped empty documents>
missing_required=<missing required-field counts>
text_raw_mb=<UTF-8 text payload size>
output=<source IAC path> size_mb=<written pack size>
```

Verify the source pack:

```bash
clintrace build source-iac \
  --input data/source_documents/demo_train.jsonl \
  --output data/00_source/demo_train.iac \
  --institution demo_train \
  --verify
```

Verification must report:

```text
verify_docs == verify_expected_docs
verify_unique_doc_ids == verify_expected_docs
verify_mismatches == 0
```

The resulting asset is:

```text
data/00_source/{site}.iac
  clinical_text pack containing original de-identified notes.
```

### 2. Build or Import Compressed Text Assets

Create or import compressed note text before compressor training. This asset is
a normal JSONL, CSV, or TSV table, not an IAC pack. Required columns are:

```text
doc_id             same de-identified document identifier as source IAC
compressed_text    compressed clinical note text
```

Accepted aliases for `compressed_text` are `text` and `output`. Optional
columns are `doc_type`, `doc_timestamp`, and `episode_index`; when omitted, the
source IAC metadata is used.

```text
data/01_compressed/{site}.jsonl
  compressed-note table keyed by doc_id.
```

The compression method is outside this public contract. It may be produced by a
human-reviewed pipeline, a local model, or an external system; ClinTrace only
requires aligned `doc_id` values and clinically readable compressed text. If a
dataset requires de-identification or identifier alignment, complete that data
preparation before building ClinTrace pairs. The open-source package does not
define or distribute private identifier-mapping protocols. For the optional
LLM client wrapper that uses the active packaged profile prompt and writes a
`paired-iac`-ready JSONL, see
[Optional LLM Client Utilities](#optional-llm-client-utilities).

Extract EPXO supervision from the same compressed-note rows before building
decision supervision. Configure an OpenAI-compatible endpoint locally; the
examples use environment variables for endpoint configuration.

```bash
export CLINTRACE_LLM_API_BASE="https://your-local-or-approved-endpoint/v1"
export CLINTRACE_LLM_API_KEY="..."
export CLINTRACE_LLM_MODEL="..."

clintrace llmc expo \
  --institution demo_train \
  --input data/01_compressed/demo_train.jsonl \
  --out data/05_decision_chains/results.jsonl \
  --api-base "$CLINTRACE_LLM_API_BASE" \
  --api-key "$CLINTRACE_LLM_API_KEY" \
  --model "$CLINTRACE_LLM_MODEL"

clintrace llmc expo \
  --institution demo_external \
  --input data/01_compressed/demo_external.jsonl \
  --out data/05_decision_chains/results.jsonl \
  --api-base "$CLINTRACE_LLM_API_BASE" \
  --api-key "$CLINTRACE_LLM_API_KEY" \
  --model "$CLINTRACE_LLM_MODEL"
```

### 3. Build and Check Paired IAC Assets

Once the source IAC and compressed table share de-identified document
identifiers, build the source/compressed training pairs:

```text
data/02_paired/{site}.iac
  source/compressed clinical_text_pair pack used by the compressor and router.
```

Build a paired source/compressed pack:

```bash
clintrace build paired-iac \
  --source-iac data/00_source/demo_train.iac \
  --compressed-input data/01_compressed/demo_train.jsonl \
  --output data/02_paired/demo_train.iac \
  --institution demo_train \
  --overwrite
```

`paired-iac` is the only command that writes compressed text into an IAC asset.
There is no standalone compressed IAC in the public workflow. If a dataset
needs de-identification or identifier mapping to make source and compressed IDs
align, complete that preparation before `paired-iac`. The paired IAC itself is
source text paired with compressed text; it is not a
de-identified/non-de-identified pair.

Record the following IAC-level acceptance metrics before model training:

```text
patients=<paired patient count>
paired_docs=<paired document count>
source_docs=<source document count>
compressed_rows=<compressed input table rows>
compressed_docs=<unique usable compressed document count>
duplicate_doc_ids=<skipped duplicate compressed document ids>
missing_compressed=<source docs without compressed counterpart>
empty_source=<skipped empty source docs>
empty_compressed=<skipped empty compressed docs>
missing_required=<missing required-field counts>
source_raw_mb=<UTF-8 source text payload size>
compressed_raw_mb=<UTF-8 compressed text payload size>
output=<paired IAC path> size_mb=<written pack size>
```

Verify the paired pack:

```bash
clintrace build paired-iac \
  --source-iac data/00_source/demo_train.iac \
  --compressed-input data/01_compressed/demo_train.jsonl \
  --output data/02_paired/demo_train.iac \
  --institution demo_train \
  --verify
```

Verification must report:

```text
verify_docs == verify_expected_docs
verify_unique_doc_ids == verify_expected_docs
verify_mismatches == 0
```

Then inspect both the raw pack and paired pack before starting a long run:

```bash
clintrace inspect iac data/00_source/demo_train.iac --head 5
clintrace inspect pairs -i demo_train --head 5
```

The IAC acceptance gate is: all expected in-scope documents are paired exactly
once, source/compressed text round-trips without mismatch, admission boundaries
and within-admission order are already resolved by the user-provided metadata,
and sampled records are clinically readable after de-identification.

### 4. Train, Select, and Export the Compressor

The compressor maps a clinical note to fixed note tokens. Train it from the
paired source/compressed IAC:

```bash
clintrace train compressor --config configs/compressor/train.yaml
```

Training writes checkpoints and metrics under `runs/` or the configured
compressor output directory. Select the checkpoint by the predeclared validation
rule, then export the release-sized compressor artifact into
`artifacts/compressor/`:

```bash
clintrace build compressor-artifact \
  --checkpoint runs/compressor/checkpoints/course_encoder_step5500.pt \
  --output artifacts/compressor/clintrace_compressor_qwen35_2b_n32_d768_step5500.pt
```

The compressor training validation rule and the exported-artifact metadata are
the training-stage acceptance record. `clintrace compress` intentionally loads
only a complete released model bundle, so it is not a checker for this local
intermediate `.pt`. Continue with feature generation after selecting and
exporting the compressor artifact.

### 5. Build Frozen Note Features

Create longitudinal indexes and frozen compressor note-token caches. These
caches are the model input substrate for downstream decision training.

The timeline index records document order and audit metadata. It does not decide
which documents enter longitudinal history. Downstream history is consumed from
fixed assets such as `history_document_keys` or admission-state rows.

```bash
clintrace build timeline
clintrace build compressor-features --checkpoint artifacts/compressor/clintrace_compressor_qwen35_2b_n32_d768_step5500.pt
```

### 6. Build Decision Supervision

Compile the extracted EPXO chains into supervision assets. The chain labels and
spans are used only as training/evaluation targets, not as inference inputs.
History context in the compiled supervision is written explicitly as
`history_document_keys`; training consumes those fixed keys instead of
reconstructing history with note-type filters.

```bash
clintrace build grounding-supervision \
  --chains data/05_decision_chains/results.jsonl \
  --timeline-dir data/03_timeline_index \
  --features-dir data/04_clintrace_features \
  --output-dir data/06_decision_supervision \
  --train-institutions demo_train \
  --external-institutions demo_external \
  --overwrite
```

The institution names above are placeholders. Use the local de-identified train
and external-site identifiers from your own `data/03_timeline_index/*.jsonl`
manifests. If no institution split is supplied, the first discovered institution
is treated as train and the rest as external.

Within each train institution, patients are assigned deterministically to
75% train, 15% validation and 10% test. The assignment keeps patients intact
while balancing document-level EPXO bundle signatures, primary supervision
roles, chain-count bins and document roles; inspect the generated `report.json`
before training.

### 7. Build Direct-Token and Decoder Planes

Build the direct-token feature plane used for compact or already-compressed
text, then cache per-note grounding features.

```bash
clintrace build decoder-plane
clintrace build grounding-features \
  --documents data/06_decision_supervision/document_samples.jsonl \
  --chains data/05_decision_chains/results.jsonl \
  --checkpoint artifacts/compressor/clintrace_compressor_qwen35_2b_n32_d768_step5500.pt \
  --output-dir data/07_grounding_features \
  --overwrite
```

`grounding-features` does not read `configs/decision/default.yaml`; pass its
document table, EPXO chain table, compressor checkpoint, and output directory
explicitly.

### 8. Build History-State and Decision-Contrast Assets

Admission-history-state summaries provide longitudinal patient context for
training. Decision-contrast pairs are conservative strict-far EPXO bundle
comparisons used to reduce near-neighbor confusion without converting
unrecorded decisions into negatives.

The same locally configured endpoint is used for admission-history state
construction:

```bash
clintrace llmc history \
  --institution demo_train \
  --compressed-input data/01_compressed/demo_train.jsonl \
  --timeline-dir data/03_timeline_index \
  --output-dir data/08_patient_state_history \
  --api-base "$CLINTRACE_LLM_API_BASE" \
  --api-key "$CLINTRACE_LLM_API_KEY" \
  --model "$CLINTRACE_LLM_MODEL"

clintrace llmc history \
  --institution demo_external \
  --compressed-input data/01_compressed/demo_external.jsonl \
  --timeline-dir data/03_timeline_index \
  --output-dir data/08_patient_state_history \
  --api-base "$CLINTRACE_LLM_API_BASE" \
  --api-key "$CLINTRACE_LLM_API_KEY" \
  --model "$CLINTRACE_LLM_MODEL"

clintrace build decision-contrast \
  --samples data/06_decision_supervision/samples.jsonl \
  --output-dir data/06_decision_supervision/expo_distance_analysis
```

### 9. Train the ClinTrace Decision Expert

The decision expert is trained through a four-part curriculum. The command
names describe the capability being learned, not separate deployable experts.

```bash
clintrace train grounding \
  --config configs/decision/local_grounding_completion.yaml \
  --output-dir runs/clintrace_grounding \
  --overwrite

clintrace train completion \
  --config configs/decision/local_grounding_completion.yaml \
  --initialization grounding_init \
  --grounding-checkpoint runs/clintrace_grounding/clintrace_grounding.pt \
  --output-dir runs/clintrace_completion \
  --overwrite

clintrace train longitudinal \
  --config configs/decision/local_history.yaml \
  --initialization completion_init \
  --completion-checkpoint runs/clintrace_completion/clintrace_decision_expert.pt \
  --output-dir runs/clintrace_longitudinal \
  --eval-splits validation test external \
  --overwrite

clintrace train navigation \
  --config configs/decision/local_navigation.yaml \
  --checkpoint runs/clintrace_longitudinal/clintrace_longitudinal.pt \
  --output-dir runs/clintrace_navigation \
  --overwrite
```

Grounding, completion, and longitudinal completion accept the same runtime override flags:
`--output-dir`, `--device`, `--batch-size`, `--token-budget`, `--num-workers`,
`--max-epochs`, and `--overwrite`. Completion additionally accepts
`--grounding-checkpoint`; longitudinal accepts both `--grounding-checkpoint` and
`--completion-checkpoint`.

`grounding` trains the span-grounding auxiliary. `completion` learns
observed-E to P/X/O completion. The first `longitudinal` run adds admission
history state `H` and strict-far ranking regularization. `navigation` accepts
only the history-conditioned completion checkpoint, freezes that pathway, and
trains only the candidate-conditioned observed-O branch.

Formal training defaults to `data.feature_loading: preload` for the >=32 GB
training target. Use `data.feature_loading: mmap` only as the lower-memory
alternative: workers retain first-touch shards as read-only memory mappings,
while each batch coalesces direct/history shard reads and prefetches subsequent
complete batches without LRU tensor caches or dense-bank copies.

`grounding` writes a content-light training sample order plan to
`data.sample_order_plan`. The plan contains sample identifiers only, not tensors
or clinical text. `completion` and `longitudinal` reuse that sample order when
available, then repack batches under their own token-budget rules so the three
phases share the same auditable order without forcing identical batch shapes.

When only EPXO chains are refreshed after the compressor note features have
already been fixed, keep `data/00_source` through `data/04_clintrace_features`
and the existing
`data/08_patient_state_history`, then rebuild:

```text
data/05_decision_chains
data/06_decision_supervision
data/07_grounding_features
runs/clintrace_grounding*
runs/clintrace_completion*
runs/clintrace_longitudinal*
```

### 10. Evaluate and Freeze Release Candidates

Evaluate every selected checkpoint on validation, internal test, and external
splits. The gated release candidate is chosen from the complete validation chain,
not from an ad hoc artifact bundle.

```bash
clintrace evaluate grounding --split validation
clintrace evaluate completion --checkpoint runs/clintrace_completion/clintrace_decision_expert.pt --split test
clintrace evaluate longitudinal --checkpoint runs/clintrace_longitudinal/clintrace_longitudinal.pt --split test
clintrace evaluate navigation \
  --config configs/decision/local_navigation.yaml \
  --checkpoint runs/clintrace_navigation/clintrace_navigation.pt \
  --split test \
  --output-dir runs/clintrace_navigation/evaluation_test
clintrace evaluate decision-contrast --help
```

After the complete validation chain is frozen, export the final release
artifact.

## Configuration

Configs are grouped by component:

```text
configs/compressor/              compressor training and local smoke configs
configs/decision/default.yaml     development defaults
configs/decision/stage2_*.yaml    recorded evidence-conditioned experiments
configs/decision/stage3_*.yaml    recorded history-conditioned experiments
configs/decision/stage4_*.yaml    recorded conditional-outcome experiments
```

Copy recorded configurations into `local_*.yaml` files before adapting them to
a new corpus. They document the frozen research run rather than a portable
dataset configuration.

## Optional LLM Client Utilities

`clintrace llmc` commands are wrappers around OpenAI-compatible chat endpoints.
They are client-side data-preparation utilities, not ClinTrace build steps. The
three frozen Chinese prompts, the `zh_cn` profile, and the EPXO label vocabulary
are bundled inside the installed package under `iatro.clintrace.assets`;
`--profile`, `--prompt`, and `--label-vocab` are optional overrides for
controlled reruns. The default profile is `zh_cn`; non-Chinese deployments
should add a separate profile asset rather than editing core code.

```text
clintrace llmc compress    profile compressor prompt -> compressed-note JSONL
clintrace llmc expo        profile EPXO prompt + label_vocab.json -> EPXO chain JSONL
clintrace llmc history     profile history-state prompt -> admission-history-state JSONL
```

`llmc compress` reads a source IAC, applies the versioned compression prompt,
and appends compressed-note rows to a JSONL file that can be consumed directly
by `clintrace build paired-iac --compressed-input`.

The output JSONL contains at least:

```text
doc_id
patient_id
institution
doc_type
doc_timestamp
episode_index
compressed_text
usage
```

Default execution targets a local OpenAI-compatible server so clinical text
stays on the host.

```bash
export OPENAI_API_BASE=http://127.0.0.1:8000/v1
export OPENAI_API_KEY=local
export OPENAI_MODEL="your-local-model-id"

clintrace llmc compress \
  --institution demo_train \
  --source-iac data/00_source/demo_train.iac \
  --out data/01_compressed/demo_train.jsonl \
  --model "$OPENAI_MODEL" \
  --workers 16 \
  --thinking disabled
```

Useful preparation checks:

```bash
clintrace llmc compress \
  --institution demo_train \
  --source-iac data/00_source/demo_train.iac \
  --out data/01_compressed/demo_train.jsonl \
  --dry-run

clintrace build paired-iac \
  --source-iac data/00_source/demo_train.iac \
  --compressed-input data/01_compressed/demo_train.jsonl \
  --output data/02_paired/demo_train.iac \
  --institution demo_train \
  --overwrite
```

Rows are resumable by `doc_id`: rerunning the wrapper skips documents that
already have a non-empty `compressed_text` in the output file. Non-local API
endpoints require `--allow-external-endpoint`; only use that with an approved
clinical-data processing endpoint.

EPXO and history-state preparation use the same endpoint policy:

```bash
clintrace llmc expo \
  --input data/01_compressed/demo_train.jsonl \
  --out data/05_decision_chains/results.jsonl \
  --model "$OPENAI_MODEL" \
  --workers 16

clintrace llmc history \
  --institution demo_train \
  --compressed-input data/01_compressed/demo_train.jsonl \
  --timeline-dir data/03_timeline_index \
  --output data/08_patient_state_history/demo_train.jsonl \
  --model "$OPENAI_MODEL" \
  --workers 16
```
