Probe Plan#
A probe plan is the human-reviewed list of calls intake may execute against a
conventional source. It is passed to assisted authoring as --probe-plan. The pipeline
measures those calls and derives certification tier A0, A1, or A2 from the
observations. A Gold freeze requires A2.
The plan is not oracle truth and is not a pack file. Generation never reads it.
tools.json names the public interface; the plan names which situations intake is
allowed to observe.
Create a Probe Plan#
Copy the A2-shaped banking example, then replace its tools, fixture ids, and cases:
cp src/nemotron/steps/byob/references/bfcl-probe-plan.example.json \
/srv/sources/library-probe-plan.json
Do not pass the example unchanged to a library or warehouse source. An optional
model-drafted plan is produced by draft_probe_plan; review that draft the same way
you would review a handwritten plan. Refer to Author a Pack with Model Assistance.
A local_python source may omit fixtures when the reviewed fixtures.json already
supplies reset state. A session-based HTTP or MCP plan must carry fixtures, because
those sessions are handed their world when they open.
Required Coverage#
Write cases that together cover:
Every published tool, at least one
expectation: successcase.Mutations, a success case with
expected_state_change: truefor each tool markedx-mutates.Confirmation, a success path for each tool marked
x-requires-confirmation.Structured errors, at least one
expectation: structured_errorcase withexpected_error_codewhen the source has error codes. Omitting error cases does not by itself block A2; it leaves error-shape evidence unobserved.Timeout cleanup, at most one
expectation: timeoutcase. Without it,check_probe_planreportsno_timeout_casewithimpact: blocks_a2, and intake cannot certify above A1.
A timeout case must name a call that actually cannot finish inside the probe deadline.
Inventing a timeout against a tool that returns promptly fails the probe rather than
proving cleanup. Timeout cases must not set expected_state_change or
expected_error_code.
Success cases require expected_state_change and must not set an error code.
Structured-error cases require expected_error_code and cannot claim a mutation.
Ground Model-Drafted Arguments#
draft_probe_plan first asks the model where each argument comes from, then
materializes a concrete reviewed plan. A fixture-owned date, identifier, free-form
reason, email, or phone must use a fixture binding during that draft. A model cannot
select one as a literal unless the parameter schema itself pins the accepted set.
Use literal bindings only for schema-pinned enums and booleans. Use
invalid_literal only when an enum, boolean, or numeric schema itself proves the
value invalid. Do not infer a string format from prose, invent an undeclared
argument, or use a plausible value that the evidence never observed.
For example, this intermediate draft is ungrounded when item_id has only an
unconstrained string schema:
{"name": "item_id", "source": "literal", "literal": "ITEM-42"}
Bind it to reviewed fixture state:
{"name": "item_id", "source": "fixture", "literal": null}
The structured draft schema represents boolean and numeric literals as strings:
write "true", "false", or "2", not JSON true, false, or 2. The final
probe-plan.json contains materialized arguments, not these binding descriptors.
Example#
This compact library fragment matches the tiny_oracle_pack catalog used in
From Domain Assets to an Oracle Pack. It is not a complete A2 plan: the bundled
tiny backend has no honest hanging call, so a Gold freeze still needs a timeout case
against a tool that actually blocks, as the assisted-authoring walkthrough adds with
rebuild_catalog_index.
{
"schema_version": "bfcl-local-probe-plan-v1",
"clock": "2026-03-02T09:00:00+07:00",
"seed": 7,
"fixtures": null,
"cases": [
{
"case_id": "a_status_available",
"tool": "get_book_status",
"arguments": {"book_id": "BK-100"},
"expectation": "success",
"expected_state_change": false
},
{
"case_id": "b_checkout_committed",
"tool": "checkout_book",
"arguments": {"book_id": "BK-100", "patron_id": "P-1", "confirm": true},
"expectation": "success",
"expected_state_change": true
},
{
"case_id": "c_unknown_book",
"tool": "get_book_status",
"arguments": {"book_id": "BK-ABSENT-1"},
"expectation": "structured_error",
"expected_error_code": "not_found"
}
]
}
Clock values must be ISO-8601 with an explicit timezone. The banking example uses
2026-03-02T09:00:00+07:00; that is the same instant as 2026-03-02T02:00:00Z.
Validate#
Check the plan against a local Python source without executing probes:
uv run python -m nemotron.steps.byob.scripts.check_probe_plan \
--source /srv/sources/library \
--probe-plan /srv/sources/library-probe-plan.json
Exit code |
Meaning |
|---|---|
|
The plan is well-formed and does not report an A2 blocker. |
|
The plan is usable for intake but cannot attain A2, usually |
|
The plan or source could not be checked. Standard error carries a JSON envelope with |
Intake remains authoritative: only it executes the probes and observes reset, isolation, confirmation, timeout cleanup, and result behavior.
A2 Readiness Checklist#
Before intake, verify:
the source static check passes with no placeholder or unimplemented handler;
every published tool has a successful probe;
every mutating tool has an observed state-changing success case;
every confirmation-gated tool can prove pending calls do not mutate and confirmed calls do;
structured error codes have representative negative probes;
repeated reset and call cases can demonstrate determinism and isolation;
one real blocking tool has the single timeout case required for cleanup evidence;
fixture values satisfy the tool schema and source preconditions;
check_probe_planreportsattainable_tier: A2.
This checklist predicts attainable coverage. It does not confer certification. Only intake execution can record A2, and neither a model nor an approval can promote an under-certified source.
Common Failures#
Symptom |
What it means |
|---|---|
|
Add one |
|
A success case claims |
Unknown tool or unsafe |
Case ids and tool names must match |
Timeout case with an outcome field |
Remove |
More than one timeout case |
Keep a single timeout probe. |
Clock without a timezone |
Use an ISO-8601 value with an explicit offset or |
Literal is not grounded |
Bind the argument to reviewed fixture state unless its schema pins an enum or boolean. |
Undeclared argument |
Remove it; every drafted argument name must appear in that tool’s parameter schema. |