Skip to content

Contribution Bundle v0 — Format Specification

Status: implemented (schema/format only) See: DR-0023 Local/Offline and Hosted Submission Model, contribution-bundle-v0-format-spec roadmap

What this document covers

A contribution bundle is a portable scientific contribution package. It carries selected scientific payloads, source-instance metadata, exporter metadata, submission metadata, bundle-local references, and integrity metadata in a format that can later be validated and ingested by a hosted TCKDB instance.

This document defines bundle v0 (bundle_version == "0.1") and the schemas implemented in backend/app/schemas/workflows/contribution_bundle.py.

What v0 is

  • A schema/format milestone only.
  • Re-uses existing thermo and kinetics upload schemas as the bundle's scientific payload, so nested validation runs through the same code paths as a normal API upload.
  • Validatable without database access.

What v0 is not

  • v0 does not export records from any database.
  • v0 does not import into any hosted instance.
  • v0 does not create submissions, jobs, or moderation events.
  • v0 does not support raw database synchronization between instances.
  • v0 does not ship artifact packaging — only the manifest shape.
  • v0 does not support full network bundles, arbitrary graph export, or mixed thermo+kinetics bundles.
  • v0 does not introduce any FastAPI route, service, or DB write.

Supported v0 bundle families

Allowed bundle_kind values:

Value Meaning
thermo Bundle carries thermo upload-equivalent payloads only.
kinetics Bundle carries kinetics upload-equivalent payloads only.

Future families intentionally not allowed in v0 (to avoid shipping bundles no exporter or importer is actually validating yet):

  • statmech
  • transport
  • network
  • mixed
  • computed_reaction

Top-level shape

{
  "bundle_format": "tckdb-contribution-bundle",
  "bundle_version": "0.1",
  "bundle_kind": "thermo",
  "created_at": "2026-04-25T00:00:00Z",
  "source_instance": { "...": "..." },
  "exporter": { "...": "..." },
  "submission": { "...": "..." },
  "records": { "thermo_uploads": [], "kinetics_uploads": [] },
  "local_refs": { "species:ethanol": { "record_type": "species", "label": "ethanol" } },
  "manifest": { "sha256": null, "files": [] }
}

bundle_format

Must be the literal string tckdb-contribution-bundle.

bundle_version

Must be the literal string 0.1 for v0.

bundle_kind

One of thermo | kinetics.

created_at

ISO-8601 UTC timestamp (Pydantic datetime).

source_instance

Identifies the TCKDB instance that produced the bundle.

Field Required Notes
instance_kind yes local or lab_server. hosted is not allowed in v0.
instance_name yes Free-text label, e.g. calvin-laptop or pi-rmgteam-server.
schema_version yes The Alembic revision the local DB is at, e.g. d861dfd60891.
software_version no Optional TCKDB software version label.
created_by_local_user no Optional local username/label.
notes no Free-text.

exporter

Provenance-only metadata about who produced the bundle. This is not the hosted actor identity. Hosted actor identity comes from hosted authentication during the future import milestone.

Field Required Notes
local_user_label yes Local label such as calvin.
orcid no ORCID iD if known. Not validated for format in v0.
affiliation no Free-text.
email no Free-text contact.
notes no Free-text.

submission

Bundle-level submission metadata. The hosted instance maps this to its own submission row at import time; the bundle does not create submissions.

Field Required Notes
title yes Short title for the contribution.
summary yes One-paragraph summary.
source_kind yes Must be local_bundle in v0.
rights no Deposit-time license agreement for every record in the bundle; see below.

submission.rights

The rights object is the wire fragment tckdb_schemas.rights.DepositRights, the same one every direct upload request carries:

"rights": {
  "license": "CC-BY-4.0",
  "depositor_attests_right_to_license": true,
  "source_terms": null
}
Field Required Notes
license yes SPDX identifier (1–64 characters). A hosted release compares it with its own data_license by exact, case-insensitive match; there is no compatibility lattice.
depositor_attests_right_to_license yes Must be literally true. A false fails validation — the bundle cannot carry a stored "no"; it omits the object instead.
source_terms no Citation or quotation of the terms the records were taken under, for records that are not the depositor's own work.

On hosted import the fragment is recorded as a depositor_agreement rights attestation on the submission, attested by the authenticated submitter — never by the local exporter label. A bundle without rights imports normally, but its records cannot be selected into a dataset release until a curator records a basis for the submission.

scripts/export_contribution_bundle.py fills the object from the standing rights attestation of the submission that deposited the exported records on the source instance. If the records were deposited under different licenses the export refuses (one bundle, one agreement); if only some of the records are attested the export also refuses, rather than extending one deposit's agreement to records nobody licensed; only if nothing at all is attested is the object omitted — the exporter never invents consent.

