Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

pulse api predict

Audience: CLI users validating a request before running it.

pulse api predict validates a types.Request against a .pulse file’s schema without executing it. It reads only the header and schema — never record data — so it’s a cheap, safe iteration loop against arbitrarily large cohorts.

LLM agents using MCP: see the pulse_predict MCP tool and the tool-predict skill. Predict is the LLM’s primary “would this work?” probe.

Synopsis

pulse api predict --request FILE [--json] [--strict] [--echo-request]

Flags

FlagAliasTypeDefaultPurpose
--request-rstring(required)Request JSON path
--jsonboolfalseEmit the standard envelope
--strictboolfalseTreat warnings as errors
--echo-requestboolfalseInclude the normalized request on envelope.request (distinct from PredictResult.Request, which echoes the raw input)

Structural ban

internal/descriptor/predict.go cannot import internal/service/ or internal/processing/. This is enforced by TestPredictNoExecutionImports. Predict is guaranteed to never touch the executor.

Output (text mode)

Valid: true
Schema: 7 fields
Warning [PULSE_AGG_NOT_MEANINGFUL_FOR_CATEGORICAL]: AGG_AVG on field region (categorical_u8)

Without --strict, that warning would still let the command exit 0. With --strict, the warning becomes an error and the command exits non-zero.

Output (--json)

{
  "format_version": "1.1",
  "data": {
    "valid": true,
    "schema_info": {"field_count": 7},
    "streamable": false,
    "streamable_reasons": [
      "AGG_MEDIAN on field price"
    ],
    "request": { /* the request as predict resolved it, with defaults applied */ }
  },
  "errors":  [],
  "warnings": [
    {"code": "PULSE_AGG_NOT_MEANINGFUL_FOR_CATEGORICAL", "message": "..."}
  ]
}

streamable reports whether the request will execute on the streaming Process path; streamable_reasons lists every gate that forced the buffered path. See Performance Notes for the full streaming/buffered table.

For a crosstab request, crosstab_fusable reports whether the grid will be built on the fused one-pass arm (memory proportional to cells + margins) instead of buffering every filter-passing record, and crosstab_fusion_reasons lists every reason it will not. Both are absent for a request without a crosstab. Output is identical on either arm. An engine built with Options.DisableCrosstabFusion answers false with that reason.

limit_findings lists every instance resource limit (Options.Limits) a predicted figure exceeds, as {limit, configured, estimated, grade}; it is absent when nothing exceeds a limit. A certain finding is an exact figure — the request is refused with PULSE_LIMIT_EXCEEDED (valid: false), exactly as process would refuse it before reading a record. A possible finding is an upper bound and only a warning. Today predict reports max_groups (possible: the group buckets the first grouper can create — a categorical’s dictionary size, a boolean’s two values, an include list, a quantile’s bins, or a date-ranges grouper’s ranges plus its unmatched bucket — capped by the record count; groupers whose keys depend on the data report nothing), max_crosstab_cells (possible: the crosstab grid, rows × columns, from the same per-grouper key counts; nothing when an axis grouper’s keys depend on the data), max_matrix_dim (a matrix’s member count) and max_join_build_rows (a join’s right-side record count, read from the right cohort’s header without reading a record). A run that does create more groups than max_groups, or a larger crosstab grid than max_crosstab_cells, is refused PULSE_LIMIT_EXCEEDED mid-scan, with no partial result.

When the request emits inferential p-values, p_values reports {total, uncorrected, basis, threshold}: how many it emits and how many no multiplicity block corrects. An uncorrected count at or above threshold (10) is the cue to add one. basis is exact, dictionary (assumes every dictionary entry of a category axis becomes a bucket, so it can over- or under-count) or lower_bound. See Multiple-Comparison Correction.

request echoes the request after defaults have been applied so you can see what would actually run. To suppress defaults, run with --no-defaults on the executing leaf (api process, api compose); predict reports defaults_applied regardless.

Smart defaults

When an aggregations[] or groups[] slot names a field but omits type, Pulse infers the operator from the named field’s schema type before running the request. Predict reports the inferred slot under data.defaults_applied so you can echo back what was filled in:

Field typeDefault aggregationDefault grouper
u4, u8..u64, f32, f64, decimal128AGG_SUMGROUP_RANGE (interval 10)
categorical_u8/u16/u32AGG_MODE_COUNTGROUP_CATEGORY
date(none — must be explicit)GROUP_DATE (component "day")
packed_boolAGG_MODE_COUNTGROUP_CATEGORY

The Nullable flag on a field never changes its default operator — it only controls per-record null-bitmap participation.

Rules: defaults never override an explicit type; they never cross categories (a missing aggregator does not insert a grouper); statistical tests (tests[], post_tests[]) are not defaulted; filter expressions, features, attributes, and windows are out of scope.

--no-defaults on pulse api process / pulse api compose disables the inference pass entirely and forces every slot to be source-of-truth. Predict still reports defaults_applied so the caller can see what would have been filled in.

Exit codes

CodeMeaning
0Valid (or valid with warnings, in non-strict mode)
1Invalid, or --strict with at least one warning

Examples

Quick validity check

pulse api predict --request req.json

Programmatic check with envelope

pulse api predict --request req.json --json | \
    jq -e '.data.valid == true' >/dev/null && echo "OK"

Strict mode for CI

pulse api predict --request req.json --strict --json

Detect that a request will buffer

pulse api predict --request req.json --json | \
    jq '.data | {streamable, streamable_reasons}'

Compose, facet and chain requests

Three sibling leaves predict the request shapes api predict does not take. Each reads --request FILE (required) and takes --json; none takes --strict or --echo-request, because the validators behind them honour neither.

LeafRequest filedata on --json
pulse api predict-composea ComposedRequestthe batch verdict: valid, the echoed request, rejected overlay pairs, overlay cost, the p-value count and each slot’s advisories
pulse api predict-faceta FacetRequestvalid, the echoed request, schema_info and the accepted overlays
pulse api predict-chaina ChainRequestvalid, the echoed request, the source schema and each stage’s inferred output columns

A refused request comes back as coded errors beside data.valid: false (exit 1 in text mode). A request with no cohort is SERVICE_VALIDATION; an unreadable cohort is DATA_FILE (ENCODING_INVALID for a malformed header). Each fault keeps its own code in errors[0]. Over MCP the same three shapes are pulse_predict’s alternative roots: composed, facet or chain, alone at the root.

pulse api predict-compose --request batch.json --json | jq '.data.valid'

Common warning codes

CodeWhat to do
PULSE_AGG_NOT_MEANINGFUL_FOR_CATEGORICALUse AGG_COUNT / AGG_MODE_COUNT instead of AGG_SUM / AGG_AVG on categoricals
PULSE_AGG_NOT_MEANINGFUL_FOR_DECIMALDecimal-typed field; switch to a decimal-aware aggregator
PULSE_ATTR_CODE_NOT_IN_DICTIONARYAn ATTR_CODE_IN code is not a label of the categorical field’s dictionary (it matches no row); fix or drop each entry in details.missing_codes
PULSE_FIELD_DESCRIPTION_LOW_QUALITYEdit the schema description; re-import
PULSE_FEAT_TARGET_LEAKAGE_RISKEvery FEAT_TARGET_ENCODE averages all rows’ targets (a prior split does not help); compute train-only means in a separate request

The full code-by-code recovery playbook is reachable per-code via the MCP pulse_errors_lookup tool or the pulse errors lookup CODE CLI; see also Troubleshooting.