Bundle Tools — MCP Tool Reference¶
A Bundle binds one Project, one Questionnaire, and a selected subset of that Questionnaire's Campaigns (plus an option to include ad-hoc surveys with no Campaign) to exactly one linear Bronze → Silver → Gold dataset chain. These tools manage the Bundle itself and its quality story; see Dataset Tools for the Bundle-scoped stage operations (extract, code + weight, refine, export).
create_bundle¶
Create a pipeline Bundle.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string |
Yes | — | Bundle name |
project_id |
string |
Yes | — | Owning project (write access required) |
questionnaire_id |
string |
Yes | — | Questionnaire whose completed surveys feed Bronze |
campaign_ids |
string[] |
No | [] |
Campaign subset to include (empty = none until set) |
include_ad_hoc |
boolean |
No | false |
Also include completed surveys with no campaign |
Returns: { bundle_id, name }
list_bundles¶
List pipeline Bundles, optionally filtered to one project.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
project_id |
string |
No | — | Restrict to Bundles owned by this project |
Returns:
{
"items": [
{
"id": "...",
"name": "Wave 1",
"project_id": "...",
"questionnaire_id": "...",
"campaign_ids": ["..."],
"include_ad_hoc": false,
"chain": {
"bronze": {"dataset_id": "...", "status": "ready"},
"silver": {"dataset_id": "...", "status": "processing"}
}
}
],
"count": 1
}
chain keys are the stages that have a dataset (bronze/silver/gold); a stage with no dataset yet is simply absent — treat it as missing.
clone_bundle¶
Deep-copy a Bundle's ready datasets and recipes into an independent variant.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Source Bundle |
name |
string |
No | "{source} (copy)" |
Name for the clone |
Returns: { bundle_id, cloned_stages } — cloned_stages lists which stages (bronze/silver/gold) had a ready dataset to copy.
The clone starts from a byte-identical copy of each ready stage and carries the same stage recipes (coding selection and its dimension codebook, weighting targets, refine field specs), so it can be re-derived independently — e.g. with different weighting targets — without touching the original Bundle. This is how you compare variants (different weighting, different refinement) of the same raw extraction.
delete_bundle¶
Delete a Bundle and its dataset chain.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle to delete |
Returns: { success: true }
Deletion is soft — the Bundle and its chain datasets are marked deleted immediately; their underlying data files are cleaned up by a background maintenance process shortly after.
Quality Tools¶
Quality is measured at the Bundle, not on individual datasets. Three of the four representativeness measures grade against the Bundle's re-assignable current Strategy (current_strategy_id) — assign one before expecting them to be measured. The Calibration Targets are the weighting instruction, not a benchmark: grading the weighted result against the spec the weighting aimed at would make a successful raking run score well by construction.
get_bundle_quality¶
The Bundle's Representativeness story in one call — one sample traced from design intent to deliverable:
- Strategy → Pool (
selection) — did sampling achieve the design? Per Pool the Bundle's Campaigns drew on, aggregated only when they agree on one Strategy - Strategy → Actual (
fielded) — how far off was the realized base before weighting? With a per-campaign breakdown;no_strategyuntil a Strategy is assigned - Strategy → Weighted (
weighted) — did weighting recover the design? Graded against the same Strategy as (2), so the two differ by exactly what weighting recovered - Pool → Actual (
fielding_shift) — what did fielding itself contribute? Pool-referenced, over pool-borne Surveys only, so it answers a different question from (1)–(3) and is not a fourth point on their scale - Response quality (
response) — entropy, straightlining, Cronbach's alpha, acquiescence, non-response (see the Quality Metrics Reference)
Alongside them, excluded_profile describes what the per-Bundle completeness threshold removed, against what it kept — compared on the Strategy's own factors, because two row counts cannot say whether a cut introduced bias. An empty excluded set reports empty rather than a divergence of zero.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle UUID |
Returns: { quality: {...} } — the five measures plus excluded_profile and chain/strategy context. Each carries a state (measured, not_measurable, no_strategy, no_weighted_factors, empty, not_derived, processing, invalidated, error) with a reason, so one unmeasurable or failing measure never hides the others and a zero is never mistaken for a grade. Measured payloads include overall score, composite error, and per-factor deviation analysis; the weighted payload also carries weighting_diagnostics (design effect, effective sample size) — the variance cost of the recovery.
compare_bundle_quality¶
Bronze-vs-Silver representativeness comparison for the Bundle's chain, graded against the Bundle's current Strategy. Its recovery field is the figure to read: a plain difference of weighted-mean error over the Strategy factors measured on both sides, so equal error reductions at different absolute levels give equal figures and two Bundles are comparable. When the two measures share no measured factor it is null with a recovery_reason rather than 0.0 — nothing was comparable, which is not the same as weighting having achieved nothing.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle UUID |
Returns: { comparison: {...} } with per-factor and overall improvement. Both the Bronze and Silver must be ready first; a chain that isn't ready yet fails with a conflict error (409 with {"error": "conflict"} on REST) rather than a validation error — finish or re-run the derive, then compare.
get_bundle_coding¶
The Bundle's open-end coding state: what may be coded, which questions the analyst chose, and — per chosen question — the dimensions proposed for it, their categories, which are selected, and whether the degraded no-credential path produced them. Read it before selecting or re-deriving.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle UUID |
Returns: { candidates, selected, discovered, units, awaiting_review, bronze_status, silver_status, pending_review }.
candidates— every open-text unit this Bundle's Bronze offers, each{unit_key, title, control_type, roster_block_id, columns}. OnlyTextareaqualifies, and it does not imply coding.Editboxis a numeric input in QML (it requires a min and a max), so its answers are counts and amounts rather than text a codebook can describe. A Roster is one candidate whosecolumnsname the Bronze columns it pools; a QuestionGroup sub-question and a Matrix cell each stay their own candidate.selected— the persisted unit choice, passed through undefaulted:nullmeans "not yet chosen",[]means "chosen: nothing". Only the second is a decision someone made.discovered— maps each coded unit to{column: dimension label}— the record of which columns the last derive actually emitted.units— the per-unit dimension state, keyed by unit key. Each carriesreviewed(has anybody decided which dimensions become columns?),selected(the chosen dimension ids,nullwhile unreviewed and[]for "reviewed, chose nothing"),degraded(the round came from the no-credential path — it is what tells a genuine one-dimension result apart from that path's single dimension),answered/missing, anddimensions. Each dimension carries its slotid,label, the frozencolumnname, itsorigin(proposed/authored/degraded), whether it isselected, itscategoriesas{id, label}, the per-column assignmentcounts, andoverlap— how many of that dimension's own categories an average answer also cleared, which reads on the codebook rather than on the respondents.awaiting_review— the selected units whose dimensions nobody has reviewed. Those units produce no coded column while the derive still succeeds, which is why this is named rather than inferred.bronze_statussits besidesilver_statusbecause an emptycandidatesmeans one of two different things — no Bronze has been extracted yet, or this questionnaire asks no open-text question at all — and the list alone cannot tell them apart.pending_review—truewhile either decision is outstanding: a ready Bronze with candidates and no unit selection, or a selected unit awaiting dimension review.
No verbatim respondent text ever comes out of this door. A category is projected as its id and label only, and the per-dimension sample answers are not projected at all — both exist for the researcher's own review surface in Balansor.
Unit selection is writable over MCP/REST via set_coding_selection below, because it is a judgement about the question, made before any model has run. Selecting dimensions, renaming them and editing their categories are not, and will not be — those are judgements about generated content, and there is deliberately no tool for them on any transport. An agent driving the pipeline should surface pending_review: true and the awaiting_review list to its user rather than re-deriving past them. See Open-End Coding for the full workflow.
set_coding_selection¶
Set which open-text units this Bundle codes into categories. The choice is a per-Bundle analysis decision on the Silver recipe, not a property of the questionnaire — a mailing address in a Textarea is worth nothing and a one-word "how did you feel?" in an Editbox is worth a codebook.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle UUID |
selected |
string[] |
Yes | — | Full replacement set of coding unit keys, in the vocabulary get_bundle_coding's candidates offers |
Returns: { bundle_id, selected }.
Requires manager permissions and an identified user — service-token-only callers are rejected, so an unattended run cannot select on nobody's behalf. Present the candidates to the researcher and write the answer they give you rather than choosing for them.
The list is a full replacement set, not a delta, and an empty list is a decision ("code nothing"), not an omission. A key that is not a candidate on this Bundle's Bronze is refused — including a single Roster iteration's column name, which looks like a real column but would pool nothing; re-read the candidate list and select the pooled unit key instead. A selection change is a Silver input: it invalidates a ready Silver and everything downstream, and applies on the next derive (a derive already in flight keeps the selection it started with).
Deselecting a unit that backs a Calibration Target is not refused here — that conflict surfaces at the derive, which refuses with weighting_factor_deselected so the recipe can be fixed in either order.
assign_bundle_strategy¶
Assign (or clear) the Bundle's current Sampling Strategy — the benchmark selection, fielded and weighted all grade against. Requires manager permissions and an identified user (service-token-only callers are rejected); assigning a strategy also requires access to the strategy's own project. Reassigning it recomputes all three of those measures; it does not touch the Calibration Targets, which are the weighting instruction.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle UUID |
strategy_id |
string |
No | null |
Strategy to assign; null clears the assignment |
Returns: { bundle_id, strategy_id, strategy_name }
To advance a strategy with reality-grounded outcome factors (e.g. political preference from the survey responses plus an external benchmark), use advance_sampling_strategy — it clones the strategy (the original is never edited) and the clone can then be assigned here. See the Sampling Tools Reference.
set_calibration_targets¶
Edit the Bundle's Calibration Targets — the editable spec derive_silver/code_open_ends actually weight to. It is the weighting instruction, not the benchmark: the weighted measure is graded against the current Strategy, so a Calibration Targets set that misses the design shows up as distance from that design rather than as a perfect score against its own aim. Seeded once from the current Strategy's factors the first time a researcher opens the Silver stage in Balansor; from then on it is independent of the current Strategy. Requires manager permissions and an identified user.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bundle_id |
string |
Yes | — | Bundle UUID |
weighting |
object |
No | — | Full replacement block {use_strategy_factors, factors} |
factors |
array |
No | — | Shorthand for weighting={factors, use_strategy_factors: false} — supplying a bare factor list is itself an opt-out of live-Strategy tracking |
Each factor is {column, target_distribution, name?, factor_type?, bucket_ranges?} — column names a bare column already present in the coded frame (a Bronze demographic/outcome column, a coded open-end dimension, or a multi-select option indicator), and target_distribution maps each value to its target proportion (summing to 1.0).
A target key is the column's stored value, not its caption
For a coded answer the stored value is the option's numeric code, so a five-point scale is targeted as {"1": 0.1, "2": 0.2, ...} — not {"Strongly agree": 0.1, ...}. If none of a factor's declared categories occurs in its column, the derive fails with an error naming the column, how many distinct values it holds, and the categories you declared. It does not quietly return weights of 1.0. A multi-select option indicator is 0/1. A coded open-end dimension is one factor across its whole category set — one target per category, 0 (unclassified) included, since its categories partition the respondents; a distribution that omits one is refused rather than silently normalized.
Returns: { bundle_id, weighting }. Two conditions are refused with a conflict error before anything is written — the same preflight the Silver derive itself runs:
- a target naming a coding category that was rejected or has since vanished from the latest coding run;
- a target naming a raw multi-select answer column. That column stores a combination of the selected options, so every observed combination would become its own weighting cell. Target the per-option indicator columns instead — one target per option.
Stage Operations¶
Extraction, coding + weighting, refinement, and export are all invoked with a bundle_id on the Dataset Tools — there is no separate "run this Bundle" tool. A typical flow:
create_bundle→ getbundle_idcreate_bronze_dataset(bundle_id)→ extract Bronzecode_open_ends(bundle_id)(or its aliasderive_silver) → codes open-ends, then weights against the Calibration Targets, producing Silvercreate_gold_dataset(bundle_id, operations=[...])→ refine Silver into Gold using the operation catalogexport_dataset(dataset_id, format)→ export any ready stageget_bundle_quality(bundle_id)→ the Representativeness story at any point
Related Documentation¶
- Dataset Tools — extraction, coding + weighting, refinement, and export parameters
- Quality Metrics Reference — metric definitions, formulas, interpretation thresholds
- Data Analysis Guide — the Bundle pipeline board from a researcher's point of view
- Open-End Coding — how open-end coding works inside the Silver derive