Note on local_bundle and the database enum. The submission.source_kind field on the bundle uses a format-level enum (BundleSubmissionSourceKind). The database enum SubmissionSourceKind in backend/app/db/models/common.py does not yet include local_bundle. Adding it is deferred to the hosted-import milestone — the bundle format only states "this submission came from a local bundle", and the hosted importer will be responsible for translating that to its own submission machinery.

records

Container for the upload-equivalent scientific payloads. Reuses the existing workflow upload schemas directly:

  • thermo_uploads: list[ThermoUploadRequest]
  • kinetics_uploads: list[KineticsUploadRequest]

Family rules for v0:

  • A thermo bundle must contain ≥ 1 thermo_uploads entry and must not contain any kinetics_uploads.
  • A kinetics bundle must contain ≥ 1 kinetics_uploads entry and must not contain any thermo_uploads.
  • Mixed bundles are explicitly rejected.

local_refs

A map from a bundle-local reference key to a small descriptor.

Local refs are not hosted IDs and not raw DB primary keys. They exist so that future bundle versions can name records inside the bundle (e.g. for cross-payload references) without claiming any hosted identity.

Local ref key rules

A local ref key has the form <namespace>:<label>:

  • Namespace: lowercase ASCII, may contain _, must start with a letter.
  • Label: alphanumeric plus _, -, .. Must start with alphanumeric.
  • Purely numeric labels (species:123) are rejected — they look like raw database primary keys and that is exactly what bundles must not carry as canonical identity.

Recommended namespaces (informational, validated as record_type):

species:ethanol
species_entry:ethanol-singlet
reaction:h_abstraction_001
transition_state:ts_h_abstraction_001
calculation:sp_001
thermo:ethanol_nasa_001
kinetics:h_abstraction_rate_001
literature:zhang_2024_jpca

Keys are unique by Python dict semantics — duplicate keys in the source JSON collapse to the last value, so the schema validates the deduped map.

Annotation-only in v0

In v0, local_refs is an annotation map, not a cross-reference graph. It may describe records, labels, or local identities that help a future exporter/importer reason about the bundle, but v0 scientific payloads (ThermoUploadRequest, KineticsUploadRequest) do not yet cite local refs.

The v0 schema therefore validates only:

  • local-ref key shape (namespaced <namespace>:<label>)
  • local-ref record_type
  • rejection of purely numeric (raw-DB-PK shape) labels
  • overall map shape

The v0 schema does not enforce coverage between local_refs and records — having a thermo:* ref does not prove it refers to a specific ThermoUploadRequest, because nothing in the upload payload binds to it yet.

Promoting local_refs to a first-class cross-reference is deferred to a future bundle version, where scientific payloads can explicitly cite local refs and the hosted importer can define a deterministic local-ref contract for import preview/diff.

manifest

Integrity metadata for any external artifacts shipped alongside the bundle. Artifact packaging is not implemented in v0; the manifest just defines the shape so future artifact bundling has a place to land.

Field Required Notes
sha256 no Optional 64-char lowercase-hex covering hash.
files yes (may be []) List of BundleManifestFile entries.
created_by_tool no Free-text.
notes no Free-text.

manifest.files[*]

Field Required Notes
path yes Path inside the bundle. Must be unique across files.
sha256 yes 64-char lowercase-hex SHA-256.
size_bytes no Non-negative integer.
content_type no Free-text MIME or label.
role no Free-text role hint (e.g. output_log, input_geometry).

A bundle without external artifacts can use:

{ "sha256": null, "files": [] }

Validation rules implemented in v0

  1. bundle_format == "tckdb-contribution-bundle".
  2. bundle_version == "0.1".
  3. bundle_kind{thermo, kinetics}.
  4. All required top-level metadata is present (source_instance, exporter, submission, records, manifest, created_at).
  5. The selected bundle kind has at least one record of the matching family.
  6. Mixed thermo+kinetics record sets are rejected.
  7. manifest.files paths are unique.
  8. local_refs keys match the namespaced format rule above.
  9. Purely numeric local-ref labels (raw-DB-PK shape) are rejected.
  10. extra="forbid" on every bundle schema rejects unknown top-level fields, so a future field cannot accidentally slip in unnoticed.
  11. Nested ThermoUploadRequest / KineticsUploadRequest payloads run their full upload-time validators (e.g. thermo must carry actual scientific content, kinetics a_units must match molecularity).

DB-backed scientific resolution (species lookup, level-of-theory resolution, deduplication, etc.) is not done in v0.

Examples

Future extension points (not in v0)

  • Adding local_bundle to the DB SubmissionSourceKind enum, when the hosted-import milestone needs to persist bundle-origin submissions.
  • Wider bundle_kind support (statmech, transport, network, etc.).
  • Cross-payload references that consume local_refs keys directly inside scientific upload payloads.
  • Real artifact packaging (tarball/zip layout, content-addressed storage).
  • Hosted dry-run, hosted import, and hosted submission lifecycle.
  • Frontend UX for bundle authoring and review.