thundercode commited on
Commit
6b7a6df
·
verified ·
1 Parent(s): cf51713

release: add docs/GLOSSARY.md

Browse files
Files changed (1) hide show
  1. docs/GLOSSARY.md +309 -0
docs/GLOSSARY.md ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Glossary — deep reference
2
+
3
+ **Purpose.** This is the vocabulary the rest of the documentation uses, defined precisely, with the
4
+ file that **defines or enforces** each term. A term is only listed if it appears in the repository; a
5
+ definition is only given if a file supports it.
6
+
7
+ **Status tags used on every substantive claim:** `IMPLEMENTED` · `VERIFIED` · `MEASURED` ·
8
+ `ATTEMPTED` · `NOT RUN` · `BLOCKED` · `DEFERRED` · `REJECTED` · `OPEN` · `RESOLVED` · `CLOSED`.
9
+
10
+ **The single most important rule in this document: do not fabricate.** Every definition is grounded in
11
+ a file that was read, and the file is named. Where a term's meaning is not established, this document
12
+ writes `UNKNOWN — not established from the available evidence` rather than inventing one.
13
+
14
+ ---
15
+
16
+ ## How to use this glossary
17
+
18
+ The entries are grouped so that a reader can read one group at a time:
19
+
20
+ | Part | Group | Jump |
21
+ |---|---|---|
22
+ | A | Tasks | [§A](#part-a--tasks) |
23
+ | B | Models and methods | [§B](#part-b--models-and-methods) |
24
+ | C | Metrics and losses | [§C](#part-c--metrics-and-losses) |
25
+ | D | Data and geospatial | [§D](#part-d--data-and-geospatial) |
26
+ | E | System concepts | [§E](#part-e--system-concepts) |
27
+ | F | Deployment and operations | [§F](#part-f--deployment-and-operations) |
28
+ | G | Status vocabulary | [§G](#part-g--status-vocabulary) |
29
+ | H | Index — where each term is defined or enforced | [§H](#part-h--index-where-each-term-is-defined-or-enforced) |
30
+
31
+ Each entry gives a **precise definition**, the **file that defines or enforces it**, and, where
32
+ relevant, a **cross-link** to the deep chapter that covers it in full.
33
+
34
+ ---
35
+
36
+ ## Part A — Tasks
37
+
38
+ The task vocabulary is a **closed set** with exactly **seven** members, defined once in
39
+ `core/schemas.py` (`class Task(str, Enum)`) and mirrored in the router's label space
40
+ (`router/label_space.py::TASK_CLASSES`). The three are not interchangeable and the planner must not
41
+ substitute one for another — `core/schemas.py:41-46` says so in a comment on `CHANGE_VQA`.
42
+
43
+ | Term | Definition | Defined / enforced |
44
+ |---|---|---|
45
+ | **`vqa`** | Visual question answering about **one** asset: a natural-language question in, a short answer out. Runs through the SmolVLM specialist. | `core/schemas.py:36` (`Task.VQA`); `router/label_space.py`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §7 |
46
+ | **`caption`** | A prose description of **one** asset. Same specialist as `vqa`, a different prompt kind. | `core/schemas.py:37`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §10 |
47
+ | **`grounding`** | Localisation: a text phrase in, boxes out. RemoteCLIP encoder + a trained head. The VLM is **never** the source of coordinates (finding C-5). | `core/schemas.py:38`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §11–§17 |
48
+ | **`change`** | The change **detector**: two temporally corresponding assets in, a spatial change map out, **no language output**. STANet-style Siamese network. | `core/schemas.py:39`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §18–§26 |
49
+ | **`change_vqa`** | **R-02.** Two temporally corresponding assets **plus** a change-oriented question in, a short answer out. Distinct from `change` (which returns a map, no language) and from `vqa` (which answers about one asset). | `core/schemas.py:41-46`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §27–§32 |
50
+ | **`optical_sar`** | Fusion of an optical and a SAR asset: CROMA encoder + a trained fusion head over 19 classes. Requires **two** modalities. | `core/schemas.py:40`; `configs/base.yaml` (`croma`, `fusion`); [`architecture/05-specialists.md`](architecture/05-specialists.md) §33+ |
51
+ | **`unsupported`** | The **refusal** class. Returned when nothing matches — never a guess. The lexical fallback returns `unsupported` with low confidence rather than inventing a task (`router/fallback.py`). | `core/schemas.py:47`; `router/fallback.py`; enforced by `core/config.py:198-206` (the task list **must** include `unsupported`) |
52
+
53
+ **Related task facts.**
54
+
55
+ - **`temporal` / `spatial_output` / `language_output`** are three binary heads, not tasks.
56
+ `TEMPORAL_TASKS = {"change"}`, `SPATIAL_TASKS = {"grounding"}`, `DUAL_MODALITY_TASKS = {"optical_sar"}`
57
+ (`router/label_space.py`). `Intent._consistency` (`core/schemas.py:107-114`) forces `temporal = True`
58
+ for `change`/`change_vqa` and `modality = optical_sar` for `optical_sar`.
59
+ - **Asset-count contract.** `change`, `change_vqa` and `optical_sar` require **exactly 2** assets; `vqa`
60
+ and `caption` require **exactly 1** ([`MODELS.md`](MODELS.md) §3.0.3). The authoritative source is
61
+ `core/planner.CAPABILITY_ASSETS` and `SpecialistSpec.requires_assets`
62
+ (`docs/DEPLOYMENT_ARCHITECTURE.md` §2.2).
63
+
64
+ ---
65
+
66
+ ## Part B — Models and methods
67
+
68
+ ### B.1 Backbones (frozen)
69
+
70
+ | Term | Definition | Defined / enforced |
71
+ |---|---|---|
72
+ | **RemoteCLIP** | The frozen vision-language encoder used by `grounding`. Repository `chendelong/RemoteCLIP`, file `RemoteCLIP-ViT-B-32.pt`, revision `bf1d8a3ccf2d`. A CLIP ViT-B/32 adapted to remote sensing. **Measured contract:** patch size 32, transformer width **768**, **projected** dim **512** (`visual.proj` is `(768, 512)`), 151,277,313 parameters. At 224 px it yields a 7×7 = 49-token grid. | `configs/base.yaml` (`grounding`); `specialists/grounding/remoteclip.py` (`_verify_contract`); [`MODELS.md`](MODELS.md) §2.3 |
73
+ | **CROMA** | The frozen multi-modal encoder used by `optical_sar`. Repository `antofuller/CROMA`, file `CROMA_base.pt`, revision `0dd28e3d633b`. `encoder_dim` 768, `image_resolution` 120 (15×15 = 225 patches), `optical_channels` 12, `sar_channels` 2. **Asymmetric** (`s1_depth=6`, `s2_depth=12`), with **directional** joint cross-attention (SAR queries optical). 194,365,440 parameters. | `configs/base.yaml` (`croma`); `specialists/optical_sar/`; [`MODELS.md`](MODELS.md) §2.4 |
74
+ | **SmolVLM** | The frozen vision-language model used by `vqa` and `caption`. `HuggingFaceTB/SmolVLM-500M-Instruct`, revision `a7da5b986cb5`, ~1015 MB safetensors, 516,165,824 base parameters. | `configs/base.yaml` (`vlm`); [`MODELS.md`](MODELS.md) §2.2 |
75
+ | **MiniLM** | The frozen sentence encoder under the intent router. `sentence-transformers/all-MiniLM-L6-v2`, revision `1110a243fdf4`, 90.9 MB, 22,713,216 parameters, **384**-dim embeddings. Tokenizer ceiling **256**; truncation set to **128**. | `configs/base.yaml` (`router`); `router/encoder.py`; [`architecture/04-router.md`](architecture/04-router.md) §2 |
76
+ | **STANet** | The architecture family the `change` detector follows: a **Siamese** network with **spatial-temporal attention** over feature differences and a progressive decoder. Reimplemented rather than vendored (the upstream is Python 3.6-era and depends on `visdom`/`apex`). Weights are **tied**, not copied: both branches call the same `SharedResNetEncoder` instance. | `specialists/change/stanet.py`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §18 |
77
+
78
+ ### B.2 Attention modules
79
+
80
+ | Term | Definition | Defined / enforced |
81
+ |---|---|---|
82
+ | **PAM** | The **spatial attention** module used in the change detector (STANet's spatial path). `SpatialAttention` is PAM-style: 1×1 `query`/`key` convolutions to `hidden = max(1, channels // reduction)` with `reduction = 8`, a 1×1 `value`, a 1×1 `out`, `softmax(q @ k / sqrt(hidden))` over positions, and a residual. `configs/base.yaml` sets `change.sa_mode: PAM`. | `specialists/change/stanet.py`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §18.4 |
83
+ | **BAM** | The alternative attention mode in the same `sa_mode` enum (`BAM | PAM`). **It raises** — the constructor accepts the value only to fail visibly rather than silently aliasing PAM. | `configs/base.yaml` (`change.sa_mode`); `STANetStyleChangeDetector.__init__`/`.forward`; [`MODELS.md`](MODELS.md) §3.0.3 |
84
+
85
+ ### B.3 Adaptation and calibration methods
86
+
87
+ | Term | Definition | Defined / enforced |
88
+ |---|---|---|
89
+ | **LoRA** | Low-Rank Adaptation: a small trainable **delta** attached to a frozen model's weight matrices. Here it is applied to the SmolVLM **text-model projections** with `r=16`, `alpha=32`, `dropout=0.05`. 8,683,520 trainable parameters on a 516,165,824-parameter base (1.68%). | `configs/base.yaml` (`training.lora_*`); `artifacts/vlm/phase6_closure.json`; [`MODELS.md`](MODELS.md) §3.6 |
90
+ | **PEFT** | Parameter-Efficient Fine-Tuning — the library/technique family that provides the LoRA adapter. The adapter is loaded with `peft.PeftModel.from_pretrained(model, dir)`. | `specialists/vqa/model.py::_attach_adapter`; [`MODELS.md`](MODELS.md) §1.1 |
91
+ | **Temperature scaling** | A **post-hoc** calibration that divides logits by a single fitted scalar `T` before the sigmoid, to bring predicted probabilities closer to observed frequencies. Here `T = 0.9772731820958189`, fitted on `Val` with `n_samples = 16441`. | `evidence/engine.py` (`calibrate`, `confidence_for`); `artifacts/calibration_v001.json`; [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §8 |
92
+ | **`_is_effective`** | The rule that a "fitted" `T` of exactly 1.0 is reported as **uncalibrated** — a `T` of 1.0 applies no transform, so claiming calibration would be a lie. | `evidence/engine.py`; [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §8.3 |
93
+
94
+ > **The calibration result is a measured negative.** ECE went **0.013755 → 0.014929** (worse). The
95
+ > calibration path is retained **only because it is in the frozen config**, not because it helped
96
+ > (`DOCS_STYLE_GUIDE.md` §3; [`LIMITATIONS.md`](LIMITATIONS.md) item 7). The path **is** live
97
+ > (`core/controller.py:218` loads it; `evidence/engine.py:643` applies it).
98
+
99
+ ---
100
+
101
+ ## Part C — Metrics and losses
102
+
103
+ Metric implementations live in the evaluation layer; the honesty rules that govern how they are
104
+ reported are in [`EVALUATION.md`](EVALUATION.md) §2 (the eight rules) and
105
+ [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md).
106
+
107
+ | Term | Definition | Where it is used / defined |
108
+ |---|---|---|
109
+ | **IoU** | Intersection over Union — `|A ∩ B| / |A ∪ B|`. For grounding, the overlap between a predicted box and a ground-truth box; the headline is **mean best IoU**. For change, the pixel-level overlap of predicted and true change masks. | `docs/PHASE7_RESOLUTION_DECISION.md`; `artifacts/grounding/remoteclip_grounding_v001/eval_result_canonical.json`; `artifacts/change/eval_test/eval_result.json` |
110
+ | **mIoU** | Mean IoU across classes — the **macro** IoU. For binary change this is the mean of the two class IoUs (change / no-change). | `artifacts/change/eval_test/eval_result.json` → `metrics.macro.miou` = 0.8457, `metrics.pooled.miou` = 0.9007 |
111
+ | **Macro vs pooled** | **Pooled** aggregates all pixels (or all items) into one confusion matrix before computing the metric; **macro** computes the metric per class and averages, giving every class equal weight regardless of frequency. On an imbalanced corpus the two differ sharply, and both must be reported — never one alone. | [`DATASETS.md`](DATASETS.md) §3.5; [`EVALUATION.md`](EVALUATION.md) Rule 4 |
112
+ | **F1** | Harmonic mean of precision and recall. Reported both pooled (0.8964) and macro (0.7962) for change. | `artifacts/change/eval_test/eval_result.json` |
113
+ | **`exact_match`** | The fraction of VLM answers that match the reference answer **exactly** after normalisation. The VLM adapter's primary endpoint: **0.963** on 1,000 adapted-test questions. | [`architecture/05-specialists.md`](architecture/05-specialists.md) §9.3 |
114
+ | **`recall@k`** | The fraction of items where a correct prediction is found within the top `k` (here a threshold ladder: `Recall@0.10`, `@0.25`, `@0.50` for grounding IoU). | `artifacts/grounding/.../eval_result_canonical.json` → `results.head_threshold.recall`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §16.5 |
115
+ | **BCE** | Binary cross-entropy. Used for the router's three binary heads (via `BCEWithLogitsLoss`) and for the change detector's change/no-change logit. The **logits form** is mandatory — see below. | `router/label_space.py`; `specialists/change/`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §29 |
116
+ | **Dice** | A region-overlap loss closely related to IoU, used alongside BCE for change (`bce_weight: 0.5`, `dice_weight: 0.5`). *"Why Dice is not decoration"* — it counteracts the class imbalance BCE alone handles poorly. | `configs/base.yaml` (`change.bce_weight`, `change.dice_weight`); [`architecture/05-specialists.md`](architecture/05-specialists.md) §20.1 |
117
+ | **GIoU** | Generalised IoU — IoU extended with a penalty for non-overlapping boxes, giving a gradient even when boxes do not intersect. The grounding head's box loss uses `box_loss_weight: 0.5`, `giou_loss_weight: 0.3`, `confidence_loss_weight: 0.2`. | `configs/base.yaml` (`grounding_training`); [`architecture/05-specialists.md`](architecture/05-specialists.md) §13.6 |
118
+ | **NMS** | Non-Maximum Suppression — merges overlapping candidate boxes, keeping the highest-scoring and suppressing the rest above an IoU threshold. Grounding uses `nms_iou: 0.50`, `max_candidates: 20`, implemented in pure torch. | `configs/base.yaml` (`grounding.nms_iou`); `specialists/grounding/`; [`architecture/05-specialists.md`](architecture/05-specialists.md) §13.5 |
119
+ | **ECE** | Expected Calibration Error — the average gap between predicted confidence and observed accuracy across confidence bins. Here it went **0.013755 → 0.014929** after temperature scaling (worse). | `artifacts/calibration_v001.json`; [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §8; [`LIMITATIONS.md`](LIMITATIONS.md) item 7 |
120
+ | **NLL** | Negative log-likelihood — a proper scoring rule; improved marginally under calibration even though ECE worsened. | `artifacts/calibration_v001.json`; `docs/API_CONTRACT.md` §4 |
121
+
122
+ > **The saturated-BCE defect.** A `BCE` implemented from `sigmoid`-then-`BCE` divides the backward pass
123
+ > by `p(1−p)`, which explodes as `p → 0` or `1`. `BCEWithLogits` **cannot** saturate. The change-VQA
124
+ > head therefore uses the logits form, and the fallback is constrained accordingly
125
+ > ([`architecture/05-specialists.md`](architecture/05-specialists.md) §29).
126
+
127
+ ---
128
+
129
+ ## Part D — Data and geospatial
130
+
131
+ Dataset details are in [`DATASETS.md`](DATASETS.md); leakage controls are in
132
+ [`EVALUATION.md`](EVALUATION.md) §3.2–§3.3 and `configs/base.yaml` (`evaluation.leakage_split_key: scene_id`).
133
+
134
+ ### D.1 Datasets
135
+
136
+ | Term | Definition | Defined / used |
137
+ |---|---|---|
138
+ | **LEVIR-CD-256** | The change-detection corpus: 256×256 bitemporal building-change tiles. Split `train: 7120`, `val: 1024`, `test: 2048` (`configs/base.yaml` → `change.levir_split`). The test split is the **only** headline that carries the `VERIFIED` tag. | [`DATASETS.md`](DATASETS.md) §3; `artifacts/change/eval_test/eval_result.json` |
139
+ | **VRSBench** | The grounding corpus. Boxes are stored **normalised to 0–100**; the project stores 0–1, hence `grounding.benchmark_box_scale: 100.0`. Train split has **noisy ground truths** (recorded). The eval used **16,159** records. | [`DATASETS.md`](DATASETS.md) §5; `configs/base.yaml` (`grounding`) |
140
+ | **CDVQA** | One of the two change-VQA corpora (question/answer annotations). | [`DATASETS.md`](DATASETS.md) §4 |
141
+ | **SECOND** | The other change-VQA corpus. **Measured finding:** *Test and Test2 are the same 968 images*; and `change_ratio_types` has a **different vocabulary in every split**. The imagery is **not shipped** with the annotations. | [`DATASETS.md`](DATASETS.md) §4.2–§4.7 |
142
+ | **BigEarthNet** | The optical-SAR fusion corpus (the reBEN v2 corpus) and a separate VLM-adaptation subset. **19 CLC classes.** The local subset is **100 % single-label**, unlike the official 1–11 multi-label scheme, so its metrics are **not comparable** to published numbers. | [`DATASETS.md`](DATASETS.md) §6; `configs/base.yaml` (`fusion.num_classes: 19`) |
143
+ | **CLC classes** | The **CORINE Land Cover** class taxonomy — the 19 label classes the fusion head predicts. **Measured limitation:** the live service returns `class_18`, a bare class index, **not** a human-readable CLC label. | `configs/base.yaml` (`fusion.num_classes: 19`); [`LIMITATIONS.md`](LIMITATIONS.md) item 6 |
144
+ | **Single-label vs multi-label** | A sample is **single-label** if it carries exactly one class; **multi-label** if it carries several. BigEarthNet's official scheme is multi-label (1–11); the project's local subset is single-label, which is why the fusion metrics must not be compared to published BigEarthNet numbers. | [`DATASETS.md`](DATASETS.md) §6.4; [`LIMITATIONS.md`](LIMITATIONS.md) item 21 |
145
+
146
+ ### D.2 Geospatial and raster terms
147
+
148
+ | Term | Definition | Defined / enforced |
149
+ |---|---|---|
150
+ | **GeoTIFF** | A TIFF raster carrying georeferencing (a CRS, an affine transform, bounds). The project reads rasters via `preprocessing/raster.py` and records geo metadata in `GeoMetadata` (`core/schemas.py:120`). | `preprocessing/raster.py`; `core/schemas.py` (`GeoMetadata`) |
151
+ | **Band** | One channel of a raster (e.g. a single spectral band). `SensorDescriptor.available_bands` / `band_map` describe which bands a sensor provides. CROMA expects exactly **12** optical and **2** SAR channels. | `core/schemas.py:138` (`SensorDescriptor`); `configs/base.yaml` (`croma.optical_channels: 12`, `sar_channels: 2`) |
152
+ | **Optical** | Imagery in the visible/near-infrared; the default modality. CROMA expects **12** optical channels; the project normalises with a percentile stretch. | `configs/base.yaml` (`optical`); `core/schemas.py` (`Modality.OPTICAL`) |
153
+ | **SAR** | Synthetic Aperture Radar imagery. CROMA expects **2** SAR channels (VV, VH). Represented in **dB**. | `configs/base.yaml` (`sar`); `core/schemas.py` (`Modality.SAR`) |
154
+ | **dB** | Decibels — the logarithmic representation of SAR backscatter. `configs/base.yaml` sets `sar.representation: db`, `clip_min_db: -30`, `clip_max_db: 5`. | `configs/base.yaml` (`sar`) |
155
+ | **Percentile stretch** | A deterministic contrast stretch mapping the 2nd and 98th percentiles of finite values to the display range. *"The same file always yields the same"* result. Implemented in `preprocessing/imagery.py`. | `preprocessing/imagery.py:63`; `configs/base.yaml` (`optical.normalization: percentile`, `lower_percentile: 2`, `upper_percentile: 98`) |
156
+ | **`scene_id`** | A stable identifier for the acquisition scene a sample came from. It is the **leakage split key**: `evaluation.leakage_split_key: scene_id`. Splits are made by scene, **never by example**. | `configs/base.yaml` (`evaluation`); `core/schemas.py:163` (`AssetMetadata.scene_id`); [`DATASETS.md`](DATASETS.md) §7.3 |
157
+ | **Split** | A named partition of a corpus (`train` / `val` / `test`). Recorded on `AssetMetadata.split`. The public test split is **immutable** (`evaluation.immutable_public_test: true`). | `configs/base.yaml` (`evaluation`); `core/schemas.py:165` |
158
+ | **Leakage** | Any way that information from a test sample influences training, inflating measured performance. The project enforces five leakage rules in code and splits **by group** (template / hard-negative family), placing hard-negative families in **test** so their accuracy measures generalisation, not memorisation (finding F4-3). | `configs/base.yaml` (`evaluation.leakage_split_key`, `router.training.hard_negatives_to_test: true`); [`DATASETS.md`](DATASETS.md) §7.2; [`EVALUATION.md`](EVALUATION.md) §3.2 |
159
+
160
+ ---
161
+
162
+ ## Part E — System concepts
163
+
164
+ ### E.1 The pipeline's nouns
165
+
166
+ | Term | Definition | Defined / enforced |
167
+ |---|---|---|
168
+ | **Router** | The **first** of two stages: it reads the query and emits an `Intent`. It is **advisory only** — *"Output of the learned router. Advisory only — the controller decides."* (`core/schemas.py:95`). Implemented as a frozen MiniLM encoder plus a five-head adapter. | `router/`; `core/schemas.py` (`Intent`); [`architecture/04-router.md`](architecture/04-router.md) |
169
+ | **Controller** | The **second** stage and the decision authority. It parses, validates, plans, dispatches specialists, aggregates, verifies and responds — the nine-state spine. It may **override** the router (asset-count-aware dispatch, below). | `core/controller.py`; `core/schemas.py` (`ControllerState`); [`architecture/03-request-lifecycle.md`](architecture/03-request-lifecycle.md) |
170
+ | **Specialist** | A module that performs exactly one task and returns exactly one `SpecialistResult`. *"Every specialist returns exactly this. No exceptions."* (`core/schemas.py:326`). Five are registered. | `specialists/`; `core/schemas.py` (`SpecialistResult`); [`architecture/05-specialists.md`](architecture/05-specialists.md) §1 |
171
+ | **Evidence** | A single, typed, inspectable record supporting a result. It is the project's answer to *"never pretend it knows more than the evidence supports"*. Every `Evidence` has a `type`, a `source_specialist`, and (if spatial) a `coordinate_system`. | `core/schemas.py:216` (`Evidence`); [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §2 |
172
+ | **Evidence engine** | The module that turns many specialists' evidence into one ordered, deduplicated, capped collection, and that applies calibration to confidence. Pipeline: collect → dedup → sort → annotate → renumber → cap. | `evidence/engine.py`; [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §5 |
173
+ | **Confidence breakdown** | The structured confidence object: a `raw` value, an optional `calibrated` value, a `method` (`"uncalibrated"` or `"temperature_scaling"`), a `components` map, and a `degraded` flag with a reason. | `core/schemas.py:259` (`ConfidenceBreakdown`); [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §7.2 |
174
+ | **Calibrated vs uncalibrated** | **Calibrated** = a fitted transform was applied (`method: "temperature_scaling"`, `effective: true`). **Uncalibrated** = no transform, or a `T` of exactly 1.0 (`method: "uncalibrated"`). Reporting uncalibrated is **honest, not broken**. | `evidence/engine.py`; `core/schemas.py` (`ConfidenceBreakdown.method`) |
175
+ | **`ResultEnvelope`** | The **top-level response object** of `POST /v1/analyze`: a `run_id`, a `SpecialistResult`, and the `ExecutionTrace`, plus a `schema_version`. The route returns it **verbatim**, trace included. | `core/schemas.py:421`; `core/controller.py:394`; [`architecture/08-api-contract.md`](architecture/08-api-contract.md) |
176
+ | **`ExecutionTrace`** | The per-run record of what happened: `run_id`, `task`, `query`, `inputs`, `modalities`, `intent`, `validation`, `workflow`, `steps`, `selected_models`, `parameters`, `outputs`, `confidence`, `timings`, `fallbacks`, `errors`, `contradiction`, `config_hash`, `started_at`, `finished_at`. It is **client-facing**. | `core/schemas.py:296`; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §3 |
177
+ | **`Intent`** | The router's structured output: a `task`, a `modality`, three booleans (`temporal`, `spatial_output`, `language_output`), a `confidence`, and a `source` (`learned` | `lexical_fallback` | `forced`). | `core/schemas.py:94`; [`architecture/04-router.md`](architecture/04-router.md) |
178
+ | **`EvidenceType`** | The **closed 11-member** vocabulary of evidence kinds: `image_crop`, `tile`, `bounding_box`, `mask`, `change_map`, `optical_view`, `sar_view`, `joint_feature_region`, `statistic`, `geolocation`, `availability_mask`. | `core/schemas.py:65`; [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §3 |
179
+ | **`CoordinateSystem`** | The frame a coordinate is expressed in. **Exactly three** values: `normalized_0_1`, `pixel`, `geo`. *"Never omit this. A bare box is meaningless without it."* (finding C-5). | `core/schemas.py:57`; [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md) §4.1 |
180
+ | **`Region`** | A general spatial result: an optional `box`, an optional `mask_ref`, a `label`, a `score`, and a `coordinate_system`. | `core/schemas.py:189` |
181
+ | **`ChangeRegion`** | A change-specific region: a required `box`, `area_pixels`, `mean_probability`, an optional `stability`, and a `coordinate_system`. | `core/schemas.py:202` |
182
+ | **Availability mask** | A per-channel boolean vector recording **which bands a sensor actually measured**. It is consumed by the **fusion head**, **not** by CROMA (finding C-1) — because handing a masked autoencoder a mask invites it to reconstruct missing channels, precisely the fabrication the sensor adapter exists to prevent. | `core/schemas.py` (`SensorDescriptor.availability_mask`, `EvidenceType.AVAILABILITY_MASK`); `specialists/optical_sar/fusion_head.py`; [`MODELS.md`](MODELS.md) §3.0.1 |
183
+
184
+ ### E.2 Behavioural concepts
185
+
186
+ | Term | Definition | Defined / enforced |
187
+ |---|---|---|
188
+ | **Degraded** | A result flag meaning *"the analysis could not be fully performed"* — e.g. no trained detector, or co-registration too poor to support a spatial claim. It is **not** *"no change was detected"*, which is a **normal, successful** outcome. | `core/schemas.py:343` (`SpecialistResult.degraded`); `core/schemas.py:353-406` (the validator, incl. the F-16c correction); [`architecture/05-specialists.md`](architecture/05-specialists.md) §4.2 |
189
+ | **Fallback** | A recorded degradation, named in `ExecutionTrace.fallbacks` as a human-readable string. It records **what degraded**, not what was retried. | `core/schemas.py:314`; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §3.7 |
190
+ | **Lexical fallback** | The **deterministic, model-free** router path: ordered lexical rules, highest specificity first, first match wins. It has **no model, no embeddings, no randomness**, and it *"never invents capability"* — if nothing matches it returns `unsupported` with low confidence. Precedence: `dual_modality > temporal > spatial > caption > vqa > unsupported`. Used when the learned router is low-confidence, or when the encoder cannot load at all. | `router/fallback.py` (`lexical_route`, `self_check`); `core/schemas.py` (`Intent.source = "lexical_fallback"`) |
191
+ | **Dispatch** | The controller's act of choosing **which** specialist to run for a request. Dispatch is **asset-count-aware**: a change-style query with **one** asset reads `change` but **dispatches** `change_vqa`. The reading is asset-count-blind; the dispatch is not. | `core/controller.py`; [`architecture/04-router.md`](architecture/04-router.md); [`LIMITATIONS.md`](LIMITATIONS.md) item 13 |
192
+ | **Asset-count-aware** | The property that a decision accounts for **how many assets** were supplied. Exactly 2 assets for `change`/`change_vqa`/`optical_sar`; exactly 1 for `vqa`/`caption`. *"A silent 'just use the first two' produces a confident answer to a question the caller did not ask."* | `core/planner.CAPABILITY_ASSETS`; `SpecialistSpec.requires_assets`; [`MODELS.md`](MODELS.md) §3.0.3 |
193
+ | **Preview path** | The frontend's **no-file** demonstration mode. It emits **all eight** production event names — the common summary *"it emits no specialist events"* is a **correction**: what the preview withholds is the **content**, not the event. Its specialist events carry a component **name** and no measurement; the result stages carry explicit emptiness. | `frontend/assets/js/mission.js:550-578`; [`architecture/09-frontend.md`](architecture/09-frontend.md) §5.2 |
194
+ | **Trace fill** | The execution-trace progress bar's fill fraction. The measured live value is **94.4444 % (17/18)** — the bar advances to the **current node** rather than to its right edge, so a **fully-completed** run stops at 94.4444 %, not 100 %. | `architecture/06-evidence-and-confidence.md` §13.3; `README.md` (trace-fill row); `DOCS_STYLE_GUIDE.md` §3 |
195
+ | **Run id** | The identifier for one analysis run, generated as `run_<12 hex>`. It appears on the `ResultEnvelope` and inside the `ExecutionTrace`. | `core/schemas.py:28` (`_new_id`), `:299` (`ExecutionTrace.run_id`); [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §5.1 |
196
+ | **Request id** | A **separate** identifier namespace, `req_<24 hex>`, generated by the gateway and echoed as `X-Request-Id`. **The two id spaces do not join** — there is no trace-context propagation. | `gateway/policy.py`; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §5.2, §5.4 |
197
+ | **Config hash** | A 16-hex-character stable digest of the whole config registry, computed in `Config.hash` over the JSON-sorted registry. It is recorded in every evaluation run and in every artifact. The frozen value is **`78f1e3700da15aa1`**. | `core/config.py:76-80`; [`architecture/07-configuration-freeze.md`](architecture/07-configuration-freeze.md) |
198
+ | **Frozen config** | The config registry whose hash is **`78f1e3700da15aa1`** and which may not move without invalidating the benchmark. *"Frozen"* means validated against the frozen architecture at load time and hashed for reproducibility. | `core/config.py`; `configs/base.yaml`; [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md) §2 |
199
+ | **Invariant** | A property **enforced at load time**, not merely documented, because the failure it prevents is a **silent shape error** — a tensor of the right shape that trains to a worse number. Examples: `fusion.input_dim == 2318`, `grounding_head.feature_dim == 2048`, `croma.image_resolution % 8 == 0`. | `core/config.py` (`_validate`); [`MODELS.md`](MODELS.md) §3.0; [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md) §2.3 |
200
+
201
+ ---
202
+
203
+ ## Part F — Deployment and operations
204
+
205
+ Topology, transport and the runbook are in [`DEPLOYMENT.md`](DEPLOYMENT.md),
206
+ [`architecture/02-deployment-topology.md`](architecture/02-deployment-topology.md) and
207
+ [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md).
208
+
209
+ | Term | Definition | Defined / enforced |
210
+ |---|---|---|
211
+ | **Gateway** | The **Render-hosted** edge service. It owns eight responsibilities — schema validation, size limits, rate limiting, CORS, request IDs, timeouts, secret custody, error translation — and **makes no model decisions**. It proxies **four** routes: `/v1/health`, `/v1/capabilities`, `/v1/analyze`, `/v1/assets`. | `gateway/app.py`, `gateway/policy.py`; `docs/DEPLOYMENT_ARCHITECTURE.md` §2.1 |
212
+ | **Orchestrator** | The gateway's role as the component that **starts the Codespace** and **waits** for it, then proxies the request. Also called the hub. | `docs/DEPLOYMENT_ARCHITECTURE.md`; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §2.3 |
213
+ | **Tunnel** | The **live transport**: an **outbound long-poll** (`POST /tunnel/agent`) from a Codespace agent to the hub. Direction is **inverted** — the Codespace dials out, which is why the design works with a **private** repository. A *forwarded* Codespace port returns **HTTP 302** for a private repo, which is *why* the tunnel exists. | `deploy/codespace/tunnel_agent.py`; `tunnel.py`; [`architecture/02-deployment-topology.md`](architecture/02-deployment-topology.md) §3 |
214
+ | **Long-poll** | A request that the server **parks** until work arrives or a timeout fires, rather than returning immediately. The tunnel agent announces itself with a long-poll `POST /tunnel/agent`. | `tunnel.py`; [`architecture/02-deployment-topology.md`](architecture/02-deployment-topology.md) §3 |
215
+ | **Wake flow** | The **fallback** path: `ensure_codespace_up()` starts a stopped Codespace via the GitHub API and polls `GET {base}/v1/health` every 2 s (10 s per-poll timeout) until it answers 200, bounded by `wake_timeout_s = 120`. | `apply-test/main.py:417-442`; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §7.2 |
216
+ | **Cold start** | The delay before a stopped Codespace (or a sleeping Render instance) can serve. Documented as **"tens of seconds"**; bounded worst case `wake_timeout_s = 120` before a `504`. **No measured distribution exists.** | [`DEPLOYMENT.md`](DEPLOYMENT.md) §8; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §7.2 |
217
+ | **Forward path** | The **fallback** transport that proxies to a forwarded Codespace port directly. For a **private** repo it returns `302`; in `auto` mode a tunnel timeout falls through to it, which is the root shape of **B-07**. | [`DEPLOYMENT.md`](DEPLOYMENT.md) §8.1; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §7.3 |
218
+ | **`tunnel_offline`** | The error code (`503`) meaning **no agent is connected** and `mode == "tunnel"`. The remedy is to start the Codespace. | `apply-test/main.py:308-332`; [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) §7.3 |
219
+ | **CORS allowlist** | The explicit list of permitted browser origins, from `SATQUERY_ALLOWED_ORIGINS`. **Never `*`** — an empty or wildcard allowlist is **refused at construction** by `GatewayConfig.__post_init__`. | `gateway/policy.py`; `docs/DEPLOYMENT_ARCHITECTURE.md` §2.1 |
220
+ | **Rate limit** | A **per-IP** and global request cap. Default `rate_limit_per_ip = 10` over `rate_limit_window_s = 60.0`. It is a **fairness control, not a protection control** — it does not prevent a bypass, and it exists to protect the GPU budget. | `gateway/policy.py`; `docs/DEPLOYMENT_ARCHITECTURE.md` §5.2 |
221
+ | **LFS** | Git **Large File Storage** — the mechanism for storing large binary files (model weights) in a Git repository by pointer. Used for the released artifacts on the Hub. | [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md) §7; [`MODELS.md`](MODELS.md) |
222
+ | **Git Data API** | The GitHub REST API used to **create commits programmatically** instead of `git push`. Chosen because it avoids a local clone/credential flow. | [`DEPLOYMENT.md`](DEPLOYMENT.md) §7.1 |
223
+
224
+ ---
225
+
226
+ ## Part G — Status vocabulary
227
+
228
+ The project uses a **fixed status vocabulary** on every substantive claim. *"Never upgrade a status:
229
+ `NOT RUN` never becomes `PASS`; `OPEN` never becomes `VERIFIED`; `REJECTED` never becomes `ACCEPTED`."*
230
+ (`DOCS_STYLE_GUIDE.md` §1.7).
231
+
232
+ | Tag | Definition |
233
+ |---|---|
234
+ | **`IMPLEMENTED`** | The code exists. It does **not** imply it was run, or that it produced a good result. |
235
+ | **`VERIFIED`** | Measured **and** independently confirmed against a frozen criterion. In this project only the change headline carries it (pooled IoU 0.8122 / macro IoU 0.8457 / pooled F1 0.8964). |
236
+ | **`MEASURED`** | A number was produced by running something and recorded in an artifact. It does not imply acceptance. |
237
+ | **`ATTEMPTED`** | Work was done but did not complete cleanly or did not resolve the question (e.g. the BigEarthNet format contradiction). |
238
+ | **`NOT RUN`** | The work was **not** done. Never to be read as a pass. |
239
+ | **`BLOCKED`** | The work cannot be done in the environment or without an external resource. A **fact**, not a decision. |
240
+ | **`DEFERRED`** | The work could be done now but was deliberately postponed, with a reason. |
241
+ | **`REJECTED`** | The work was done and the answer was **no**. Used for the 448 grounding resolution and the ZeroGPU deployment target. |
242
+ | **`OPEN`** | The item is unresolved and **not** closed. Used for B-07, B-02, the missing `LICENSE`, and the 50,822-vs-51,725 comment discrepancy. |
243
+ | **`RESOLVED`** | A previously open item was **closed with evidence**. |
244
+ | **`CLOSED`** | The item is finished and no longer tracked. |
245
+ | **`USABLE_VERIFIED`** | The **VLM adapter's** state: its metrics are usable (`exact_match` 0.963), verified against the run record. It is **not** the same as accepted. |
246
+ | **`ACCEPTANCE-REJECTED`** | The artifact passed verification but was **not promoted** for production use. The VLM adapter is `USABLE_VERIFIED` **and** `ACCEPTANCE-REJECTED` — *"Those are different words about different things."* The deployed caption/VQA path uses the **unadapted** model. |
247
+ | **`TRAINED_UNVERIFIED`** | A training run produced an artifact that has **not** been evaluated on a held-out split. The change-VQA run record's state, with the note: *"training produces an artifact, not a verified capability. R-02 reaches VERIFIED only after the returned checkpoint has been evaluated on the held-out split."* Superseded by the promotion record but retained on disk. |
248
+ | **`OPEN` ruling** | A verdict that is **not settled** — the metric is measured but the acceptance decision is unmade. Used for optical-SAR (accuracy 0.931 with macro-F1 0.434161) and change-VQA (test 0.697626/0.378373; test2 0.651469/0.372309). *"Never accuracy without macro-F1."* |
249
+
250
+ **Related honesty rules that recur with these tags:**
251
+
252
+ - **`USABLE ≠ ACCEPTED`** ([`EVALUATION.md`](EVALUATION.md) Rule 7).
253
+ - **Two protocols are never collapsed** ([`EVALUATION.md`](EVALUATION.md) Rule 2): grounding is reported
254
+ under canonical (0.2838) **and** matched6 (0.2566).
255
+ - **Two test sets are never collapsed** (Rule 3): change-VQA has test **and** test2.
256
+ - **Validation is not test** (Rule 5): the router's 0.965116 is **validation**, ungated, n = 86; the test
257
+ split was **NOT RUN**.
258
+ - **A negative result stays negative** (Rule 6): calibration made ECE worse and stays reported as worse.
259
+
260
+ ---
261
+
262
+ ## Part H — Index — where each term is defined or enforced
263
+
264
+ | Term / concept | Primary file(s) |
265
+ |---|---|
266
+ | Task vocabulary (7 tasks) | `core/schemas.py` (`Task`); `router/label_space.py` (`TASK_CLASSES`) |
267
+ | Modality vocabulary | `core/schemas.py` (`Modality`); `router/label_space.py` (`MODALITY_CLASSES`) |
268
+ | `Intent`, `EvidenceType`, `CoordinateSystem`, `Region`, `ChangeRegion` | `core/schemas.py` |
269
+ | `SpecialistResult`, `ResultEnvelope`, `AnalysisRequest`, `HealthStatus` | `core/schemas.py` |
270
+ | `ExecutionTrace`, `TraceStep`, `ModelRef`, `ConfidenceBreakdown`, `Evidence` | `core/schemas.py` |
271
+ | Config hash, invariants, device resolution | `core/config.py` |
272
+ | Frozen values and budgets | `configs/base.yaml` (frozen `configs/deploy.yaml` is inert) |
273
+ | Router encoder / adapter / label space / fallback | `router/encoder.py`, `router/adapter.py`, `router/label_space.py`, `router/fallback.py` |
274
+ | Controller, dispatch, nine-state spine | `core/controller.py` |
275
+ | Planner, capability asset counts | `core/planner.py` |
276
+ | Evidence engine, calibration, confidence | `evidence/engine.py`, `evidence/confidence.py` |
277
+ | Specialists | `specialists/vqa/`, `specialists/grounding/`, `specialists/change/`, `specialists/optical_sar/` |
278
+ | Input-quality gate, percentile stretch | `preprocessing/quality.py`, `preprocessing/imagery.py`, `preprocessing/raster.py` |
279
+ | Gateway policy, rate limit, CORS, error taxonomy | `gateway/policy.py`, `gateway/app.py`, `gateway/assets.py` |
280
+ | Deployment report / capability adapter | `app/deployment.py`, `app/space_app.py` |
281
+ | Six artifact byte counts and digests | [`../models/manifest.json`](../models/manifest.json), [`../models/checksums.sha256`](../models/checksums.sha256) |
282
+ | Status vocabulary | `DOCS_STYLE_GUIDE.md` §2; [`EVALUATION.md`](EVALUATION.md) §2 |
283
+
284
+ ### Cross-references
285
+
286
+ - [`PERFORMANCE.md`](PERFORMANCE.md) — the footprint, the component timings, the cost traps, and the
287
+ explicit statement that **no end-to-end benchmark exists**.
288
+ - [`MODELS.md`](MODELS.md) — the artifact and backbone reference, with enforced invariants.
289
+ - [`BENCHMARKS.md`](BENCHMARKS.md) — every measured metric with its artifact key path.
290
+ - [`EVALUATION.md`](EVALUATION.md) — the eight honesty rules and the protocols.
291
+ - [`DATASETS.md`](DATASETS.md) — the corpora, splits and leakage controls.
292
+ - [`TRAINING.md`](TRAINING.md), [`REPRODUCIBILITY.md`](REPRODUCIBILITY.md) — how the artifacts were made
293
+ and how the claims are re-checked.
294
+ - [`DEPLOYMENT.md`](DEPLOYMENT.md) — the live topology, transport and cold start.
295
+ - [`LIMITATIONS.md`](LIMITATIONS.md) — the exhaustive catalogue of what is not done or not known.
296
+ - [`architecture/05-specialists.md`](architecture/05-specialists.md),
297
+ [`architecture/06-evidence-and-confidence.md`](architecture/06-evidence-and-confidence.md),
298
+ [`architecture/10-observability-and-ops.md`](architecture/10-observability-and-ops.md) — the deep
299
+ chapters for the specialists, the evidence/confidence subsystem, and operations.
300
+
301
+ ---
302
+
303
+ ## Terms deliberately not defined here
304
+
305
+ The following appear in some drafts but are **not** established by any file read, so this glossary does
306
+ not define them: a general "quality score", a "system accuracy", an "end-to-end latency", a
307
+ "cost-per-request", or a "throughput". Where a reader needs one of these, the honest answer is
308
+ `UNKNOWN — not established from the available evidence`, and the place to look is
309
+ [`PERFORMANCE.md`](PERFORMANCE.md) §8 and [`LIMITATIONS.md`](LIMITATIONS.md) §3.