Review the available design information¶
scene.check().ok means that the static checks found no errors. A cell
with unidentified equipment, missing specifications or unrecorded electrical
properties can still satisfy that condition. bt.review makes those gaps
visible alongside the evidence available from a cell report.
import botrail as bt
review = bt.review(scene, stage="design")
print(review.to_markdown())
review.save("design_review.json")
for item in review.blockers():
print(item.id, item.target, item.status, item.next_action)
The review reads the scene; it does not simulate or assign missing values.
It preserves the existing check(), requirements(), cell_report() and
bom.total() contracts. The new report includes the static check as
review.check, the optional cell report as review.cell_report, and items.
Reading an item¶
| result | meaning |
|---|---|
pass |
the named comparison passed, or the named execution/measurement was supplied |
fail |
an explicit inconsistency or static error was found |
unknown |
inputs are incomplete, or the supplied observation cannot establish the requested conclusion |
not_run |
no relevant execution, comparison or document evidence was supplied |
not_applicable |
no applicable target, or an explicit author-supplied reason for excluding this item |
Each item has an id, group, target, message, basis, evidence,
next_action, required and blocking. review.counts counts each status.
Equipment identity and specification comparisons are separate items: a model
number does not fill a missing payload rating. A BOM line for which no
specification comparison was derived is not_run.
Electrical items check assignments and declared field/channel voltage
and logic. Missing values on either end are unknown. A known mismatch
is fail even when the existing I/O lint calls it a warning. Voltage uses
the same 0.5 V tolerance as that lint, not voltage-range or circuit analysis.
Internal/cosmetic points need no physical channel. Numeric interfaces remain
explicitly unevaluated.
Choosing the review scope¶
| stage | required groups by default |
|---|---|
concept (default) |
checks |
design |
checks, equipment, specifications, connections, simulation |
required adds group names or exact item IDs. Other groups are totals,
scenarios and deliverables.
review = bt.review(scene, stage="concept", required=["connections", "totals"])
assert review.ready, review.to_markdown()
Explicit failures block either stage, including in optional groups.
Required items with unknown or not_run also block. Concept reviews may
leave equipment selection and specifications unresolved; these items stay
visible. Additional requirements never remove a stage's defaults. Unknown
group/item names raise ValueError.
ready applies to the listed review scope. It does not certify a
complete design, infer omitted equipment, evaluate project-specific cycle
budgets or clearance margins, or establish safety performance. Project
acceptance conditions still belong in the project's tests.
Known subtotals¶
By default the review counts whole-BOM mass_kg. Each subtotal contains
known_subtotal, target_qty, known_qty, targets and missing.
Five panels with known mass and four components without it are explicitly
reported as five of nine items contributing. All values missing yields
None; a supplied zero is known. Non-numeric, negative or non-finite values
are listed as missing/invalid.
review = bt.review(scene, required=["totals"], totals={
"mass_kg": None, # the whole BOM
"current_a": ["valve", "photo_eye"], # these declared loads only
})
print(review.totals["current_a"])
Include every name of a merged BOM row when selecting it: its quantity
cannot be split reliably from names alone. Unknown names are rejected.
totals={} requests no subtotal. The review does not infer which equipment
uses a particular utility; select the applicable loads explicitly.
These are sums of declared values. For supply-specific capacity checks, use
the physical connection plan. It sums directly connected
loads and preserves unknown consumption. The review includes its findings
under connections:physical:..., and checks each power supply's specification
against these budgets. A supply without a declared supply port stays
unknown. The former whole-BOM current requirement is removed.
Simulation evidence¶
runs = scene.simulate_scenarios(["pick"])
measured = scene.cell_report(scenarios=runs)
review = bt.review(scene, report=measured, sequences=["pick"], stage="design")
review.save("design_review.md")
A program without a matching baseline cycle in the supplied report is
not_run. Clearance is a separate measurement: a completed bake does not
fill a skipped scan. No robots or no environment obstacles makes that
measurement explicitly not_applicable.
Executed scenarios retain the observed completion/failure but remain
unknown: neither outcome alone establishes expected-behaviour acceptance.
Before execution they are not_run. Caller-supplied deliverable digests remain
unknown for revision consistency: hashes alone do not establish a common
design revision. No deliverable records means not_run.
Use bt.review(scene, manifest="deliverables/rev1/cell_manifest.json") to
verify a batch export
against the current cell before using its report. The package supplies the
program scope unless explicitly supplied; a different scope blocks the review.
Changed inputs/files block the review, generated files with verified provenance
pass their revision check, and external attachments remain unknown. Export
warnings and PLCopen stubs are separate unresolved items. Add
required=["deliverables"] to make resolving those items a review requirement.
When using report= directly, correspondence with the scene is the caller's
responsibility. Neither report mode evaluates FAT expectations. Requiring
scenarios or deliverables keeps unevaluated conclusions visible as blockers.
Sources and follow-up work¶
Use the report's item IDs to attach a source, assumption or follow-up:
review = bt.review(scene, annotations={
"connections:(unhosted):input:eye:voltage": {
"source_kind": "manufacturer",
"reference": "sensor_datasheet.pdf p.3",
"assumptions": "Confirm the ordered revision",
"owner": "electrical design",
"next_action": "Confirm the sensor output voltage",
},
})
source_kind accepts manufacturer, user_input, assumption, derived,
measured or unknown. Manufacturer/measured sources require a reference;
a catalog identity alone does not establish a specification's source.
Optional due records the follow-up date as text. Annotation values must
be nonempty strings; unknown IDs/fields are rejected. A reference supplies
no missing specification value and does not resolve an unknown result.
An annotation can contain not_applicable with a reason, for example when
PNP/NPN comparison is inapplicable to a dry contact reviewed separately.
The original status stays in evidence.observed_status. Explicit failures
cannot be excluded this way. Review options are separate inputs; they are
not added to the .botrail project.
Command line¶
botrail review cell.py
botrail review cell.py --stage design --simulate --report review.md
botrail review cell.py --scenarios --require scenarios
botrail review cell.py --config review_options.json --markdown
--config accepts a JSON object with required, totals and/or annotations,
as in Python. Repeatable --require adds to configured requirements.
--scenarios implies simulation; --sequence selects programs. JSON is
printed by default. Exit codes are 0 for a ready review scope, 1 for
unresolved items or a failed bake, and 2 for invalid input/configuration.
Existing botrail check exit codes are unchanged.
review
¶
review(
scene,
*,
report=None,
manifest: str | Path | None = None,
sequences: list[str] | None = None,
stage: str = "concept",
required: Iterable[str] | None = None,
totals: Mapping[str, Iterable[str] | None]
| None = None,
annotations: Mapping[str, Mapping[str, str]]
| None = None,
) -> ReviewReport
Review the design information available for a cell, without baking it.
report is an optional Scene.cell_report() result. Alternatively,
manifest verifies an export_cell package against this cell and
uses its report and program scope. Invalid packages block the review;
external attachments and export warnings remain unresolved.
sequences
selects the programs being reviewed (default all). stage='concept'
permits unresolved information outside static checks; 'design' also
requires equipment identity, specifications, connections and simulation.
An explicit failure blocks either stage, even in an optional group.
required adds group names or exact item IDs to that stage's scope.
totals selects numeric attributes and BOM names to count, e.g.
{'current_a': ['valve', 'eye']}; None as a selection means the
whole BOM. By default only whole-BOM mass_kg is counted. Supply
capacity and power consumption are not inferred from these subtotals.
annotations is keyed by item ID. It accepts source_kind (one of
manufacturer/user_input/assumption/derived/measured/unknown), reference,
assumptions, owner, due, next_action and not_applicable
(a nonempty reason). Manufacturer/measured sources require a reference.
An annotation documents an input; it never fills a missing value or
turns a failed comparison into a pass. An explicit failure cannot be
marked not applicable. Unknown item IDs are rejected.
ReviewReport
¶
Review observations, known subtotals and unresolved required items.
The original check and optional cell_report are included as JSON
snapshots. A supplied cell report is evidence supplied by the caller;
its correspondence to the current scene is not authenticated here.
ReviewItem
¶
One observation; an explicit failure blocks every review stage.
next_action
class-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
required
class-attribute
¶
bool(x) -> bool
Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.