SPEC-041 · TYPE M · SIZE L · V1
READY FOR BUILD
Low-light retrieval fidelity for open-vocabulary camera search
ML / AI EDGEPUBLIC-SECTOR SURVEILLANCERFC2119CLS-2026-09-04 · LIVE
PART I · THE DECISIONHUMAN · NON-NORMATIVE Read this to decide whether the build should exist. An implementation agent skips it.
WHERE THIS SITS
The product makes cameras a customer has already installed searchable in plain language, on the customer's own hardware, with no fixed list of things it can find. A conventional system answers "was there a person" because someone trained it on a class called person; this one answers "a man in a light jacket carrying a long bag near the north gate" because nothing was enumerated in advance. This spec covers the hours when that promise is weakest and the customer needs it most.
DECISION ORIENTATION
Problem. Open-vocabulary search degrades exactly when security work matters. After dark a camera switches to infrared illumination: the colour channel stops carrying information and the noise floor rises. A model trained on well-lit imagery does not fail loudly on that input; it returns a confident, ranked, wrong list.
Who + inheritance. A security operator searching a live network at night, under time pressure. Inherits the committed capability "illumination-aware retrieval path", its kill conditions, and the deployed density that defines unit economics: fifty concurrent feeds on one consumer GPU.
The build. Classify the lighting of every segment, route infrared and low-lux crops to an embedding head trained for them, suppress query attributes the signal cannot carry, and decline to answer when nothing is left to match.
Scope and risk. Four bounded work packets inside the perception and query paths. No change to stream acquisition, storage or the index.
VERDICT · MAKES SENSE: the honest half (the gate, the marker, the abstention) is cheap, ships before the model work, and converts an invisible failure into a visible limit. Does not make sense if the improved head cannot beat the current head by 12 points of recall on infrared footage after two training cycles, or cannot hold fifty feeds.
JOB TO BE DONE
"When I am searching a camera network at two in the morning against a description I was given over the radio, I want to know what this lighting can and cannot answer, so I spend the next ten minutes on the cameras that can answer it."
WHAT THE OPERATOR SEES
MOMENTTODAYWITH THIS BUILD
"red jacket, north side" at 02:0020 confident results, no lighting shownInfrared results marked "Infrared (no colour)", with "Unavailable in this lighting: red"
"anything red" at 02:00A ranked list scored on noise"Not enough signal to answer." Try shape, object, or text.
A camera at duskSame treatment as noonMarked "Low light"; colour retained, the signal still carries it
Footage indexed before this buildSilently treated as daylightMarked "Lighting not assessed"
LITERAL STRINGS ARE BOUND IN §4 · IF SURFACE AND VOCABULARY DISAGREE, §4 GOVERNS
OPTIONS CONSIDERED
Illumination-aware retrieval path CHOSENHonest results immediately, better results after the head lands. Two moving parts.
A preset night-object classifierReliable, quickly, but a return to the enumerated categories this product exists to remove.
Frame enhancement pre-embedderOne component, no routing, but it invents pixels, and an enhanced hallucination is still a hallucination.
A cloud-hosted night modelBest available weights, but this breaks the on-premises deployment that makes the product installable at all.
THE THREE RISKS THAT MATTER
RISKTRIGGER YOU WOULD SEEWHAT HAPPENS
The night ceiling is in the signal, not the modelInfrared recall fails to beat the current head by 12 points after two cyclesHALT
The second head costs feeds50-feed all-infrared bench drops a feed or exceeds 22 GBHALT
A colour term the gate does not recogniseAn unlisted colour-dependent term scored on an infrared segmentRESIDUAL · §18
Business impact. Roughly half the clock is dark. A retrieval product that cannot be trusted for half the recorded day is bought as half a product, and the failure is invisible at demo time, which means it is discovered post-sale.
PART II · THE BUILD CONTRACTAGENT-EXECUTABLE
PART I IS NOT BUILD INPUT · IF IT CONTRADICTS PART II, PART II GOVERNS
§0 · HEADER
spec_id: SPEC-041
spec_type: M # model_or_algorithm
agent_executable: true
size_class: L status: ready_for_build
domain_profile: ml_ai_edge
regulatory_class: public_sector_surveillance
target_agents: [claude-code, codex]
scope_in:
- perception/illumination/**
- perception/embedding/**
- query/planner/attribute_gating.**
- ui/results/** # markers only (REQ-007)
- eval/lowlight/**
scope_out:
- ingest/rtsp/** # out of scope under any instruction
- storage/retention/**
- deploy/customer_configs/**
source_of_truth: this file
§1 · AGENT OPERATING INSTRUCTIONS
→Build only P0 items in §10. P1 begins after every P0 passes verification.
→Modify only scope_in. Never touch scope_out. Report the conflict instead.
→Never implement anything in §18. If a §18 item blocks you, stop and report the blocking pair.
→Use only §4 vocabulary in identifiers and user-facing strings.
→A cast is not a check. The regime arrives as a typed enum; validate it at the seam.
→Every guard ships a negative test, shown firing on a fixture built to trip it.
→Any counter reports both arms. A counter that only increments cannot distinguish never-seen from never-ran.
→Not every verification is yours to run (§14.2). Never mark one of those passed.
→If the spec is ambiguous or self-contradictory, stop. Never resolve ambiguity by inference.
§3 · CONSTRAINTS AND PROHIBITIONS
MUST
CON-001Sustain 50 concurrent 1080p@15fps feeds on one RTX 4090 (24 GB) with the low-light path enabled.
CON-002All inference on-premises. No frame, crop, embedding or query text leaves the customer network.
CON-003Derive the regime per segment from decode-path frame statistics. No new sensor input, no vendor API.
CON-004Added end-to-end query latency ≤ 120 ms at p95 over the current baseline.
CON-005Every retrieval result carries the regime it was produced under, including unassessed.
MUST NOT
PRO-001Return a match scored on a gate-classified colour attribute from an ir_monochrome segment. Colour does not exist in that signal.
PRO-002Silently substitute the low-light head for the daylight head. Every routing decision is recorded.
PRO-003Introduce a cloud model endpoint, a telemetry beacon, or any egress path.
PRO-004Reduce daylight recall to buy low-light recall. Daylight is a hard floor, not a trade.
PRO-005Introduce a preset object-category vocabulary into the retrieval label space. Open vocabulary is the product. Carve-out: the ENT-003 attribute lexicon constrains what the parser may suppress, never what the system may retrieve.
REQUIRES HUMAN APPROVAL
APR-001Any change to the deployed embedding model version on an existing install. Adding the low-light head counts; the gate is §15 step 5.
§4 · CLOSED VOCABULARY
TERMIDENTIFIERUSER-FACING STRING
Segmentsegment· not clip, chunk, window
Infrared monochromeir_monochrome“Infrared (no colour)”
Low-lux colourlow_lux_colour“Low light”
Daylightdaylight“Daylight”
Unassessed lightingunassessed“Lighting not assessed”
Attribute gateattribute_gate“Unavailable in this lighting”
Abstentionabstain“Not enough signal to answer”
Regime marginregime_margin· not score, probability, certainty
NO SYNONYMS, IN CODE OR COPY · IF A NEEDED TERM IS MISSING, STOP AND REQUEST IT
§7.1 · REGIME CLASSIFICATION · DETERMINISTIC
// inputs: mean_luma, luma_p05/p95, chroma_energy, temporal_noise
1 if chroma_energy < 2.0 and mean_luma < 90 → ir_monochrome
2 elif mean_luma < 40 or (temporal_noise > 8.0
and mean_luma < 70) → low_lux_colour
3 else → daylight
stats invalid / unavailable → unassessed (0.0)
margin(value, threshold) = clamp(|value − threshold| / threshold, 0, 1)
rule margin = min over conjuncts, max over disjuncts
// worked: chroma 0.7, luma 31.4 → min(0.65, 0.651) = 0.65 ir_monochrome
// counter: chroma 14.2, luma 28.0 → low_lux_colour, margin 0.30 (never IR)
§7.2 gating. On ir_monochrome, drop every colour-valued attribute before scoring and record it. low_lux_colour retains colour; the channel is noisy, not absent. unassessed applies no gating and says exactly that on the result. “red van” reduces to “van”; “anything red” reduces to nothing and must abstain.
§10 · FUNCTIONAL REQUIREMENTS
REQ-001 P0Regime is computed for every segment
GIVENa decoded 2 s segment
WHENstatistics are available and valid
THENa segment_illumination record is produced with a typed regime and confidence
ANDthe computation adds no more than 3 ms per segment per feed
VERIFICATION TST-001 · DEPENDS ON ENT-001
REQ-002 P0Routing is recorded, never implicit
GIVENany segment
WHENthe regime router selects an embedding head
THENhead_used and regime are written to the retrieval_result
ANDthe head counter emits both arms every query, zeros included
VERIFICATION TST-002 · SATISFIES PRO-002
REQ-003 P0Colour attributes are dropped on infrared segments
GIVENa query containing an ENT-003 colour-valued attribute
WHENthe segment regime is ir_monochrome
THENthe attribute is removed before scoring and listed in attributes_dropped
ANDno returned result is scored on that term
VERIFICATION TST-003, TST-005 · SATISFIES PRO-001
REQ-004 P0A query with nothing left to match abstains
GIVENa query whose every attribute is dropped by the gate
WHENresults would otherwise be ranked
THENthe system abstains and returns ERR-003 (ST-004a)
VERIFICATION TST-004
REQ-006 P0Feed density is preserved under the worst case
GIVEN50 concurrent 1080p@15fps feeds, all in ir_monochrome
WHENthe low-light path is enabled
THENno feed is dropped and peak GPU memory stays under 22 GB
VERIFICATION TST-006 · SATISFIES CON-001 · EXECUTOR: HUMAN
REQ-008 P0Pre-existing footage is marked, never assumed
GIVENa segment indexed before this build, with no illumination record
WHENit is searched
THENit is returned as unassessed with the “Lighting not assessed” marker
ANDno attribute gating is applied to it · statistics are NOT backfilled
VERIFICATION TST-013 · SATISFIES CON-005
§15 · BUILD PLAN
#DELIVERABLEGATE
0Baselines measured and frozen: BASE_IR, BASE_LOWLUX, BASE_DAY written into §12.2STOP
1segment_illumination entity, statistics, validation, ERR-004 path, fixturesAUTO
2Regime classifier with both §7.1 worked examples reproduced exactlySTOP
3Regime router and both-arm countersAUTO
4ENT-003 lexicon, attribute gate, ST-004a abstentionAUTO
5Low-light embedding head integrated behind the routerSTOP + APR-001
5bRegime score floors measured and written as versioned constants; ST-004bSTOP
6Failure paths, fallback, and the REQ-009 runtime switchAUTO
7Unassessed marking; surface markers and dropped-attribute displaySTOP
8Density and egress verificationAUTO
9Traceability matrix and §17 evidence tableSTOP
A STOP GATE MAY NOT BE PASSED BY SELF-ASSESSMENT · EVIDENCE MEANS AN ARTIFACT
§18 · OPEN QUESTIONSDO NOT IMPLEMENT
OQ-001 · Is customer footage usable for training under the existing data agreement, per install? Blocks DS-NIGHT-TRAIN scope · needed before step 5.
OQ-002 · Does glare need handling in v2, and as what? A peer regime would route a saturated night frame to the daylight head and un-gate colour.
OQ-003 · Which IR illuminator hardware is in the deployed base? Wavelength changes what the head must handle · blocks EVL-001 slice design.
OQ-004 · Do any deployed installs receive non-English queries? The lexicon is English-only, which puts PRO-001 at risk on that install.
KILL CONDITIONS INHERITED FROM THE UPSTREAM DECISION
Recall on infrared footage fails to beat BASE_IR by 12 points after two training cycles: halt. The ceiling is in the signal, not the model.
CON-001 cannot hold at 50 all-infrared feeds: halt. A slower pipeline is a different product.
END OF CONTRACT · §0–§18 · LAST HUMAN REVIEW 2026-09-04SOURCE OF TRUTH