Complex identification: the field guide
The one-page working reference. The concept page explains why it works this way and the authoring page covers building a pack from scratch; this page is what you keep open while running one. Examples use the shipped garden-survey pack.
The mental model, in six steps
- Detect. Every sampled frame is scanned: the wide-net model pass proposes codeable things with boxes, and free geometric detectors add candidates the model misses (thin linear features especially).
- Track. Proposals are followed across frames. One physical thing = one track, however many frames it appears in. Code flip-flop within a family never splits a track.
- Funnel. Free checks decide what deserves a paid call: an area floor, shape routing for thin candidates, sheet screening for unproposed regions, the registry gates run on proposals, and tracks cluster into whole features.
- Confirm. Each feature gets ONE model call with its best views, the stage-1 proposal, and a verdict expected: confirm, reclassify with a reason, or withdraw.
- Gate. The answer passes the deterministic gates: enum lock, legality, surface, region, host, channel, extent, residual, readings, grade lookup. Anything contradictory is kept and flagged to review, never dropped, never silently accepted.
- Record. Instances project to records per each code's record mode; the report collapses runs to start-finish, the portal layer keeps every frame.
One sentence: the model sees, the standard decides, and everything doubtful goes to review with its reason attached.
Commands
# codebook lifecycle neuraframe codebook # what pack is set, and the reuse setting neuraframe codebook check DIR # validate a pack: every problem listed, nothing silent sudo neuraframe codebook use DIR # set the pack sudo neuraframe codebook off neuraframe codebook reuse on|off # reuse gate while coding (default off) # the runner neuraframe codebook run --input FILE_OR_FRAMEDIR --out DIR [--config run.json] [--stub] neuraframe codebook run --help # every run-block knob as a --flag
--stub runs the whole spine with zero model calls. Use it before every live run and
after any pack edit. A folder of ordered frames works as input too. Common overrides (flags win
over the config file):
--sample-fps 4 # examine more frames per second (0 = every frame) --start-ms 60000 --end-ms 120000 # code one window of the footage --equirect off # flat footage instead of 360 --detector local # free detection instead of the model wide net --residual-pass on # second look after masking confirmed findings --workers 8 # concurrent confirmation calls
The pack: seven files, all yours
my_pack/ manifest.json the domain tables: context, bands, legality, regions, hosts, readings, surfaces registry.json every code: family, mode, grading, evidence, hosts, regions, floors rules.md domain knowledge, rides on EVERY model call detect.md task framing for the wide-net pass (used verbatim) confirm.md task framing for the confirmation pass (used verbatim) notes.md optional standing site guidance, appended to confirmations excluded.json codes out of scope for this deployment
Edits to the .md files apply on the next run, no rebuild. After editing the .json files, run
check, then use again.
A registry entry, every key that matters
{"code": "WGD", "title": "Growth, dense run",
"family": "growth", groups codes for tracking and remap; families never merge
"record_mode": "EXTENSIVE", SINGULAR point | EXTENSIVE run | REPEATED per host |
PROMOTABLE point-that-can-become-run | STATE reader
"graded": true, "band_set": "A",
"grading": {"ornamental": {"type": "threshold", "rules": [
{"band": "<=10", "grade": 2}, ...]}}, per context column; fixed or threshold
"expected_region": "ground", geometric legality, checked against OUR tracked position
"evidence_primary": "L", L structure | C colour | T rate and motion
"requires_host": ["stake"], what must independently exist nearby (manifest hosts says how)
"state_trigger": "survey_start", STATE only: survey_start (always exists, anchored at start)
| on_change (exists ONLY at a transition; absent is normal)
"residual_code": true, a last-resort bucket: rejections required, downgrades logged
"min_extent": {"min_sightings": 6, "min_clock_span_hours": 3}, extent floor, BOTH must hold
"anchored": true, survey structure from the job header, never inferred from imagery
"position_constraint": "survey_boundary", may only exist at the survey start or end
"clock_applicable": false, occupies the full view; a position-localised candidate is not it
"fields": {"cont": "-"}} cont "-" forbids a run for this code
Rule of thumb: the model only ever answers what a camera can see (a code, a band, real or not, a note, declared readings). Everything else in the entry is deterministic engine work.
The manifest tables, what each does
| Table | What it does |
|---|---|
context_fields + defaults | The job facts. Anything defaulted is stamped on every record as an assumption a reviewer can see. |
grading_field / grading_columns | Which context field selects the grading column. |
band_sets | The percentage ladders codes resolve grades on. |
legality | Context value to illegal families. Unknown context = the gate stands down, never blocks. |
conditional_legality | Codes only legal under certain context. Blocking, not advisory. |
presence_gated_families | Families only legal when a context flag is true. |
remap_families | Letter-to-family routing for loose model codes; kept for recoding, never dropped. |
surfaces + surface_rules | What surface a code may sit on. |
regions | Clock-position definitions that make expected_region machine-checkable. |
hosts | What satisfies each requires_host name: nearby codes/families, a context fact, external (never inferable from imagery, routes to review), or visual (the confirmation call judges). |
readings | Numeric values some codes carry, asked in YOUR words with the datum named, range-validated. |
state_at_start | Fallback list of anchored states; the registry's state_trigger wins when declared. |
run config: the four blocks
One JSON (--config): run (sampling, detection, funnel, tracking - also
CLI flags), coder (endpoint, dossier, location, channels), records
(projection and verification thresholds), context (the job facts). The
Vision CLI reference documents every knob; the ones you will
actually reach for:
| Knob | Default | Why you would touch it |
|---|---|---|
run.sample_fps | 2 | More frames examined = more sightings, more cost. 0 = every frame. |
run.detector | local | model is the propose-then-confirm accuracy setup. |
run.equirect | off | On for 360 footage: seam-aware, clock-aware tracking. |
run.min_seen | 2 | Sightings to qualify; singles go to review. |
coder.views_per_dossier | 4 | Frames of the same feature per confirmation call. |
coder.constrained_codes | off | On = the model answers item numbers; transposition impossible. |
records.merge_gap_ms | 4000 | The same-physical-thing constant (also drives feature clustering). |
run.price_in / price_out | - | Your $/1M tokens; the cost block then shows dollars. |
Outputs
| File | What it is |
|---|---|
report.md | The deliverable: one row per finding (runs as start-finish spans, wrapping findings as clock spans), then the review queue with reasons. |
portal.jsonl | One row per FRAME per finding, all tagged the same feature_id. Scrub anywhere, see the finding. Never collapsed. |
segment.json | Records, ratings, review, assumptions, the funnel and cost metrics, and the exact configuration used. |
observations.jsonl | Every per-frame annotation, dense, with the stage-1 proposals. |
dossiers/*.jpg | Exactly what the model was shown, per decision. |
The review queue, decoded
The review queue is the recode workbench: everything the engine kept but would not certify, each with its reason. What the reasons mean:
| Reason starts with | It means | What to do |
|---|---|---|
below_min_seen | Seen once - usually a blip | Confirm real, or ignore |
uncoded_or_off_book | No valid code (a failed call, or an unknown answer; the evidence rides along) | Recode by hand |
gate_flagged: surface/region_mismatch | Coded somewhere that code cannot be | Usually a recode |
gate_flagged: suspect_channel | A structure code with colour-only support - probably a stain | Check the dossier |
gate_flagged: residual_unjustified | A catch-all answered with no rejections of the specific alternatives | Recode to the specific |
gate_flagged: residual_downgrade_review | One call overrode a well-supported proposal with a catch-all | Judge the dossier yourself |
host_missing | The code asserts something else exists nearby, and it does not | Check the host, or recode |
pregate_* | Refuted before any money was spent (the same rules, run on the proposal) | Scan; mostly ignore |
extent_below_floor | An extent-gated code below its sighting or span floor | Recode - it is not that thing |
state_unchanged | A state sighting with no real change | Ignore - kept for comparison |
context_contradiction | A record inconsistent with what the rest of the record set implies | Check the job facts |
anchored_structure | The model named a boundary landmark for a tracked feature; the real record comes from the job header | Set the anchor type in context |
position_constraint | A boundary-only code seen mid-survey - a contradiction, not an observation | Usually the scene ahead |
clock_localised | A full-view code localised to one position - a wall feature by construction | Recode to what it actually is |
The numbers to watch
- The funnel line - raw detections, past the floor, tracks, screened, pregated, features, confirm calls. Where the money went.
- not_a_finding rate - under ~20% is healthy. High means incoherent dossiers or a leaking funnel, not a careful model.
- The conversion table - proposed vs recorded, per code. A code proposed hundreds of times and recorded zero is a systematic override, not a series of judgments.
- code_mix - the top code's share of findings. Most findings on one code is a degenerate distribution whichever code it is.
- Portal sanity - sighting counts equal portal rows, exactly; the run warns if not.
- Clean-scene calibration - run footage with nothing in it; the target is zero emissions, and everything emitted is a false positive by construction.
Recipes
- Flat (non-360) footage:
--equirect off, and considercoder.location_mode: "grid". - Cheaper pass:
--detector local --sample-fps 1. Less accurate; the funnel still runs. - Something got missed: check the review queue first (it is usually there), then the conversion table, then
--residual-pass onfor overlapping conditions. - The model keeps confusing two codes: add a discriminator line to
rules.md. It rides on every call, next run, no rebuild. - Tune a floor or threshold: registry
min_extent, the run-block knobs, the records thresholds - all policy, all yours. Re-runcheckafter registry edits. - One-off site guidance: point
coder.notes_fileat a text file for that job. - Prove a fresh install, free:
python3 vision/nf_codebook_board.pyruns the mechanism board;--stubproves your pack and config end to end.