Initial public release
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s

This commit is contained in:
Jens
2026-08-31 21:56:53 +02:00
commit faeb58ef6d
1386 changed files with 263203 additions and 0 deletions
View File
+124
View File
@@ -0,0 +1,124 @@
# START HERE — GeoIntel Architect Canonical Entry Point
This is the single canonical entry point for Codex, reviewers and future contributors.
Older handoff files are historical. If documents conflict, follow the precedence order in this file.
## Current milestone
**v1.0.0 - Belgium/North Sea release**
The implementation is in final release-candidate acceptance for Belgium and
the Belgian North Sea. Mol and the Kempen remain golden regression areas, not
the product boundary.
## Product one-liner
GeoIntel is a map-first GeoAI Workbench for Belgium and the Belgian North Sea
that processes governed raster data, vector data and AI outputs into
geospatially correct analysis, detections, segmentations, QA/QC metrics and
exports.
## Non-negotiable product identity
GeoIntel is:
- a GeoAI Workbench;
- a geospatial data processing product;
- a platform for raster/vector/AI/QA workflows;
- a portfolio-grade implementation of GIS, remote sensing, computer vision and data engineering.
GeoIntel is not primarily:
- a generic dashboard;
- a reporting-only tool;
- a chatbot;
- a QGIS clone;
- a mock demo app.
## Canonical read order for Codex
Read these files in order before coding:
1. `docs/00-start/START_HERE.md`
2. `docs/RC_SCOPE_FREEZE_BELGIUM_NORTH_SEA.md`
3. `docs/RC_ROADMAP_BELGIUM_NORTH_SEA.md`
4. `docs/governance/GEOINTEL_CONSTITUTION.md`
5. `docs/governance/ARCHITECTURE_INVARIANTS.md`
6. `docs/governance/FORBIDDEN_DECISIONS.md`
7. `docs/API_CONTRACTS.md`
8. `docs/DATABASE_IMPLEMENTATION_PLAN.md`
9. `docs/DATA_SPECIFICATION.md`
10. `docs/DATA_SOURCES.md`
11. `docs/STORAGE_ARCHITECTURE.md`
12. `docs/DEFINITION_OF_DONE.md`
13. `docs/RELEASE_RUNBOOK.md`
## Canonical first implementation target
The first vertical slice is:
**Project + Area + Dataset + Raster/Vector metadata + Reference polygons + Detection result import + QA/QC + GeoJSON export.**
Do not start with full AI inference if the foundation is not stable. The first goal is to prove the data lifecycle and geospatial correctness.
## Canonical V1 golden path
1. Create project.
2. Create/select an Area in the Kempen.
3. Upload or load a raster/vector dataset.
4. Extract and persist metadata.
5. Load reference polygons, initially demo GRB-like buildings.
6. Import or generate predicted building detections.
7. Convert outputs to valid geospatial features.
8. Run QA/QC against the reference layer.
9. Show results on the map and in metrics panels.
10. Export GeoJSON.
## What Codex may improve autonomously
Codex may improve:
- implementation quality;
- test coverage;
- type safety;
- error handling;
- UI clarity;
- documentation clarity;
- internal helper abstractions;
- performance within defined budgets.
Codex may not change:
- product identity;
- core stack;
- CRS policy;
- database choice;
- async job architecture;
- API envelope shape;
- state machine names;
- golden path priority;
- forbidden decisions.
## Conflict resolution
If any older document conflicts with the active RC layer, follow this order:
1. Constitution and architecture invariants.
2. Forbidden decisions.
3. State machines and canonical models.
4. API/database contracts.
5. Build order dependency graph.
6. Belgium/North Sea scope freeze and RC roadmap.
7. Older milestone and sprint handoff documents.
## Required pass ending
Every Codex pass must end with:
- files changed;
- commands run;
- tests passed/failed;
- known limitations;
- whether golden paths still pass;
- whether any architecture invariant was touched;
- next recommended pass.
+81
View File
@@ -0,0 +1,81 @@
# Regression Traps
This document lists common failure modes Codex must actively avoid.
## Geospatial Traps
### CRS Loss
Never store or return geometries without CRS context. GeoJSON is usually WGS84 by convention, but source CRS must still be preserved in dataset metadata.
### Bounding Box Confusion
Never mix `[minx, miny, maxx, maxy]` with `[west, south, east, north]` without explicitly naming fields.
### Area Units
Never compute area in degrees. Reproject to an appropriate projected CRS before area or distance calculations. For Flanders/Kempen, prefer Belgian Lambert 72 / EPSG:31370 for metric calculations unless a stronger reason is documented.
### Raster/Vector Alignment
Never compare raster-derived outputs with vector reference layers without documenting resolution, CRS and alignment assumptions.
### Invalid Geometry
Always validate polygons. Attempt safe fixes only when documented; otherwise return a validation error.
## AI Traps
### Confidence Is Not Accuracy
Do not present model confidence as accuracy. Accuracy requires comparison against reference or labels.
### Fixture Detection Is Not Real AI
When using fixture/stub output, label it clearly as fixture/demo mode.
### Silent Model Fallback
Never silently fall back from real model inference to fixture mode. The response must indicate the mode used.
### Mask Polygonization Noise
Segmentation polygonization must include simplification/cleanup parameters and preserve original mask path.
## Backend Traps
### Long Work in Request Thread
Do not run heavy raster/AI operations synchronously inside request handlers. Use a job boundary.
### Inconsistent Status Values
Use the frozen status enum only: `queued`, `running`, `completed`, `failed`, `cancelled`.
### File Path Leakage
API responses may expose logical storage keys or download URLs, not arbitrary host paths.
## Frontend Traps
### UI-Only State
Do not create project, area, dataset or analysis state only in frontend memory. Persist via API.
### Empty Success Screens
Every page must distinguish loading, empty, error, ready and completed states.
### Map Layer Ambiguity
Every map layer must show source, timestamp, opacity, visibility and legend where applicable.
## Documentation Traps
### TODO Instead of Decision
Do not use TODO comments for architecture gaps. Either implement, document a limitation, or ask for a decision.
### Contract Drift
If code changes API responses, update contract docs and examples in the same pass.
+58
View File
@@ -0,0 +1,58 @@
# Self-Review Checklist for Codex
Codex must run this checklist before ending every implementation pass.
## Product Fit
- [ ] Does the work still support GeoIntel as a GeoAI Workbench?
- [ ] Did the pass avoid adding unrelated dashboard/chat features?
- [ ] Is the Kempen/GRB-first strategy preserved?
## API and Backend
- [ ] Are new endpoints documented?
- [ ] Do endpoints return stable JSON shapes?
- [ ] Are errors structured and useful?
- [ ] Are validation failures explicit?
- [ ] Are long-running tasks behind a job/status boundary?
## Database
- [ ] Are migrations included?
- [ ] Are geometry columns documented?
- [ ] Are timestamps and provenance fields included?
- [ ] Is source metadata preserved?
## Geospatial Correctness
- [ ] Is CRS captured?
- [ ] Are metric calculations done in a projected CRS?
- [ ] Are geometries validated?
- [ ] Are bounds and area units explicit?
## AI Pipeline Correctness
- [ ] Is model mode clear: real, stub or fixture?
- [ ] Is confidence not mislabeled as accuracy?
- [ ] Are generated detections georeferenced or explicitly not georeferenced?
- [ ] Are model parameters stored with the run?
## Frontend
- [ ] Are loading, empty, error and success states implemented?
- [ ] Does the UI use API data instead of hardcoded business data?
- [ ] Are map layers inspectable?
- [ ] Can users understand what happened after running an analysis?
## Testing
- [ ] Were relevant tests added or updated?
- [ ] Do smoke scripts still pass?
- [ ] Are fixtures deterministic?
## Documentation
- [ ] Was `CHANGELOG.md` updated?
- [ ] Was `docs/BUILD_STATUS.md` updated?
- [ ] Were affected specs updated?
- [ ] Are known limitations explicit?
@@ -0,0 +1,147 @@
# Build Sequence Lock
This file freezes the order in which Codex should build GeoIntel V1. Codex can split passes into smaller chunks, but it must not reorder major dependencies.
## Phase 0 — Repository Verification
- Verify folder structure.
- Verify documentation set exists.
- Verify `.env.example` and docker-compose exist.
- Verify scripts are executable or document how to run them.
- Verify fixtures are valid GeoJSON.
Exit criteria:
- all preflight scripts run or have clear remediation notes.
## Phase 1 — Backend Foundation
- FastAPI app shell.
- Health endpoint.
- Settings/config loader.
- Structured error response model.
- CORS configured for local frontend.
- Logging baseline.
Exit criteria:
- backend imports successfully.
- `/health` returns service status.
- config is read from environment.
## Phase 2 — Database Foundation
- SQLAlchemy or SQLModel models.
- Alembic migrations.
- PostGIS extension migration.
- project, area, dataset, analysis_run base tables.
- geometry storage strategy implemented.
Exit criteria:
- migrations run against PostGIS.
- seed script creates one project and one area.
## Phase 3 — Project, Area and Dataset APIs
- CRUD for projects.
- CRUD for areas.
- dataset upload endpoint.
- metadata extraction queue boundary.
- file storage path convention.
Exit criteria:
- OpenAPI docs expose complete endpoints.
- API tests pass for create/list/read flows.
## Phase 4 — Geospatial Metadata
- vector metadata extraction.
- raster metadata extraction.
- CRS validation.
- bounds extraction.
- geometry validation.
Exit criteria:
- sample GeoJSON returns feature count, bounds and CRS status.
- sample raster placeholder or documented stub returns safe metadata response.
## Phase 5 — Frontend Shell
- React app.
- routing.
- layout.
- API client.
- project list.
- project workspace.
- map workspace placeholder.
Exit criteria:
- frontend starts.
- health check visible.
- project list loads from API.
## Phase 6 — Map and Layer Foundation
- MapLibre map.
- draw/select area.
- layer manager.
- vector layer rendering.
- dataset detail panel.
Exit criteria:
- fixture GeoJSON renders on map.
- drawn area can be saved through API.
## Phase 7 — QA/QC Foundation
- load predicted and reference polygons.
- compute IoU-based matching.
- compute precision, recall and F1.
- create QA result payload.
- render QA dashboard.
Exit criteria:
- fixture QA returns deterministic metrics.
- false positives and false negatives are exported as GeoJSON.
## Phase 8 — Detection Interface Boundary
- detection run model.
- detection service interface.
- model registry stub.
- deterministic fixture-based inference fallback.
- later YOLO integration boundary.
Exit criteria:
- detection run can produce geospatial detections using fixture mode.
- output is stored and visible as layer.
## Phase 9 — Export Pipeline
- export GeoJSON.
- export metrics JSON.
- prepare report shell.
- export provenance metadata.
Exit criteria:
- user can download GeoJSON output from UI.
## Phase 10 — Stabilization
- smoke tests.
- contract tests.
- docs update.
- changelog.
- known limitations.
Exit criteria:
- V1 vertical slice is demonstrable end-to-end.
@@ -0,0 +1,51 @@
# Codex Decision Boundaries
This document defines where Codex has freedom and where it must not decide alone.
## Codex Can Decide
- internal helper function names
- folder organization within already approved domains
- UI microcopy that clarifies state
- additional tests
- stricter validation when compatible with contracts
- small refactors that reduce duplication
- dependency minor versions when compatible
- CSS implementation details
## Codex Must Follow Existing Specs
- primary tech stack
- FastAPI backend
- React frontend
- PostGIS database
- GRB-first reference strategy
- status enums
- API envelopes
- CRS calculation rules
- QA/QC formulas
- V1 scope boundaries
- build sequence
## Codex Must Ask or Stop
- replacing FastAPI, PostGIS, React or MapLibre
- changing project direction from GeoAI Workbench
- adding authentication
- adding paid services
- changing reference data strategy
- changing scoring/math definitions
- presenting fixture output as real AI
- introducing non-deterministic tests
- removing docs/tests to make builds pass
## Improvement Rule
If Codex sees a better approach, it may implement it only when:
1. it is backward compatible with specs
2. it improves correctness, reliability or clarity
3. it updates docs and tests
4. it does not expand V1 scope
If not, document it as a proposal in `docs/PROPOSED_IMPROVEMENTS.md`.
@@ -0,0 +1,89 @@
# M7 Implementation Control Layer
This layer exists to keep Codex productive without allowing it to improvise core architecture.
## Purpose
M7 adds strict execution control around the existing GeoIntel specifications. It defines how Codex should sequence work, how each pass should prove completion, which traps to avoid, and when it is allowed to improve the design.
## Operating Principle
Codex may improve implementation quality, developer experience, robustness, performance and UX clarity, but it may not silently change product direction, data model semantics, analysis definitions, geospatial meaning or API contracts.
## Build Priorities
1. Keep the vertical slice working at all times.
2. Build backend contracts before frontend polish.
3. Prefer small complete modules over broad incomplete scaffolding.
4. Every result must be reproducible from fixtures or documented sample data.
5. Every analysis output must retain source, parameters, units and assumptions.
6. Every geospatial geometry must carry CRS awareness.
7. Every long-running process must expose status, errors and recoverability.
## Mandatory Per-Pass Output
At the end of every Codex pass, update or create:
- `CHANGELOG.md`
- `docs/BUILD_STATUS.md`
- relevant TODO checkboxes
- test notes
- known limitations
- next recommended pass
If a pass changes API contracts, update `contracts/api/` and all affected frontend service calls.
If a pass changes database models, update migrations, schema docs and seed data.
If a pass changes analysis logic, update analysis specifications, tests and expected fixtures.
## Allowed Improvements
Codex may add:
- better validation
- better error messages
- safer defaults
- clearer UI states
- test fixtures
- helper utilities
- small performance improvements
- developer scripts
- documentation clarifications
Codex may not add without explicit approval:
- multi-user auth
- paid external services
- unrelated AI chat features
- unrelated dashboards
- LiDAR production implementation before V1 slice
- training studio before detection and QA/QC are stable
- new primary data sources that conflict with GRB-first strategy
## Stop Conditions
Codex must stop and report instead of continuing if:
- a core specification conflicts with another specification
- a required dependency cannot be installed
- tests fail for reasons that require product decision changes
- geospatial output cannot be tied to CRS or source metadata
- generated outputs would be misleading or scientifically invalid
## M7 Completion Target
The repository is ready for autonomous implementation when Codex can execute:
1. preflight checks
2. backend foundation
3. database foundation
4. dataset upload and metadata
5. map workspace
6. raster/vector preview
7. demo detection stub or real YOLO integration boundary
8. QA/QC fixture comparison
9. GeoJSON export
10. smoke tests
without needing manual architecture decisions.
@@ -0,0 +1,16 @@
# Module Completion Matrix
This matrix defines what counts as complete for each V1 module.
| Module | Backend | Frontend | Tests | Docs | V1 Complete When |
|---|---|---|---|---|---|
| Project Manager | CRUD endpoints, models | list/detail/create | API tests | API + UI docs | User can create/open project |
| Area Manager | geometry validation, save area | draw/save/list areas | geometry fixture tests | geospatial rules updated | User can draw and persist polygon |
| Dataset Manager | upload, metadata, storage | upload form, dataset table | upload/metadata tests | storage + data docs | Dataset can be uploaded and inspected |
| Raster Lab | metadata boundary, clip/preview stubs | metadata panel, preview state | metadata tests | raster spec | Raster dataset has readable metadata |
| Vector Lab | GeoJSON import, feature count, bounds | map overlay, details | fixture render/API tests | vector spec | Vector layer renders and can be inspected |
| Detection Lab | analysis run + fixture inference | run form, output layer | deterministic fixture tests | detection spec | Fixture detection output is stored and shown |
| Segmentation Lab | analysis run boundary | planned UI state | contract tests | segmentation spec | V1 may show prepared state unless detection is stable |
| QA/QC Lab | IoU, precision, recall, F1 | metrics panel, error layers | golden QA tests | QA spec | Fixture predictions compare to reference |
| Export Center | GeoJSON/metrics export | download buttons | export tests | export spec | User downloads GeoJSON result |
| Build Status | changelog/status docs | optional UI link | smoke docs test | build status | Status remains truthful |
@@ -0,0 +1,79 @@
# API Response Rules
All API responses must be stable and implementation-friendly.
## Success Envelope
For single resources:
```json
{
"data": {},
"meta": {}
}
```
For lists:
```json
{
"data": [],
"meta": {
"count": 0,
"limit": 50,
"offset": 0
}
}
```
## Error Envelope
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human readable message",
"details": {},
"trace_id": "optional"
}
}
```
## Required Resource Fields
Most persisted resources should include:
- `id`
- `created_at`
- `updated_at`
Geospatial resources should also include:
- `crs`
- `bounds`
- `geometry_type` where applicable
Analysis resources should include:
- `status`
- `parameters`
- `outputs`
- `metrics`
- `error_message` when failed
## Pagination
Use `limit` and `offset` for V1. Cursor pagination can be added later if needed.
## Sorting
Default sort: newest first for projects, datasets, analyses and exports.
## Contract Drift Rule
If implementation changes any response shape, update:
- `contracts/api/`
- API docs
- frontend API client types
- tests
@@ -0,0 +1,70 @@
# Frontend State Rules
GeoIntel frontend must be predictable, API-driven and resistant to partial build regressions.
## State Layers
Use three state categories:
1. Server state: projects, datasets, areas, analysis runs, metrics, exports.
2. UI state: selected tab, open panel, layer opacity, map camera.
3. Draft state: unsaved polygon, upload form, threshold slider before run.
Server state must be loaded through API client functions. Do not duplicate server truth in Zustand except as cached references managed by query tooling.
## Required Page States
Every data-driven page must render:
- initial loading
- empty state
- error state
- ready state
- processing state when jobs exist
## Map State
Map layer state must include:
- id
- name
- source
- visibility
- opacity
- style
- legend label
- feature count if known
## Analysis Run State
Analysis run UI must display:
- status
- started_at
- completed_at when available
- parameters
- model mode if AI-related
- output layers
- metrics
- errors if failed
## Form Validation
Client validation improves UX but must not replace backend validation.
## Navigation
The navigation should preserve the mental model:
- Projects
- Workspace
- Map
- Datasets
- Raster
- Vector
- Detection
- Segmentation
- QA/QC
- Exports
Do not hide core modules behind unrelated dashboard labels.
@@ -0,0 +1,87 @@
# Geospatial Calculation Rules
These rules define how GeoIntel must handle geospatial calculations.
## Coordinate Reference Systems
Default display CRS: EPSG:4326.
Default metric calculation CRS for Flanders/Kempen: EPSG:31370.
Every dataset must store:
- source CRS
- normalized/display CRS if converted
- metric calculation CRS used for area/distance outputs
## Geometry Validation
Before inserting vector features:
1. check geometry exists
2. check geometry type
3. check validity
4. check empty geometry
5. compute bounds
6. compute source feature count
Invalid geometries should be recorded in dataset metadata. Auto-fix may be attempted using buffer(0) or make_valid only if the metadata records this correction.
## Area Calculation
Area values must include units.
Preferred units:
- `m2` for feature-level area
- `ha` for summary land cover areas
- `km2` for large area summaries
Never calculate area from EPSG:4326 degrees.
## Distance Calculation
Distance values must include units.
Preferred units:
- `m` for local distances
- `km` for totals and densities
## Density Calculation
Densities must define denominator:
- buildings per km2
- road km per km2
- vegetation ha per km2
## IoU Calculation
For polygons A and B:
`IoU = area(intersection(A, B)) / area(union(A, B))`
Both geometries must be projected to metric CRS before area calculation.
## Matching Rule
Default object matching threshold for building QA/QC:
`IoU >= 0.5`
Alternative thresholds may be exposed in UI but must default to 0.5 for first V1 implementation.
## Precision, Recall and F1
- TP: predicted feature matched to one reference feature above threshold
- FP: predicted feature without reference match
- FN: reference feature without predicted match
`precision = TP / (TP + FP)`
`recall = TP / (TP + FN)`
`f1 = 2 * precision * recall / (precision + recall)`
If denominator is zero, return null and include explanatory reason.
@@ -0,0 +1,43 @@
# Codex Handoff Briefing
You are inheriting GeoIntel Kempen, a GeoAI Workbench for the Belgian Kempen.
## Read first
1. `README.md`
2. `AGENTS.md`
3. `docs/V1_SCOPE_FREEZE.md`
4. `docs/SERVICE_ARCHITECTURE.md`
5. `docs/REPOSITORY_CONVENTIONS.md`
6. `docs/15-tomorrow-execution/M8_TOMORROW_EXECUTION_PACK.md`
7. `docs/15-tomorrow-execution/DAY_1_EXECUTION_TIMELINE.md`
8. the current pass prompt under `prompts/codex/day-1/`
## Build philosophy
Build thin but real vertical slices. Do not hide missing functionality behind convincing UI. A small working API with tests is better than a beautiful mock.
## The first usable vertical slice
The first vertical slice is:
```text
Project -> Area -> Dataset registration -> Metadata -> Map/Workbench display -> Export-ready internal structure
```
Object detection, segmentation and QA/QC are important, but they must sit on a stable foundation.
## Common failure modes to avoid
- Creating frontend-only mock data that bypasses API state.
- Mixing geometry parsing into random route handlers.
- Adding AI dependencies before the data model is stable.
- Hardcoding local file paths.
- Ignoring CRS metadata.
- Creating database models that cannot handle future PostGIS geometries.
- Implementing upload without storage policy.
- Writing TODOs instead of completing the requested pass.
## Improvement freedom
You may add helper modules, stricter validation, better tests, and cleaner component structure. You may not change the product scope or stack.
@@ -0,0 +1,124 @@
# Day 1 Execution Timeline
This is a practical day plan for Codex. Times are indicative, not strict.
## Block 0 — Repository audit
Goal: understand the repo, identify existing docs, confirm no missing foundation files.
Deliverables:
- updated `docs/CODEX_EXECUTION_LOG.md`;
- short implementation plan;
- no product scope changes.
Do not implement features in this block.
## Block 1 — Backend foundation
Goal: create the minimal FastAPI application architecture.
Deliverables:
- app factory or main app;
- health endpoint;
- config module;
- logging setup;
- consistent response/error envelope;
- backend test harness.
Acceptance:
- backend imports cleanly;
- health test passes;
- no database dependency required for health endpoint.
## Block 2 — Database and domain
Goal: add SQLAlchemy/Alembic/PostGIS-ready domain foundation.
Deliverables:
- database config;
- migration folder;
- core models for projects, areas, datasets, analysis_runs, exports;
- geometry strategy documented in code comments where needed.
Acceptance:
- migrations run on local Postgres/PostGIS;
- tests can run with a safe test DB or mocked DB session layer;
- no raw geometry hacks in API layer.
## Block 3 — Project, Area and Dataset APIs
Goal: implement first real domain APIs.
Deliverables:
- create/list/read projects;
- create/list/read areas;
- dataset registration/upload scaffold;
- validation schemas;
- contract tests.
Acceptance:
- documented API contract examples match actual responses;
- invalid GeoJSON produces structured validation error;
- areas store geometry metadata.
## Block 4 — Frontend shell
Goal: create a navigable frontend shell matching the workbench model.
Deliverables:
- Vite/React/TypeScript app;
- route layout;
- left navigation;
- workspace pages;
- API client with typed methods;
- empty/loading/error states.
Acceptance:
- frontend runs;
- routes do not crash;
- API base URL is environment-driven;
- no random fake product flow.
## Block 5 — Raster/vector metadata
Goal: add the first geospatial processing services.
Deliverables:
- vector metadata parser for GeoJSON;
- raster metadata service scaffold using Rasterio when available;
- dataset metadata endpoint;
- fixture-driven tests.
Acceptance:
- fixtures return deterministic metadata;
- unsupported file type returns controlled error;
- processing outputs are stored according to storage spec.
## Block 6 — Vertical slice stabilization
Goal: make the foundation coherent.
Deliverables:
- smoke script;
- updated docs;
- TODO checked/updated;
- changelog entry;
- known limitations list.
Acceptance:
- one command or documented sequence verifies backend + frontend basics;
- no broken imports;
- no undocumented architectural shortcuts.
@@ -0,0 +1,84 @@
# M8 Tomorrow Execution Pack
This package exists so Codex can start tomorrow with minimal manual steering.
## Operating mode
Codex must work in controlled autonomous passes. Each pass must:
1. read the relevant docs before editing;
2. implement one coherent layer only;
3. run the documented validation commands;
4. write a concise completion report;
5. update TODO, CHANGELOG and CODEX_EXECUTION_LOG;
6. stop when a blocker requires product/architecture judgement.
## Non-negotiable product direction
GeoIntel Kempen is a **GeoAI Workbench**, not a generic dashboard and not a CRUD demo.
The V1 vertical slice must prove:
- geospatial project/area/dataset management;
- raster/vector metadata extraction;
- map-based spatial workflow;
- PostGIS-ready geometry handling;
- controlled AI detection pipeline scaffolding;
- QA/QC against reference geodata;
- geospatial export.
## Day-1 success condition
A successful first Codex day should end with a running foundation that can be started locally and demonstrates:
- backend health endpoint;
- database connection and migrations;
- project/area/dataset APIs;
- frontend shell with routes;
- map workspace placeholder wired to API state;
- deterministic fixtures and smoke checks;
- no uncontrolled mock-only business logic.
## Recommended execution order
1. `prompts/codex/day-1/00_START_HERE.md`
2. `prompts/codex/day-1/01_REPO_AUDIT_AND_PLAN.md`
3. `prompts/codex/day-1/02_BACKEND_FOUNDATION.md`
4. `prompts/codex/day-1/03_DATABASE_AND_DOMAIN.md`
5. `prompts/codex/day-1/04_PROJECT_AREA_DATASET_API.md`
6. `prompts/codex/day-1/05_FRONTEND_SHELL.md`
7. `prompts/codex/day-1/06_RASTER_VECTOR_METADATA.md`
8. `prompts/codex/day-1/07_VERTICAL_SLICE_STABILIZATION.md`
## What Codex may improve without asking
Codex may improve naming, folder hygiene, small helper abstractions, test coverage, typing, validation, error messages, and developer ergonomics if the changes preserve the documented contracts.
## What Codex may not change without explicit approval
Codex may not change:
- product positioning;
- selected stack;
- V1 scope boundaries;
- database aggregate names;
- API envelope conventions;
- storage layout;
- QA/QC metric definitions;
- GRB as primary reference strategy;
- incremental build discipline.
## Required end-of-pass response format
Every pass must end with:
```text
PASS COMPLETED: <name>
CHANGED FILES:
- ...
VALIDATION RUN:
- command: result
OPEN ISSUES:
- ... or none
NEXT RECOMMENDED PASS:
- ...
```
@@ -0,0 +1,31 @@
# Next Pass After Day 1
If Day 1 succeeds, the next priority is not broad feature expansion. The next priority is the first true GeoAI/GIS capability.
## Preferred Day 2 sequence
1. GRB/reference adapter scaffold.
2. Raster tiling interface.
3. Detection model registry scaffold.
4. Deterministic detection fixture adapter.
5. Detection output as GeoJSON.
6. QA/QC overlap metrics against reference fixture.
7. Map overlay display.
## Why this sequence
It creates the first portfolio-relevant technical loop:
```text
Raster/Dataset -> Detection -> Geospatial output -> Reference comparison -> QA metrics -> Export
```
## Do not jump directly to
- full SAM integration;
- real Sentinel downloads;
- LiDAR processing;
- training studio;
- complex report generation.
Those need the Day 1 foundation and Day 2 detection/QA loop first.
@@ -0,0 +1,45 @@
# Autonomy Boundaries for Codex
Codex should be proactive, but not uncontrolled.
## Green zone — Codex can decide
- function and class names when consistent with docs;
- internal helper extraction;
- validation improvements;
- error message clarity;
- test fixture additions;
- component decomposition;
- minor styling improvements;
- logging improvements;
- dependency pinning within the approved stack.
## Yellow zone — Codex can decide but must document
- replacing a library with an equivalent only if dependency installation fails and the replacement stays within the stack intent;
- changing endpoint internals while preserving contracts;
- adding new tables that support existing aggregates;
- adding background job scaffolding earlier than planned;
- improving storage folder structure while preserving published paths.
Must be documented in:
- `docs/CODEX_EXECUTION_LOG.md`;
- `CHANGELOG.md`;
- relevant ADR/RFC if architectural.
## Red zone — Codex must stop and ask
- changing FastAPI/React/PostGIS stack;
- removing GRB-centered QA/QC direction;
- turning the product into a generic GIS dashboard;
- removing AI pipeline readiness;
- changing V1 scope boundaries;
- adding authentication/multi-user as core V1;
- adding paid/cloud-only dependencies as mandatory;
- implementing real external downloads without source strategy and license notes;
- changing output formats away from GeoJSON/COCO/YOLO/masks without approval.
## Safe fallback principle
When a dependency, data source or model cannot be used yet, implement a controlled adapter interface and deterministic fixture-backed behavior. Mark it as a scaffold, not as production-complete.
@@ -0,0 +1,51 @@
# Failure Recovery Playbook
Codex must not spiral when a build fails. Use this playbook.
## Backend import failure
1. Run the smallest import command available.
2. Fix circular imports first.
3. Verify package `__init__.py` files.
4. Ensure config does not require unavailable services at import time.
5. Add or update a smoke test.
## Database failure
1. Check environment variables.
2. Check whether PostGIS extension is required at migration time.
3. Separate pure unit tests from DB integration tests.
4. Do not remove geometry capability to make tests pass.
5. Document required local Postgres/PostGIS command.
## Frontend build failure
1. Run TypeScript check.
2. Fix missing exports/imports.
3. Do not silence errors with `any` unless documented and temporary.
4. Ensure API types match contract fixtures.
5. Add an empty/error state rather than fake success.
## Rasterio/GDAL dependency failure
1. Keep service interface intact.
2. Add graceful unavailable-state handling.
3. Keep GeoJSON/vector paths working.
4. Document local dependency requirement.
5. Do not fake raster metadata as real metadata.
## YOLO/SAM unavailable
1. Keep model registry and detection service interface.
2. Implement deterministic fixture inference adapter.
3. Mark adapter as demo/scaffold.
4. Preserve output shape expected by QA/QC.
5. Do not block foundation work.
## External data source unavailable
1. Fall back to fixtures.
2. Preserve source adapter contract.
3. Add retry/error state.
4. Do not hardcode one live response.
5. Document the failure in execution log.
@@ -0,0 +1,43 @@
# Improvement Policy
GeoIntel should be strict enough for autonomous execution but flexible enough for good engineering.
## Desired improvements
Codex is encouraged to improve:
- typed API clients;
- service boundaries;
- validation specificity;
- reusable geospatial utilities;
- test determinism;
- frontend state handling;
- developer commands;
- logging and diagnostics;
- small UX clarity improvements.
## Undesired improvements
Do not add:
- unrelated dashboards;
- user accounts before V1;
- payment/billing;
- social features;
- generic file manager replacing dataset manager;
- raw LLM chatbot as a central feature;
- unsupported live data scraping;
- excessive styling frameworks beyond the chosen frontend stack.
## Improvement report format
When making improvements beyond the exact prompt, add:
```text
IMPROVEMENT:
- what changed
- why it helps GeoIntel
- why it does not change scope
```
inside `docs/CODEX_EXECUTION_LOG.md`.
@@ -0,0 +1,24 @@
# Quality Gate Matrix
Every implementation pass must satisfy the relevant gates.
| Gate | Backend | Frontend | Data/GIS | AI | Required before merge |
|---|---|---|---|---|---|
| Import/build | app imports | TS builds | processing modules import | model adapters import | yes |
| Contract | response envelope | API client typed | metadata shape stable | detection output shape stable | yes |
| Validation | request schemas | form errors | CRS/file errors | threshold/model errors | yes |
| Tests | unit/contract | component where feasible | fixture processing | adapter test | yes for touched area |
| Docs | route/service docs | UI states docs | source/operation docs | model notes | yes |
| No fake success | errors visible | empty states real | unsupported explicit | unavailable explicit | yes |
## Minimum gates for Day 1
- Backend health passes.
- Project/area/dataset contracts pass.
- Frontend shell builds.
- Fixture metadata tests pass.
- Smoke script documents exact failures if any remain.
## Gate failure response
If a gate fails, Codex must either fix it or mark the pass incomplete. Do not claim completion when validation was skipped.
@@ -0,0 +1,91 @@
# M9 API Validation Examples
All errors must use the documented API envelope.
## Invalid Project Name
Request:
```json
{ "name": "" }
```
Response:
```json
{
"success": false,
"data": null,
"error": {
"code": "validation_error",
"message": "Project name is required.",
"details": { "field": "name" }
},
"meta": {}
}
```
## Invalid GeoJSON Polygon
```json
{
"success": false,
"data": null,
"error": {
"code": "invalid_geometry",
"message": "Area geometry must be a valid Polygon or MultiPolygon in EPSG:4326.",
"details": {
"reason": "self_intersection"
}
},
"meta": {}
}
```
## Unsupported Dataset Type
```json
{
"success": false,
"data": null,
"error": {
"code": "unsupported_dataset_type",
"message": "This file type is not supported in V1.",
"details": {
"allowed_extensions": [".geojson", ".json", ".tif", ".tiff", ".gpkg"]
}
},
"meta": {}
}
```
## External Source Unavailable
```json
{
"success": false,
"data": null,
"error": {
"code": "external_service_unavailable",
"message": "The GRB service is unavailable. Use cached data or retry later.",
"details": { "source": "GRB" }
},
"meta": {}
}
```
## Job Failed
```json
{
"success": true,
"data": {
"job_id": "uuid",
"status": "failed",
"error_code": "model_not_available",
"error_message": "No compatible detection model is configured."
},
"error": null,
"meta": {}
}
```
@@ -0,0 +1,89 @@
# M9 Autonomous Build Doctrine
## Purpose
This document defines how Codex should behave when building GeoIntel with minimal human intervention.
## Build Philosophy
GeoIntel must grow like a professional engineering system:
1. Contracts first.
2. Backend services second.
3. Frontend integration third.
4. AI pipelines only after stable data flow.
5. QA/QC after outputs exist.
6. Polish only after functionality is testable.
## Strictness Levels
### Frozen
Codex must not change these:
- FastAPI backend.
- React TypeScript frontend.
- PostgreSQL/PostGIS database.
- Docker Compose local stack.
- Project/Area/Dataset/Analysis domain model.
- API response envelope.
- Storage root conventions.
- V1 scope.
### Guided
Codex may choose implementation details within these:
- exact Python package split,
- React component granularity,
- internal helper names,
- validation library patterns,
- test fixture organization,
- queue abstraction internals.
### Open Improvement Area
Codex may improve freely if documented:
- UI microcopy,
- accessibility,
- loading states,
- logging clarity,
- test coverage,
- developer command quality,
- type safety.
## Self-Driving Loop
Every build pass must follow this loop:
1. Read relevant specs.
2. Identify scope for the pass.
3. Implement the smallest complete vertical slice.
4. Run tests/lint/type checks where available.
5. Update execution log.
6. Update build status.
7. List next pass.
## Anti-Patterns
Do not:
- create huge untested code dumps,
- implement UI without API contracts,
- invent fake geospatial values,
- build YOLO UI before dataset IO works,
- create multiple competing state stores,
- store geospatial data as plain strings when PostGIS geometry is required,
- ignore CRS handling,
- call external services without adapter boundaries.
## Autonomy Boundary
Codex can keep working independently as long as:
- tests are passing or failures are honestly documented,
- no frozen decision is changed,
- V1 scope is preserved,
- every new file belongs to an approved module,
- build logs are updated.
@@ -0,0 +1,101 @@
# M9 Build Blockers and Recovery
## Database connection failure
Symptoms:
- backend cannot connect to PostgreSQL,
- migrations fail,
- PostGIS extension missing.
Recovery:
1. Check Docker Compose service names.
2. Check environment variables.
3. Confirm database is reachable from backend container or local process.
4. Run a minimal connection test.
5. Do not replace PostGIS with SQLite except for explicitly isolated unit tests.
## PostGIS geometry error
Symptoms:
- invalid geometry,
- SRID missing,
- geometry column cannot be created.
Recovery:
1. Store all app geometry in EPSG:4326 unless a processing-specific CRS is required.
2. Validate GeoJSON before persistence.
3. Use Shapely for geometry validation.
4. Use PostGIS geometry column for persistent area/reference features.
5. Document any CRS transformation.
## Frontend API mismatch
Symptoms:
- UI expects raw data but API returns envelope,
- errors not shown,
- undefined data states.
Recovery:
1. Update frontend API client, not individual components.
2. Normalize envelope handling centrally.
3. Ensure every component handles loading, empty, error and ready states.
## Dependency installation failure
Symptoms:
- GDAL/Rasterio install errors,
- PyTorch package issue,
- platform binary mismatch.
Recovery:
1. Do not remove the feature from docs.
2. Add dependency note to `docs/DEPENDENCY_LOCK_PLAN.md`.
3. Implement interfaces and tests around pure-Python parts first.
4. Defer heavy binary package execution if needed, but leave adapter boundaries.
## External data unavailable
Symptoms:
- WFS unavailable,
- Sentinel catalog unavailable,
- credentials missing.
Recovery:
1. Use demo fixtures.
2. Keep adapter disabled but present.
3. Return explicit `external_service_unavailable` status.
4. Do not fake that live data was fetched.
## AI model unavailable
Symptoms:
- YOLO weights missing,
- SAM unavailable,
- GPU unavailable.
Recovery:
1. Build model registry and adapter interface.
2. Add CPU-safe mock inference only if marked as demo mode.
3. Keep output schema identical to real inference.
4. Do not present demo inference as production inference.
## Test failures
Recovery:
1. Fix tests if implementation is wrong.
2. Fix implementation if test reflects contract.
3. Update specs only if they are clearly inconsistent.
4. Document unresolved failures in execution log.
@@ -0,0 +1,110 @@
# M9 Detailed Data Contracts
## Project
```json
{
"id": "uuid",
"name": "Geel Building Detection Demo",
"description": "Building detection and QA against reference features.",
"region": "Kempen",
"created_at": "2026-06-11T12:00:00Z",
"updated_at": "2026-06-11T12:00:00Z"
}
```
Validation:
- name is required,
- region defaults to Kempen,
- description optional.
## Area
```json
{
"id": "uuid",
"project_id": "uuid",
"name": "Geel center test area",
"geometry": { "type": "Polygon", "coordinates": [] },
"crs": "EPSG:4326",
"area_m2": 12345.67,
"bounds": [4.98, 51.15, 5.02, 51.18]
}
```
Validation:
- geometry must be Polygon or MultiPolygon,
- geometry must be valid,
- geometry must not be empty,
- area_m2 must be computed server-side,
- CRS is EPSG:4326 for API IO unless explicitly documented.
## Dataset
```json
{
"id": "uuid",
"project_id": "uuid",
"name": "reference_buildings.geojson",
"dataset_type": "vector",
"source_mode": "demo",
"source_name": "fixture",
"storage_path": "storage/projects/.../raw/reference_buildings.geojson",
"status": "uploaded|processing|ready|failed",
"crs": "EPSG:4326",
"bounds": [4.98, 51.15, 5.02, 51.18],
"feature_count": 100,
"metadata": {}
}
```
## Analysis Run
```json
{
"id": "uuid",
"project_id": "uuid",
"area_id": "uuid",
"analysis_type": "object_detection|segmentation|qaqc|raster_metadata|vector_metadata",
"status": "queued|running|completed|failed|cancelled",
"parameters": {},
"started_at": null,
"finished_at": null,
"error": null
}
```
## Detection Feature
```json
{
"id": "uuid",
"analysis_run_id": "uuid",
"class_name": "building",
"confidence": 0.91,
"geometry": { "type": "Polygon", "coordinates": [] },
"bbox": [4.99, 51.16, 4.991, 51.161],
"source_tile": "tile_001.tif",
"metadata": {}
}
```
## QA/QC Result
```json
{
"analysis_run_id": "uuid",
"reference_dataset_id": "uuid",
"predicted_dataset_id": "uuid",
"match_threshold_iou": 0.5,
"precision": 0.94,
"recall": 0.91,
"f1": 0.925,
"true_positives": 94,
"false_positives": 6,
"false_negatives": 9,
"findings": []
}
```
@@ -0,0 +1,46 @@
# M9 Final Pre-Code Checklist
Before starting a long Codex build session, verify:
## Repository
- [ ] Full zip extracted cleanly.
- [ ] Git initialized.
- [ ] Initial commit made before Codex changes.
- [ ] `.env.example` exists.
- [ ] Docker Compose file exists.
- [ ] README explains the project.
## Codex Input
- [ ] Master prompt available.
- [ ] Build order available.
- [ ] Definition of Done available.
- [ ] Scorecards available.
- [ ] Failure recovery available.
## Scope
- [ ] V1 scope freeze read.
- [ ] No LiDAR in first pass.
- [ ] No training studio in first pass.
- [ ] No QGIS plugin in first pass.
- [ ] No advanced Sentinel implementation in first pass.
## Expected First Output
- [ ] Pass 0 audit.
- [ ] Execution log.
- [ ] Build status.
- [ ] Gap report.
## Local Environment
- [ ] Docker available.
- [ ] Node available.
- [ ] Python available.
- [ ] PostgreSQL/PostGIS preferably via Docker.
## Human Intervention Rules
Only intervene if Codex asks to change a frozen decision or cannot proceed due to environment failure.
@@ -0,0 +1,54 @@
# M9 Gap-to-Task Conversion Rules
When Codex finds a gap, it must convert it into an actionable task instead of leaving vague notes.
## Task Format
```md
### TASK-ID: Short title
Type: backend | frontend | docs | test | devops | data | ai
Priority: P0 | P1 | P2 | P3
Status: open | in_progress | done | blocked
Owner: Codex
Context:
...
Required changes:
- ...
Acceptance criteria:
- [ ] ...
Validation commands:
- ...
Blocked by:
- none or exact blocker
```
## Priority Rules
### P0
Blocks app startup, database, API envelope, project/area/dataset foundation.
### P1
Blocks V1 core workflow but not app startup.
### P2
Improves quality, tests, UX, docs.
### P3
Nice-to-have or future extension.
## Gap Handling
- If gap is architecture-related: update docs before code.
- If gap is implementation-related: create ticket and implement if in current pass.
- If gap is dependency-related: document in dependency plan and add fallback interface.
- If gap is scope expansion: move to proposed improvements.
@@ -0,0 +1,90 @@
# M9 Geospatial Edge Cases
Codex must account for these cases early to avoid later rewrites.
## Invalid polygon
Examples:
- self-intersection,
- unclosed ring,
- empty coordinates,
- wrong coordinate nesting.
Required behavior:
- reject with validation error,
- return specific message,
- do not persist.
## MultiPolygon
Required behavior:
- accept for areas and vector features,
- compute total area across all parts,
- display as a single layer.
## CRS mismatch
Scenario:
- reference data is EPSG:31370,
- API uses EPSG:4326,
- raster processing may use native CRS.
Required behavior:
- store original CRS in dataset metadata,
- transform API geometries to EPSG:4326 for frontend,
- use projected CRS for area/length calculations when needed,
- document transformations.
## Very large file
Required behavior:
- reject files above configured limit with clear error,
- do not load huge files into memory at once,
- expose future chunking/tile strategy.
## Raster without georeference
Required behavior:
- accept only as non-georeferenced image if supported,
- mark geospatial operations unavailable,
- do not pretend map alignment exists.
## Feature outside selected area
Required behavior:
- clip if operation requested,
- otherwise keep original and display warning if used for area analysis.
## Geometry collection
Required behavior:
- reject for V1 unless explicitly converted,
- explain supported geometry types.
## Zero-area feature
Required behavior:
- keep for line/point layers,
- reject or ignore for polygon-area metrics,
- record warning in analysis result.
## Duplicate features
Required behavior:
- do not automatically delete without audit trail,
- expose duplicate count in data quality metadata.
## Antimeridian/global edge cases
Not relevant for Kempen V1. Document as out of scope.
@@ -0,0 +1,59 @@
# M9 Implementation Review Script
Use this manual review script after Codex produces a build.
## 1. Repository Hygiene
- [ ] No random root-level files.
- [ ] No duplicate docs with conflicting instructions.
- [ ] No generated caches committed.
- [ ] No secrets committed.
- [ ] `.env.example` updated if env vars changed.
## 2. Backend
- [ ] App starts.
- [ ] Health endpoint returns envelope or documented health format.
- [ ] API routes grouped logically.
- [ ] Validation errors are structured.
- [ ] Database models match schema docs.
- [ ] Geometry fields are not plain unvalidated strings.
- [ ] Tests exist for implemented endpoints.
## 3. Frontend
- [ ] App starts.
- [ ] No blank route screens.
- [ ] API client centralizes envelope parsing.
- [ ] Loading, empty, error states present.
- [ ] Demo workflow visible.
- [ ] Map shell does not depend on unavailable live data.
## 4. Geospatial Logic
- [ ] CRS metadata preserved.
- [ ] Area calculations are server-side.
- [ ] Invalid geometries rejected.
- [ ] Demo fixtures load correctly.
- [ ] No fake geospatial metrics presented as real.
## 5. Documentation
- [ ] Changelog updated.
- [ ] Build status updated.
- [ ] Execution log updated.
- [ ] Known limitations updated if needed.
## 6. Commands
Run what is available:
```bash
python -m pytest
npm test
npm run build
npm run lint
docker compose config
```
If commands are not available yet, Codex must document why.
@@ -0,0 +1,27 @@
# M9 Long-Form Codex Prompt Variants
Use these prompts when Codex needs a more specific instruction after the master prompt.
## Prompt: Backend Foundation Only
Build only the backend foundation for GeoIntel. Do not work on frontend or AI. Implement FastAPI app startup, settings, health endpoint, response envelope, structured error handling, and basic tests. Follow `docs/API_CONTRACTS.md`, `docs/ERROR_HANDLING_AND_STATUSES.md`, and `docs/17-max-prep/M9_PASS_SCORECARDS.md`. Update execution log, build status and changelog.
## Prompt: Database Foundation Only
Implement database foundation only. Configure PostgreSQL/PostGIS using the documented Docker Compose environment. Add ORM models and migrations for projects, areas, datasets and analysis_runs. Geometry must use PostGIS-compatible fields. Do not implement AI or advanced datasets. Add tests where possible and update docs.
## Prompt: Dataset Manager Only
Implement the V1 Dataset Manager skeleton. Support upload metadata, storage path conventions, dataset status lifecycle and list/read endpoints. Use demo fixtures for tests. Do not fetch live GRB or Sentinel yet. Ensure source_mode is present. Update execution log and build status.
## Prompt: Frontend Shell Only
Implement the frontend shell with React TypeScript. Add routing, layout, project list, workspace shell, dataset manager shell and map workbench placeholder with correct states. Use API client envelope parsing. Do not hardcode fake analysis results.
## Prompt: QA/QC Skeleton Only
Implement pure geometry QA utilities and tests: IoU, precision, recall, F1 using fixture polygons. Add a backend service interface and endpoint skeleton if foundation exists. Do not require YOLO outputs yet; use fixture reference/predicted layers.
## Prompt: Stabilization Pass
Do not add features. Run all available tests/builds/lints. Fix failures. Update docs, changelog, known limitations and execution log. Remove dead code and root-folder clutter. Ensure app startup paths are documented.
@@ -0,0 +1,83 @@
# M9 Max Preparation Pack
Status: specification expansion after M8.
Purpose: make GeoIntel as close as possible to a self-driving Codex project while still allowing Codex to make local implementation improvements.
## Goal
GeoIntel must be prepared so that Codex can:
1. read the repository,
2. understand the product and constraints,
3. build the foundation,
4. validate itself,
5. recover from common failures,
6. report honestly what was completed,
7. avoid architectural drift.
## Principle
Strict on architecture. Flexible on implementation details.
Codex may improve:
- component structure inside the approved route/component map,
- service internals if IO contracts remain stable,
- validation messages if API envelope remains stable,
- tests if they increase coverage,
- UI polish if it does not change the workflow.
Codex may not change without explicit approval:
- backend framework,
- frontend framework,
- database choice,
- PostGIS requirement,
- core entity names,
- API response envelope,
- dataset storage layout,
- project positioning as a GeoAI Workbench,
- V1 scope freeze.
## M9 Additions
This pack adds:
- final autonomous build doctrine,
- exact day-one Codex master prompt,
- build pass scorecards,
- gap-to-task conversion rules,
- real-versus-demo data policy,
- geospatial edge case handling,
- failure mode catalog,
- module data contracts,
- UI empty/loading/error states,
- API validation examples,
- seed fixtures policy,
- regression map,
- implementation review scripts,
- handoff checklist.
## Expected Use Tomorrow
1. Extract the full zip.
2. Open the repository in Codex.
3. Paste `prompts/codex/M9_DAY_ONE_MASTER_PROMPT.md`.
4. Let Codex run Pass 0 first.
5. Require Codex to update `docs/CODEX_EXECUTION_LOG.md` after each pass.
6. Do not allow feature expansion until Pass 1-4 are green.
## Success Definition
The preparation is successful if Codex can start from an empty implementation and produce:
- a working FastAPI app,
- a working React app,
- Docker Compose services,
- PostGIS models/migrations,
- project/area/dataset APIs,
- demo fixture loading,
- initial map UI shell,
- validation and health checks,
- tests for the implemented pieces,
- a changelog and execution log.
@@ -0,0 +1,133 @@
# M9 Module Dataflow Checklist
Every module must declare its dataflow.
## Dataset Manager
Input:
- file upload,
- project id,
- optional area id.
Processing:
- validate extension,
- store raw file,
- inspect metadata,
- persist dataset record,
- schedule optional processing job.
Output:
- dataset record,
- status,
- metadata.
## Raster Lab
Input:
- raster dataset id,
- optional area geometry.
Processing:
- read raster metadata,
- compute bounds,
- inspect bands,
- clip if requested,
- generate preview/tiles later.
Output:
- metadata,
- preview descriptor,
- derived dataset if clipped.
## Vector Lab
Input:
- vector dataset id,
- optional area geometry.
Processing:
- load features,
- validate CRS,
- compute feature count,
- compute bounds,
- clip if requested.
Output:
- vector metadata,
- clipped layer,
- operation report.
## Detection Lab
Input:
- raster dataset id,
- model id,
- threshold,
- classes.
Processing:
- tile raster,
- run model adapter,
- merge detections,
- georeference outputs,
- persist detection layer.
Output:
- detection dataset/layer,
- analysis run,
- metrics.
## Segmentation Lab
Input:
- raster dataset id,
- model id,
- classes/prompts.
Processing:
- generate masks,
- polygonize,
- clean geometry,
- compute areas,
- persist layer.
Output:
- mask path,
- polygon layer,
- metrics.
## QA/QC Lab
Input:
- reference vector layer,
- predicted vector layer,
- matching threshold.
Processing:
- spatial match,
- IoU calculation,
- precision/recall/F1,
- false positive/negative features.
Output:
- QA metrics,
- findings,
- QA overlay layers.
+91
View File
@@ -0,0 +1,91 @@
# M9 Build Pass Scorecards
Use these scorecards after every Codex pass. A pass is not considered complete until its scorecard is mostly green.
## Pass 0 — Audit
- [ ] Repository tree inspected.
- [ ] Existing docs summarized.
- [ ] Missing implementation listed.
- [ ] Build blockers listed.
- [ ] Next pass selected.
- [ ] No feature code added.
## Pass 1 — Backend Foundation
- [ ] FastAPI app starts.
- [ ] Health endpoint exists.
- [ ] Settings load from environment.
- [ ] CORS configured for local frontend.
- [ ] API envelope helper exists.
- [ ] Error handler exists.
- [ ] Backend tests run.
## Pass 2 — Database Foundation
- [ ] SQLAlchemy or approved ORM configured.
- [ ] Alembic migrations initialized.
- [ ] PostGIS extension migration exists.
- [ ] Project model exists.
- [ ] Area model exists with geometry.
- [ ] Dataset model exists.
- [ ] Local database connection documented.
## Pass 3 — Project/Area APIs
- [ ] Create/list/read project.
- [ ] Create/list/read area.
- [ ] GeoJSON polygon validation.
- [ ] Area size calculation.
- [ ] Envelope responses.
- [ ] Error responses for invalid geometry.
- [ ] Tests for happy and failure paths.
## Pass 4 — Dataset Manager Skeleton
- [ ] Dataset upload endpoint.
- [ ] File stored under documented storage root.
- [ ] Metadata extraction placeholder with real file inspection when possible.
- [ ] Dataset list/read APIs.
- [ ] Status lifecycle present.
- [ ] Tests with fixtures.
## Pass 5 — Frontend Foundation
- [ ] React app starts.
- [ ] Route shell exists.
- [ ] API client uses envelope.
- [ ] Error/loading/empty states exist.
- [ ] Project list page exists.
- [ ] Workspace shell exists.
## Pass 6 — Map Workbench Shell
- [ ] MapLibre or approved map abstraction installed.
- [ ] Area polygon can be displayed.
- [ ] Demo GeoJSON can be loaded.
- [ ] Layer panel shell exists.
- [ ] No hardcoded fake analysis results.
## Pass 7 — Raster/Vector Core Skeleton
- [ ] Raster metadata endpoint skeleton.
- [ ] Vector metadata endpoint skeleton.
- [ ] CRS field exposed.
- [ ] Bounds field exposed.
- [ ] UI metadata panels exist.
## Pass 8 — QA/QC Skeleton
- [ ] QA service interface exists.
- [ ] IoU function unit-tested with fixtures.
- [ ] Precision/recall formulas implemented.
- [ ] QA endpoint accepts reference and predicted layer IDs or fixture IDs.
- [ ] QA result card exists.
## Pass 9 — Stabilization
- [ ] All smoke commands documented.
- [ ] Changelog updated.
- [ ] Known limitations updated.
- [ ] Next advanced module recommendation written.
@@ -0,0 +1,59 @@
# Real vs Demo Data Policy
GeoIntel may use demo fixtures during early development, but the UI and backend must clearly distinguish demo data from live data.
## Data Categories
### Real Data
Data fetched from or uploaded by a real source:
- GRB WFS/cache,
- user-uploaded GeoTIFF,
- user-uploaded GeoJSON/Shapefile/GPKG,
- Sentinel scene,
- DHMV product.
### Demo Fixture Data
Small repository-contained examples used for development and tests:
- `demo/geel/reference_buildings.geojson`,
- `demo/geel/demo_detections.geojson`,
- `fixtures/geojson/*`.
### Synthetic Test Data
Minimal generated data used only in unit tests.
## Rules
- Demo data may be used to build UI states and verify pipelines.
- Demo data must be labeled as demo in API responses.
- Real-data adapters must not silently fall back to demo data.
- A failed external fetch must return an error/status, not demo data.
- Synthetic data must not appear in production UI unless under a test/demo route.
## Dataset Metadata Field
Every dataset must include:
```json
{
"source_mode": "real|demo|synthetic",
"source_name": "GRB|OSM|user_upload|fixture|generated_test",
"license": "string or unknown",
"retrieved_at": "ISO date or null"
}
```
## UI Requirement
The dataset table must display a source badge:
- Real
- Demo
- Synthetic
- Unknown
Synthetic should never be shown in normal user workflows.
+81
View File
@@ -0,0 +1,81 @@
# M9 Regression Map
These are the most likely regressions during autonomous builds.
## API Envelope Drift
Risk: some endpoints return raw data while others return envelopes.
Prevention:
- central response helper,
- API client tests,
- sample responses.
## Geometry Stored Incorrectly
Risk: GeoJSON stored as text everywhere.
Prevention:
- PostGIS geometry columns,
- schema tests,
- validation utilities.
## Demo Data Masquerades as Real Data
Risk: UI shows fixture metrics without labeling them.
Prevention:
- source_mode field,
- demo badge,
- no fallback-to-fixture for external failures.
## Frontend State Duplication
Risk: every component fetches differently.
Prevention:
- central API client,
- shared hooks,
- state contracts.
## Heavy AI Implemented Too Early
Risk: Codex spends time on YOLO/SAM before storage and datasets work.
Prevention:
- pass scorecards,
- V1 ordering,
- disabled state for model features.
## CRS Ignored
Risk: area/length values wrong.
Prevention:
- CRS field mandatory,
- projected calculations documented,
- geospatial edge cases.
## Docs Not Updated
Risk: implementation diverges from specs.
Prevention:
- Definition of Done includes docs,
- execution log mandatory.
## Root Folder Pollution
Risk: scripts and generated outputs appear at root.
Prevention:
- repository conventions,
- review script.
+108
View File
@@ -0,0 +1,108 @@
# M9 UI State Specification
Every page and major component must implement these states.
## Required States
### Initial
No user action yet.
Example copy:
> Start by creating a project or opening the Geel demo.
### Loading
Data is being fetched or processed.
Requirements:
- spinner or skeleton,
- clear label,
- no layout jump where avoidable.
### Empty
Request succeeded but no records exist.
Example:
> No datasets have been added to this project yet.
### Ready
Data exists and actions are available.
### Error
Request failed or validation failed.
Requirements:
- readable error,
- retry action where safe,
- technical details hidden behind details/expand if useful.
### Disabled/Future
Feature is planned but not implemented in V1.
Requirements:
- show disabled state,
- explain why,
- do not show fake results.
## Page Requirements
### Home
- Initial: explain GeoIntel.
- Empty: no recent projects.
- Ready: project cards and demo card.
### Project Workspace
- Loading project.
- Missing project error.
- Empty datasets/areas states.
- Ready dashboard.
### Dataset Manager
- Empty upload area.
- Upload progress.
- Upload failed.
- Processing.
- Ready metadata.
### Map Workbench
- No area selected.
- Area loaded.
- Layer loading.
- Layer error.
- Unsupported layer type.
### Detection Lab
- No raster selected.
- No model configured.
- Running job.
- Completed detections.
- Failed inference.
### QA/QC Lab
- Missing reference dataset.
- Missing predicted dataset.
- Running comparison.
- Metrics ready.
- No matches found.
## Do Not
- Do not leave blank panels.
- Do not show random demo metrics in ready state.
- Do not hide errors in console only.
@@ -0,0 +1,41 @@
# Autonomous Build Charter
## Mission
Codex must build GeoIntel Kempen as a production-shaped GeoAI Workbench, not as a demo-only UI. Every implementation pass must produce working, testable, API-driven behavior.
## Frozen Product Identity
GeoIntel is a GeoAI Workbench for the Kempen focused on raster/vector processing, AI detection, segmentation, QA/QC against reference data, and geospatial exports.
## Allowed Autonomy
Codex may improve:
- internal code organization when it keeps documented contracts intact;
- UI microcopy and layout when it improves clarity;
- validation and error messages;
- tests, fixtures, logging, and developer tooling;
- performance optimizations that do not alter outputs;
- accessibility and keyboard navigation;
- extra helper utilities that support documented workflows.
## Not Allowed Without Explicit User Approval
Codex must not:
- replace FastAPI, React, TypeScript, PostgreSQL/PostGIS, or Python GIS stack;
- introduce a different product direction such as a generic chatbot or CRUD dashboard;
- remove GRB/QA/QC as a first-class concept;
- make LiDAR, training studio, or MLOps part of V1 core;
- hardcode fake results while presenting them as real processing;
- break existing documented API contracts;
- silently change geometry formats or CRS assumptions;
- ignore tests because a dependency is missing.
## Output Expectations Per Pass
Every Codex pass must end with:
1. changed files list;
2. completed tasks;
3. skipped tasks with reason;
4. commands run;
5. test results;
6. known limitations;
7. next recommended pass.
## Quality Principle
If a feature cannot be fully implemented in the pass, Codex must implement the durable skeleton plus honest status handling, not a fake success path.
+66
View File
@@ -0,0 +1,66 @@
# Build Pass Template
Use this exact structure for every Codex build pass.
## Pass Name
Example: `Pass 03 — Dataset Manager Backend`
## Goal
One sentence describing the feature outcome.
## Inputs
- Required docs:
- Required contracts:
- Required fixtures:
- Previous pass dependencies:
## Scope
### Must implement
- [ ] Item
### May improve
- [ ] Item
### Must not touch
- [ ] Item
## Implementation Steps
1. Inspect existing repo state.
2. Confirm relevant contracts.
3. Implement backend/domain changes.
4. Implement frontend/API client changes if applicable.
5. Add or update tests.
6. Add fixtures if needed.
7. Update docs and TODO status.
8. Run validation commands.
9. Produce pass summary.
## Validation Commands
```bash
# backend
pytest
ruff check backend || true
# frontend
npm run build
npm run typecheck || true
npm run lint || true
```
## Acceptance Criteria
- [ ] Feature works through API or UI.
- [ ] Errors are explicit and typed.
- [ ] No mock success path is presented as real.
- [ ] Tests or fixtures cover the happy path and at least one failure path.
- [ ] Documentation is updated.
## Handoff Format
```md
# Pass Summary
## Completed
## Changed Files
## Commands Run
## Test Results
## Known Issues
## Next Step
```
+24
View File
@@ -0,0 +1,24 @@
# Codex Start Here
Read these files first, in this exact order:
1. `README.md`
2. `AGENTS.md`
3. `docs/18-ultra-prep/AUTONOMOUS_BUILD_CHARTER.md`
4. `docs/V1_SCOPE_FREEZE.md`
5. `docs/SERVICE_ARCHITECTURE.md`
6. `docs/REPOSITORY_CONVENTIONS.md`
7. `docs/API_CONTRACTS.md`
8. `docs/DATABASE_IMPLEMENTATION_PLAN.md`
9. `docs/18-ultra-prep/CRITICAL_PATH_TO_V1.md`
10. `docs/18-ultra-prep/BUILD_PASS_TEMPLATE.md`
Then execute the first incomplete pass from:
- `prompts/codex/M10_PASS_SEQUENCE.md`
Rules:
- Do not skip ahead.
- Do not start UI polish before backend contracts exist.
- Do not fake geospatial processing; return honest pending/unavailable states.
- Update TODO/checklists after every pass.
@@ -0,0 +1,27 @@
# Connector Implementation Guide
## Connector Interface
Every external data connector should expose:
- `name`
- `capabilities`
- `is_configured()`
- `health_check()`
- `fetch_by_area(area_geometry, parameters)`
- `normalize(raw_result)`
- `cache_key(area, parameters)`
## Required Connectors
### GRB Connector
V1 target: fetch or register reference building polygons. If live WFS cannot be implemented immediately, build the interface and support fixture/local import honestly.
### OSM Connector
V1 target: fetch buildings/roads/water/green where possible using Overpass or local fixture fallback.
### Sentinel Connector
V2 target. In V1 it should remain disabled with clear roadmap state.
## Connector Failure Behavior
- timeout -> `CONNECTOR_TIMEOUT`
- missing config -> `CONNECTOR_UNCONFIGURED`
- invalid response -> `CONNECTOR_INVALID_RESPONSE`
- no data -> valid empty result, not error
+35
View File
@@ -0,0 +1,35 @@
# Critical Path to V1
This is the shortest reliable path to a portfolio-ready V1.
## V1 Critical Path
1. Repo foundation and dev environment.
2. Database and PostGIS schema.
3. Project and area CRUD.
4. Dataset upload and metadata extraction.
5. Vector import and display.
6. Raster import and metadata display.
7. Map workbench with layer management.
8. OSM/GRB reference ingest interface or stubbed real-data connector with honest unavailable state.
9. Detection pipeline architecture with YOLO adapter.
10. Detection result storage as geospatial features.
11. QA/QC comparison engine against reference polygons.
12. GeoJSON export.
13. Demo scenario page.
14. Smoke tests and documentation.
## V1 Can Be Portfolio-Ready Without
- full Sentinel automation;
- actual production GRB WFS credentials or final endpoint if unavailable;
- LiDAR processing;
- model training;
- multi-user auth;
- perfect visual polish.
## V1 Cannot Be Portfolio-Ready Without
- a working map-driven workflow;
- actual geospatial data models;
- real CRS/geometry handling;
- honest dataset status handling;
- at least one end-to-end detection/QA workflow, even if it uses a small local demo fixture/model adapter first;
- clear export output.
+24
View File
@@ -0,0 +1,24 @@
# CRS Policy
## API Boundary
GeoJSON in API responses should be EPSG:4326.
## Analytical Operations
For Belgium/Kempen projected calculations, use EPSG:31370 where possible.
## Raster Operations
Raster operations must preserve source CRS unless a reproject operation is explicitly requested.
## Required Metadata
Every dataset must store:
- source CRS;
- normalized CRS string;
- bounds in source CRS;
- bounds in EPSG:4326;
- transform/affine for rasters where available.
## Unsupported Cases
If CRS cannot be determined:
- dataset can be stored as `metadata_failed` or `requires_crs`;
- processing requiring geospatial alignment must be blocked;
- UI must ask for CRS or show limitation.
+36
View File
@@ -0,0 +1,36 @@
# Error Taxonomy
All API errors must use a consistent shape.
```json
{
"error": {
"code": "DATASET_UNSUPPORTED_FORMAT",
"message": "The uploaded file format is not supported for this operation.",
"details": {},
"trace_id": "optional"
}
}
```
## Core Error Codes
- `VALIDATION_ERROR`
- `NOT_FOUND`
- `CONFLICT`
- `FEATURE_DISABLED`
- `DATASET_UPLOAD_FAILED`
- `DATASET_UNSUPPORTED_FORMAT`
- `CRS_MISSING`
- `CRS_UNSUPPORTED`
- `GEOMETRY_INVALID`
- `RASTER_METADATA_FAILED`
- `VECTOR_METADATA_FAILED`
- `PROCESSING_JOB_FAILED`
- `MODEL_UNAVAILABLE`
- `INFERENCE_FAILED`
- `REFERENCE_LAYER_MISSING`
- `QA_MATCHING_FAILED`
- `EXPORT_FAILED`
## Frontend Requirements
Every error code should render a useful message and suggested next action.
@@ -0,0 +1,34 @@
# Feature Flag Strategy
Feature flags prevent future modules from appearing as broken V1 features.
## Required Flags
- `ENABLE_GRB_CONNECTOR`
- `ENABLE_OSM_CONNECTOR`
- `ENABLE_SENTINEL_LAB`
- `ENABLE_SAM_SEGMENTATION`
- `ENABLE_YOLO_DETECTION`
- `ENABLE_LIDAR_LAB`
- `ENABLE_TRAINING_STUDIO`
- `ENABLE_QGIS_EXPORT`
## V1 Defaults
```env
ENABLE_GRB_CONNECTOR=true
ENABLE_OSM_CONNECTOR=true
ENABLE_SENTINEL_LAB=false
ENABLE_SAM_SEGMENTATION=false
ENABLE_YOLO_DETECTION=true
ENABLE_LIDAR_LAB=false
ENABLE_TRAINING_STUDIO=false
ENABLE_QGIS_EXPORT=false
```
## UI Behavior
Disabled features may be visible as roadmap cards, but must not look like broken tools. They should show:
- why disabled;
- what dependency is missing;
- which milestone enables them.
## Backend Behavior
Disabled endpoints return a typed `FEATURE_DISABLED` error, not 404 and not silent success.
@@ -0,0 +1,14 @@
# Final Pre-Codex Checklist
Before starting tomorrow's Codex build:
- [ ] Extract latest full zip.
- [ ] Open repo root in Codex environment.
- [ ] Confirm `.env.example` exists.
- [ ] Confirm Docker/PostGIS plan is present.
- [ ] Give Codex `prompts/codex/M10_MASTER_AUTONOMOUS_PROMPT.md`.
- [ ] Tell Codex to execute only one pass at a time.
- [ ] After each pass, require pass report.
- [ ] Reject pass if it changes frozen scope.
- [ ] Reject pass if it hides missing functionality behind fake success.
- [ ] Save output as new update/full zip after meaningful passes.
@@ -0,0 +1,30 @@
# Frontend State Machine
Every async module must model these states explicitly:
- `idle`
- `loading`
- `empty`
- `ready`
- `error`
- `unavailable`
- `disabled`
## Dataset Card
- idle: not selected
- loading: metadata extraction running
- empty: no datasets uploaded
- ready: dataset metadata available
- error: upload/extraction failed
- unavailable: operation unsupported for this dataset type
- disabled: feature flag off
## Analysis Run
- queued
- running
- succeeded
- failed
- cancelled
## UI Rule
Never leave users with a blank panel. Every panel must explain what is happening or what to do next.
+29
View File
@@ -0,0 +1,29 @@
# Geometry Contracts
## Internal Geometry Standard
- Database geometries are stored in PostGIS.
- Default storage CRS: EPSG:31370 for Belgian projected operations where appropriate, or EPSG:4326 for API interchange.
- API GeoJSON is always EPSG:4326 unless explicitly stated.
- Area calculations must use projected CRS, not raw WGS84 degrees.
## Accepted Area Input
- GeoJSON Polygon
- GeoJSON MultiPolygon
- drawn polygon from frontend
- future: municipality selection
## Validation Rules
- polygon must be closed;
- polygon must be valid;
- polygon must have non-zero area;
- self-intersections must be rejected or repaired explicitly;
- extremely large areas must require confirmation or be rejected by configured max area.
## Output Rules
- include `crs` metadata if transformed;
- include computed area in square meters;
- include bounds;
- include geometry validity status.
## Common Trap
Never compute area or distance in degrees.
@@ -0,0 +1,16 @@
# Known Limitations Template
Use this file format after each major build.
## Current Limitations
| Area | Limitation | Impact | Workaround | Target Milestone |
|---|---|---|---|---|
| Detection | YOLO weights not configured | Demo adapter only | Configure local weights | V1.x |
## Data Limitations
- GRB live connector may require endpoint details or local downloads.
- Sentinel automation is V2.
- LiDAR is outside V1.
## Technical Debt
List only real debt, not unfinished planned scope.
+34
View File
@@ -0,0 +1,34 @@
# Model Adapter Guide
## Purpose
Detection and segmentation must be implemented behind stable adapters so V1 can support demo/local model flows while remaining ready for YOLO/SAM integration.
## Detection Adapter Interface
```python
class DetectionAdapter:
name: str
supported_classes: list[str]
def is_available(self) -> bool: ...
def predict(self, image_tile, parameters) -> list[DetectionResult]: ...
```
## Detection Result
Fields:
- class_name
- confidence
- bbox_pixel
- bbox_geo optional after georeferencing
- source_tile
- metadata
## Segmentation Adapter Interface
```python
class SegmentationAdapter:
name: str
supported_classes: list[str]
def is_available(self) -> bool: ...
def segment(self, image_tile, parameters) -> list[SegmentationResult]: ...
```
## V1 Rule
If real YOLO weights are not configured, use a demo adapter only when clearly labelled as demo and never present it as production AI.
+34
View File
@@ -0,0 +1,34 @@
# Observability Plan
## Required Logs
- request start/end with trace id;
- dataset upload registration;
- metadata extraction status;
- job lifecycle transitions;
- model adapter selection;
- inference start/end;
- QA/QC matching summary;
- export creation.
## Required Health Checks
- API health;
- database connection;
- PostGIS extension availability;
- storage write check;
- optional Redis check;
- optional model registry check.
## Diagnostics Endpoint
`GET /system/diagnostics`
Should return safe non-secret status:
```json
{
"api": "ok",
"database": "ok",
"postgis": "ok",
"storage": "ok",
"redis": "unconfigured",
"models": "unconfigured"
}
```
+25
View File
@@ -0,0 +1,25 @@
# Performance Budgets
## API
- health endpoint: < 200ms local
- project list: < 500ms for 100 projects
- dataset metadata: < 500ms after extraction
- synchronous upload response: should register file quickly and hand off heavy work to job queue
## Raster
- never load large rasters fully into memory for preview;
- prefer windowed reads and overviews;
- large tiling must run as background job.
## Vector
- use spatial indexes for intersection/QA operations;
- simplify only for display, not source-of-truth unless explicitly stored as derived layer.
## Frontend
- initial app load should not require heavy GIS data;
- map layers should be lazy-loaded;
- large GeoJSON should be paged, tiled, or simplified.
## Jobs
Long-running operations must have status transitions:
`queued -> running -> succeeded|failed|cancelled`.
@@ -0,0 +1,41 @@
# QA/QC Matching Algorithm
## Goal
Compare AI detections/segmentations with a reference layer such as GRB buildings.
## Inputs
- predicted polygons
- reference polygons
- class filter
- IoU threshold, default 0.5
## Steps
1. Validate CRS alignment.
2. Reproject to analytical CRS.
3. Build spatial indexes.
4. For every predicted polygon, find candidate reference polygons by bbox intersection.
5. Compute IoU for candidates.
6. Assign best match above threshold greedily, one reference per prediction.
7. Count true positives, false positives, false negatives.
8. Compute precision, recall, F1, mean IoU.
9. Produce unmatched prediction layer and unmatched reference layer.
## Metrics
```text
precision = TP / (TP + FP)
recall = TP / (TP + FN)
f1 = 2 * precision * recall / (precision + recall)
IoU = intersection_area / union_area
```
## Output Layers
- matched predictions
- false positives
- false negatives
- low IoU matches
## Edge Cases
- empty predictions and empty reference: score should be explicit `no_objects` not perfect success;
- empty predictions with reference: recall 0;
- predictions with empty reference: precision 0;
- invalid polygons must be repaired or excluded with warning.
+13
View File
@@ -0,0 +1,13 @@
# M10 Ultra Preparation Pack
This folder contains the additional control layer for making GeoIntel as autonomous-build-ready as possible for Codex.
Purpose:
- remove hidden architecture ambiguity;
- give Codex concrete implementation contracts;
- define allowed freedom versus frozen decisions;
- provide validation and recovery procedures;
- prevent common GIS/AI/web-app regressions;
- make each build pass reviewable without manual guessing.
M10 does not replace the previous documentation. It adds the final execution scaffolding around it.
+27
View File
@@ -0,0 +1,27 @@
# V1 Release Gate
GeoIntel V1 is releasable when all gates pass.
## Product Gate
- [ ] User can create project.
- [ ] User can create/select area.
- [ ] User can upload at least one vector dataset.
- [ ] User can upload/register at least one raster dataset.
- [ ] User can see datasets on map or metadata panel.
- [ ] User can run a detection workflow or labelled demo adapter.
- [ ] User can compare detections to reference polygons.
- [ ] User can export GeoJSON.
## Engineering Gate
- [ ] Backend starts from clean checkout.
- [ ] Frontend builds from clean checkout.
- [ ] Database migrations apply.
- [ ] Tests run.
- [ ] Smoke script passes.
- [ ] Docs explain setup.
## Integrity Gate
- [ ] No fake success states.
- [ ] CRS assumptions documented.
- [ ] Feature-disabled states are clear.
- [ ] Known limitations are listed.
+28
View File
@@ -0,0 +1,28 @@
# Repo Hygiene Rules
## Do Commit
- source code;
- documentation;
- small fixtures;
- config examples;
- migration files;
- test data under size limits.
## Do Not Commit
- `.env` with secrets;
- large rasters;
- model weights;
- generated cache;
- local database volumes;
- node_modules;
- Python virtualenvs;
- personal paths.
## Naming
- backend modules use snake_case;
- frontend components use PascalCase;
- docs use uppercase topic names or numbered folders;
- fixtures describe region and purpose.
## Generated Outputs
Generated exports should go under `exports/` and be gitignored unless they are tiny documented sample fixtures.
@@ -0,0 +1,26 @@
# Security and Secret Handling
## Secrets
Never commit API keys, tokens, model credentials, STAC credentials, database passwords, or private URLs.
## Environment Variables
All secrets must be loaded from `.env` or deployment environment.
## File Upload Safety
- limit accepted extensions;
- validate MIME/type where possible;
- store uploads outside source directories;
- generate server-side filenames;
- never execute uploaded files;
- reject path traversal.
## External Connectors
- log endpoint names but not credentials;
- timeout external requests;
- cache responses where appropriate;
- show connector status in UI.
## AI/Model Safety
- model files must be treated as artifacts;
- do not auto-download arbitrary executable code;
- keep model registry metadata separate from weights.
+37
View File
@@ -0,0 +1,37 @@
# UI Copy Bank
## Product Language
Use:
- GeoAI Workbench
- Dataset
- Analysis Run
- Reference Layer
- Detection Result
- QA/QC
- Export
Avoid:
- magic AI
- automatic truth
- perfect detection
- black box conclusions
## Empty States
### No Projects
"Start a GeoAI project by selecting an area in the Kempen or opening the prepared demo scenario."
### No Datasets
"Upload a GeoTIFF, GeoJSON, Shapefile, or use a connector to add reference data."
### No Analysis Runs
"Run a raster, vector, detection, segmentation, or QA/QC analysis to generate geospatial outputs."
## Error Suggestions
### CRS Missing
"This dataset has no detected CRS. Add CRS metadata before using it in spatial operations."
### Model Unavailable
"No detection model is configured. Configure YOLO weights or use the labelled demo adapter."
### Reference Missing
"QA/QC requires a reference layer such as GRB buildings or a local reference GeoJSON."
@@ -0,0 +1,81 @@
# M11 Architect Audit Report
## Audit summary
The repo has strong breadth: product docs, architecture docs, API plans, build prompts, fixtures, smoke scripts and milestone handoffs exist. The main risk is no longer lack of documentation; it is competing documentation and missing hierarchy.
## Findings
### Finding 1 — Too many competing start points
There are multiple handoff files and prompt files from M0 through M10. This is useful historically but dangerous for Codex.
Resolution:
- added `docs/00-start/START_HERE.md` as canonical entry point;
- added decision precedence;
- older files remain historical.
### Finding 2 — Governance rules were implied, not constitutional
Previous docs often said what to build, but not which principles override conflicts.
Resolution:
- added GeoIntel Constitution;
- added Architecture Invariants;
- added Forbidden Decisions.
### Finding 3 — Domain language needed locking
Terms like Dataset, Layer, Analysis, Detection and Segmentation could be implemented inconsistently.
Resolution:
- added Canonical Domain Models.
### Finding 4 — State machines needed canonical names
Multiple docs referenced statuses, but a single source of truth was missing.
Resolution:
- added `STATE_MACHINES.md`.
### Finding 5 — Build order needed dependency graph, not only phase lists
Codex needs to know not only tasks, but why one task must precede another.
Resolution:
- added Build Order Dependency Graph.
### Finding 6 — Golden paths needed stronger protection
The desired demo was clear, but not protected as regression-critical workflows.
Resolution:
- added `GOLDEN_PATHS.md`.
### Finding 7 — Error handling needed stable codes
The frontend and backend need a common error taxonomy.
Resolution:
- added `ERROR_CATALOG.md`.
## Remaining recommendations for M12+
1. Generate actual starter code skeleton aligned with the docs.
2. Add OpenAPI YAML snapshot once backend exists.
3. Add migration files once database models exist.
4. Convert golden paths into executable tests.
5. Add real small GeoTIFF fixture if licensing/file size allows.
6. Add GRB WFS proof-of-concept adapter after local fixture path is stable.
7. Add QGIS export verification later.
## Architect verdict
The repo is now suitable for a disciplined autonomous Codex build, provided Codex starts from `docs/00-start/START_HERE.md` and treats older handoff docs as historical.
@@ -0,0 +1,86 @@
# Codex Tomorrow Runbook
## Before starting
Use the latest full repo zip, extract it, and open the repository root.
Read:
1. `CODEX_START.md`
2. `docs/00-start/START_HERE.md`
3. `docs/20-run-readiness/RUN_READINESS_FINAL.md`
4. `docs/20-run-readiness/PASS_SEQUENCE_FINAL.md`
5. `prompts/codex/final/DAY_1_MASTER_PROMPT.md`
## Operating rhythm
For each pass:
1. Restate the pass goal.
2. List files expected to change.
3. Implement only the pass scope.
4. Run the relevant commands.
5. Fix failures within scope.
6. Update status docs.
7. Produce pass report.
## Do not allow Codex to drift into
- redesigning the product;
- adding auth/multi-user early;
- building a chatbot first;
- implementing LiDAR first;
- building a full report generator first;
- replacing FastAPI/PostGIS/React;
- using only demo data without real-data-ready interfaces;
- hiding broken states behind TODO comments.
## Recommended first commands
```bash
find . -maxdepth 3 -type f | sort | head -200
bash scripts/check_repo_structure.sh
python scripts/smoke_docs.py
python scripts/validate_fixtures.py
python scripts/preimplementation_audit.py
```
If scripts fail because permissions are missing, run them with `bash scriptname.sh` or `python scriptname.py` rather than changing architecture.
## Pass report template
```text
Pass:
Scope:
Files changed:
Commands run:
Tests/smoke checks:
What works now:
Known limitations:
Architecture invariants touched:
Golden path status:
Next pass:
```
## Stop conditions
Stop and create a proposal note instead of coding when:
- a required architecture decision is missing;
- a chosen dependency conflicts with the dependency policy;
- a requested change violates an invariant;
- API contracts require breaking changes;
- a geospatial assumption is unclear and affects data correctness.
## Success definition for tomorrow
A successful day does not require every advanced module. A successful day means:
- backend foundation exists;
- database/domain foundation exists;
- project/area/dataset flow works;
- fixture vector import works;
- QA/QC can run on fixture buildings;
- GeoJSON export exists;
- minimal UI can display the workflow or at least consume the API;
- docs and tests reflect reality.
@@ -0,0 +1,40 @@
# Implementation Readiness Checklist
## Repo readiness
- [ ] `CODEX_START.md` exists at repo root.
- [ ] `docs/00-start/START_HERE.md` exists.
- [ ] `docs/20-run-readiness/RUN_READINESS_FINAL.md` exists.
- [ ] `prompts/codex/final/DAY_1_MASTER_PROMPT.md` exists.
- [ ] `scripts/preimplementation_audit.py` runs.
- [ ] Demo fixtures validate.
## Architecture readiness
- [ ] Product identity is fixed.
- [ ] Stack is fixed.
- [ ] Database choice is fixed.
- [ ] CRS/GIS standards are fixed.
- [ ] State machines are fixed.
- [ ] Golden paths are fixed.
- [ ] Forbidden decisions are explicit.
## Build readiness
- [ ] Pass order is known.
- [ ] First vertical slice is known.
- [ ] V1 exclusions are known.
- [ ] Definition of Done is known.
- [ ] Smoke tests are known.
- [ ] Pass report format is known.
## Release readiness target
- [ ] Backend imports.
- [ ] Health endpoint works.
- [ ] Database models exist.
- [ ] Project/Area/Dataset APIs exist.
- [ ] Fixtures can be imported.
- [ ] QA/QC metrics can be computed.
- [ ] GeoJSON can be exported.
- [ ] Minimal UI can show results.
@@ -0,0 +1,206 @@
# Final Codex Pass Sequence
Codex must execute these passes in order. Do not skip ahead unless the previous pass is complete and smoke-checked.
## Pass 0 — Repo audit and bootstrap
Goal: confirm the repo can be used as an implementation workspace.
Deliverables:
- confirm folder structure;
- install/dependency plan selected;
- create missing backend/frontend scaffolding only if absent;
- no product feature work yet;
- run docs smoke scripts.
Exit criteria:
- `CODEX_START.md` is acknowledged;
- canonical docs are read;
- no conflicting start path remains unaddressed in notes.
## Pass 1 — Backend application foundation
Goal: create a FastAPI app that imports and serves health/status endpoints.
Deliverables:
- `backend/app/main.py`;
- settings/config module;
- API router structure;
- health endpoint;
- error envelope helper;
- minimal tests.
Exit criteria:
- backend imports successfully;
- health endpoint test passes;
- no database required yet.
## Pass 2 — Database and domain foundation
Goal: establish SQLAlchemy/Alembic/PostGIS-ready domain models.
Deliverables:
- DB config;
- migration skeleton;
- models for Project, Area, Dataset, AnalysisRun, Detection, Metric, Export;
- schemas for request/response;
- geometry storage strategy documented in code comments and docs.
Exit criteria:
- migrations can be generated/applied in local environment;
- models match canonical domain docs;
- no geometry stored as arbitrary string when PostGIS type is available.
## Pass 3 — Project and Area API
Goal: implement the first user-managed domain objects.
Deliverables:
- project CRUD;
- area CRUD;
- geometry validation;
- area calculation;
- API tests;
- response envelope compliance.
Exit criteria:
- create/list/read project works;
- create/list/read area works;
- invalid geometry returns controlled error.
## Pass 4 — Dataset manager foundation
Goal: register datasets and extract basic metadata.
Deliverables:
- dataset upload/registration endpoint;
- metadata schema;
- storage path convention;
- fixture registration path;
- dataset state machine implemented.
Exit criteria:
- fixture vector dataset can be registered;
- dataset moves through valid states;
- failed validation is explicit.
## Pass 5 — Vector processing core
Goal: load reference polygons and predicted detection polygons.
Deliverables:
- GeoJSON import;
- geometry normalization;
- CRS handling;
- feature count and bounds metrics;
- persistence of reference and predicted layers.
Exit criteria:
- reference buildings fixture imports;
- predicted buildings fixture imports;
- invalid GeoJSON is rejected safely.
## Pass 6 — QA/QC engine foundation
Goal: compare predicted detections against reference polygons.
Deliverables:
- IoU/overlap matching;
- precision, recall, F1;
- false positive/false negative outputs;
- quality check records;
- tests with demo fixtures.
Exit criteria:
- expected demo metrics are reproduced or documented;
- algorithm is deterministic;
- matching thresholds are configurable but defaulted.
## Pass 7 — GeoJSON export
Goal: export geospatial outputs from the system.
Deliverables:
- export endpoint;
- export records;
- GeoJSON FeatureCollection output;
- export validation;
- smoke test.
Exit criteria:
- detections export as valid GeoJSON;
- QA/QC outputs can be exported;
- no broken geometry emitted.
## Pass 8 — Frontend workbench shell
Goal: create a minimal but coherent UI.
Deliverables:
- React/TypeScript app shell;
- route structure;
- project list/detail;
- map workbench placeholder with layer panel;
- API client;
- loading/error/empty states.
Exit criteria:
- frontend builds;
- health/status can be displayed;
- no hardcoded permanent fake data except clearly marked demo fixtures.
## Pass 9 — Map and metrics integration
Goal: show the vertical slice visually.
Deliverables:
- render area/reference/prediction layers;
- metrics panel;
- QA/QC result cards;
- export action;
- basic style guide compliance.
Exit criteria:
- demo Geel workflow can be clicked through;
- layer visibility/opacity works at minimum level;
- UI does not obscure the map or results.
## Pass 10 — Stabilization and release candidate
Goal: make the first vertical slice releasable.
Deliverables:
- smoke tests;
- docs update;
- known limitations;
- changelog;
- run instructions;
- regression checklist.
Exit criteria:
- backend tests pass;
- frontend build passes;
- demo workflow documented;
- no architecture invariant violated.
@@ -0,0 +1,37 @@
# Repo Conflict Resolution
The repo contains many milestone documents. This is intentional, but implementation must not follow conflicting instructions.
## Conflict categories
### Product conflict
Example: one document says GeoIntel is a dashboard, another says GeoIntel is a GeoAI Workbench.
Resolution: follow `GEOINTEL_CONSTITUTION.md`.
### Stack conflict
Example: one document suggests another backend framework.
Resolution: follow ADRs and `ARCHITECTURE_INVARIANTS.md`.
### Scope conflict
Example: one older document prioritizes reports before QA/QC.
Resolution: follow `PASS_SEQUENCE_FINAL.md` and `V1_SCOPE_FREEZE.md`.
### API conflict
Example: endpoint naming differs between older docs.
Resolution: follow `API_CONTRACTS.md`, `API_CONTRACT_FREEZE_M2.md`, and response envelope contracts.
### CRS/geospatial conflict
Resolution: follow `GIS_STANDARDS.md`, `CRS_POLICY.md`, and canonical geometry contracts.
## Rule
When implementing, newer canonical control docs are binding. Older milestone docs are explanatory only.
@@ -0,0 +1,75 @@
# M12 Run Readiness Final Audit
## Purpose
This document converts the large GeoIntel preparation set into a practical final execution layer for Codex. The repo contains many useful milestone documents, but the implementation run must follow one canonical path.
## Final readiness status
GeoIntel is ready to start implementation when Codex follows the canonical path below and does not treat older milestone documents as competing instructions.
## Canonical control stack
1. Product identity: `docs/governance/GEOINTEL_CONSTITUTION.md`
2. Architecture invariants: `docs/governance/ARCHITECTURE_INVARIANTS.md`
3. Forbidden decisions: `docs/governance/FORBIDDEN_DECISIONS.md`
4. Decision precedence: `docs/governance/DECISION_PRECEDENCE.md`
5. Domain models: `docs/specs/CANONICAL_DOMAIN_MODELS.md`
6. GIS standards: `docs/specs/GIS_STANDARDS.md`
7. Raster standards: `docs/specs/RASTER_STANDARDS.md`
8. State machines: `docs/specs/STATE_MACHINES.md`
9. Golden paths: `docs/workflows/GOLDEN_PATHS.md`
10. Build dependency graph: `docs/build/BUILD_ORDER_DEPENDENCY_GRAPH.md`
11. Final pass sequence: `docs/20-run-readiness/PASS_SEQUENCE_FINAL.md`
12. Day 1 master prompt: `prompts/codex/final/DAY_1_MASTER_PROMPT.md`
## Older milestone documents
Older M0-M11 documents remain valuable as supporting context. They are not deleted because they contain useful details, but they must not override the canonical control stack.
When in doubt, Codex must follow:
`CODEX_START.md``START_HERE.md` → M12 run-readiness docs → governance/specs → implementation prompts.
## Final V1 scope
V1 is the foundation GeoAI Workbench vertical slice.
V1 includes:
- backend skeleton;
- database models and migrations;
- project CRUD;
- area CRUD with geometry validation;
- dataset registration/upload metadata;
- vector import using fixtures first;
- raster metadata extraction where libraries are available;
- reference polygon loading;
- predicted detection import;
- QA/QC matching against reference polygons;
- metric persistence;
- GeoJSON export;
- minimal frontend workbench;
- status/error handling;
- smoke tests.
V1 excludes:
- live production GRB sync as a blocker;
- heavy model training;
- full SAM/YOLO production inference as a blocker;
- LiDAR processing;
- MLOps registry implementation;
- QGIS plugin;
- multi-user permissions;
- advanced PDF report generation.
## Implementation policy
Codex may improve implementation details, UX clarity, tests, types, helper abstractions and documentation. Codex must not alter product identity, stack, state machines, response envelope, database choice, CRS policy or golden path priority without an ADR proposal.
## Final release target
The first release target is not a complete GeoAI platform. It is a stable, demonstrable vertical slice proving that GeoIntel can move geospatial data through the core pipeline:
`data → processing → geospatial output → QA/QC → export`.
@@ -0,0 +1,43 @@
# M13 Codex Optimization Overview
M13 adds an optimization layer on top of the M12 run-ready repository. The goal is to improve Codex output quality by making the implementation process more constrained where correctness matters, while still allowing local improvements inside documented boundaries.
## M13 purpose
Codex should be able to:
1. choose the correct entry document without ambiguity;
2. work pass-by-pass without re-planning the whole product;
3. use reusable skills for repeated implementation patterns;
4. respect token and context budgets;
5. avoid secrets leakage;
6. split work safely across parallel agents or worktrees;
7. self-review every implementation pass against explicit gates;
8. escalate only real blockers.
## New canonical Codex flow
1. Read `CODEX_START.md`.
2. Read `docs/30-codex-optimization/CODEX_RUN_CHECKLIST.md`.
3. Read `docs/30-codex-optimization/PROMPT_DISCIPLINE.md`.
4. Select the active pass from `docs/20-run-readiness/PASS_SEQUENCE_FINAL.md`.
5. Select only the relevant skill from `skills/`.
6. Implement the smallest coherent pass.
7. Run `make readiness` plus module-specific checks.
8. Fill in `docs/CODEX_EXECUTION_LOG.md`.
9. Produce a pass summary using `prompts/codex/m13/PASS_COMPLETION_REPORT_PROMPT.md`.
## M13 rule hierarchy
If instructions conflict, follow this order:
1. `docs/governance/GEOINTEL_CONSTITUTION.md`
2. `docs/governance/ARCHITECTURE_INVARIANTS.md`
3. `docs/governance/FORBIDDEN_DECISIONS.md`
4. `CODEX_START.md`
5. `docs/30-codex-optimization/*`
6. active pass prompt
7. module documentation
8. historical milestone documents
Historical M0-M12 documents remain useful, but they must not override governance, invariants, M12 final readiness, or M13 optimization rules.
@@ -0,0 +1,48 @@
# Codex Run Checklist
Use this checklist at the start and end of every Codex session.
## Before starting
- [ ] Confirm the current branch/worktree.
- [ ] Read `CODEX_START.md`.
- [ ] Read `docs/00-start/START_HERE.md`.
- [ ] Read `docs/30-codex-optimization/CODEX_OPTIMIZATION_OVERVIEW.md`.
- [ ] Read `docs/30-codex-optimization/PROMPT_DISCIPLINE.md`.
- [ ] Read only the active pass prompt.
- [ ] Read the relevant skill from `skills/`.
- [ ] Run `make readiness` if the repository has shell/python available.
- [ ] Identify the exact files expected to change.
## During implementation
- [ ] Keep changes scoped to the active pass.
- [ ] Do not introduce new frameworks without ADR.
- [ ] Do not change API contracts unless the active pass explicitly requires it.
- [ ] Do not create permanent mock-only implementations.
- [ ] Prefer small, verifiable service boundaries.
- [ ] Keep GIS units and CRS assumptions explicit.
- [ ] Record real limitations as limitations, not hidden TODOs.
## Before finishing
- [ ] Run relevant tests/smoke checks.
- [ ] Run `make readiness` when possible.
- [ ] Update `docs/CODEX_EXECUTION_LOG.md`.
- [ ] Update `CHANGELOG.md`.
- [ ] List changed files.
- [ ] List what works.
- [ ] List what remains incomplete.
- [ ] List any deliberate deviations from docs.
- [ ] Produce a self-review scorecard.
## Stop conditions
Stop and report instead of guessing when:
- a governance invariant would be violated;
- a required external credential is missing;
- a data source license or endpoint is unclear;
- a destructive migration would be needed;
- tests indicate a core regression;
- implementation requires a new major dependency not already approved.
@@ -0,0 +1,28 @@
# Codex Skills Index
Skills are reusable implementation workflows. Use one skill per implementation pass unless the task clearly spans two tightly coupled areas.
## Available skills
| Skill | Use when |
|---|---|
| `geoai-backend-build` | creating FastAPI services, routers, schemas, domain logic |
| `postgis-migration` | creating database models, Alembic migrations, geometry fields |
| `raster-pipeline` | implementing Rasterio/GDAL-style raster metadata, clip, tile, indices |
| `vector-processing` | implementing GeoPandas/Shapely vector operations and exports |
| `frontend-maplibre-workbench` | building React/MapLibre pages, layers, UI states |
| `qaqc-review` | implementing IoU, precision/recall, false positives/negatives |
| `codex-pass-review` | final self-review, regression scan and pass completion reports |
## Skill usage protocol
1. Read active pass prompt.
2. Select the closest skill.
3. Read `skills/<skill>/SKILL.md`.
4. Implement using the skill checklist.
5. Run module-specific checks.
6. End with the skill's required report fields.
## Skill conflict rule
If a skill conflicts with governance docs, governance wins. Update the skill later; do not violate governance.
@@ -0,0 +1,29 @@
# M13 Handoff Summary — Codex Optimization Pack
M13 adds the final layer intended to improve tomorrow's Codex execution quality.
## Added
- Codex optimization overview.
- Codex run checklist.
- Prompt discipline rules.
- Token/context budget policy.
- Secrets and environment policy.
- Parallel agent strategy.
- Codex skills index.
- Reusable skills under `skills/`.
- M13 day-one optimized master prompt.
- Pass completion report prompt.
- Updated readiness checks for M13 assets.
## Why this matters
M12 made the repository run-ready. M13 makes the repository easier for Codex to execute correctly without wasting context, drifting from contracts, leaking secrets, or making undocumented architecture choices.
## Recommended next action
Use:
- `prompts/codex/m13/DAY_1_OPTIMIZED_MASTER_PROMPT.md`
for the first serious Codex build run.
@@ -0,0 +1,87 @@
# Parallel Agent Strategy
GeoIntel can use multiple Codex agents only when their work areas do not conflict.
## Safe parallel tracks
### Track A — Backend foundation
Allowed paths:
- `backend/`
- `tests/backend/`
- database docs when needed
Do not touch frontend except API contract comments.
### Track B — Frontend shell
Allowed paths:
- `frontend/`
- `tests/frontend/`
- UI docs when needed
Do not change API contracts without coordination.
### Track C — Documentation/runbooks
Allowed paths:
- `docs/`
- `prompts/`
- `skills/`
- `checklists/`
Do not change implementation code.
### Track D — Fixtures/tests
Allowed paths:
- `tests/fixtures/`
- `fixtures/`
- `scripts/`
- test docs
Do not alter production services except to expose stable test hooks.
## Unsafe parallel work
Do not run parallel agents on:
- database schema plus API schemas unless coordinated;
- API contracts plus frontend client generation unless coordinated;
- storage paths plus dataset manager unless coordinated;
- detection output schemas plus QA/QC engine unless coordinated.
## Worktree naming convention
```text
worktrees/
geointel-backend-foundation
geointel-frontend-shell
geointel-qaqc-engine
geointel-docs-control
```
## Merge order
1. governance/docs updates;
2. database/domain foundation;
3. backend APIs;
4. frontend API client;
5. UI pages;
6. tests/fixtures;
7. polish.
## Parallel agent completion report
Every agent must report:
- branch/worktree name;
- files changed;
- contracts touched;
- tests run;
- merge risks;
- required follow-up from other tracks.
@@ -0,0 +1,94 @@
# Prompt Discipline for Codex Runs
Codex performs best when each run has one active objective, a clear source of truth, explicit stop conditions, and a small set of expected outputs.
## Required prompt shape
Every implementation prompt should contain:
1. Active milestone.
2. Active pass.
3. Required documents to read.
4. Forbidden documents to treat as historical only.
5. Expected files or directories to touch.
6. Expected tests/checks.
7. Definition of Done.
8. Reporting format.
## Good prompt pattern
```text
You are working on GeoIntel Kempen.
Active pass: PASS_02_DATABASE_DOMAIN.
Read first: CODEX_START.md, docs/30-codex-optimization/CODEX_RUN_CHECKLIST.md, skills/postgis-migration/SKILL.md, docs/DATABASE_IMPLEMENTATION_PLAN.md.
Do not modify frontend files in this pass.
Implement only the database/domain foundation described in the active pass.
Run make readiness and relevant backend checks.
End with changed files, commands run, tests, risks, next pass.
```
## Bad prompt pattern
```text
Build the whole platform. Improve whatever you see. Make it production ready.
```
This is forbidden because it causes scope creep, undocumented architecture choices, and conflicting implementations.
## Improvement boundary
Codex may improve:
- naming consistency;
- validation details;
- typing;
- docstrings;
- tests;
- small helper functions;
- error messages;
- UI empty/loading/error states;
- non-breaking internal structure.
Codex may not independently change:
- primary stack;
- database choice;
- job queue choice;
- CRS policy;
- API contract shape;
- V1 scope;
- security model;
- storage architecture;
- model governance rules.
## Context loading rule
Do not read the entire repository for every pass. Load context in this order:
1. root start files;
2. governance docs;
3. active pass prompt;
4. relevant skill;
5. directly relevant module docs;
6. code files affected by the pass;
7. tests/fixtures for the affected area.
## End-of-pass response format
Codex must end each pass with:
```md
## Completed
## Changed files
## Commands run
## Test results
## Known limitations
## Deviations from docs
## Next recommended pass
```
@@ -0,0 +1,50 @@
# Secrets and Environment Policy
GeoIntel must be safe to publish as a portfolio repository.
## Absolute rules
- Never commit real API keys.
- Never commit credentials, tokens, cookies or private endpoints.
- Never place secrets in docs, fixtures, tests or screenshots.
- `.env.example` may contain placeholder values only.
- Runtime secrets are read from environment variables.
- If a real key is accidentally found, remove it and rotate it outside the repo.
## Approved environment variables
- `DATABASE_URL`
- `POSTGRES_HOST`
- `POSTGRES_PORT`
- `POSTGRES_DB`
- `POSTGRES_USER`
- `POSTGRES_PASSWORD`
- `REDIS_URL`
- `STORAGE_ROOT`
- `OPENAI_API_KEY`
- `COPERNICUS_CLIENT_ID`
- `COPERNICUS_CLIENT_SECRET`
- `GRB_WFS_BASE_URL`
- `OSM_OVERPASS_URL`
## Codex behavior
When credentials are missing, Codex must:
1. implement a clear configuration error;
2. document the missing variable;
3. provide an example in `.env.example`;
4. avoid hardcoded fallback secrets;
5. keep external-service calls behind adapters.
## Local development fallback
For V1 foundation work, services should be able to run with:
- local PostGIS;
- local Redis;
- fixture datasets;
- disabled external fetchers;
- deterministic demo outputs.
This fallback is not fake production behavior. It is a development mode and must be labeled as such.
@@ -0,0 +1,45 @@
# Token and Context Budget Policy
This repository is intentionally documentation-heavy. Codex must not load all documents for every task.
## Context tiers
### Tier 0 — Always read
- `CODEX_START.md`
- `docs/00-start/START_HERE.md`
- `docs/30-codex-optimization/CODEX_RUN_CHECKLIST.md`
- active pass prompt
### Tier 1 — Read when architecture-sensitive
- `docs/governance/GEOINTEL_CONSTITUTION.md`
- `docs/governance/ARCHITECTURE_INVARIANTS.md`
- `docs/governance/FORBIDDEN_DECISIONS.md`
- relevant ADRs
### Tier 2 — Read when module-specific
- relevant module spec
- relevant skill
- relevant API/database contract
- relevant tests/fixtures
### Tier 3 — Historical reference only
- old milestone handoff summaries
- previous pass prompts not active for the current run
- release notes from previous preparation milestones
## Budget rules
- Prefer reading indexes before detailed specs.
- Prefer targeted `grep/find` over opening large unrelated docs.
- Do not re-summarize old milestones unless needed.
- Work in small coherent diffs.
- If a task requires touching more than three major subsystems, split it into passes.
- If the active prompt conflicts with governance, stop and report.
## Large file policy
Large generated files, model artifacts, tiles, rasters and exports must not be created during documentation-preparation passes unless they are tiny fixtures. Real heavy assets belong outside git or in storage paths documented by `docs/STORAGE_ARCHITECTURE.md`.
@@ -0,0 +1,41 @@
# BACKLOG PRIORITIES — MoSCoW
## Must have for Sprint 1
- Backend app foundation.
- Database/PostGIS foundation.
- Project Manager.
- Area Manager.
- Dataset Manager for GeoJSON.
- Metadata extraction.
- Frontend shell.
- MapLibre map.
- Demo fixture display.
- Readiness checks.
## Should have for Sprint 1 if musts are complete
- GeoJSON export baseline.
- Area import from fixture.
- Dataset detail metadata panel.
- Simple layer tree.
- Basic smoke tests for frontend build.
## Could have later in same early phase
- Reference/prediction fixture import.
- QA/QC schema validation.
- Simple feature statistics.
- Layer opacity controls.
## Won't have in Sprint 1
- Live YOLO inference.
- Live SAM segmentation.
- GRB live WFS.
- Sentinel automation.
- LiDAR processing.
- Training Studio.
- AI Copilot.
- Full PDF report generator.
- Multi-user auth.
+78
View File
@@ -0,0 +1,78 @@
# BUILD ORDER GRAPH — M14 Launch
Codex must follow this dependency graph for implementation.
## Graph
```text
Repository readiness
-> Environment/config
-> Backend app foundation
-> Database/PostGIS foundation
-> Domain models/schemas
-> Migrations
-> Project API
-> Area API
-> Dataset API
-> Storage service
-> Metadata extraction
-> Frontend shell
-> Frontend API client
-> Map workbench shell
-> Dataset UI
-> Fixture layer display
-> Export baseline
-> Tests and readiness
```
## Blocked until foundation is stable
The following are blocked until the above graph is green:
- Detection Lab.
- Segmentation Lab.
- QA/QC engine beyond fixture/schema validation.
- Remote Sensing Lab.
- GRB live adapter.
- OSM live adapter.
- LiDAR Workbench.
- Training Studio.
## Rule
If a later module requires missing foundation work, Codex must complete the foundation work first instead of building around it.
## Preferred first implementation passes
### Pass 1 — Backend and config
- Create app structure.
- Add config/settings.
- Add health endpoint.
- Add response envelope and error handling.
### Pass 2 — Database and domain
- Add database connection.
- Add migrations.
- Add core models.
- Enable PostGIS.
### Pass 3 — Project/Area/Dataset API
- Implement CRUD.
- Validate geometry.
- Extract metadata.
### Pass 4 — Frontend shell and map
- React app.
- Layout.
- MapLibre.
- API client.
### Pass 5 — Fixture-driven integration
- Load demo area/reference layer.
- Display layers.
- Run smoke tests.
@@ -0,0 +1,106 @@
# BUILD SUCCESS DEFINITION — Sprint 1 / First Codex Run
This document defines the exact point at which Codex must stop expanding scope and consider the first implementation run successful.
## Purpose
The first build is not successful because many features exist. It is successful when the foundation is stable, testable and ready for the next module.
## Sprint 1 success statement
Sprint 1 is successful when GeoIntel can run locally with a backend, frontend, database and a minimal geospatial dataset workflow.
The vertical slice is:
```text
Project
-> Area
-> Dataset upload/registration
-> Metadata extraction
-> PostGIS persistence
-> Minimal map display
-> GeoJSON export
```
## Required backend success criteria
- FastAPI application starts without import errors.
- `/health` returns a successful response.
- `/docs` or OpenAPI schema is available in development.
- Database configuration is loaded from environment variables.
- PostgreSQL connection is verified by a health or readiness check.
- PostGIS extension is created or verified by migration/bootstrap logic.
- Project CRUD works through API endpoints.
- Area CRUD works with valid GeoJSON polygon input.
- Dataset registration or upload works for at least GeoJSON.
- Dataset metadata is extracted and persisted.
- API responses use the canonical response envelope.
- Errors use the canonical error format.
## Required database success criteria
- Alembic or equivalent migration path exists.
- Core tables exist:
- `projects`
- `areas`
- `datasets`
- `dataset_versions` or documented equivalent
- `analysis_runs` placeholder/table if needed for future compatibility
- `exports` placeholder/table if needed for future compatibility
- Geometry columns use PostGIS types.
- CRS/SRID rules follow `docs/specs/GIS_STANDARDS.md`.
- Demo seed data can be loaded or fixtures can be used in tests.
## Required frontend success criteria
- React/Vite application starts.
- Main layout is visible.
- MapLibre map renders.
- Project list/detail state exists.
- Dataset upload/registration UI exists for the Sprint 1 dataset type.
- Area display or drawing/import flow exists in minimal form.
- API client uses configured backend base URL.
- Loading, empty and error states exist for the implemented pages.
## Required storage success criteria
- Uploaded/registered dataset files are stored under a controlled storage path.
- Storage paths are not hardcoded to a developer machine.
- Metadata in the database references stored files where applicable.
- Generated exports go to a controlled exports folder.
## Required testing success criteria
At minimum:
- Backend import smoke test passes.
- Health endpoint test passes.
- Database connection/migration smoke test passes or has a documented fallback if no DB is available in CI.
- GeoJSON fixture validation passes.
- Frontend build or typecheck passes.
- `make readiness` passes.
## Explicitly not required for Sprint 1
Do not block Sprint 1 on:
- YOLO inference.
- SAM inference.
- Sentinel download automation.
- GRB live WFS integration.
- LiDAR processing.
- Training Studio.
- AI Copilot.
- Advanced reporting.
- Multi-user authentication.
- Production deployment.
## Stop condition
When all Sprint 1 success criteria are met, Codex must stop feature expansion and produce:
- changelog entry;
- commands run;
- test results;
- known limitations;
- next pass recommendation.
+45
View File
@@ -0,0 +1,45 @@
# CODEX STOP RULES
Codex must stop or pause expansion when these conditions occur.
## Hard stop conditions
Stop implementation and report if:
- backend cannot import;
- frontend cannot build due to own changes;
- migrations cannot be generated or applied due to unclear schema conflict;
- API contract conflict is found;
- architecture invariant would need to be broken;
- dependency choice conflicts with ADRs;
- secrets or API keys are accidentally introduced;
- external service is required for a Sprint 1 must-have.
## Soft stop conditions
Pause expansion and finish cleanup if:
- tests fail after the intended module is implemented;
- a feature starts requiring a non-Sprint-1 module;
- implementation requires more than one new abstraction not already documented;
- generated code duplicates existing logic;
- TODO comments are being used to hide incomplete logic.
## What Codex must do at stop
Report:
- exact blocker;
- files affected;
- commands run;
- failing output summary;
- recommended fix;
- whether rollback is needed.
## What Codex must not do
- Do not continue building unrelated modules while the build is broken.
- Do not silence errors by weakening tests.
- Do not replace real functionality with permanent mock logic.
- Do not change the architecture to make one test pass.
- Do not introduce a new dependency without ADR-compatible justification.
@@ -0,0 +1,116 @@
# DATA ACQUISITION PLAYBOOK
This playbook tells Codex how to think about data acquisition without spending the first build researching or overengineering live integrations.
## Principle
Sprint 1 uses local demo fixtures first. Live external data integrations are later adapters.
The data hierarchy is:
1. Golden fixtures for tests and UI development.
2. Local user-uploaded files.
3. Cached reference extracts.
4. Live external data services.
## Sprint 1 data sources
### Golden GeoJSON fixtures
Use existing files in `demo/geel/` as the first source of truth:
- `area_geel_center.geojson`
- `reference_buildings.geojson`
- `demo_detections.geojson`
- `expected_qaqc_metrics.json`
These are not meant to be geographically complete. They are contract fixtures.
### User upload/register
Support GeoJSON first. Validate:
- file extension;
- JSON parse;
- FeatureCollection shape;
- geometry existence;
- CRS handling fallback;
- bounds calculation.
## GRB strategy
GRB is the professional reference layer for Vlaanderen. It is the preferred future reference for buildings and related vector features.
### Sprint 1
- Do not implement live GRB WFS yet.
- Use GRB-like local fixture data.
- Design a `ReferenceDataAdapter` interface so GRB can be added without rewriting QA/QC.
### Sprint 2+
- Add GRB adapter.
- Prefer bbox/area-scoped retrieval.
- Cache retrieved features in PostGIS.
- Track source, retrieval timestamp and layer name.
### Fallback
If GRB is unavailable:
- use cached extract;
- show external-source-unavailable status;
- do not fake live data.
## OSM strategy
OSM can be useful as a broad fallback/reference but must not replace GRB for professional building QA where GRB is available.
### Sprint 1
- No live OSM required.
- Keep adapter boundary ready.
### Later
- Use Overpass or local extracts for bounded areas.
- Cache in PostGIS.
## Sentinel strategy
Sentinel belongs to the Remote Sensing Lab, not Sprint 1.
### Sprint 1
- No Sentinel automation.
- Do not add Copernicus dependencies.
### Later
- Prefer STAC-based lookup where possible.
- Support NDVI/NDWI/NDBI through raster pipeline.
- Cache downloaded scenes/derived rasters.
## DHMV / height data strategy
DHMV/DEM/DSM belongs after raster/vector foundations are stable.
### Sprint 1
- No height integration.
### Later
- Add DEM/DSM products as raster datasets.
- Reuse raster metadata, clipping and tiling pipelines.
## Data acquisition acceptance criteria
A new data source is accepted only when it has:
- adapter boundary;
- source metadata;
- cache strategy;
- error handling;
- tests or fixture equivalent;
- documentation update.
+75
View File
@@ -0,0 +1,75 @@
# FOLDER OWNERSHIP AND RESPONSIBILITIES
Codex must keep responsibilities separated.
## `backend/app/api/`
HTTP routes only. No heavy business logic.
## `backend/app/schemas/`
Pydantic request/response models and API DTOs.
## `backend/app/models/`
Database ORM models.
## `backend/app/services/`
Business logic and orchestration.
## `backend/app/repositories/`
Database access patterns if repository layer is used.
## `backend/app/workers/`
RQ/Celery/background job entry points.
## `backend/app/geo/`
GIS-specific helpers: CRS, geometry validation, bounds, area calculations.
## `backend/app/storage/`
File storage logic.
## `backend/tests/`
Backend tests. Tests should not live beside production modules unless project conventions are changed deliberately.
## `frontend/src/pages/`
Route-level pages.
## `frontend/src/components/`
Reusable UI components.
## `frontend/src/features/`
Feature-oriented frontend modules, e.g. projects, datasets, map, exports.
## `frontend/src/services/`
API client/services.
## `frontend/src/stores/`
Client state only if needed.
## `docs/`
Architecture, specs and governance. Update docs when contracts or build rules change.
## `demo/`
Small golden fixtures and demo manifests. Not production storage.
## `datasets/`
Local development data folders. Do not commit large real datasets.
## `storage/`
Runtime storage. Keep `.gitkeep`, do not commit generated artifacts.
@@ -0,0 +1,67 @@
# GOLDEN DATASET PACKAGE
The golden dataset package defines the stable demo/test inputs that Codex must protect.
## Purpose
Golden data allows Codex to build and test without depending on live external services.
## Golden area
`demo/geel/area_geel_center.geojson`
Represents the canonical Sprint 1 area fixture. It must remain valid GeoJSON.
## Golden reference layer
`demo/geel/reference_buildings.geojson`
Represents reference building polygons. In future this will map to GRB-like reference data.
Required properties:
- stable feature IDs where possible;
- polygon or multipolygon geometry;
- deterministic feature count;
- valid geometries.
## Golden prediction layer
`demo/geel/demo_detections.geojson`
Represents predicted building detections or imported detection outputs.
Required properties:
- class label;
- confidence where available;
- polygon or bbox-derived polygon geometry;
- stable enough for QA/QC fixture checks.
## Golden expected metrics
`demo/geel/expected_qaqc_metrics.json`
Represents expected QA/QC output for the demo fixture. Codex may update this only if:
- the fixture geometry intentionally changes;
- the QA/QC algorithm version changes;
- changelog explains the reason.
## Golden data rules
- Do not delete golden fixtures.
- Do not replace golden fixtures with random generated data.
- Do not make tests depend on external services when golden fixtures are sufficient.
- Keep fixtures small enough for fast CI/smoke runs.
- If new fixture files are added, update `docs/DEMO_FIXTURE_MANIFEST.md`.
## Sprint 1 usage
Codex should use golden data for:
- frontend map layer smoke display;
- backend fixture validation;
- dataset metadata extraction tests;
- future QA/QC regression tests;
- export contract tests.
@@ -0,0 +1,83 @@
# MODULE ACCEPTANCE CRITERIA
This document defines when a module is considered done enough to move forward.
## Backend foundation
Done when:
- app imports without error;
- health endpoint works;
- config is environment-driven;
- response envelope is used;
- error shape is canonical;
- backend smoke test exists.
## Database foundation
Done when:
- database connection is configured;
- PostGIS is enabled or checked;
- migrations exist;
- core tables can be created;
- geometry storage works;
- tests or smoke checks exist.
## Project Manager
Done when:
- project create/list/read works;
- invalid payloads return canonical errors;
- frontend can display projects;
- tests cover at least one create/list/read path.
## Area Manager
Done when:
- valid GeoJSON polygon can be stored;
- invalid geometry is rejected;
- bounds or area metadata is returned where practical;
- geometry is stored in PostGIS;
- frontend can display at least one area on the map.
## Dataset Manager
Done when:
- GeoJSON dataset can be registered/uploaded;
- metadata is extracted;
- metadata is persisted;
- original file or reference is stored;
- dataset state follows the state machine;
- frontend can list datasets.
## Map Workbench Foundation
Done when:
- MapLibre renders;
- fixture layer can be displayed;
- layer loading state exists;
- error state exists;
- map controls do not break layout.
## Export baseline
Done when:
- at least one valid GeoJSON export path exists;
- export file is stored or streamed consistently;
- export metadata is recorded or returned;
- invalid export requests fail gracefully.
## QA/QC skeleton
Done when:
- schema for reference and prediction layers is documented/implemented;
- no live AI inference is required;
- future QA engine can plug into analysis run structure;
- fixture metrics can be validated if implemented.
+68
View File
@@ -0,0 +1,68 @@
# RELEASE STRATEGY
GeoIntel releases must be small, testable and aligned with the build order graph.
## Version targets
### v0.1 — Foundation
- Backend starts.
- Frontend starts.
- Database/PostGIS works.
- Health/readiness works.
### v0.2 — Project and Area Manager
- Project CRUD.
- Area CRUD.
- Geometry persistence.
- Map displays area fixtures.
### v0.3 — Dataset Manager
- GeoJSON upload/register.
- Metadata extraction.
- Dataset list/detail UI.
### v0.4 — Raster/Vector Foundation
- Raster metadata skeleton if dependencies are available.
- Vector operations baseline.
- Layer display improvements.
### v0.5 — Detection Import / Detection Lab Skeleton
- Detection result import.
- Detection layer display.
- Model-adapter boundary, no heavy inference required yet.
### v0.6 — QA/QC Foundation
- Reference vs prediction matching.
- Metrics.
- False positive/false negative outputs.
### v0.7 — GeoJSON Export and Review
- Stable export workflow.
- Export validation.
- Basic review UI.
### v1.0 — GeoAI Workbench MVP
- Stable dataset workflow.
- Raster/vector foundations.
- Detection/segmentation architecture.
- QA/QC workflow.
- Export workflow.
- Portfolio-ready demo.
## Release rule
A release cannot be cut if:
- readiness checks fail;
- golden paths regress;
- docs are stale;
- API contracts drift without documentation;
- known limitations are hidden.
+82
View File
@@ -0,0 +1,82 @@
# RISK REGISTER
This register captures known build and product risks before the first implementation run.
## R1 — Scope creep during first Codex run
Impact: high.
Mitigation:
- Follow `SPRINT_1_SCOPE_FREEZE.md`.
- Use `CODEX_STOP_RULES.md`.
- Add out-of-scope items to backlog.
## R2 — External data source instability
Impact: medium/high.
Mitigation:
- Use golden fixtures in Sprint 1.
- Add live adapters later.
- Cache retrieved external data.
## R3 — GIS CRS mistakes
Impact: high.
Mitigation:
- Follow `docs/specs/GIS_STANDARDS.md`.
- Validate geometries.
- Store SRID explicitly.
- Test fixture bounds.
## R4 — Raster files too large
Impact: medium.
Mitigation:
- No heavy raster processing in Sprint 1.
- Use tiling strategy later.
- Enforce file size limits when upload is implemented.
## R5 — AI modules introduced too early
Impact: high.
Mitigation:
- Keep live inference out of Sprint 1.
- Implement adapter boundaries only when needed.
- Use imported demo detections before live models.
## R6 — Frontend becomes dashboard-first
Impact: medium.
Mitigation:
- Follow Constitution: data -> processing -> QA/QC -> export.
- Map supports analysis; it is not the product by itself.
## R7 — Mock data becomes permanent
Impact: high.
Mitigation:
- Golden fixtures are contract data, not fake product behavior.
- Mark demo/fixture paths clearly.
- Production endpoints must use persisted data.
## R8 — Too many competing docs
Impact: medium.
Mitigation:
- Follow `CODEX_START.md` and `docs/00-start/START_HERE.md`.
- M14 launch docs supersede older first-run plans where conflicts exist.
@@ -0,0 +1,97 @@
# SPRINT 1 SCOPE FREEZE
This document freezes the first implementation scope. Codex must not expand Sprint 1 beyond this boundary.
## Sprint 1 goal
Build the GeoIntel foundation vertical slice: a locally runnable app that proves project, area, dataset, PostGIS and map foundations.
## Must build
### Backend foundation
- FastAPI app skeleton.
- Settings/config module.
- Structured logging baseline.
- Health/readiness endpoint.
- API response envelope.
- Error handling middleware or equivalent.
- CORS configuration for local frontend.
### Database foundation
- PostgreSQL/PostGIS connection.
- Migration tooling.
- Core models/schemas for projects, areas and datasets.
- Geometry persistence.
- Minimal seed/fixture support.
### Project and area workflow
- Create/list/read project.
- Create/list/read area.
- Store area geometry.
- Validate geometry.
- Return area metadata such as area size where practical.
### Dataset workflow
- Register/upload GeoJSON dataset.
- Store original file or registered reference.
- Extract metadata:
- dataset type;
- feature count;
- geometry type;
- CRS if available;
- bounds.
- Persist metadata.
### Frontend foundation
- Vite/React/TypeScript app.
- Main shell/layout.
- MapLibre map.
- Project workspace page.
- Dataset manager page/panel.
- Minimal layer display using demo GeoJSON.
- API client.
### Tooling
- Docker Compose for DB and services.
- README quickstart updated if implementation changes commands.
- `make readiness` remains green.
- Basic tests/smoke scripts.
## Should build if Sprint 1 musts are complete
- Area import from fixture.
- GeoJSON export endpoint for area or dataset features.
- Minimal QA placeholder that validates reference vs prediction fixture schema, but does not run full QA engine yet.
- Frontend layer opacity toggle.
## May build only if zero risk
- Demo fixture loader.
- Simple statistics card for feature count and area.
- Simple project status panel.
## Must not build in Sprint 1
- YOLO live inference.
- SAM live segmentation.
- Sentinel/STAC integration.
- GRB live WFS client.
- DHMV integration.
- LiDAR LAS/LAZ processing.
- Training Studio.
- Model registry UI.
- AI Copilot.
- Advanced PDF reports.
- Multi-user authentication.
- Role-based permissions.
- Production Kubernetes/deployment stack.
## Scope conflict rule
If a task seems useful but is not listed under `Must`, `Should` or `May`, Codex must not implement it in Sprint 1. Add it to backlog/open issues instead.
+66
View File
@@ -0,0 +1,66 @@
# Acceptance Criteria
## Milestone M1 — Working foundation
M1 is accepted when:
- backend starts successfully;
- frontend starts successfully;
- project can be created;
- area can be added as polygon;
- dataset can be uploaded or fixture-imported;
- metadata is persisted;
- basic map/workbench UI exists;
- tests cover project/area basics.
## Milestone M2 — Raster/vector foundation
M2 is accepted when:
- vector data can be imported;
- raster metadata can be read;
- CRS/bounds/resolution are visible;
- area/length calculations use metric CRS;
- vector clipping works;
- raster clipping either works or fails with a clear limitation message;
- outputs are persisted as artifacts.
## Milestone M3 — Detection foundation
M3 is accepted when:
- a detection run can be started;
- detections are persisted with class, confidence and geometry;
- detections can be visualized/listed;
- detections can be exported as GeoJSON;
- provider interface supports future YOLO implementation.
## Milestone M4 — QA/QC foundation
M4 is accepted when:
- predictions can be compared with a reference layer;
- IoU matching works;
- precision, recall and F1 are calculated;
- false positives and false negatives are available as separate findings/layers;
- unit tests cover edge cases.
## Milestone M5 — End-to-end demo
M5 is accepted when Demo 1 runs from UI:
1. Open project.
2. Select area.
3. Load raster/reference fixtures.
4. Run detection.
5. Run QA/QC against reference.
6. View map/results.
7. Export GeoJSON and summary.
## Quality gates
Before any handoff:
- no syntax errors;
- no obvious broken imports;
- backend test suite run;
- frontend build/typecheck run if available;
- docs updated;
- limitations documented.
## Rejection criteria
Reject a build if:
- core pages are placeholder-only;
- endpoints return hardcoded success without persisted data;
- geospatial outputs lack CRS metadata;
- code ignores service boundaries;
- major errors are hidden from UI;
- a feature claims GRB/YOLO/SAM support without provider separation or explicit development-provider labeling.
+62
View File
@@ -0,0 +1,62 @@
# Acceptance Matrix
## Foundation
Accepted when:
- Backend starts.
- Frontend starts.
- Database connects.
- Health endpoint works.
- Environment variables are documented.
## Dataset Manager
Accepted when:
- Datasets can be registered and listed.
- Upload status is persisted.
- Metadata extraction is visible.
- Unsupported files are rejected cleanly.
## Map Workbench
Accepted when:
- Areas can be displayed as GeoJSON.
- Layers can be toggled.
- Selected features show metadata.
## Raster Lab
Accepted when:
- Raster metadata is extracted.
- Raster bounds are shown.
- Clip job can be queued.
- Raster artifacts are stored predictably.
## Vector Lab
Accepted when:
- GeoJSON fixture imports.
- Clip/intersection operation works.
- Area/length metrics are correct.
## Detection Lab
Accepted when:
- Detection run can be created.
- Results are stored as geospatial features.
- Confidence threshold is respected.
- GeoJSON export works.
## QA/QC Lab
Accepted when:
- Prediction/reference matching works.
- Precision/recall/F1/IoU are calculated.
- False positives and false negatives are visible.
+66
View File
@@ -0,0 +1,66 @@
# Acceptance Test Catalog
## Foundation
- Health endpoint returns application status.
- API error responses follow the standard envelope.
- CORS is configured for frontend local development.
- Database connection failure is reported but does not crash import-time tests.
## Projects
- Create project with valid payload.
- Reject empty name.
- List projects sorted by newest first.
- Get missing project returns 404 envelope.
## Areas
- Create area from valid Polygon GeoJSON.
- Reject invalid geometry.
- Store geometry with expected SRID.
- Return FeatureCollection for project areas.
## Datasets
- Upload supported vector file.
- Extract geometry type, feature count, bounds and CRS when available.
- Reject unsupported extension with explicit error code.
- Dataset status transitions: uploaded -> metadata_extracted -> ready or failed.
## Raster
- Read raster metadata when valid raster available.
- Return band count, bounds, CRS, width, height and resolution.
- Clip request creates a processing job.
- Tile request creates deterministic tile manifest.
## Vector
- Read vector metadata from GeoJSON fixture.
- Clip vector features to area.
- Buffer vector features by distance in meters.
- Intersect two vector layers.
## Detection
- Create detection analysis run.
- Demo-mode detector creates stable predictions.
- Detections include class, confidence, geometry and source tile.
- Detection outputs are exportable as GeoJSON.
## Segmentation
- Create segmentation analysis run.
- Demo-mode segmenter creates stable polygons.
- Segmentations include class, area_m2, confidence and optional mask path.
## QA/QC
- Match detection to reference by IoU threshold.
- Calculate TP, FP, FN.
- Calculate precision, recall and F1.
- Generate false positive and false negative layers.
## Frontend
- Every route has loading, empty, error and success states.
- Project creation navigates to workspace.
- Map page can render GeoJSON area fixture.
- Dataset detail shows extracted metadata.
- Analysis status updates are visible.
## Export
- GeoJSON export returns downloadable file.
- CSV metrics export includes metric key, value and unit.
- Export records are listed in project exports.
+34
View File
@@ -0,0 +1,34 @@
# Accuracy, modelgrenzen en bewijs
GeoIntel behandelt AI-resultaten als voorstellen die aan brondata,
modelidentiteit, ruimtelijke context en kwaliteitsmetingen gekoppeld blijven.
Een model wordt niet automatisch gedownload of geactiveerd.
## Wat gebruikers mogen verwachten
- GIS-bewerkingen en AI-inferentie bewaren hun invoer- en uitvoerprovenance.
- Referentie- en kandidaatdata blijven afzonderlijk herkenbaar.
- Precision, recall, F1, IoU, false positives en false negatives zijn
inspecteerbaar waar een geschikte referentieset beschikbaar is.
- Een groen technisch proces is geen garantie dat een model voor elk gebied,
seizoen, sensortype of objecttype betrouwbaar is.
- Modeloutput vraagt menselijke of taakgerichte kwaliteitscontrole vóór gebruik
in beslissingen met operationele, juridische of veiligheidsimpact.
## Releasegrens
Modelpromotie vereist een reproduceerbaar benchmarkmanifest, een exacte
model-SHA-256, gescheiden ontwikkel- en evaluatiesets, leakagecontroles en de
toepasselijke releasegates. Ontbrekend bewijs faalt gesloten.
## Publieke versus lokale evidence
De repository bevat alleen broncode, methodedocumentatie en expliciet publieke
fixtures. Runtime-databases, exacte operationele locaties, modelgewichten,
contact sheets, trainingsdata en gegenereerde evaluatierapporten worden lokaal
of in gecontroleerde artefactopslag bewaard. De scripts onder `scripts/` kunnen
deze evidence opnieuw genereren zonder ze aan Git toe te voegen.
Zie ook [SECURITY.md](../SECURITY.md),
[docs/KNOWN_LIMITATIONS.md](KNOWN_LIMITATIONS.md) en
[docs/DEFINITION_OF_DONE.md](DEFINITION_OF_DONE.md).
+793
View File
@@ -0,0 +1,793 @@
# AI Pipelines
The cross-task PyTorch scope, capability matrix and national promotion waves are
defined in `docs/PYTORCH_MODEL_PROGRAM.md`. PyTorch is used only for trainable
imagery tasks; authoritative GIS measurements remain source-derived. The
single-class tile exporter accepts explicit `--class-name`,
`--reference-source` and `--reference-layer` bindings and persists them in its
evidence summary. Production Tower training uses `TRAIN_DEVICE=cuda:0` with
`TRAIN_REQUIRE_CUDA=true`, which fails closed without CUDA and records the
PyTorch/CUDA runtime in `training_summary.json`.
## 1. Object Detection Pipeline
```text
Raster dataset
Clip to analysis area
Tile raster
Normalize tiles
Run YOLO/PyTorch inference
Filter by confidence
Convert pixel boxes to geospatial polygons
Merge overlapping detections
Store in PostGIS
Expose as GeoJSON layer
Run QA/QC if reference data exists
```
### Sprint 8 foundation status
Sprint 8 implements the detection persistence and execution boundary only:
- `detections` are first-class PostGIS records linked to project, dataset, job and analysis run.
- `analysis_runs` remain separate from jobs and store model metadata, parameters, result summaries and lifecycle status.
- `yolo-placeholder` reports `not_configured`; no YOLO/PyTorch model is downloaded or executed.
- `manual-fixture-detector` is test/demo-only and persists detections only when `fixture_mode=true` and fixture detections are explicitly supplied.
- Normal application behavior must not create fake detections.
### Sprint 8B configured YOLO status
Sprint 8B adds an import-safe real YOLO adapter path:
- `ultralytics` and `torch` are optional backend extras, not default runtime dependencies.
- `yolo-configured` reports `not_configured` until `YOLO_ENABLED=true`, `YOLO_MODEL_PATH` points to an existing local model file and optional AI dependencies are installed.
- GeoIntel never downloads model weights automatically.
- Real YOLO inference uses an existing raster tile manifest generated by the raster tile operation.
- YOLO raster tiles are normalized to RGB for inference when the tile artifact is not already a 3-band RGB image; the persisted georeferencing still comes from the tile manifest.
- YOLO pixel boxes are converted to EPSG:4326 detection polygons from tile transform or tile bounds metadata.
- YOLO class labels are normalized to lowercase for persisted detection records and filtering, while the original model label remains available in detection provenance.
- Detection runs remain synchronous behind the existing job and analysis-run persistence boundary for Sprint 8B.
The guided Detection Lab action does not introduce another inference pipeline. It creates a tile manifest through the existing raster service, validates that manifest and the selected local asset through YOLO preflight, then invokes the same configured detection service. Persisted `Detection` geometry remains the authoritative map output; QA continues to compare those rows against persisted reference `vector_features` and stores `QualityCheck`/`Metric` records.
### Sprint 13 YOLO operational preflight
Sprint 13 adds a local preflight command for configured YOLO operation:
```bash
python scripts/yolo_preflight.py --model-path /absolute/path/to/model.pt --tile-manifest-path /absolute/path/to/manifest.json
```
For machines without optional AI dependencies, path and manifest checks can be exercised without pretending inference is available:
```bash
python scripts/yolo_preflight.py --model-path /absolute/path/to/model.pt --tile-manifest-path /absolute/path/to/manifest.json --assume-dependencies --json
```
The preflight checks:
- `YOLO_ENABLED` / explicit enabled state;
- optional dependency availability unless `--assume-dependencies` is used;
- local model file existence;
- tile manifest JSON validity;
- tile count against `YOLO_MAX_TILES`;
- referenced tile file existence.
JSON output also reports runtime diagnostics: whether dependencies were assumed,
the configured model directory, `YOLO_CONFIG_DIR`, installed `torch` and
`ultralytics` versions, and CUDA availability when dependency checks pass.
The preflight does not load the model, does not import Ultralytics unless dependency discovery requires package metadata, does not run inference and never downloads model weights.
Sprint 25 adds an explicit local model compatibility smoke:
```bash
python scripts/yolo_preflight.py --model-path /absolute/path/to/model.pt --tile-manifest-path /absolute/path/to/manifest.json --check-model-load --json
```
`--check-model-load` requires real optional AI dependencies and an existing local
model file. It loads that local file through the configured adapter to verify
Ultralytics/PyTorch compatibility, but it still does not run tile prediction and
does not download weights. It cannot be combined with `--assume-dependencies`
because that would turn the smoke into a false positive.
Docker AI dependencies remain opt-in. Set `GEOINTEL_INSTALL_AI=true`
at build time to install the backend `.[gis,ai]` extra into the container. Leave
it unset or `false` for the default GIS-only image. Runtime model files should be
mounted into the container, for example `/app/models/local-model.pt`, and enabled
with `YOLO_ENABLED=true` plus `YOLO_MODEL_PATH=/app/models/local-model.pt`.
GeoIntel never downloads weights automatically.
Environment variables:
- `GEOINTEL_INSTALL_AI`
- `YOLO_ENABLED`
- `YOLO_MODELS_DIR`
- `YOLO_MODEL_PATH`
- `YOLO_MODEL_ID`
- `YOLO_MODEL_DISPLAY_NAME`
- `YOLO_MODEL_VERSION`
- `YOLO_DEVICE`
- `YOLO_REQUIRE_CUDA` (set to `true` on the production server; inference then
fails closed when CUDA is unavailable or `YOLO_DEVICE` selects CPU)
- `YOLO_MODEL_CLASSES` (the active promoted detector is `building` only)
- `YOLO_ENFORCE_VALIDATION_SCOPE` (keep `true` in production)
- `YOLO_VALIDATION_SCOPE_MANIFEST_PATH` and
`YOLO_VALIDATION_SCOPE_MANIFEST_SHA256` (production accepts inference only
when the exact active model bytes match the manifest and the complete
persisted Dataset AOI is covered by its valid EPSG:4326 geometry)
- `YOLO_VALIDATED_AREA_NAMES` is deprecated display metadata and never grants
inference access
- `YOLO_IMAGE_SIZE`
- `YOLO_MAX_TILES`
- `YOLO_MAX_DETECTIONS`
- `YOLO_DUPLICATE_IOU_THRESHOLD`
- `YOLO_BATCH_SIZE`
`YOLO_MAX_DETECTIONS` is forwarded to Ultralytics as `max_det` for each
prediction call. GeoIntel defaults it to `1000` because building-rich AOIs can
contain far more than the Ultralytics default of 300 candidate boxes; keeping
the upstream default would cap recall before QA/QC begins. Operators may lower
the value for small rasters or raise it for dense urban tiles after reviewing
runtime and false-positive behavior.
Create a new immutable scope artifact whenever either the model bytes or the
governed validation boundary changes:
```bash
python /app/scripts/build_model_validation_scope_manifest.py \
--model /app/models/active-building.pt \
--model-id yolo-configured \
--scope-geojson /app/storage/operator-data/geographic-scopes/kempen-transport-region/kempen_transport_region_boundary_YYYY-MM-DD.geojson \
--scope-key kempen-transport-region \
--authority "Digitaal Vlaanderen VRBG/Refgem" \
--snapshot-date YYYY-MM-DD \
--output /app/storage/operator-data/model-validation-scopes/active-building-model.json
```
The command refuses to overwrite an existing manifest and prints the checksum
for `YOLO_VALIDATION_SCOPE_MANIFEST_SHA256`. Area names are intentionally not
part of this decision: they are mutable presentation text, not accuracy or
authorization evidence.
After YOLO boxes are georeferenced, configured-YOLO runs apply a GeoIntel
cross-tile duplicate suppression pass before persistence. Candidates are grouped
by canonical class and sorted by confidence; lower-confidence same-class
candidates with EPSG:4326 geometry IoU greater than or equal to
`YOLO_DUPLICATE_IOU_THRESHOLD` are suppressed. The default is `0.5`; set it to
`0` to disable this post-processing for operator debugging. Run summaries record
raw, persisted and suppressed detection counts so calibration evidence remains
auditable.
### Persisted false-positive visual review
Detection QA labels a candidate as a false-positive only relative to the
selected persisted reference dataset and matching tolerance. That finding is
not automatically a model error: the reference can be incomplete or stale, and
alignment can be wrong. GeoIntel therefore exposes persisted detection
confidence/model/tile/bbox provenance in the existing QA evidence GeoJSON and
provides a read-only contact-sheet workflow.
The operator must explicitly select one of:
- `confirmed_model_false_positive`;
- `reference_gap_or_change`;
- `qa_alignment_mismatch`;
- `uncertain`;
- `unreviewed`.
Only records explicitly marked `confirmed_model_false_positive` are emitted by
the validator as possible hard-negative review input. The workflow does not
train a model, mutate QA persistence, fetch data or infer review decisions.
### Persisted false-negative visual review
False negatives require the same manual distinction. A missed reference can be
a true model miss, a stale reference, an obscured object, a box-to-footprint
matching failure or an object outside the raster actually presented to the
model. The read-only false-negative renderer resolves the persisted tile
manifest from the fixed-threshold run and overlays:
- red: the missed GRB/reference footprint;
- blue: nearby persisted candidate detections;
- green: nearby matched reference footprints.
The decision contract is `confirmed_model_false_negative`,
`reference_gap_or_change`, `qa_alignment_mismatch`,
`imagery_obscured_or_uncertain` or `unreviewed`. References outside every
persisted inference tile are written to a separate exclusion GeoJSON and are
not treated as reviewable model misses. This renderer does not alter persisted
QA metrics; coverage-adjusted values remain audit diagnostics until the QA
service evaluation population is deliberately hardened.
`validate_detection_false_negative_review_decisions.py` provides the same
fail-closed validation as the false-positive workflow. It requires an exact
one-to-one set of reviewed reference ids and emits only explicit
`confirmed_model_false_negative` geometries. `--require-complete` rejects any
remaining `unreviewed` row. The July 2026 96-card review is recorded in
the controlled model-review evidence outside Git; it yielded no novel,
leakage-free labels and therefore did not trigger model training.
### Local model asset catalog
GeoIntel can list local runtime model files mounted into the backend model
directory through `GET /api/v1/detection/model-assets`. The catalog is
filesystem-backed and read-only: it reports existing `.pt`, `.onnx` and
`.engine` files, size, checksum and whether the file matches `YOLO_MODEL_PATH`.
Detection runs still use `model_id="yolo-configured"` for the configured YOLO
execution path. A selected `model_asset_id` can be supplied to use one specific
cataloged file for that run. The backend resolves the ID to a local path and
persists the selected asset metadata in Job/AnalysisRun parameters. GeoIntel
does not download weights or accept arbitrary model paths from the browser.
Operational runtime validation can be run against Docker/Tower with:
```bash
bash scripts/verify_model_asset_detection_workflow.sh http://192.0.2.10:1202
```
The smoke seeds the explicit offline demo raster, creates a tile manifest,
selects a local model asset, checks read-only preflight, runs the existing
configured-YOLO detection endpoint and verifies persisted AnalysisRun,
Detection list and Detection GeoJSON outputs. It intentionally does not inject
detector fixtures or download weights. A zero detection count is acceptable on
the synthetic demo raster; production usefulness still requires validation on
real georeferenced orthophotos and reference vectors.
### Map-driven building analysis
The primary map can hand an explicit EPSG:4326 rectangle to the bounded
orthophoto acquisition endpoint. Its canonical raster Dataset then uses the
unchanged configured-YOLO pipeline: 512 px tiles with 64 px overlap, preflight,
local inference, Job + AnalysisRun + Detection persistence and persisted
GeoJSON. When a ready GRB buildings reference Dataset exists, the same action
launches existing detection QA and persists QualityCheck and Metric rows.
This flow does not download a model, bypass the model registry, write directly
to Detection/vector tables or present AI boxes as official building truth.
The 1 m request sampling is an operational model profile; provenance retains
the official orthophoto source and latest-mosaic limitation.
### Real-data detection and QA validation
The real operational validation path uses operator-provided files rather than
demo fixtures:
```bash
REAL_RASTER_PATH=/mnt/user/appdata/geointel/data/orthophoto.tif \
REAL_REFERENCE_VECTOR_PATH=/mnt/user/appdata/geointel/data/reference-buildings.geojson \
bash scripts/verify_real_data_detection_qa_workflow.sh http://192.0.2.10:1202
```
The script verifies the full persisted chain:
- source raster upload with CRS and bounds metadata;
- reference building vector upload as `dataset_role=reference`;
- raster inspect and tile manifest generation;
- local model asset selection and read-only YOLO preflight;
- configured-YOLO detection run through Job, AnalysisRun and Detection rows;
- detection GeoJSON generated from persisted geometry;
- detection QA against persisted reference `vector_features` with persisted
`QualityCheck` and `Metric` rows;
- detection run GeoJSON export.
It refuses to run without a real GeoTIFF-style raster and GeoJSON/JSON reference
vector. It does not seed demo data, use `fixture_mode`, fetch live providers or
download model weights. A zero detection count is valid as runtime evidence only
when the selected model genuinely returns no usable detections after canonical
class filtering; it does not prove the model is useful for the target imagery.
Documented operator samples can be prepared inside the all-in-one runtime
container:
```bash
docker exec -it geointel python3 /app/scripts/prepare_operator_real_data_samples.py
```
The helper fetches explicit Digitaal Vlaanderen orthophoto/GRB GBG sample pairs
for the documented AOIs only and writes `operator_samples_manifest.json`. The
default corpus includes dense reference AOIs for Geel, Mol, Turnhout, Herentals,
Balen, Retie and Westerlo plus explicitly marked background candidates for
Postel-bos, Lommel-heide, Kasterlee-bos, Dessel-heide, Ravels-bos,
Meerhout-bos, Geel-Bel, Arendonk-heide and Herenthout-bos. Background
candidates may persist empty GRB FeatureCollections for negative-tile training;
normal reference AOIs still fail on empty GRB responses. Dense GRB references
are fetched through OGC API `rel=next` pagination links instead of trusting only
the first 1000-feature page. Generated reference GeoJSON records
`reference_pages_fetched`, `reference_truncated`, `reference_page_limit`,
`reference_max_features` and `source_urls` for auditability. The application
itself still does not perform live provider fetching.
### Mol operational validation pack
The operator registry includes a Mol-first validation pack: Mol center,
Achterbos residential, Gompel mixed settlement, Donk canal/industrial and
Postel rural village. The four new zones are marked as validation holdouts so
future training exports cannot silently consume the operational benchmark.
Postel-bos is evaluated separately as a background control.
`run_mol_operational_validation.sh` composes the existing positive multi-sample
quality matrix and background detection matrix. Positive runs use persisted GRB
`vector_features` and create real `QualityCheck`/`Metric` rows; background runs
only report persisted detection pressure and never synthesize QA metrics. AOI
bounds from the operator manifest are persisted as EPSG:4326 `Area` records so
every generated project opens as a complete map context.
In the all-in-one runtime combined JSON/Markdown evidence defaults to
`/app/storage/operator-evidence/mol-operational-validation`, which is part of
the persistent storage mount rather than the replaceable container layer.
For confidence-threshold calibration, use the sweep wrapper:
```bash
REAL_RASTER_PATH=/mnt/user/appdata/geointel/storage/operator-data/geel_orthophoto_wms_512.tif \
REAL_REFERENCE_VECTOR_PATH=/mnt/user/appdata/geointel/storage/operator-data/geel_grb_gbg_buildings.geojson \
CALIBRATION_THRESHOLDS="0.50 0.35 0.25 0.15" \
bash scripts/run_detection_calibration_sweep.sh http://192.0.2.10:1202
```
The sweep runs the real-data workflow once per threshold and then reads the
persisted project quality-check list to build `calibration_summary.json`.
Results are honest QA/QC evidence from persisted detections and persisted
reference `vector_features`; no demo detections, live provider fetches or model
downloads are introduced by the calibration tool.
Summaries include raw detection candidate count, persisted detection count and
suppressed duplicate count so operators can distinguish model output volume from
GeoIntel post-processing.
For model/tile/threshold selection, use the quality matrix wrapper:
```bash
REAL_RASTER_PATH=/mnt/user/appdata/geointel/storage/operator-data/geel_orthophoto_wms_512.tif \
REAL_REFERENCE_VECTOR_PATH=/mnt/user/appdata/geointel/storage/operator-data/geel_grb_gbg_buildings.geojson \
QUALITY_MODEL_ASSET_IDS="yolov8n-building-segmentation-pt yolov8n-pt" \
QUALITY_TILE_SIZES="512 640" \
QUALITY_TILE_OVERLAPS="64" \
QUALITY_THRESHOLDS="0.50 0.15" \
bash scripts/run_detection_quality_matrix.sh http://192.0.2.10:1202
```
The matrix repeats the same persisted real-data workflow for every combination
and writes `quality_matrix_summary.json` with detection count, QA score,
precision, recall, F1, mean IoU and false-positive/false-negative counts. The
rankings `best_by_score`, `best_by_recall` and `best_by_precision` are operator
decision aids only; GeoIntel still does not download models, seed fixture
detections or treat AI detections as ground truth without QA/QC. The same
candidate should also pass the background false-positive matrix before it is
considered as a default:
```bash
OPERATOR_SAMPLE_MANIFEST_PATH=storage/operator-data/operator_samples_manifest.json \
OPERATOR_BACKGROUND_SAMPLE_SLUGS="postel_bos lommel_heide kasterlee_bos" \
QUALITY_MODEL_ASSET_IDS="geointel-building-yolov8s-aoi1024bg512r3e50-pt" \
QUALITY_TILE_SIZES="512" \
QUALITY_TILE_OVERLAPS="64" \
QUALITY_THRESHOLDS="0.35 0.15" \
BACKGROUND_SPLIT_OUTPUT_DIR=artifacts/detection-hard-negatives/aoi1024bg512r3e50-split \
bash scripts/run_background_corpus_split_matrix.sh http://192.0.2.10:1202
```
The split runner writes `background_corpus_split_summary.json` and Markdown
handoff output with a strict `pure_empty_negative` gate and a separate
review-only `sparse_building_context` block.
Use that split summary directly in the model promotion report:
```bash
python scripts/build_detection_model_promotion_report.py \
--positive-portfolio artifacts/detection-quality-matrix/multi-sample/aoi1024bg512r3e50-positive/multi_sample_quality_summary.json \
--background-split-summary artifacts/detection-hard-negatives/aoi1024bg512r3e50-split/background_corpus_split_summary.json \
--output-dir artifacts/detection-model-promotion/aoi1024bg512r3e50-split-aware \
--min-positive-samples 7 \
--min-background-samples 2 \
--min-mean-f1 0.25 \
--max-background-detections-per-sample 0
```
The promotion report follows the split contract: `pure_empty_negative` is the
only strict background gate for default promotion, while
`sparse_building_context` remains review-only evidence in the report. This keeps
contextual buildings from being treated as empty-background false positives.
For the Tower/runtime pass, run the split matrix and promotion report together:
```bash
PROMOTION_POSITIVE_PORTFOLIO_PATH=artifacts/detection-quality-matrix/multi-sample/aoi1024bg512r3e50-positive/multi_sample_quality_summary.json \
OPERATOR_SAMPLE_MANIFEST_PATH=storage/operator-data/operator_samples_manifest.json \
QUALITY_MODEL_ASSET_IDS="geointel-building-yolov8s-aoi1024bg512r3e50-pt" \
QUALITY_TILE_SIZES="512" \
QUALITY_TILE_OVERLAPS="64" \
QUALITY_THRESHOLDS="0.35 0.15" \
BACKGROUND_SPLIT_OUTPUT_DIR=artifacts/detection-hard-negatives/aoi1024bg512r3e50-split \
PROMOTION_OUTPUT_DIR=artifacts/detection-model-promotion/aoi1024bg512r3e50-split-aware \
bash scripts/run_split_background_promotion_workflow.sh http://192.0.2.10:1202
```
The wrapper keeps the same safety boundary: existing dataset upload, configured
YOLO detection and report tooling only. It does not change model configuration
or bypass the persisted QA/QC evidence requirement.
For a quick post-redeploy check before the long matrix starts, use
`--preflight-only` with the same positive portfolio and operator manifest. This
checks local paths, required background categories and the runtime API envelope
without running inference:
Legacy operator manifests that do not yet contain explicit `background_category`
remain supported: the preflight derives `pure_empty_negative` from
`reference_feature_count == 0` and `sparse_building_context` from background
samples with persisted reference features, matching the matrix runner.
```bash
PROMOTION_POSITIVE_PORTFOLIO_PATH=artifacts/detection-quality-matrix/multi-sample/aoi1024bg512r3e50-positive/multi_sample_quality_summary.json \
OPERATOR_SAMPLE_MANIFEST_PATH=storage/operator-data/operator_samples_manifest.json \
bash scripts/run_split_background_promotion_workflow.sh --preflight-only http://192.0.2.10:1202
```
The underlying single-category matrix remains available:
```bash
OPERATOR_SAMPLE_MANIFEST_PATH=storage/operator-data/operator_samples_manifest.json \
OPERATOR_BACKGROUND_CATEGORIES="pure_empty_negative" \
OPERATOR_BACKGROUND_SAMPLE_SLUGS="postel_bos lommel_heide kasterlee_bos" \
QUALITY_MODEL_ASSET_IDS="geointel-building-yolov8n-expanded160e50-pt geointel-building-yolov8n-tile30-pt yolov8s-building-segmentation-pt" \
QUALITY_TILE_SIZES="640" \
QUALITY_TILE_OVERLAPS="64" \
QUALITY_THRESHOLDS="0.25 0.15 0.05" \
bash scripts/run_operator_hard_negative_detection_matrix.sh http://192.0.2.10:1202
```
The hard-negative matrix uploads only background rasters and counts detections
as false-positive pressure. It does not run QA/QC or invent reference metrics
for empty/sparse background AOIs. Operator manifests classify background
samples as `pure_empty_negative` when GRB returns zero reference buildings and
`sparse_building_context` when contextual buildings are present. Use
`OPERATOR_BACKGROUND_CATEGORIES="pure_empty_negative"` for default-promotion
hard-negative gates, then run `sparse_building_context` as a separate review
matrix. The first expanded local model improved dense AOI F1, but Kasterlee-bos
false positives block default promotion.
The focused small-building local model asset,
`geointel-building-yolov8s-smallbld-minpx3-img640-ft30-pt`, is the current
recommended Detection Lab operator profile. Use tile size `512`, overlap `64`
and confidence threshold `0.15`. Its original promotion evidence at match IoU
`0.25` across seven positive AOIs measured mean precision `0.5898`, recall
`0.5770` and F1 `0.5825`; minimum per-AOI F1 was `0.5528`. The strict
three-sample pure-empty
background gate produced zero detections. Compared with the previous balanced
profile, the same persisted reference populations contain 1,571 fewer false
negatives, including 745 fewer misses in the 25-100 m2 bucket and 181 fewer
below 25 m2. This recall gain increases the false-positive review load, so the
previous `geointel-building-yolov8s-aoi1024expandedminpx4vis035e50-pt` profile
remains available as a higher-precision legacy `0.15` choice. The older
`geointel-building-yolov8s-aoi1024bg512r3e50-pt` remains the conservative
`0.35` profile. Sparse-context detections remain review-only evidence, not a
default-promotion blocker. Every production-like run still requires persisted
QA/QC against suitable reference data.
The map-driven building workflow uses canonical footprint IoU `0.25`, matching
the promotion evidence above. A July 2026 Mol-only holdout audit compared
confidence `0.10` and `0.15` over Achterbos, Gompel, Donk and Postel. Confidence
`0.15` produced the better F1 in all four positive zones; both thresholds
produced zero detections in the pure-empty Postel forest control. The active
confidence therefore remains `0.15`. This result does not claim production
perfection and does not justify another model-training run by itself.
A coverage-aligned July 2026 rerun supersedes the older displayed profile
averages above without changing the active model or threshold. On the exact
current pipeline, the seven independent Mol/Kempen zones measured mean
precision `0.6141`, recall `0.6062` and F1 `0.6069`; the minimum zone F1 was
`0.4749` in Mol Postel. The active model again produced zero detections in
Postel-bos, Lommel-heide and Arendonk-heide. These are the values shown in the
Detection Lab operator profile.
The reviewed-accuracy experiment added six training-only AOIs from Arendonk,
Dessel, Meerhout, Laakdal, Nijlen and Hulshout. The paged GRB export contained
9,964 complete reference features. Its audited `512`-tile corpus retained 252
tiles and 79,192 labels with no invalid or missing labels. The inactive
`geointel-building-yolov8s-reviewedexp6-minpx3-img640-ft20-pt` challenger
improved mean seven-zone F1 to `0.6248`, but produced two detections in the
explicitly empty Postel-bos control. The formal fail-closed promotion report
therefore retained the current active model. Positive-score gains never
override a failed pure-empty background gate.
False-positive and false-negative evidence from persisted detection QA can be
classified through `detection_reviews`. The queue derives from quality-check
evidence ids and resolves persisted Detection and reference VectorFeature rows.
`qa_alignment_mismatch`, `reference_gap_or_change`, uncertain imagery and
unreviewed items must never be exported as hard-negative or missed-positive
training labels. Canonical QA metrics remain unchanged after review.
The persisted seven-AOI evidence for this profile contains 5,568 false
positives among 13,613 candidate detections. The read-only audit command in
`scripts/README.md` reports the largest review volumes in Turnhout, Herentals
and Geel, a median false-positive geometry area of about 184.5 m2, and 25.8%
tiny/small geometry below 100 m2. Current evidence does not include
per-detection confidence, so model-review reports must retain confidence
coverage as zero rather than treating threshold `0.15` as an observed score.
Combined false-positive GeoJSON is evidence for operator review only; a feature
must be visually confirmed before it is used as a hard-negative label.
To update a Tower/Unraid `.env` from a promoted report, use the guarded
activation helper. It validates the exact report candidate key, verifies that
the candidate has `promotion_status=promote_candidate`, resolves the local model
asset under the mounted models directory, and writes environment updates only
when `--apply` is supplied:
```bash
python scripts/activate_promoted_yolo_candidate.py \
--promotion-report storage/operator-data/model-review/small-building-candidate/promotion/detection_model_promotion_report.json \
--candidate-key 'geointel-building-yolov8s-smallbld-minpx3-img640-ft30-pt|512|64|0.15' \
--models-dir /mnt/user/appdata/geointel/models \
--env-file /mnt/user/appdata/geointel/.env \
--json
```
Re-run with `--apply` only after reviewing the emitted env updates. The helper
does not download weights, load a model or run inference. Restart or rebuild the
runtime after applying because `YOLO_MODEL_PATH` is read from environment
configuration.
To compare the same model/tile/threshold grid across all prepared operator
samples, use:
```bash
OPERATOR_SAMPLE_MANIFEST_PATH=storage/operator-data/operator_samples_manifest.json \
QUALITY_MODEL_ASSET_IDS="yolov8n-building-segmentation-pt yolov8n-pt" \
QUALITY_TILE_SIZES="512 640" \
QUALITY_TILE_OVERLAPS="64" \
QUALITY_THRESHOLDS="0.50 0.15" \
bash scripts/run_multi_sample_detection_quality_matrix.sh http://192.0.2.10:1202
```
The multi-sample summary exposes `best_overall_by_score`,
`best_overall_by_recall`, `best_overall_by_precision` and `best_by_sample` so
model-quality decisions are based on repeated persisted QA/QC evidence rather
than one AOI.
When repeated public model benchmarks remain too weak, the operator can convert
the prepared real-data samples into a local YOLO training dataset:
```bash
docker exec -it geointel python3 /app/scripts/export_operator_yolo_dataset.py \
--manifest-path /app/storage/operator-data/operator_samples_manifest.json \
--output-dir /app/storage/operator-data/yolo-building-dataset \
--val-samples turnhout \
--force
```
The exporter creates a standard YOLO detection layout with `dataset.yaml`,
`images/train`, `labels/train`, `images/val` and `labels/val`. It converts GRB
building reference geometries to pixel-space bounding boxes for the matching
orthophoto sample and records `yolo_dataset_summary.json`.
A minimal local training smoke can then be run explicitly in an AI-enabled
runtime:
```bash
docker exec \
-e OPERATOR_YOLO_DATASET_DIR=/app/storage/operator-data/yolo-building-dataset \
-e YOLO_BASE_MODEL_PATH=/app/models/yolov8n.pt \
-e TRAIN_MODEL_OUTPUT_PATH=/app/models/geointel-building-detector.pt \
-e TRAIN_EPOCHS=8 \
-e TRAIN_IMGSZ=512 \
-e TRAIN_BATCH=2 \
-e TRAIN_WORKERS=0 \
-e TRAIN_DEVICE=cpu \
-e PYTHON_BIN=python3 \
geointel bash /app/scripts/train_operator_yolo_detector.sh
```
This remains operator tooling only. GeoIntel does not expose Training Studio in
V1, does not generate labels from predictions and does not treat the trained
artifact as useful until it passes the same real-data Detection + QA matrix.
If the whole-image dataset underfits or produces unusable detections, export
overlapping tile-level samples:
```bash
docker exec -it geointel python3 /app/scripts/export_operator_yolo_tile_dataset.py \
--manifest-path /app/storage/operator-data/operator_samples_manifest.json \
--output-dir /app/storage/operator-data/yolo-building-tile-dataset \
--tile-size 192 \
--stride 96 \
--negative-keep-ratio 0.5 \
--val-samples turnhout \
--force
```
The tile exporter clips reference building boxes into tile-local YOLO labels
and records the positive/negative tile counts. This gives the training smoke
more image samples while preserving the same explicit operator-data and QA/QC
validation boundary.
Focused small-building experiments use Beerse, Rijkevorsel, Hoogstraten and
Vorselaar as training AOIs, with Vosselaar and Grobbendonk retained as
independent validation AOIs. The exporter accepts an explicit `--samples`
subset and records `source_manifest_sample_count`, `selected_sample_slugs` and
`excluded_sample_slugs` in its summary. Manifest-backed validation samples
cannot silently enter training.
For visual error inspection, export the persisted QA evidence from a calibration
summary:
```bash
CALIBRATION_SUMMARY_PATH=/mnt/user/appdata/geointel/artifacts/detection-calibration/20260707T002103Z/calibration_summary.json \
bash scripts/export_detection_calibration_evidence.sh http://192.0.2.10:1202
```
The evidence bundle calls
`/api/v1/projects/{project_id}/quality-checks/{quality_check_id}/evidence/geojson`
for the persisted quality checks and writes combined GeoJSON plus an HTML/SVG
review artifact. This is an inspection aid only; it does not rerun inference or
alter stored detections.
### Sprint 8C detection visualization and QA status
Sprint 8C makes persisted detections reviewable:
- Detection runs can be listed and selected.
- Persisted detections can be listed and filtered by run, dataset, class and minimum confidence.
- Persisted detection geometries can be returned as GeoJSON FeatureCollections for MapLibre display.
- Detection QA compares candidate detection geometries against persisted reference `vector_features`.
- QA results reuse `quality_checks` and `metrics`; no parallel QA persistence system is introduced.
- Configured-YOLO QA derives its evaluation extent from the persisted tile
manifest. Tile bounds are transformed from their explicit source CRS to
EPSG:4326 and unioned. The union is first applied as a GiST-backed PostGIS
spatial predicate, then used to clip the bounded candidate/reference
populations before canonical footprint-IoU matching. Complete source counts
remain in QA evidence, but regional geometries outside inference coverage are
not materialized in application memory and do not count as false negatives.
- Canonical one-to-one IoU matching uses an in-memory spatial index only to
discard geometries whose envelopes cannot intersect. It does not change the
configured IoU threshold, greedy match ownership or persisted metrics.
- A separate reference-envelope IoU pass is persisted as
`box_to_footprint_diagnostics`. It quantifies possible matching artifacts from
comparing rectangular detections with irregular building footprints, but is
diagnostic only and never changes canonical QA metrics.
- Segmentation remains out of scope for Sprint 8C.
## 2. Tile Metadata
Elke tile moet opslaan:
- tile path
- parent raster id
- pixel window
- geospatial bounds
- transform
- CRS, and the manifest must also carry source CRS metadata
- tile size
- overlap
Zonder tile metadata kunnen modeloutputs niet correct teruggeprojecteerd worden.
## 3. Detection Output Contract
Elke detectie bevat:
- class_name
- confidence
- bbox pixel coords
- source tile
- geospatial polygon
- model id/version
- analysis run id
## 4. Segmentation Pipeline
```text
Raster dataset
Clip/tile
Run segmentation model
Generate mask
Georeference mask
Polygonize mask
Simplify/clean geometries
Store polygons + mask path
Expose as map layer
```
### Sprint 9 segmentation foundation status
Sprint 9 implements the segmentation persistence and review boundary only:
- `segmentations` are first-class PostGIS records linked to project, dataset, job and analysis run.
- PostGIS MultiPolygon geometry in EPSG:4326 is authoritative for map display, QA and GeoJSON output.
- Mask paths are persisted as artifact/provenance references, not authoritative feature state.
- `segmentation-placeholder`, `yolo-seg-configured` and `sam-configured` report `not_configured`.
- `fixture-segmenter` is test/demo-only and persists segmentations only when `fixture_mode=true` and fixture segmentations are explicitly supplied.
- Segmentation QA compares persisted segmentation geometries against persisted reference `vector_features`.
- QA results reuse `quality_checks` and `metrics`; no parallel QA system is introduced.
- GeoIntel does not install SAM, run YOLO-seg, download model weights or fake production segmentations in Sprint 9.
## 5. Change Detection Pipeline
Fase 1: vector/detection based.
```text
Run A detections
+
Run B detections
Spatial matching
added / removed / changed
Change polygons
Metrics
```
Fase 2: raster index based.
```text
Raster A index
+
Raster B index
Difference raster
Threshold
Polygonize changed zones
```
Fase 3: segmentation based.
```text
Mask A
+
Mask B
Class difference
Change polygons
```
## 6. Model Strategy
V1:
- gebruik een bestaande YOLO-integratie met configureerbaar modelpad
- demo-model mag lokaal worden geplaatst in `models/`
- code moet ook zonder model kunnen starten, maar detection job moet dan duidelijke fout geven
V2:
- SAM/YOLO segmentation
V3:
- annotation export
- finetuning
## 7. Reproduceerbaarheid
Elke analysis run moet bewaren:
- model id
- model version
- parameters
- confidence threshold
- tile size
- overlap
- input dataset id
- code path/version indien mogelijk
+160
View File
@@ -0,0 +1,160 @@
# Analysis Engine
De Analysis Engine bevat alle reproduceerbare berekeningen. AI mag interpretaties schrijven, maar de cijfers komen uit deze engine.
## 1. BuildingAnalyzer
### Input
- gebouwpolygonen uit GRB, OSM of detecties
- analysegebied
### Output metrics
```json
{
"building_count": 123,
"building_area_total_m2": 45678.9,
"building_density_per_km2": 87.2,
"average_building_area_m2": 371.4,
"built_ratio": 0.23
}
```
## 2. RoadAnalyzer
### Input
- wegvectoren
- analysegebied
### Output
- totale weglengte
- wegendichtheid
- verdeling per wegtype
- nabijheid tot hoofdwegen
## 3. RasterAnalyzer
### Input
- rasterdataset
- analysegebied
### Output
- metadata
- bounds
- resolutie
- bandstatistieken
- histogram
- nodata-percentage
## 4. VegetationAnalyzer
### Input
- NDVI-raster of vegetatiesegmentatie
### Output
- vegetatieoppervlakte
- vegetatiepercentage
- gemiddelde NDVI
- lage vegetatiegebieden
- hoge vegetatiegebieden
## 5. WaterAnalyzer
### Input
- waterpolygonen of NDWI-raster
### Output
- wateroppervlakte
- waterpercentage
- afstand tot water
- waterverandering later
## 6. DetectionAnalyzer
### Input
- detecties
- analysegebied
### Output
- aantal per klasse
- gemiddelde confidence
- confidence distributie
- oppervlakte per klasse indien polygonen beschikbaar
- detectiedichtheid
## 7. SegmentationAnalyzer
### Input
- mask/polygon segmentaties
### Output
- oppervlakte per klasse
- segment count
- gemiddelde confidence
- dekking binnen analysegebied
## 8. QAAnalyzer
### Input
- AI-output
- referentielaag
- IoU threshold
### Output
```json
{
"true_positives": 100,
"false_positives": 8,
"false_negatives": 12,
"precision": 0.9259,
"recall": 0.8928,
"f1": 0.9090,
"mean_iou": 0.71
}
```
### Regels
- Een detectie matcht met een referentieobject als IoU >= threshold.
- Meerdere detecties op één referentieobject moeten gededupliceerd worden.
- Niet-gematchte detecties zijn false positives.
- Niet-gematchte referentieobjecten zijn false negatives.
## 9. ChangeAnalyzer
### Input
- analysis run A
- analysis run B
### Output
- added objects
- removed objects
- changed objects
- changed area
- change density
## 10. ScoreEngine later
Scores zijn niet de primaire focus voor de vacaturegerichte versie, maar kunnen later worden toegevoegd:
- Open Space Pressure Score
- Urban Expansion Score
- Nature Connectivity Score
- Water Resilience Score
+250
View File
@@ -0,0 +1,250 @@
# GeoIntel Kempen — Analysis Specifications v1.0
This file defines exact inputs, outputs and formulas for the first implementation of the analysis engine.
## Global rules
- All area-based metrics must be calculated in a projected CRS suitable for Belgium/Flanders, preferably EPSG:31370 internally for metric calculations.
- Store geometries consistently and transform only at API/render boundaries when needed.
- All metrics must include unit, input dataset ids, analysis run id and calculation parameters.
- Never let the AI copilot invent metrics. Metrics must come from the analysis engine.
## AreaAnalyzer
### Input
- Area polygon.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `area_m2` | m² | `ST_Area(area.geometry)` |
| `area_km2` | km² | `area_m2 / 1_000_000` |
| `perimeter_m` | m | `ST_Perimeter(area.geometry)` |
| `bbox` | geometry/json | calculated bounds |
## BuildingAnalyzer
### Input
- Area polygon.
- Building polygons from GRB, OSM, user vector layer, or AI segmentation/detection polygons.
### Processing
1. Clip building geometries to area.
2. Remove invalid geometries or repair with `make_valid`.
3. Calculate per-building clipped area.
4. Aggregate.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `building_count` | count | number of building features intersecting area |
| `building_area_total_m2` | m² | sum clipped building area |
| `building_area_total_ha` | ha | `building_area_total_m2 / 10000` |
| `building_coverage_ratio` | ratio | `building_area_total_m2 / area_m2` |
| `building_density_per_km2` | count/km² | `building_count / area_km2` |
| `mean_building_area_m2` | m² | `building_area_total_m2 / building_count` |
| `largest_building_area_m2` | m² | max building area |
### Output layers
- `buildings_clipped`
- `building_centroids`
- `large_buildings_top_20`
## RoadAnalyzer
### Input
- Area polygon.
- Road line or polygon features.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `road_length_total_m` | m | sum clipped road lengths |
| `road_length_total_km` | km | `/1000` |
| `road_density_km_per_km2` | km/km² | `road_length_total_km / area_km2` |
| `major_road_length_km` | km | filtered by road class if available |
### Output layers
- `roads_clipped`
- `major_roads_clipped`
## GreenAnalyzer
### Input options
- Green polygons from OSM/GRB/landuse.
- NDVI raster threshold result.
- Segmentation polygons classified as vegetation.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `green_area_total_m2` | m² | sum green polygons clipped to area |
| `green_ratio` | ratio | `green_area_total_m2 / area_m2` |
| `green_patch_count` | count | number of disjoint green patches |
| `largest_green_patch_m2` | m² | max patch area |
| `green_fragmentation_index` | index | `green_patch_count / max(green_area_total_ha, 0.01)` |
### Interpretation
High fragmentation means green is split into many smaller patches.
## WaterAnalyzer
### Input
- Water polygons/lines from GRB/OSM.
- NDWI threshold polygons later.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `water_area_total_m2` | m² | sum clipped water polygon area |
| `water_ratio` | ratio | `water_area_total_m2 / area_m2` |
| `watercourse_length_m` | m | sum water line length |
| `distance_to_nearest_water_m` | m | minimum distance from area centroid to water geometry |
## RasterAnalyzer
### Input
- Raster dataset.
- Optional area polygon.
### Output metrics
Per band:
| Key | Unit |
|---|---|
| `band_min` | band unit |
| `band_max` | band unit |
| `band_mean` | band unit |
| `band_std` | band unit |
| `nodata_ratio` | ratio |
### Required operations
- Read metadata.
- Clip by area.
- Compute statistics.
- Generate preview tile or PNG.
## RemoteSensingIndexAnalyzer
### NDVI
Formula:
```text
NDVI = (NIR - Red) / (NIR + Red)
```
Output:
- `ndvi_mean`
- `ndvi_median`
- `ndvi_low_ratio` using threshold configurable, default `< 0.2`
- `ndvi_high_ratio` using threshold configurable, default `> 0.5`
- vectorized high/low vegetation zones later
### NDWI
```text
NDWI = (Green - NIR) / (Green + NIR)
```
### NDBI
```text
NDBI = (SWIR - NIR) / (SWIR + NIR)
```
## DetectionAnalyzer
### Input
- Detection records with class, confidence and geometry.
- Area polygon.
### Output metrics
| Key | Unit | Formula |
|---|---|---|
| `detection_count` | count | detections within area |
| `detection_count_by_class` | json | group by class |
| `mean_confidence` | ratio | average confidence |
| `low_confidence_count` | count | confidence below threshold |
| `detected_area_m2_by_class` | json | sum polygon area where available |
## ScoreEngine v1
The score engine must be transparent. Every score returns value, inputs, weights and explanation.
### Open Space Pressure Score
Default weights:
```yaml
building_coverage_ratio: 0.35
road_density_normalized: 0.25
green_ratio_inverse: 0.25
urban_growth_normalized: 0.15
```
Score:
```text
100 * weighted_sum(normalized_factors)
```
### Nature Connectivity Score
Default weights:
```yaml
green_ratio: 0.35
largest_green_patch_ratio: 0.25
fragmentation_inverse: 0.25
major_road_barrier_inverse: 0.15
```
### Water Resilience Score
Default weights:
```yaml
green_ratio: 0.30
water_buffer_presence: 0.20
impervious_inverse: 0.30
low_point_risk_inverse: 0.20
```
V1 may calculate a simplified score without height data by marking height-dependent factors as unavailable.
## Metric storage contract
Each metric row must include:
```json
{
"analysis_run_id": "uuid",
"key": "building_density_per_km2",
"value": 123.4,
"unit": "count/km2",
"method": "BuildingAnalyzer.v1",
"inputs": ["dataset_uuid"],
"parameters": {},
"quality_flags": []
}
```
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
# API Contract Freeze M2
## Required V1 endpoints
### Health
`GET /health`
Response:
```json
{"status":"ok","service":"geointel-backend"}
```
### Projects
`POST /projects`
Request:
```json
{"name":"Geel Building Detection","description":"Demo project","region":"Kempen"}
```
Response: project object.
`GET /projects`
Response: paginated projects.
### Areas
`POST /projects/{project_id}/areas`
Request must contain GeoJSON polygon.
### Datasets
`POST /projects/{project_id}/datasets/upload`
Multipart upload. Returns dataset object and metadata status.
`GET /projects/{project_id}/datasets`
Returns datasets.
### Analysis runs
`POST /analysis/object-detection`
Request:
```json
{
"project_id": "uuid",
"dataset_id": "uuid",
"area_id": "uuid",
"model_id": "yolov8n-building-demo",
"confidence_threshold": 0.5
}
```
Response: job envelope.
`GET /analysis-runs/{id}`
Returns run status, metrics, outputs.
### QA/QC
`POST /analysis/qaqc/building-detection-vs-reference`
Request:
```json
{
"project_id": "uuid",
"prediction_run_id": "uuid",
"reference_dataset_id": "uuid",
"iou_threshold": 0.5
}
```
Response: job envelope.
### Exports
`POST /exports/geojson`
Exports detections, segmentations, QA findings, or vector layers.
+113
View File
@@ -0,0 +1,113 @@
# API Example Responses
## Error Envelope
```json
{
"error": {
"code": "DATASET_UNSUPPORTED_FORMAT",
"message": "The uploaded file extension is not supported.",
"details": {"extension": ".txt"},
"request_id": "req_01HY"
}
}
```
## Health
```json
{
"status": "ok",
"services": {
"database": "ok",
"redis": "ok",
"storage": "ok"
},
"version": "1.0.0"
}
```
## Project
```json
{
"id": "prj_geel_demo",
"name": "Geel Building Detection Demo",
"description": "Portfolio demo for GeoAI object detection and GRB QA.",
"region": "Kempen",
"created_at": "2026-06-10T00:00:00Z"
}
```
## Area FeatureCollection
```json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"id": "area_geel_center",
"name": "Geel Centrum",
"area_m2": 1250000
},
"geometry": {
"type": "Polygon",
"coordinates": [[[4.98,51.16],[5.00,51.16],[5.00,51.18],[4.98,51.18],[4.98,51.16]]]
}
}
]
}
```
## Dataset Metadata
```json
{
"id": "ds_grb_buildings_geel",
"project_id": "prj_geel_demo",
"name": "GRB Buildings Geel Demo",
"dataset_type": "vector",
"source": "demo_fixture",
"status": "ready",
"crs": "EPSG:4326",
"bounds": [4.98, 51.16, 5.00, 51.18],
"metadata": {
"feature_count": 12,
"geometry_types": ["Polygon"]
}
}
```
## Detection Run
```json
{
"id": "run_detection_001",
"project_id": "prj_geel_demo",
"analysis_type": "object_detection",
"status": "completed",
"parameters": {
"model_id": "demo-yolo-buildings-v1",
"confidence_threshold": 0.35,
"tile_size": 512
},
"metrics": {
"detection_count": 14,
"mean_confidence": 0.82
}
}
```
## QA/QC Result
```json
{
"id": "qc_001",
"analysis_run_id": "run_detection_001",
"reference_dataset_id": "ds_grb_buildings_geel",
"iou_threshold": 0.5,
"metrics": {
"true_positive": 11,
"false_positive": 3,
"false_negative": 1,
"precision": 0.7857,
"recall": 0.9167,
"f1": 0.8462
}
}
```
+229
View File
@@ -0,0 +1,229 @@
# API Specification v1.0
Basispad: `/api/v1`
## Projects
### GET /projects
Geeft alle projecten terug.
### POST /projects
Maakt een project aan.
Body:
```json
{
"name": "Geel gebouwdetectie demo",
"description": "Detectie en QA/QC van gebouwen in Geel",
"region": "Kempen"
}
```
### GET /projects/{project_id}
Geeft projectdetails terug.
### DELETE /projects/{project_id}
Verwijdert een project en gekoppelde metadata. Bestanden moeten veilig afgehandeld worden.
## Areas
### GET /projects/{project_id}/areas
Geeft analysegebieden van een project.
### POST /projects/{project_id}/areas
Maakt analysegebied aan.
Body:
```json
{
"name": "Geel Centrum",
"geometry": { "type": "Polygon", "coordinates": [] }
}
```
### GET /areas/{area_id}
Geeft gebieddetails.
## Datasets
### POST /projects/{project_id}/datasets/upload
Uploadt raster of vector dataset.
Multipart:
- file
- name
- dataset_type
- source
### GET /projects/{project_id}/datasets
Lijst datasets.
### GET /datasets/{dataset_id}
Datasetdetails.
### GET /datasets/{dataset_id}/metadata
Metadata.
### POST /datasets/{dataset_id}/extract-metadata
Start metadata extraction job.
## Reference Data
### POST /projects/{project_id}/reference/grb/fetch
Haalt GRB-data op voor een area.
Body:
```json
{
"area_id": "uuid",
"layers": ["buildings"]
}
```
### POST /projects/{project_id}/reference/osm/fetch
Haalt OSM-data op voor een area.
## Raster
### POST /datasets/{dataset_id}/raster/clip
Clipt raster op area.
### POST /datasets/{dataset_id}/raster/tile
Maakt tiles voor AI-inference.
Body:
```json
{
"tile_size": 640,
"overlap": 64,
"area_id": "uuid"
}
```
### POST /datasets/{dataset_id}/raster/indices/ndvi
V2: berekent NDVI.
## Vector
### POST /datasets/{dataset_id}/vector/clip
Clipt vectorlaag op area.
### POST /datasets/{dataset_id}/vector/buffer
Maakt buffers.
### POST /datasets/{dataset_id}/vector/validate
Valideert geometrieën.
## Analysis
### POST /analysis/object-detection
Start objectdetectie.
Body:
```json
{
"project_id": "uuid",
"area_id": "uuid",
"dataset_id": "uuid",
"model_id": "uuid-or-default",
"classes": ["building"],
"confidence_threshold": 0.35
}
```
### POST /analysis/segmentation
Start segmentatie.
### POST /analysis/change-detection
Start change detection.
### GET /analysis/{analysis_run_id}
Geeft runstatus en resultaten.
### GET /analysis/{analysis_run_id}/detections
Geeft detecties als GeoJSON FeatureCollection.
### GET /analysis/{analysis_run_id}/segmentations
Geeft segmentaties als GeoJSON FeatureCollection.
## QA/QC
### POST /analysis/{analysis_run_id}/quality-check
Vergelijkt AI-resultaten met referentiedataset.
Body:
```json
{
"reference_dataset_id": "uuid",
"iou_threshold": 0.5,
"class_mapping": {
"building": "building"
}
}
```
### GET /quality-checks/{quality_check_id}
Geeft QA/QC-resultaten.
## Exports
### POST /exports/geojson
Exporteert analysis output naar GeoJSON.
### POST /exports/yolo
Exporteert annotaties naar YOLO-formaat.
### POST /exports/coco
Exporteert annotaties naar COCO-formaat.
### GET /exports/{export_id}/download
Download exportbestand.
## Jobs
### GET /jobs/{job_id}
Geeft jobstatus.
### GET /projects/{project_id}/jobs
Geeft jobs van een project.
+148
View File
@@ -0,0 +1,148 @@
# Architecture
## 1. Overzicht
GeoIntel bestaat uit:
- React/TypeScript frontend
- FastAPI backend
- PostgreSQL/PostGIS database
- background job queue
- file/object storage
- GIS processing services
- AI inference services
## 2. Hoofdcomponenten
```text
Frontend
↓ REST/WebSocket
FastAPI Backend
PostgreSQL + PostGIS
Storage: uploads, processed rasters, tiles, masks, exports
Workers: GIS processing, AI inference, QA/QC, export
```
## 3. Frontend
Aanbevolen stack:
- React
- TypeScript
- MapLibre GL
- Deck.gl
- Tailwind
- TanStack Query
- Zustand of vergelijkbare lichte state store
- Recharts voor eenvoudige grafieken
Belangrijke principes:
- kaart centraal, maar analysepanelen even belangrijk
- labs per workflow
- duidelijke jobstatus
- outputs altijd exporteerbaar
- geen verborgen mockgedrag
## 4. Backend
Aanbevolen stack:
- FastAPI
- SQLAlchemy 2.x
- GeoAlchemy2
- Alembic
- Pydantic
- RQ/Celery
- Rasterio
- GeoPandas
- Shapely
- PyProj
- NumPy
- OpenCV
- Ultralytics/PyTorch
## 5. Database
PostgreSQL met PostGIS is verplicht voor:
- projectgebieden
- vectorfeatures
- detectiepolygonen
- segmentatiepolygonen
- spatial joins
- intersects
- IoU berekeningen
- bounds queries
## 6. Storage
Bewaar grote bestanden niet in de database.
Opslagcategorieën:
- originele uploads
- verwerkte rasters
- raster tiles
- masks
- model outputs
- exports
- rapporten
Database bewaart metadata en paden.
## 7. Jobs
Langlopende processen moeten via background jobs:
- raster metadata extraction
- raster clipping
- raster tiling
- vector import
- AI inference
- segmentation polygonize
- QA/QC
- change detection
- export generation
## 8. AI Inference
Inference pipeline:
```text
Raster dataset
→ clip to area
→ tile raster
→ normalize/preprocess
→ model inference
→ convert pixel coords to geospatial coords
→ merge/filter outputs
→ save detections/segmentations
→ expose as map layer
```
## 9. CRS-regels
- Alle interne geometrieën worden opgeslagen in PostGIS met bekende SRID.
- Voor metrische berekeningen wordt een geschikte projectie gebruikt.
- API-output naar frontend mag in EPSG:4326 of WebMercator-compatible formaat.
- Elke dataset zonder CRS krijgt status `needs_crs_review`.
## 10. Developmentstrategie
Bouwvolgorde:
1. backend foundation
2. database schema
3. project/area API
4. dataset upload en metadata
5. frontend workspace en kaart
6. vector import
7. raster import
8. processing jobs
9. detection lab
10. QA/QC
11. export
+108
View File
@@ -0,0 +1,108 @@
# Audit remediation roadmap
Status: active, 2026-07-26
## Release outcome
GeoIntel may accept every valid AOI inside the governed Belgium and Belgian
North Sea scope. It may only call a theme operational where bounded processing,
source coverage, provenance, resolution and validation evidence support that
claim. Production AI inference on the server uses its NVIDIA GPU and fails
closed when CUDA is unavailable; CPU fallback is not an accepted production
state.
## Wave 0 - Runtime truth and NVIDIA GPU (in progress)
- expose the NVIDIA device to the Unraid container;
- set `YOLO_DEVICE=cuda:0` and `YOLO_REQUIRE_CUDA=true` in the server runtime;
- make preflight and model loading reject missing CUDA instead of using CPU;
- report configured device, CUDA requirement and accelerator readiness;
- rebuild on Tower and capture `nvidia-smi`, CUDA-enabled PyTorch, preflight and
one bounded inference smoke as release evidence.
Exit gate: the live container sees the NVIDIA GPU, `torch.cuda.is_available()`
is true, preflight is ready, and a persisted smoke run records the configured
CUDA device. A CPU-only image or unavailable device remains `not_configured` /
unavailable and cannot run production inference.
## Wave 1 - General AOI orchestration (in progress)
- [x] introduce one persisted parent operation with source-specific partitions;
- [x] derive partitions from provider side budgets supplied by the governed plan;
- [x] support queued execution, bounded retries, checkpoints and restart recovery;
- make partition application idempotent and retain exact request/checksum
provenance;
- [x] reuse source-aware vector deduplication and raster mosaic contracts and
aggregate their Dataset identities into one parent result;
- [x] expose one progress/result contract to the frontend system workspace.
Start with existing orthophoto, GRB and raster partition services; do not create
a second provider or persistence path. Keep per-source limits internal. A source
that cannot cover a partition returns explicit partial/not_configured evidence.
Exit gate: interrupted cross-region and coastal golden AOIs resume without
duplicate rows and finish as one inspectable result.
## Wave 2 - Zone x theme x source coverage truth (implemented; live gate pending)
- [x] materialize the resolver contract for land, regions and legal maritime zones;
- [x] evaluate partition-union spatial coverage and expose source edition,
resolution, time, CRS, attribution, licence and checksum evidence;
- [x] derive only `operational`, `partial`, `not_configured` or `unsupported`;
- [x] show missing partitions and limitations in API and map states;
- [x] prohibit UI wording that implies complete national analysis from selection
acceptance alone.
Exit gate: all frozen golden areas have checksum-bound coverage evidence and no
theme is promoted from file presence or a Mol-only success.
## Wave 3 - Source completion
- resolve North Sea bathymetry through a TLS-valid, authority-approved endpoint
or reviewed bounded operator acquisition; never bypass TLS;
- close configured orthophoto/nature/soil gaps for Wallonia where authoritative
machine access permits;
- close Brussels orthophoto gaps and retain unsupported statuses where no
source-appropriate analytical contract exists;
- add explicit external-catalog review evidence for the six source families
currently requiring review.
Exit gate: every required theme/zone cell has current evidence and honest status;
vertical datums remain separate and water volume remains unavailable without a
governed compatible model.
## Wave 4 - Model portfolio and validation (current active model gated)
- [x] inventory model assets without treating presence as configuration;
- [x] bind the current active model to persisted Mol/Kempen Area evidence;
- [x] retain building-only semantics for the current active detector;
- add segmentation only with a configured model, georeferencing tests and
persisted polygon/mask evidence;
- [x] require a model/region pair to pass reproducible holdout, hard-negative and
QA gates pass.
Exit gate: UI and API operational labels are derived from validation evidence,
not run counts; no claim that PyTorch itself is trained on themes.
## Wave 5 - Release proof
- run Mol/Kempen plus Walloon, Brussels, language-boundary, coastal and maritime
golden workflows;
- test fresh install, upgrade, rollback, restart/resume and sustained runtime;
- audit OpenAPI envelopes, CRS/units, provenance, exports and frontend
loading/empty/error states;
- publish exact checksums, source editions, model evidence and known limitations.
Exit gate: `docs/DEFINITION_OF_DONE.md` and the RC freeze are satisfied. The
product claim remains location-complete at source-native resolution, never
literal centimetre-resolution.
## Execution order
1. Finish Wave 0 and verify it live on Tower.
2. Implement the parent/partition state machine and one GRB/orthophoto vertical
slice from Wave 1.
3. Generalize that slice across compatible raster/vector providers.
4. Deliver Wave 2 before promoting additional source cells.
5. Run Waves 3 and 4 in parallel only where their evidence is independent.
6. Close with Wave 5; do not advertise the audited guarantee before its gate.
+80
View File
@@ -0,0 +1,80 @@
# Backend Package Map
Target backend layout:
```text
backend/
app/
main.py
api/
router.py
routes/
health.py
projects.py
areas.py
datasets.py
raster.py
vector.py
analysis.py
qaqc.py
exports.py
core/
config.py
database.py
logging.py
security.py
errors.py
models/
project.py
area.py
dataset.py
layer.py
analysis.py
detection.py
segmentation.py
quality.py
export.py
job.py
event.py
schemas/
common.py
project.py
area.py
dataset.py
analysis.py
quality.py
export.py
services/
project_service.py
area_service.py
dataset_service.py
raster_service.py
vector_service.py
grb_service.py
detection_service.py
segmentation_service.py
qaqc_service.py
export_service.py
event_service.py
workers/
queue.py
jobs.py
repositories/
base.py
projects.py
areas.py
datasets.py
analysis_runs.py
scripts/
seed_demo.py
tests/
```
## Rules
- API routes should be thin.
- Business logic belongs in services.
- SQLAlchemy query composition belongs in repositories where useful.
- Pydantic schemas are the API contract.
- Models are persistence structures, not API response structures.
- GIS processing functions must be testable outside HTTP handlers.
+152
View File
@@ -0,0 +1,152 @@
# Bathymetry expansion roadmap
## Purpose
GeoIntel must distinguish three different questions:
1. Where were cross-sections measured and what does the source document say?
2. What is the continuous elevation of the bed at a specific survey epoch?
3. What is the water depth or volume at a specific moment?
The first question is operational for Flanders through VHA cross-section
profiles. The second is now operational for bounded, surveyed Walloon
waterways through the official SPW raster. A bed model does not provide water
depth without a compatible water-surface elevation. Flood-hazard maximum depth
is a scenario result and must not be reused as current water level.
## Governed source matrix
| Source | Coverage | Data | Vertical reference | GeoIntel status |
| --- | --- | --- | --- | --- |
| VMM VHA Digital Atlas | Flanders | Point locations, structured profile fields, PDF evidence | Document-specific | Operational, bounded vector acquisition |
| MDK Belgian Continental Shelf model | Belgian North Sea | Continuous 20 x 20 m bathymetric raster | LAT | Available, not integrated |
| SPW navigable waterways and reservoir lakes | Wallonia | 0.5 m bed-elevation raster and XYZ cloud | mDNG | Operational, pinned operator archive and bounded COG |
| Port of Antwerp-Bruges publications | Port survey areas | Periodic soundings | Product-specific | Catalog candidate |
VHA contains approximately 129,643 profile points across Flanders at the
observed catalog state. This is a scale indication, not a fixed contractual
count. Mol contained 828 exact in-boundary points during source validation,
715 with document links and 112 with a structured depth field. Production
provisioning always records the live counts and checksums.
## Operational tier 1: Mol
- Query only an explicit EPSG:4326 bbox.
- Intersect the bbox with the exact persisted Mol Area.
- Page the official ArcGIS FeatureServer response without truncation.
- Resolve VHA watercourse names from the official atlas layer.
- Normalize profile points to EPSG:4326.
- Persist the artifact through `DatasetService.import_vector_bytes`.
- Persist every point through `VectorFeatureService`; the provider never
writes directly to `vector_features`.
- Expose document, measurement date, depth and width fields without parsing or
inventing values from scanned PDFs.
- Keep volume unsupported.
## Tier 2: all of Flanders
Flanders must be provisioned as exact municipality or other approved Area
partitions, not as one monolithic request. The backend feature limit protects
the provider and the application. A regional logical layer may group complete
partitions, but each Dataset retains its Area id, query URLs, checksums, exact
count and measurement-date range.
Regional activation now uses the complete checksum-bound municipality
manifest. The Map flow chooses the exact Area partition for a municipality and
uses a bounded multi-Dataset PostGIS query for regional rectangles or the
complete Flanders Area. GeoJSON remains limited to 1,000 rendered features;
counts and configured metrics cover the complete spatial result. Individual
profile dates remain authoritative and no Dataset-level survey date is
fabricated.
Remaining operational follow-up:
- add freshness/version probing for the VHA MapServer;
- keep selection-performance evidence as the profile inventory grows;
- retain explicit no-profile municipalities in every refreshed manifest.
## Tier 3: Belgium
Belgian coverage is a federation of source adapters with one normalized
contract, not one assumed national dataset:
- Flanders: VHA profiles and future validated bed rasters;
- Wallonia: SPW bathymetry for measured navigable waterways/reservoirs;
- Brussels: hydrological context until an authoritative public bathymetric
product is identified;
- federal/maritime: MDK and legally appropriate maritime boundaries.
Every adapter must emit:
- authority and owner;
- exact geographic and temporal coverage;
- horizontal and vertical CRS/datum;
- survey/acquisition time;
- resolution or sample density;
- source URL, request identity, checksum, attribution and license;
- explicit supported and unsupported metrics.
LAT, TAW and mDNG values must never be merged or compared without a documented,
tested vertical transformation and uncertainty statement.
## Tier 4: the Belgian North Sea
The map must distinguish:
- the Belgian land boundary and baseline;
- the territoriale zee (up to 12 nautical miles);
- the Belgian EEZ and continental shelf, which are jurisdictional maritime
zones and should not be labelled ordinary municipal or provincial
"grondgebied".
The MDK bathymetry WCS is the preferred continuous source candidate. Activation
requires a live Docker validation of TLS/certificates, GetCapabilities,
coverage identifiers, bounded GeoTIFF retrieval, CRS, LAT, nodata, pixel size,
response limits and maritime clipping. WMTS can support visual context but is
not the analytical source.
## Depth and volume rules
For a compatible bed raster and water-surface raster at the same time and
vertical datum:
`volume_m3 = sum(max(0, water_surface_z - bed_z) * cell_area_m2)`
For surveyed cross-sections along a connected reach:
`volume_m3 = sum(((section_area_i + section_area_i+1) / 2) * reach_length_i)`
The second method requires complete profile geometry, ordered chainage,
contemporaneous water level and defensible interpolation. VHA profile points
alone do not satisfy those prerequisites.
Historical evolution compares only survey epochs with documented compatible
coverage, datum and method. A changed raster footprint is not automatically
bed evolution.
## Implementation order
1. Operate and validate the Mol VHA profile Dataset and map flow. **Done.**
2. Add VHA municipal partition orchestration for Flanders. **Done and live:
285/285 municipality partitions accounted for, 269 with data, 16 explicit
no-profile results, 128,913 profile points and zero failures. Regional
selection and export now aggregate the latest complete manifest in
PostGIS.**
3. Implement a bounded MDK WCS probe, then acquisition behind live evidence.
**Probe implemented. Acquisition blocked because the live endpoint fails
strict hostname validation and does not expose usable capabilities.**
4. Implement SPW download staging and vertical-datum metadata validation.
**Done: pinned official ZIP, safe `/vsizip/` access, bounded COG,
DatasetService persistence, map overlay and mDNG selection metrics.**
5. Add maritime boundaries as separate authoritative scope layers.
**Done for the Belgian territorial sea, EEZ and continental shelf.**
6. Add cross-source vertical-datum transformation only with authoritative
grids/parameters and uncertainty tests.
7. Add volume only after a compatible measured or modeled water-surface source
is part of the same analysis contract.
The Flanders scope is land-only and is dynamically derived from the complete
current VRBG municipality collection (285 members at the 2026-07-17
validation). Belgium is not represented by expanding that polygon. Wallonia,
Brussels, the territorial sea and the Belgian EEZ/continental shelf require
their own authoritative adapters and legal scope labels.
+179
View File
@@ -0,0 +1,179 @@
# Belgian building detector: closed training loop
## Meaning of complete
`100% trained` means that every frozen release gate below passes. It does not
mean a fabricated 100% precision, recall or mAP score. A model that memorises a
small test set is not complete.
The loop is:
1. provision new, spatially independent AOIs from governed official services;
2. freeze imagery, labels, metadata and checksums into a new corpus version;
3. reject invalid, duplicate and sub-resolution labels and run spatial-leakage
checks;
4. train only on the train split with CUDA on the Tower NVIDIA GPU;
5. use validation for early stopping and calibration only for threshold choice;
6. evaluate the fixed threshold once on regional test and background-test data;
7. attribute false positives and false negatives to a region, AOI and context;
8. add new training-only examples for the observed failure modes and repeat;
9. stop only when every objective gate passes; request human review afterward.
Protected calibration, test and background-test AOIs never become training
data. A new iteration adds independent training AOIs instead.
## Frozen release gates
| Area | Gate |
| --- | --- |
| Runtime | CUDA required; NVIDIA device visible; no CPU fallback |
| Corpus | Immutable manifest and artifacts with SHA-256 evidence |
| Geographic composition | Each land region has at least 15 train, 2 val, 3 calibration, 3 test and 2 background-test AOIs |
| Contexts | Dense urban, suburban, rural, industrial and difficult negative contexts represented |
| Leakage | No intersecting AOIs across protected split roles |
| Label integrity | No malformed rows; sub-resolution labels explicitly rejected |
| Temporal truth | Unknown per-pixel dates remain unknown; acquisition dates may not masquerade as observation dates |
| Threshold selection | Calibration set only; maximise the worst regional F1 before aggregate F1 |
| Test aggregate | F1 at least 0.55 at the frozen footprint/detection match IoU 0.25 contract |
| Dense-tile capacity | Retain up to 1000 detections per tile; the library default of 300 is below observed Belgian urban label density |
| Regional test | Every region: F1 at least 0.45, precision at least 0.50 and recall at least 0.40 |
| Pure background | Zero detections on every pure-empty tile at the selected threshold |
| Production | Exact candidate checksum and fail-closed promotion report required |
| Final review | Human accepts every queued AOI contact sheet after all automated gates pass |
These are minimum release gates, not performance targets. Raising a confidence
threshold until detections disappear cannot pass because regional recall is a
simultaneous gate.
## Current gap inventory
The active v31 rotated-holdout corpus contains 142 independent AOIs and 26,041
accepted source building labels. Its automated corpus audit has no failures:
spatial leakage is zero, temporal identity is explicit and 272 sub-resolution
plus 393 post-imagery labels are rejected rather than silently trained. The
tile-quality audit records 51,244 visible training instances, zero invalid or
missing label files, zero low-variance positive tiles and 214 negative tiles.
It covers coastal, ribbon-development, farmland, park, forest, industrial,
rail, quarry and additional urban contexts. Its remaining known gaps are:
- dated 2025 imagery is used for Flanders and Brussels and the dated 2024 SPW
campaign for Wallonia. Exact flight days remain a later metadata refinement,
but all corpus relations are now measured periods rather than download dates;
- GRB/PICC/UrbIS describe ground footprints, whereas visible roofs can remain
displaced. The existing detector QA contract therefore uses IoU 0.25; the
threshold is frozen and cannot be relaxed per candidate;
- the active v38 loop still has to prove the frozen regional calibration gates;
iteration 2 improved aggregate calibration F1 to 0.573 but remained below
the Flemish F1/precision/recall gates and the Walloon precision gate;
- Oostende coastal fabric is the dominant observed Flemish calibration
failure. Independent train-only coastal positives and port/dunes negatives
are therefore selected by the failure-driven sampler without opening or
copying protected calibration data;
- sparse hard contexts pass the empty-image test more easily than dense urban
recall, so both gates must remain independent;
- building boxes are a valid first detector contract, but footprint-perfect
geometry ultimately requires a separately validated segmentation model.
The active production model remains unchanged while any gate fails.
The v31 expansion added eighteen independent train-only AOIs after the v30
rotated-holdout calibration isolated the remaining domain gaps. Nine Flemish
AOIs cover industrial roofs, ribbon development and coastal urban fabric. Nine
Walloon AOIs add dense urban, rural-town, regional-architecture and difficult
industrial/rail/quarry negatives. Existing validation, calibration, test and
background-test AOIs remain frozen. The provisioner can load a short-lived
operator session from a mode-0600 token file, allowing governed acquisition on
an authenticated runtime without exposing credentials in process arguments.
## Reproducible evidence
- corpus assembler: `scripts/assemble_belgium_building_corpus.py`;
- corpus auditor: `scripts/audit_belgium_building_corpus.py`;
- tile exporter/auditor/contact sheets: the `operator_yolo` scripts;
- per-AOI evaluator: `scripts/evaluate_belgium_building_candidate.py`;
- calibration-only selection and release gates:
`scripts/assess_belgium_building_training_iteration.py`.
- checkpointed CUDA orchestration:
`scripts/run_belgium_building_training_loop.py`.
Every failed assessment returns `continue_training_loop`. Only a report with
`training_complete` may proceed to final human review and guarded activation.
Optimizer, initial learning rate, image size and geometric augmentation are
explicit loop inputs. This permits a conservative aerial-imagery finetune
(for example AdamW with mosaic disabled) without changing calibration, test
or release gates.
After a failed assessment,
`scripts/build_failure_driven_yolo_sampling.py` creates a checksummed,
train-only sampling manifest. Positive tiles from regions that fail F1 or
recall are repeated, while true negative train tiles are repeated when a
regional precision gate or the pure-background gate fails. Calibration, test,
background-test and validation AOIs are excluded by their frozen corpus split;
the generated evidence records that no protected sample entered training.
Per-AOI calibration evidence also identifies failed region/context pairs.
Train-only AOIs with the same governed context receive a stronger repeat factor
than the remaining failed region, so correction rounds target distinct failure
modes without copying a protected AOI into training. The sampling evidence
records both context sets and repeat factors. When no matching train context
exists, regional sampling remains active and the missing context becomes a
concrete input for the next immutable corpus expansion.
Failure weighting may not let one region exceed 65% of the sampled entries.
The deterministic cap removes only repeated entries and retains every unique
train tile at least once; manifests record pre-cap counts, final counts and the
number of dropped repeats. This keeps a weak region prominent without turning
the national detector into a single-region expert.
Precision correction expands failed semantic contexts into related negative
families: coastal urban failures target port/dunes negatives, industrial
failures target industrial/rail/port negatives, and ribbon/rural/regional
architecture failures target their governed farmland, forest or quarry
counterparts. These diagnostic negative repeats are ordered ahead of generic
repeats so the regional cap cannot discard them first.
The checkpointed orchestrator invokes this builder after every rejected
iteration, stores its checksum in `training-loop-state.json`, and uses the
resulting dataset YAML for the next checkpoint. A restart resumes both the
candidate weights and that exact failure-driven training input.
An already completed out-of-band checkpoint enters the same contract with
`--evaluate-initial-model`: the first iteration skips fitting, copies and
hashes the checkpoint, and begins at calibration. A rejection then follows
the identical failure-driven CUDA path and cannot open protected test evidence
early.
Tower's v37 supervisor binds the completed `results.png` artifact to a
versioned JSON argv list. The handoff starts the orchestrator detached exactly
once; shell strings are not accepted. Subsequent iterations retain the frozen
180-degree aerial rotation, vertical/horizontal flip, scale and translation
parameters rather than silently reverting to generic augmentation defaults.
Before fitting a state-pending iteration, the orchestrator checks its canonical
run directory for `weights/last.pt`. If present, it resumes that exact CUDA
checkpoint instead of restarting from the prior candidate. A host-side parent
supervisor monitors the exact loop-process marker and persisted loop state; on
container recreation it restores the current orchestrator script and launches
the versioned JSON argv command. Invalid state and bounded launch exhaustion
fail closed.
The orchestrator refuses to start unless every automated frozen-dataset gate
passes and the corpus contains zero blank/low-variance positive tiles. The
separate train tile-quality audit is a required checksummed loop input; missing
invalid-label, missing-label-file or low-variance evidence fails closed rather
than being interpreted as zero. The
audit status may remain `needs_human_review` while training and objective
evaluation continue: final human sign-off is deliberately the last gate and
can never be interpreted as model promotion approval in advance.
For dated imagery, GRB `BEGINDATUM` and PICC `DATE_CREAT` are compared with the
end of the imagery period. A feature created afterward is retained in the
audit but excluded from training as `created_after_imagery_period`. UrbIS does
not expose an equivalent feature creation field in this acquisition contract,
so its remaining temporal relation stays an explicit sample-level limitation.
An opt-in visible-roof experiment can dissolve source footprints that truly
touch or overlap; separated footprints are never bridged. The audit retains
every contributing native feature identifier and reports both source-feature
and visible-instance counts. This mode is not the default: the Belgium v8
experiment showed that unconditional touching-footprint dissolve can merge
whole urban blocks and therefore must pass the same independent gates before
it can replace native instances.
The compact-roof variant therefore merges a connected group only when it has
at most 12 source footprints and fills at least 55% of its axis-aligned
envelope. Larger or irregular connected groups retain their native instances
and are marked `native_instance_complex_touch_group`. These fixed criteria
prevent administrative row-house chains from becoming one ambiguous detector
box while keeping the experiment deterministic and auditable.
+9
View File
@@ -0,0 +1,9 @@
# Build Governance
Elke pass heeft doel, inputdocumenten, taken, niet-doen lijst, acceptatiecriteria, testcommando's en handoff-output.
Codex werkt altijd bij: `CHANGELOG.md`, `docs/TODO.md`, relevante contractdocs en `docs/CODEX_EXECUTION_LOG.md`.
Stopregels: backend start niet, frontend buildt niet, migrations falen, API-contracten inconsistent, demo-flow breekt.
Visuele polish pas na werkende dataflow, API en tests/smoke checks.
+74
View File
@@ -0,0 +1,74 @@
# GeoIntel Build Status
Updated: 2026-07-19
## Current state
GeoIntel `v1.0.0` is an accepted map-first GeoAI workbench for Belgium
and the legally distinct Belgian maritime scopes. It runs as an immutable
all-in-one Unraid image with PostGIS, FastAPI, React/MapLibre, local Ollama
integration and optional local YOLO/PyTorch inference.
Mol and the Kempen are deep regression areas, not the product boundary. The
national workbench also has deterministic golden journeys for Wallonia,
Brussels, a language-boundary selection, the coast and the Belgian North Sea.
## Release status
There are no open release blockers for `v1.0.0`. RC-0 through RC-11 and the
post-RC national data closeout are complete. Backup/restore, fresh install,
upgrade, rollback, fail-closed readiness, one Alembic head, API contracts,
supply-chain policy, responsive browser journeys and live PostGIS acceptance
are proven against the final release candidate image.
The final repository gate passes 1,052 backend tests, 22 frontend tests,
frontend typecheck/build, one Alembic head and the complete readiness script.
The live SPW bathymetry persistence and browser journey are accepted for the
final version: EPSG:3812 mDNG bed elevation, 2019-2022 survey period, bounded
coverage and no unsupported depth/volume inference.
## Operational product loop
- Open one national map without selecting a technical project.
- Select an understandable theme and draw or reuse a bounded Area.
- Resolve governed coverage per Belgian jurisdiction.
- Analyse persisted PostGIS vectors or bounded raster artifacts.
- Show source-appropriate metrics, provenance, time and limitations.
- Compare compatible Statbel 2021-2025 and other governed historical series.
- Export persisted evidence or question it through the local Ollama assistant.
- Run configured local YOLO detection with persisted QA and explicit human
review limitations.
## Explicit non-blocking boundaries
- MDK analytical North Sea bathymetry remains `not_configured`: the public
endpoint fails strict hostname validation and the official low-resolution
product is currently request-based. TLS and source-integrity checks are not
bypassed.
- SPW supplies governed Walloon waterbed elevation in mDNG, not current water
depth. Water volume remains unsupported until a compatible water-surface,
time, vertical-datum and uncertainty contract exists.
- Building detection is an assisted review workflow. The retained benchmark
still requires independent false-negative review before any claim of
autonomous production accuracy or another training pass.
- Real SAM/YOLO-seg inference, a training studio, LiDAR, production
multi-user authentication and real-time monitoring remain post-V1 scope.
- Additional official datasets may improve coverage, but they are not V1
completion blockers when the coverage matrix reports absence honestly.
## Reproduce current repository evidence
```bash
bash scripts/run_readiness_check.sh
cd backend && python -m alembic upgrade head --sql
bash -n scripts/live_migration_smoke.sh
```
Live release evidence:
```bash
python scripts/capture_release_evidence.py \
--output storage/release-evidence/rc-current/baseline.json \
--release-id rc-belgium-north-sea \
--live-base-url http://192.0.2.10:1202
```
+203
View File
@@ -0,0 +1,203 @@
# Build Tickets M3
This file converts the implementation epics into concrete Codex-ready tickets.
## Ticket format
Each ticket must be implemented with:
- backend changes if applicable
- frontend changes if applicable
- tests where applicable
- documentation updates
- changelog entry
## T-001 Backend package scaffold
Create FastAPI package structure:
```text
backend/app/main.py
backend/app/api/router.py
backend/app/core/config.py
backend/app/core/database.py
backend/app/models/
backend/app/schemas/
backend/app/services/
backend/app/workers/
backend/tests/
```
Acceptance:
- `GET /health` returns status ok.
- backend imports cleanly.
- tests can run without external geospatial data.
## T-002 Database and Alembic scaffold
Add SQLAlchemy and Alembic setup for PostgreSQL/PostGIS.
Acceptance:
- database URL comes from environment.
- migrations directory exists.
- first migration creates PostGIS extension if available.
- migration plan documented.
## T-003 Project model and API
Implement project entity.
Acceptance:
- create project
- list projects
- read project
- update project
- soft delete or archive project
- response envelope followed
## T-004 Area model and geometry API
Implement areas linked to projects.
Acceptance:
- create polygon area as GeoJSON
- validate geometry
- store geometry in PostGIS
- calculate area in square meters using projected CRS
- return bounds and centroid
## T-005 Frontend foundation
Create React + TypeScript app structure.
Acceptance:
- app boots
- route layout exists
- API client exists
- error/loading components exist
- navigation includes Workspace, Map, Datasets, Raster, Vector, Detection, QA/QC, Exports
## T-006 Map workbench foundation
Implement map page and area drawing contract.
Acceptance:
- map displays Kempen default viewport
- user can draw or load an example polygon
- polygon can be submitted to backend as area
- active area can be selected
## T-007 Dataset upload API
Implement dataset registration and upload.
Acceptance:
- accepts GeoTIFF, GeoJSON, ZIP shapefile, GPKG placeholder handling
- stores original file under storage/originals
- creates dataset row
- status starts as uploaded
- returns metadata extraction job status
## T-008 Raster metadata service
Implement Rasterio metadata extraction.
Acceptance:
- CRS
- bounds
- width/height
- band count
- resolution
- nodata
- dtype
- transform
- summary stats for small rasters or sampled stats for large rasters
## T-009 Vector metadata service
Implement GeoPandas metadata extraction.
Acceptance:
- CRS
- bounds
- feature count
- geometry types
- columns
- invalid geometry count
- area summary where applicable
## T-010 GRB reference fetcher skeleton
Implement service contract for GRB WFS fetch.
Acceptance:
- service accepts area geometry
- builds BBOX or polygon filter request
- stores retrieved features as dataset/layer
- if live WFS unavailable, returns a clear source_unavailable status without crashing
## T-011 Detection pipeline interface
Implement detection run model and interface.
Acceptance:
- request creates analysis_run
- job lifecycle status exists
- deterministic fixture inference can populate detections for demo fixtures
- output geometries are stored and exported as GeoJSON
## T-012 QA/QC engine v1
Implement reference-vs-prediction matching.
Acceptance:
- IoU threshold configurable, default 0.5
- precision, recall, F1 calculated
- false positives and false negatives classified
- QA result stored
- fixture test passes with known expected metrics
## T-013 Export API
Implement export registry and GeoJSON export.
Acceptance:
- export detection results as FeatureCollection
- export QA false positives/negatives as FeatureCollection
- export analysis summary JSON
- exports have stable file paths under storage/exports
## T-014 Frontend dataset and analysis panels
Implement visible pages for dataset, detection and QA workflows.
Acceptance:
- dataset list shows status and metadata
- detection page starts run and shows result state
- QA page shows metrics and error classes
- map overlays are connected to available GeoJSON outputs
## T-015 Stabilization pass
Acceptance:
- no broken navigation
- no unhandled promise rejections
- backend health green
- core tests green
- README quickstart updated
- CHANGELOG updated
+18
View File
@@ -0,0 +1,18 @@
# Changelog M4
## Added
- Autonomous build readiness specification.
- M4 sprint board.
- Module build contracts.
- Acceptance test catalog.
- API example response contracts.
- Job lifecycle contract.
- Frontend state and route contracts.
- Backend service IO contracts.
- Model registry seed specification.
- Demo fixture manifest.
- Codex autonomous runbook.
- Codex pass prompts for backend, database, dataset manager, map workspace, AI demo pipelines and QA/QC exports.
## Intent
M4 prepares the repository for long Codex implementation sessions with minimal human intervention.

Some files were not shown because too many files have changed in this diff Show More