cBioPortal logoOutcomes

The Study Update That Reviews Itself

The clearest way to describe what changes when a cBioPortal study is governed is to follow one ordinary study update through a working week — the same update your team already ships, with the governance layer switched on.

The Study Update That Reviews Itself

The clearest way to describe what changes when a cBioPortal study is governed is to follow one ordinary study update through a working week — the same update your team already ships, with the governance layer switched on.

Monday: the pull request answers back

A curator opens a pull request against the study repository. Two attributes added to data_clinical_sample.txt, one description rewritten, one datatype corrected from STRING to NUMBER. Before, this is where the review happened: two people reading a tab-separated diff and hoping to notice what moved.

Now a CI step posts the staging files to the audit endpoint on the machine-to-machine surface — POST https://coremodels.example.com/v1/{PROJECT_ID}/integrations/cbioportal/audit, authenticated with a user API key as $TOKEN — and the pull request gets an answer. The response carries data.errorCount, data.warningCount, counts keyed by finding code, the list of drifted objects, the artifact fingerprint, and data.markdown: a report written for humans that the step drops straight into the job summary or a pull-request comment. data.errorCount > 0 fails the build. That is the entire gate.

The two new attributes come back as coverage findings, because they are not yet governed. The retyped column comes back as field-type-drift, naming the attribute and both types. And one of the new attributes was typed in a hurry as Days_to_followup, so it comes back as attribute-id-not-upper — a warning that says this ID will fail cBioPortal validation, delivered in a pull request rather than at the portal three days later.

The reviewer's job did not get harder. It got specific.

Tuesday: the README carries the state

The audit run was recorded, so the badge moved. GET /v1/{PROJECT_ID}/integrations/cbioportal/badge returns an SVG straight into the README: green when the latest recorded run was clean, yellow when only warnings remain, red when there are errors, gray when nothing has been recorded yet.

It is a small thing that does something specific: it makes the schema's health a property of the repository rather than a question someone has to ask. A collaborator landing on the study repo for the first time can see whether the clinical model currently agrees with the governed definitions without knowing that any of this machinery exists.

Wednesday: the model moves, and the files do not

Governance changes go the other way too. Someone tightens a definition across studies — what an attribute is supposed to mean, which values it is allowed to carry. The staging files have not changed at all, so nothing in CI will fire, and under the old workflow this drift is invisible by construction.

One call covers it. POST /graph/integrations/cbioportal/reaudit/{PROJECT_ID} with an empty body replays the study snapshot stored at import time against the current governed model. No artifacts to re-extract, no credentials, no portal. The question it answers is the mirror image of the CI gate: not "do these new files still fit the model?" but "does the last-known study still fit the model now that the model has moved?" The run is always recorded, because a model-side drift check is exactly the kind of event you want on the record.

Thursday: the trail is readable

GET /graph/integrations/cbioportal/history/{PROJECT_ID} returns the rolling audit trail per study: each run with its timestamp, what triggered it, the error, warning, and info counts, the finding codes, and the artifact fingerprint. Newest first.

That turns a recurring conversation into a lookup. "Did this attribute always have that type?" becomes a read of the trail: here is the run where the code first appeared, here is the run where it went back to green, here is the fingerprint of the artifacts each ran against. Drift stops being an anecdote someone half-remembers and becomes a sequence of comparable data points.

If you want to know where the study stands right now rather than how it got here, GET /graph/integrations/cbioportal/status/{PROJECT_ID} returns the last-import state: whether an import has happened, the recorded state facts, and how many governed datasets the vendor identities resolve to.

Friday: the next study starts conformant

A new cohort opens, and the old move was to copy last study's staging file and edit it — inheriting its typos, its blank descriptions, and its inconsistencies along with its structure.

Instead: POST /graph/integrations/cbioportal/generate/{PROJECT_ID}. The connector emits one data_clinical_{instrument}.txt per governed Type — an upload-ready staging-file header scaffold with all four # rows filled in from the governed model: display names, descriptions, datatypes derived from the governed kinds, priorities, and UPPER_CASE attribute IDs minted from the governed labels. Pass typeNames to restrict it to the instruments you want; leave it empty for everything eligible. Governed types with no elements are skipped, and the response says so as declared lossiness rather than emitting an invalid empty file.

Two of the failure modes from Monday cannot occur in a generated scaffold. The attribute IDs are UPPER_CASE because the generator mints them that way, and the description row is populated because the governed model has descriptions to populate it with.

What the after-state adds up to

Stack the week up and four things are true that were not true before.

The schema has a home outside the header rows. Each clinical file is a governed Type, each attribute a governed Element carrying its description and datatype with display name and priority preserved as metadata, PATIENT_ID and SAMPLE_ID are declared identities, and the sample file's PATIENT_ID is a governed reference to the patient instrument — the study's join, queryable rather than remembered.

Both directions of drift are covered. Fresh files against the model in CI; the stored study snapshot against the model on demand.

Every run leaves evidence. Coded findings, counts, fingerprints, timestamps, and a badge that reflects the latest recorded run.

The loop closes outward. The governed model does not only receive study files, it emits them.

None of this asks you to curate differently, and none of it asks for a credential. The import is one call with the files you already maintain; everything after it is reading. What changes is that the careful work of curation stops being the only thing standing between the study and a broken upload.

The cBioPortal quickstart in the CoreModels integration docs shows each of these calls with its exact request and response shape.