Skip to content

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:

  1. Strategy → Pool (selection) — did sampling achieve the design? Per Pool the Bundle's Campaigns drew on, aggregated only when they agree on one Strategy
  2. Strategy → Actual (fielded) — how far off was the realized base before weighting? With a per-campaign breakdown; no_strategy until a Strategy is assigned
  3. Strategy → Weighted (weighted) — did weighting recover the design? Graded against the same Strategy as (2), so the two differ by exactly what weighting recovered
  4. 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
  5. 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}. Only Textarea qualifies, and it does not imply coding. Editbox is 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 whose columns name 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: null means "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 carries reviewed (has anybody decided which dimensions become columns?), selected (the chosen dimension ids, null while 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, and dimensions. Each dimension carries its slot id, label, the frozen column name, its origin (proposed / authored / degraded), whether it is selected, its categories as {id, label}, the per-column assignment counts, and overlap — 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_status sits beside silver_status because an empty candidates means 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_reviewtrue while 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:

  1. create_bundle → get bundle_id
  2. create_bronze_dataset(bundle_id) → extract Bronze
  3. code_open_ends(bundle_id) (or its alias derive_silver) → codes open-ends, then weights against the Calibration Targets, producing Silver
  4. create_gold_dataset(bundle_id, operations=[...]) → refine Silver into Gold using the operation catalog
  5. export_dataset(dataset_id, format) → export any ready stage
  6. get_bundle_quality(bundle_id) → the Representativeness story at any point