docs: reconcile current reconstruction architecture
This commit is contained in:
parent
7574362ba9
commit
a3a005b38e
6 changed files with 2407 additions and 2723 deletions
|
|
@ -1,180 +1,408 @@
|
||||||
# Geometric Verification
|
# Geometric Verification Model
|
||||||
|
|
||||||
## Scope
|
## Status
|
||||||
|
|
||||||
Geometric Verification Model est le contrat persistant placé après le Matcher.
|
|
||||||
Sa représentation stocke les identités scientifiques Geometric Verifier v1/v2
|
|
||||||
historiques et v3 courantes, sans changement de schéma : `verifier_version` et
|
|
||||||
`parameter_fingerprint` appartiennent déjà à l'identité exacte. Il stocke un
|
|
||||||
résultat terminé, compact et immutable. Il n'est ni un moteur de calcul ni une
|
|
||||||
tâche.
|
|
||||||
Aucun RANSAC, USAC, MAGSAC, calcul d'inliers ou backend géométrique n'appartient à ce ticket.
|
|
||||||
|
|
||||||
## Position in reconstruction pipeline
|
|
||||||
|
|
||||||
La chaîne d'ownership est :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Feature Set → Candidate Pair → Match Result → Geometric Verification Result
|
GEOMETRIC_VERIFICATION_MODEL=IMPLEMENTED
|
||||||
|
PROJECT_DB_GEOMETRIC_VERIFICATION=v12
|
||||||
|
|
||||||
|
HISTORICAL_VERIFIER_V1=VALID
|
||||||
|
HISTORICAL_VERIFIER_V2=VALID
|
||||||
|
CURRENT_PRODUCTION_VERIFIER_V3=FROZEN
|
||||||
|
|
||||||
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
|
REAL_S21_GV_V3=PASS/FROZEN
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
```
|
```
|
||||||
|
|
||||||
Le masque indexe exclusivement l'ordre des entrées du Match File canonique du Match Result. Il
|
This document owns the **persistent Geometric Verification Result model**.
|
||||||
n'indexe directement ni les features, ni la Candidate Pair, ni un ordre temporaire de backend.
|
|
||||||
|
|
||||||
## Scientific ownership
|
It does not own the numerical estimator implementation. The current executable scientific verifier is
|
||||||
|
documented in `geometric_verifier.md`.
|
||||||
|
|
||||||
Le parent scientifique est `match_result_id`. L'API accepte uniquement un Match Result existant,
|
The persistence model was deliberately version-ready from Project DB v12: `verifier_version` and
|
||||||
`MATCHED`, avec `match_count` strictement positif. `NO_MATCH` et les erreurs runtime ne peuvent pas
|
`parameter_fingerprint` already belong to exact result identity. Therefore historical verifier v1/v2
|
||||||
produire de résultat géométrique.
|
and current v3 results coexist without a schema reinterpretation.
|
||||||
|
|
||||||
## Parent Match Result
|
## Pipeline position
|
||||||
|
|
||||||
Le Match Store reste propriétaire de la validation du Match File. La création consulte le parent
|
```text
|
||||||
et son `match_count` en DB ; elle ne relit pas l'asset. Un load valide aussi l'existence et l'état du
|
Feature Set
|
||||||
parent afin qu'une ligne corrompue ne soit jamais rendue comme résultat valide.
|
-> Candidate Pair
|
||||||
|
-> Match Result
|
||||||
|
-> Geometric Verification Result
|
||||||
|
-> Track Builder
|
||||||
|
-> Track Model
|
||||||
|
```
|
||||||
|
|
||||||
|
The inlier mask indexes the canonical Match File entry order.
|
||||||
|
|
||||||
|
It does not directly index:
|
||||||
|
|
||||||
|
- Feature Store physical order;
|
||||||
|
- Candidate Pair order;
|
||||||
|
- temporary backend order.
|
||||||
|
|
||||||
|
## Scientific parent
|
||||||
|
|
||||||
|
The exact parent is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
match_result_id
|
||||||
|
```
|
||||||
|
|
||||||
|
A Geometric Verification Result may be created only for a valid `MATCHED` parent with positive
|
||||||
|
`match_count`.
|
||||||
|
|
||||||
|
`NO_MATCH` and runtime failures do not produce a scientific geometric result.
|
||||||
|
|
||||||
## Persistent identity
|
## Persistent identity
|
||||||
|
|
||||||
L'identité demandée et unique est :
|
Exact identity:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
(match_result_id, verifier_kind, verifier_version, parameter_fingerprint)
|
(
|
||||||
|
match_result_id,
|
||||||
|
verifier_kind,
|
||||||
|
verifier_version,
|
||||||
|
parameter_fingerprint
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Le fingerprint est le SHA-256 opaque de 32 octets déjà standard dans le projet. Il représentera
|
No selection by timestamp or "latest" is permitted.
|
||||||
un encodage de paramètres versionné, stable, à ordre de champs explicite et, pour les nombres
|
|
||||||
binaires, little-endian. Aucun timestamp, résultat, PID, durée ou identifiant matériel n'y entre.
|
The fingerprint is an opaque canonical SHA-256 scientific parameter identity.
|
||||||
|
|
||||||
|
It excludes:
|
||||||
|
|
||||||
|
- Task ID;
|
||||||
|
- PID;
|
||||||
|
- elapsed time;
|
||||||
|
- CPU count;
|
||||||
|
- batch size;
|
||||||
|
- GPU identity;
|
||||||
|
- hardware identity.
|
||||||
|
|
||||||
## Verifier kind
|
## Verifier kind
|
||||||
|
|
||||||
Le modèle supporte uniquement `FUNDAMENTAL`, valeur persistante stable 1. Aucun comportement fictif
|
The persistent supported model kind is:
|
||||||
`ESSENTIAL` ou `HOMOGRAPHY` n'est réservé dans l'API publique.
|
|
||||||
|
|
||||||
## Persistent states
|
```text
|
||||||
|
FUNDAMENTAL = 1
|
||||||
|
```
|
||||||
|
|
||||||
- `GEOMETRIC_REJECTED=1` : calcul scientifique terminé, critère non satisfait ;
|
Do not reserve fictitious `ESSENTIAL` or `HOMOGRAPHY` values in prose without an explicit versioned
|
||||||
- `GEOMETRIC_VERIFIED=2` : calcul scientifique terminé, critère satisfait.
|
implementation decision.
|
||||||
|
|
||||||
`FAILED`, `RUNNING`, `PAUSED` et `CANCELLED` appartiennent au Task Runtime. REJECTED peut conserver
|
## Scientific states
|
||||||
un nombre d'inliers non nul.
|
|
||||||
|
|
||||||
## Model representation
|
Completed scientific states are:
|
||||||
|
|
||||||
FUNDAMENTAL utilise neuf colonnes SQLite `REAL`, en ordre ligne-major `m00` à `m22`. SQLite
|
```text
|
||||||
convertit les valeurs numériques en binary64 sans exposer une ABI C. VERIFIED exige les neuf
|
GEOMETRIC_REJECTED = 1
|
||||||
valeurs présentes et finies. REJECTED exige les neuf valeurs NULL. Le modèle n'impose ni rang 2,
|
GEOMETRIC_VERIFIED = 2
|
||||||
ni déterminant, ni normalisation ou échelle canonique ; ces règles relèvent du futur verifier.
|
```
|
||||||
|
|
||||||
## Inlier representation
|
Runtime states such as RUNNING, FAILED, PAUSED or CANCELLED belong to Task Runtime, not this model.
|
||||||
|
|
||||||
Le masque est un BLOB SQLite obligatoire de taille exacte `ceil(match_count / 8)`. Pour l'entrée
|
A rejected result may still contain non-zero inlier support.
|
||||||
`i`, `byte_index=i/8`, `bit_index=i%8` et le masque vaut `1u << bit_index`. Le bit 0 est donc le bit
|
|
||||||
de poids faible de l'octet 0. Cette convention est indépendante de l'endianness CPU et de l'ABI.
|
|
||||||
Les bits de padding du dernier octet valent zéro et le popcount est exactement `inlier_count`.
|
|
||||||
|
|
||||||
Le masque existe pour REJECTED comme pour VERIFIED. Avec 8192 matches, il mesure au maximum
|
## Fundamental matrix representation
|
||||||
1024 octets. Un BLOB SQLite évite les milliers de lignes secondaires et la publication, le hash,
|
|
||||||
le nettoyage et la récupération d'un asset externe d'environ 1 Kio. Une liste `uint32_t` serait
|
|
||||||
jusqu'à 32 fois plus grande au cas dense et aurait un encodage supplémentaire à versionner.
|
|
||||||
|
|
||||||
## Invariants
|
A verified Fundamental result contains nine SQLite `REAL` values:
|
||||||
|
|
||||||
- `0 <= inlier_count <= parent.match_count <= 8192` ;
|
```text
|
||||||
- longueur, padding et popcount du masque sont canoniques ;
|
m00 ... m22
|
||||||
- REJECTED possède un masque cohérent et aucun modèle ;
|
```
|
||||||
- VERIFIED possède un masque cohérent et exactement neuf valeurs finies ;
|
|
||||||
- kind, version et fingerprint ont une sérialisation stable ;
|
|
||||||
- une ligne publiée est complète et immutable.
|
|
||||||
|
|
||||||
Exemple : pour 100 matches, une identité FUNDAMENTAL v1, v2 ou v3/fingerprint
|
in row-major order.
|
||||||
X peut publier REJECTED avec 23 inliers, un masque de 13 octets et aucun modèle.
|
|
||||||
Une autre identité peut publier VERIFIED avec 67 inliers, le même format de
|
|
||||||
masque et une matrice 3×3 finie.
|
|
||||||
|
|
||||||
## Persistence semantics
|
The persistent representation is binary64 through SQLite numeric semantics, not a C ABI struct dump.
|
||||||
|
|
||||||
Une création valide puis insère identité, état, masque et modèle dans une transaction courte. Le
|
A verified row requires nine finite values.
|
||||||
calcul futur se fera entièrement avant cette transaction. SQLite fournit l'atomicité ; aucun asset
|
|
||||||
ou journal secondaire n'est créé.
|
A rejected row contains no model.
|
||||||
|
|
||||||
|
Rank/canonicalization/scientific-estimator rules belong to the versioned verifier contract.
|
||||||
|
|
||||||
|
## Inlier mask
|
||||||
|
|
||||||
|
The mask is a required SQLite BLOB of exact size:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ceil(match_count / 8)
|
||||||
|
```
|
||||||
|
|
||||||
|
Bit convention for Match File entry `i`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
byte = i / 8
|
||||||
|
bit = i % 8
|
||||||
|
mask[byte] & (1u << bit)
|
||||||
|
```
|
||||||
|
|
||||||
|
The mask is LSB-first inside each byte.
|
||||||
|
|
||||||
|
Padding bits in the final byte are zero.
|
||||||
|
|
||||||
|
The mask popcount must equal `inlier_count`.
|
||||||
|
|
||||||
|
The mask exists for both verified and rejected scientific results.
|
||||||
|
|
||||||
|
With the current Match File bound of 8192 matches, the mask is at most 1024 bytes.
|
||||||
|
|
||||||
|
## Persistent invariants
|
||||||
|
|
||||||
|
For every row:
|
||||||
|
|
||||||
|
```text
|
||||||
|
0 <= inlier_count <= parent.match_count <= 8192
|
||||||
|
mask size is canonical
|
||||||
|
padding bits are zero
|
||||||
|
mask popcount == inlier_count
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally:
|
||||||
|
|
||||||
|
```text
|
||||||
|
REJECTED -> no Fundamental matrix
|
||||||
|
VERIFIED -> exactly nine finite matrix coefficients
|
||||||
|
```
|
||||||
|
|
||||||
|
A published row is immutable.
|
||||||
|
|
||||||
|
## Publication
|
||||||
|
|
||||||
|
Numerical estimation completes before the short Project DB publication transaction.
|
||||||
|
|
||||||
|
Publication inserts:
|
||||||
|
|
||||||
|
- exact parent;
|
||||||
|
- exact verifier identity;
|
||||||
|
- completed state;
|
||||||
|
- canonical mask;
|
||||||
|
- optional verified Fundamental model.
|
||||||
|
|
||||||
|
No external asset is required because the bounded mask/model fit naturally in SQLite.
|
||||||
|
|
||||||
|
Rollback leaves no partial scientific result.
|
||||||
|
|
||||||
## Reuse
|
## Reuse
|
||||||
|
|
||||||
Le reuse cherche uniquement l'identité exacte, jamais le résultat le plus récent. Une identité
|
Exact reuse uses only the full persistent identity.
|
||||||
existante retourne une erreur de contrainte à `create`; le runtime fera `find`, validera puis
|
|
||||||
réutilisera. `INSERT OR REPLACE` est interdit, même si le nouveau contenu semble identique.
|
|
||||||
|
|
||||||
## Invalidations
|
Existing exact result:
|
||||||
|
|
||||||
Un nouveau Match Result possède un nouvel ID et ne réutilise donc aucun ancien résultat
|
```text
|
||||||
géométrique. La FK emploie `ON DELETE CASCADE` : supprimer explicitement le parent supprime ses
|
find
|
||||||
enfants et ne crée pas d'orphelin. Aucun moteur d'invalidation parallèle n'est nécessaire.
|
-> validate
|
||||||
|
-> reuse
|
||||||
|
```
|
||||||
|
|
||||||
## Project DB schema
|
Never:
|
||||||
|
|
||||||
Project DB v12 ajoute `geometric_verification_results`, une contrainte UNIQUE sur l'identité et un
|
```text
|
||||||
index de pagination `(match_result_id, geometric_verification_result_id)`. Les CHECK SQL portent
|
INSERT OR REPLACE
|
||||||
les bornes scalaires, tailles locales et nullabilité modèle/état. La cohérence avec le parent, le
|
latest result
|
||||||
padding, le popcount et la finitude restent validés en C.
|
closest fingerprint
|
||||||
|
same parent with different version
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
A new scientific verifier version creates another result identity.
|
||||||
|
|
||||||
L'API publique implémente :
|
## Parent deletion
|
||||||
|
|
||||||
- `lardon3d_project_db_create_geometric_verification_result()` ;
|
The parent FK uses delete-cascade semantics.
|
||||||
- `lardon3d_project_db_load_geometric_verification_result()` ;
|
|
||||||
- `lardon3d_project_db_find_geometric_verification_result()` ;
|
|
||||||
- `lardon3d_project_db_list_geometric_verification_results()`.
|
|
||||||
|
|
||||||
La liste est bornée à 256 entrées, filtrée par parent puis ordonnée par ID croissant avec curseur.
|
Explicit deletion of a Match Result deletes its dependent geometric results.
|
||||||
Le résultat en mémoire contient son `created_at` et son masque dans une capacité fixe de 1024
|
|
||||||
octets : aucun ownership dynamique ni fonction de destruction. Les fonctions copient fingerprint,
|
|
||||||
masque et neuf coefficients ; l'appelant conserve ses entrées.
|
|
||||||
|
|
||||||
Parent absent retourne `NOT_FOUND`; parent NO_MATCH ou parent incohérent retourne `CONSTRAINT` à
|
No parallel invalidation engine is required.
|
||||||
la création. Masque, modèle ou arguments locaux invalides retournent `INVALID_ARGUMENT`; duplicate
|
|
||||||
identity retourne `CONSTRAINT`. Un loader qui rencontre une ligne ou un parent incohérent retourne
|
|
||||||
`CORRUPT`, sans résultat partiel.
|
|
||||||
|
|
||||||
## Resource bounds
|
## Schema
|
||||||
|
|
||||||
Un résultat contient au plus 1024 octets de masque et 72 octets de valeurs numériques, plus de
|
Project DB v12 introduced `geometric_verification_results`.
|
||||||
petites métadonnées. Une page est bornée. Le loader vérifie les entiers et tailles SQLite avant
|
|
||||||
tout cast ou copie. Il n'existe ni cache global, ni lecture non bornée, ni Content Store associé.
|
|
||||||
Le Match File parent mesure au plus 98 336 octets ; le futur job peut donc rester une petite unité.
|
|
||||||
|
|
||||||
## Error ownership
|
The current schema head is v25.
|
||||||
|
|
||||||
Seuls les résultats scientifiques terminés sont persistés. OOM, exception, annulation, timeout,
|
Later schema additions do not redefine the v12 row format or identity.
|
||||||
device lost, I/O transitoire ou panne de thread appartiennent à l'exécution de tâche. État du modèle
|
|
||||||
et état d'exécution sont deux contrats distincts.
|
|
||||||
|
|
||||||
## Recovery semantics
|
## Public API
|
||||||
|
|
||||||
Après commit, le résultat est complet et réutilisable après réouverture. Avant commit, le rollback
|
The model provides bounded create/load/find/list APIs for Geometric Verification Results.
|
||||||
ne laisse aucune ligne partielle. Un loader rejette toute ligne incohérente comme corruption au
|
|
||||||
lieu de réparer ou d'interpréter au mieux.
|
|
||||||
|
|
||||||
## Verifier execution contract
|
The list API is paged and ordered by increasing ID.
|
||||||
|
|
||||||
L'exécution prend un Match Result et son Match File borné. L'accès nécessaire existe via
|
In-memory result storage remains bounded: the inlier mask has fixed maximum capacity and no result-owned
|
||||||
`lardon3d_feature_reader_keypoints()`, borné à 256 keypoints par appel ; l'intégration devra relier
|
heap destructor is required for the core row object.
|
||||||
les deux Feature Sets et les indices du Match File sans modifier le Feature Store. Le verifier
|
|
||||||
estimera hors transaction, dérivera état/masque/modèle, publiera en une courte transaction,
|
|
||||||
checkpoint puis libérera les buffers. Une paire est l'unité atomique. Task Runtime et Resource
|
|
||||||
Governor décideront admission, threads et lots ; zram/swap ne sont jamais un budget.
|
|
||||||
|
|
||||||
Un backend reste hors identité seulement s'il est scientifiquement transparent. Sinon son
|
Exact function declarations in the public headers remain authoritative.
|
||||||
algorithme ou contrat doit apparaître dans kind/version/fingerprint avant publication. Toute seed
|
|
||||||
influençant le résultat doit avoir une politique déterministe versionnée ou être couverte par le
|
|
||||||
fingerprint. Aucun nombre de threads ou hardware ID n'est un paramètre scientifique par défaut.
|
|
||||||
|
|
||||||
## Explicitly out of scope
|
## Error semantics
|
||||||
|
|
||||||
GPU, Vulkan, OpenCL, shader et nouvelle orchestration restent hors périmètre de ce contrat de
|
Creation distinguishes invalid local arguments from parent/identity constraints.
|
||||||
persistance.
|
|
||||||
|
|
||||||
## Versioning
|
Loaders return corruption rather than a partially interpreted result if:
|
||||||
|
|
||||||
Project DB schema version 12 décrit le stockage. `verifier_version` décrit indépendamment le
|
- parent is missing or invalid;
|
||||||
contrat scientifique. Changer un algorithme n'impose une migration DB que si la représentation
|
- stored mask length is wrong;
|
||||||
persistante change.
|
- padding is non-canonical;
|
||||||
|
- popcount disagrees;
|
||||||
|
- model/state nullability is inconsistent;
|
||||||
|
- a verified matrix contains non-finite values.
|
||||||
|
|
||||||
|
Scientific rejection is not a database/runtime failure.
|
||||||
|
|
||||||
|
Runtime OOM, exception, cancellation, estimator failure or device failure are not persisted as
|
||||||
|
`GEOMETRIC_REJECTED`.
|
||||||
|
|
||||||
|
## Current verifier lineage
|
||||||
|
|
||||||
|
The model stores all supported versions through the same identity fields.
|
||||||
|
|
||||||
|
### v1
|
||||||
|
|
||||||
|
Historical Fundamental verifier v1 remains immutable and valid.
|
||||||
|
|
||||||
|
### v2
|
||||||
|
|
||||||
|
Historical Fundamental verifier v2 remains immutable and valid.
|
||||||
|
|
||||||
|
V2 added the distinct-canonical-observation preflight in the scientific execution contract.
|
||||||
|
|
||||||
|
### v3
|
||||||
|
|
||||||
|
Current production verifier is Fundamental v3.
|
||||||
|
|
||||||
|
Production fingerprint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
```
|
||||||
|
|
||||||
|
V3 preserves the persistent model and adds its versioned scientific preflight before the unchanged
|
||||||
|
eligible estimator path.
|
||||||
|
|
||||||
|
No Project DB migration was needed for v3 because v12 already stores verifier version and fingerprint.
|
||||||
|
|
||||||
|
## Task relationship
|
||||||
|
|
||||||
|
The production Task Kind is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
geometric_verifier.run/1
|
||||||
|
```
|
||||||
|
|
||||||
|
Project DB v13 adds only its typed durable Task payload.
|
||||||
|
|
||||||
|
The Task:
|
||||||
|
|
||||||
|
```text
|
||||||
|
pages Match Results
|
||||||
|
-> validates eligibility
|
||||||
|
-> computes or reuses exact GVR identity
|
||||||
|
-> owner publishes in canonical parent order
|
||||||
|
-> advances typed cursor
|
||||||
|
-> checkpoints
|
||||||
|
-> sequence_break
|
||||||
|
```
|
||||||
|
|
||||||
|
Task/runtime state remains separate from GVR scientific state.
|
||||||
|
|
||||||
|
## Current resource boundary
|
||||||
|
|
||||||
|
One Match Result is the scientific atomic item.
|
||||||
|
|
||||||
|
Current validated outer-parallel Task execution may prepare independent parents concurrently.
|
||||||
|
|
||||||
|
The owner publishes the contiguous canonical prefix.
|
||||||
|
|
||||||
|
Current validated bounds include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
useful CPU participants <= 8
|
||||||
|
safe parent/window size <= 16
|
||||||
|
per-item reservation approximately 8 MiB
|
||||||
|
GPU = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
The internal USAC/MAGSAC scientific solver remains `isParallel=false`.
|
||||||
|
|
||||||
|
These operational values do not enter GVR identity.
|
||||||
|
|
||||||
|
## Real S21 v3 evidence
|
||||||
|
|
||||||
|
Retained S21 proof:
|
||||||
|
|
||||||
|
```text
|
||||||
|
REAL_S21_GV_V3=PASS/FROZEN
|
||||||
|
|
||||||
|
Match Results 172,741
|
||||||
|
Applicable MATCHED 172,275
|
||||||
|
Verified GVRs 24,065
|
||||||
|
Rejected GVRs 148,210
|
||||||
|
non-applicable 466
|
||||||
|
duplicate mappings 0
|
||||||
|
```
|
||||||
|
|
||||||
|
The source Matcher project was retained unchanged and GV ran only from the Match Result boundary.
|
||||||
|
|
||||||
|
Restart/idempotence evidence preserved the complete GVR result set.
|
||||||
|
|
||||||
|
No Track/Sparse work belonged to the original GV-only boundary.
|
||||||
|
|
||||||
|
## Real A6000 v3 evidence
|
||||||
|
|
||||||
|
Retained current A6000 pre-SfM continuation:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Match Results 38,420
|
||||||
|
Applicable GVRs 37,805
|
||||||
|
Verified GVRs 10,952
|
||||||
|
Rejected GVRs 26,853
|
||||||
|
duplicate mappings 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Fingerprint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
```
|
||||||
|
|
||||||
|
The continuation then built Tracks and stopped before real Sparse SfM.
|
||||||
|
|
||||||
|
Checkpoint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
|
||||||
|
This persistence model does not define:
|
||||||
|
|
||||||
|
- RANSAC/USAC/MAGSAC implementation;
|
||||||
|
- GPU kernels;
|
||||||
|
- Task scheduling;
|
||||||
|
- Track construction;
|
||||||
|
- Essential pose;
|
||||||
|
- triangulation;
|
||||||
|
- Sparse SfM;
|
||||||
|
- Homography competition.
|
||||||
|
|
||||||
|
Those belong to their versioned scientific/runtime contracts.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
```text
|
||||||
|
GEOMETRIC_VERIFICATION_MODEL=IMPLEMENTED
|
||||||
|
PROJECT_DB_GEOMETRIC_VERIFICATION=v12
|
||||||
|
PROJECT_DB_GEOMETRIC_VERIFIER_TASK=v13
|
||||||
|
|
||||||
|
CURRENT_PRODUCTION_VERIFIER=FUNDAMENTAL_V3
|
||||||
|
CURRENT_VERIFIER_FINGERPRINT=6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
|
||||||
|
REAL_S21_GV_V3=PASS/FROZEN
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
|
||||||
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,468 +1,486 @@
|
||||||
# Geometric Verifier v1 / v2 / v3
|
# Geometric Verifier v1 / v2 / v3
|
||||||
|
|
||||||
## Scope
|
## Status
|
||||||
|
|
||||||
Ce document décrit l'exécution scientifique qui transforme un Match Result `MATCHED` en résultat
|
```text
|
||||||
Fundamental `GEOMETRIC_REJECTED` ou `GEOMETRIC_VERIFIED`. Le contrat persistant reste défini par
|
HISTORICAL_GEOMETRIC_VERIFIER_V1=FROZEN
|
||||||
[`geometric_verification.md`](geometric_verification.md). Tracks, pose, Essential, compétition
|
HISTORICAL_GEOMETRIC_VERIFIER_V2=FROZEN
|
||||||
Homography, triangulation et SfM sont hors périmètre.
|
CURRENT_GEOMETRIC_VERIFIER_V3=PASS/FROZEN
|
||||||
|
|
||||||
V1 et v2 restent des identités scientifiques historiques et immutables : leurs versions,
|
CURRENT_VERIFIER_KIND=FUNDAMENTAL
|
||||||
fingerprints, lignes et résultats existants ne sont jamais réinterprétés. V2 conserve l'estimator,
|
CURRENT_VERIFIER_VERSION=3
|
||||||
les paramètres, l'ordre et l'acceptance v1, mais ajoute avant USAC le support minimal par
|
CURRENT_VERIFIER_FINGERPRINT=6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
observations canoniques distinctes décrit ci-dessous. V3 est la policy de production courante :
|
|
||||||
après les mêmes validations intégrales, elle compose ce support v2 avec la preuve exacte de
|
GEOMETRIC_VERIFIER_GPU=NOT_JUSTIFIED
|
||||||
faisabilité d'acceptation `match_count >= min_inlier_count`. Chaque policy possède sa version et son
|
REAL_S21_GV_V3=PASS/FROZEN
|
||||||
fingerprint distincts ; le schéma les stocke déjà depuis v12 et la tête courante
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
Project DB v23 ne nécessite aucune migration GV.
|
```
|
||||||
|
|
||||||
|
This document owns the scientific execution that turns one valid `MATCHED` Match Result into one
|
||||||
|
completed Fundamental Geometric Verification Result.
|
||||||
|
|
||||||
|
The persistent row model is owned by `geometric_verification.md`.
|
||||||
|
|
||||||
|
Tracks, Essential pose, triangulation and Sparse SfM are downstream.
|
||||||
|
|
||||||
|
## Version lineage
|
||||||
|
|
||||||
|
### v1
|
||||||
|
|
||||||
|
Verifier v1 is a frozen historical scientific identity.
|
||||||
|
|
||||||
|
Its existing fingerprints and GVR rows remain immutable.
|
||||||
|
|
||||||
|
### v2
|
||||||
|
|
||||||
|
Verifier v2 preserves the v1 estimator/acceptance path but adds a bounded preflight requiring enough
|
||||||
|
distinct canonical observations on both sides before estimator execution.
|
||||||
|
|
||||||
|
It has its own version/fingerprint.
|
||||||
|
|
||||||
|
### v3
|
||||||
|
|
||||||
|
Verifier v3 is the current production policy.
|
||||||
|
|
||||||
|
It preserves v2 validation and additionally rejects estimator-ineligible parents when:
|
||||||
|
|
||||||
|
```text
|
||||||
|
match_count < min_inlier_count
|
||||||
|
```
|
||||||
|
|
||||||
|
because acceptance is mathematically impossible in that case.
|
||||||
|
|
||||||
|
At equality, the parent remains estimator-eligible.
|
||||||
|
|
||||||
|
V3 does not relabel or mutate v1/v2 rows.
|
||||||
|
|
||||||
|
Project DB v12 already stores verifier version/fingerprint, so no GVR schema migration is needed.
|
||||||
|
|
||||||
|
Current project schema head is v25.
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
|
|
||||||
Le parent DB fournit les deux Feature Set IDs, le compte, le chemin, la taille et le SHA-256 du
|
The exact Match Result supplies:
|
||||||
Match File. Le reader Feature Store ouvre séparément chaque Feature Set validé et expose les
|
|
||||||
keypoints par plages d'au plus 256. Le verifier n'a besoin d'aucun descriptor : charger les blocs
|
|
||||||
ORB ou SIFT/RootSIFT serait inutile et est interdit dans le chemin normal.
|
|
||||||
|
|
||||||
Les keypoints persistants portent des coordonnées `binary32`. `x/y` sont exprimés en pixels de
|
- Candidate Pair relation;
|
||||||
l'image exactement décodée par OpenCV lors de l'extraction, avec origine en haut à gauche et
|
- Feature Set A/B identities;
|
||||||
positions subpixel possibles. Les dimensions décodées sont disponibles dans les métadonnées du
|
- Match File path/size/SHA;
|
||||||
Feature File.
|
- `match_count`.
|
||||||
|
|
||||||
## Fundamental matrix contract
|
Feature readers provide keypoints for the two immutable Feature Sets.
|
||||||
|
|
||||||
Le seul modèle v1 est une matrice Fundamental 3×3. Une sortie acceptée doit être unique, finie,
|
The verifier does not need descriptor blocks in its normal geometry path.
|
||||||
de norme non nulle et canonique avant publication. V1 ne projette pas la matrice vers le rang 2.
|
|
||||||
|
Feature coordinates are persistent binary32 decoded-image pixels with top-left origin.
|
||||||
|
|
||||||
|
They are converted to binary64 `Point2d` for geometric computation.
|
||||||
|
|
||||||
## Input ordering
|
## Input ordering
|
||||||
|
|
||||||
L'entrée `i` de l'estimator correspond exactement à l'entrée `i` du Match File :
|
Estimator row `i` corresponds exactly to Match File entry `i`.
|
||||||
`feature_index_a` sélectionne le Feature Set A et `feature_index_b` le Feature Set B. Le Match
|
|
||||||
File impose déjà des indices A strictement croissants ; le verifier ne trie et ne filtre pas les
|
|
||||||
correspondances. Toute corruption d'index est une erreur d'exécution, jamais un rejet scientifique.
|
|
||||||
|
|
||||||
V2 distingue le nombre brut de lignes des observations canoniques distinctes. Les identités sont
|
The verifier does not reorder or deduplicate Match File rows.
|
||||||
`A=(feature_set_id_a, feature_index_a)` et
|
|
||||||
`B=(feature_set_id_b, feature_index_b)`. Après validation intégrale du parent, du Match asset, des
|
|
||||||
Feature Sets et Feature assets, v2 exige au moins sept A distincts **et** sept B distincts. Sinon il
|
|
||||||
publie `GEOMETRIC_REJECTED`, `inlier_count=0`, masque intégralement nul de longueur exactement
|
|
||||||
`ceil(match_count/8)`, sans modèle et sans appel USAC.
|
|
||||||
|
|
||||||
Ce préflight ne modifie jamais l'évidence Matcher : aucune déduplication, tri, contrainte
|
The published inlier bit `i` always maps back to Match File entry `i`.
|
||||||
one-to-one, unicité de coordonnées, limite de multiplicité, analyse de rang/conditionnement/
|
|
||||||
colinéarité ou compétition Homography n'est appliquée. Des IDs distincts ayant les mêmes
|
|
||||||
coordonnées restent des observations distinctes. Le Match File canonique rendant A strictement
|
|
||||||
croissant, une insuffisance A implique en pratique moins de sept lignes valides ; B peut en revanche
|
|
||||||
être insuffisant malgré un grand nombre de lignes brutes.
|
|
||||||
|
|
||||||
V3 exécute ensuite USAC seulement si `match_count >= min_inlier_count`. Lorsque cette inégalité
|
Out-of-range Feature indices or corrupt assets are runtime/input failure, not scientific rejection.
|
||||||
échoue, au plus `match_count` bits du masque pourraient être inliers : l'acceptation est donc
|
|
||||||
mathématiquement impossible. V3 publie alors le même rejet zéro borné sans appel estimator. La
|
|
||||||
borne vient du paramètre durable, jamais d'une constante `16`. À l'égalité, l'entrée reste éligible.
|
|
||||||
Ce contrat n'ajoute aucune règle `N<20`, rang, coordonnées, homographie, déduplication ou retry ;
|
|
||||||
toute entrée qui franchit les deux préflights appelle l'USAC inchangé et toute exception inattendue
|
|
||||||
reste un échec Task sans publication.
|
|
||||||
|
|
||||||
## Coordinate representation
|
## Canonical observation identity
|
||||||
|
|
||||||
Le stockage source reste `binary32`. Sur 1024 points, bruit 0,75 px et 50 % d'outliers, Point2f et
|
For preflight counting:
|
||||||
Point2d ont produit le même masque et la même qualité, en 3,58 et 3,55 ms. La production convertit
|
|
||||||
vers Point2d pour rendre le calcul et la sortie binary64 explicites, pour 256 Kio au maximum.
|
|
||||||
Aucune mise à l'échelle par résolution ni conversion de repère n'est appliquée implicitement.
|
|
||||||
|
|
||||||
## Algorithm candidates
|
```text
|
||||||
|
A = (feature_set_id_a, feature_index_a)
|
||||||
|
B = (feature_set_id_b, feature_index_b)
|
||||||
|
```
|
||||||
|
|
||||||
OpenCV 5 installé expose `FM_RANSAC`, `USAC_DEFAULT`, `USAC_ACCURATE`, `USAC_PROSAC` et
|
V2/v3 require at least seven distinct A observations and seven distinct B observations.
|
||||||
`USAC_MAGSAC`. La shortlist Gate A est FM_RANSAC comme baseline, puis USAC_DEFAULT,
|
|
||||||
USAC_MAGSAC et USAC_ACCURATE. PROSAC est `NOT_APPLICABLE` en v1 : la distance descriptor est
|
|
||||||
persistée mais l'ordre canonique suit l'index de query, pas un classement de qualité benchmarké.
|
|
||||||
|
|
||||||
## Benchmark methodology
|
Failure publishes a zero-inlier `GEOMETRIC_REJECTED` result with a correctly sized all-zero mask and
|
||||||
|
no Fundamental model.
|
||||||
|
|
||||||
Un corpus synthétique déterministe avec Fundamental ground truth couvrira bruit, outliers,
|
This preflight does not:
|
||||||
résolutions, tailles, géométries saines, faibles et adversariales. Les méthodes seront comparées
|
|
||||||
par précision/recall du masque, erreurs épipolaires, échecs, repeatability, temps et ressources.
|
|
||||||
Le benchmark lourd restera hors build et suite par défaut. Aucune fixture photo réelle ne sera
|
|
||||||
revendiquée sans fixture non sensible présente dans le dépôt.
|
|
||||||
|
|
||||||
La campagne Gate A du 9 août 2026 utilise OpenCV 5.0.0, Clang 22.1.8, une seed fixe et 32
|
- rewrite Matcher evidence;
|
||||||
répétitions. Elle couvre 7 à 8192 points, 0 à 100 % d'outliers, bruit 0 à 1,5 px, 1280×720 à
|
- enforce one-to-one matching;
|
||||||
4000×3000, baseline faible/large, concentration, quasi-colinéarité, planéité, rotation dominante
|
- deduplicate coordinates;
|
||||||
et duplications. Aucune fixture photo réelle représentative n'existe dans le dépôt.
|
- perform a rank test;
|
||||||
|
- perform collinearity analysis;
|
||||||
|
- run Homography competition.
|
||||||
|
|
||||||
| Algorithme | P/R 1024, 30 % | P/R 8192, 70 % | Médiane/p95/pire 8192 | Seed locale | Stable 32× |
|
Distinct Feature IDs with identical coordinates remain distinct observations.
|
||||||
|---|---:|---:|---:|---|---|
|
|
||||||
| FM_RANSAC | 0,998/0,720 | 0,993/0,413 | 316,4/318,9/319,7 ms | non | oui observé |
|
|
||||||
| USAC_DEFAULT | 0,996/0,960 | 0,997/0,959 | 43,0/43,2/44,8 ms | preset non | oui |
|
|
||||||
| USAC_MAGSAC | 0,993/0,965 | 0,994/0,962 | 11,4/12,0/12,1 ms | preset non | oui |
|
|
||||||
| USAC_ACCURATE | 0,996/0,960 | 0,996/0,961 | 30,5/32,0/32,1 ms | preset non | oui |
|
|
||||||
| MAGSAC params v1 | 0,997/0,957 | 0,996/0,894 | 10,8/11,0/11,4 ms | oui | oui |
|
|
||||||
|
|
||||||
FM_RANSAC est rejeté pour son recall et son pire temps. DEFAULT et ACCURATE n'améliorent pas assez
|
## v3 acceptance-feasibility preflight
|
||||||
la qualité pour leur coût. La production emploie des UsacParams explicites : la seed par appel
|
|
||||||
prime sur la variation du cas extrême liée à la seed fixe. À bruit 0,75 px/50 % d'outliers, les
|
|
||||||
seuils 0,5/1,0/1,5/2,0/3,0 donnent des recalls 0,535/0,811/0,961/0,990/1,000 et des precisions
|
|
||||||
0,996/0,988/0,990/0,986/0,985. Le compromis retenu est 1,5 px.
|
|
||||||
|
|
||||||
## Determinism
|
V3 additionally checks the durable configured `min_inlier_count`.
|
||||||
|
|
||||||
USAC expose `cv::UsacParams::randomGeneratorState`, un entier par appel, ainsi que les paramètres
|
When:
|
||||||
de sampling, score, optimisation locale et polishing. Cette API est préférable à une mutation de
|
|
||||||
`cv::theRNG()` process-global. FM_RANSAC restera une baseline scientifique tant que son contrôle
|
|
||||||
RNG et sa repeatability n'ont pas été mesurés.
|
|
||||||
|
|
||||||
Les cinq candidats ont donné un hash modèle+masque identique sur 32 appels et dans trois processus
|
```text
|
||||||
distincts. La garantie v1 reste intra-environnement : mêmes octets, ordre, configuration, seed,
|
match_count < min_inlier_count
|
||||||
OpenCV 5.0.0 et architecture. Aucun bit-exact cross-version ou cross-architecture n'est promis.
|
```
|
||||||
|
|
||||||
## Random seed policy
|
the maximum possible support cannot satisfy acceptance, so V3 publishes the canonical zero rejection
|
||||||
|
without calling USAC.
|
||||||
|
|
||||||
La policy v1 calcule SHA-256 sur `L3DGVSE1`, le SHA-256 du Match File puis le fingerprint. Les
|
The threshold comes from configuration, never a hidden constant.
|
||||||
quatre premiers octets sont décodés little-endian et les 31 bits faibles alimentent
|
|
||||||
`randomGeneratorState`. La policy est version 1.
|
|
||||||
|
|
||||||
## Parameter fingerprint
|
## Scientific model
|
||||||
|
|
||||||
Le fingerprint v1/v2/v3 est SHA-256 des 84 octets suivants. Les entiers sont little-endian ; les doubles
|
The only production model is a 3x3 Fundamental matrix.
|
||||||
sont leurs bits IEEE-754 binary64 écrits comme `uint64_t` little-endian. NaN/Inf sont refusés et
|
|
||||||
le seul champ autorisant zéro signé, `min_inlier_ratio`, normalise `-0.0` en `+0.0`. Aucun octet ne
|
|
||||||
provient d'un dump de structure.
|
|
||||||
|
|
||||||
| Offset | Taille | Champ |
|
Accepted output must be finite, non-zero and canonical.
|
||||||
|---:|---:|---|
|
|
||||||
| 0 | 8 | domaine ASCII `L3DGVFP1` |
|
|
||||||
| 8 | 4 | version encodage = 1 |
|
|
||||||
| 12 | 4 | kind FUNDAMENTAL = 1 |
|
|
||||||
| 16 | 4 | verifier version = 1, 2 ou 3 |
|
|
||||||
| 20 | 4 | algorithme USAC_MAGSAC explicite = 1 |
|
|
||||||
| 24 | 8 | threshold binary64 |
|
|
||||||
| 32 | 8 | confidence binary64 |
|
|
||||||
| 40 | 4 | max iterations |
|
|
||||||
| 44 | 4 | minimum inlier count |
|
|
||||||
| 48 | 8 | minimum inlier ratio binary64 |
|
|
||||||
| 56 | 4 | seed policy version |
|
|
||||||
| 60 | 4 | canonicalisation version |
|
|
||||||
| 64 | 1 | représentation Point2d = 2 |
|
|
||||||
| 65 | 1 | sampler uniforme = 0 |
|
|
||||||
| 66 | 1 | score MAGSAC = 2 |
|
|
||||||
| 67 | 1 | isParallel = 0 |
|
|
||||||
| 68 | 1 | LO inner = 1 |
|
|
||||||
| 69 | 4 | LO iterations = 5 |
|
|
||||||
| 73 | 4 | LO sample size = 14 |
|
|
||||||
| 77 | 1 | neighbor grid = 1 |
|
|
||||||
| 78 | 1 | COV polisher = 3 |
|
|
||||||
| 79 | 4 | polisher iterations = 3 |
|
|
||||||
| 83 | 1 | réservé nul |
|
|
||||||
|
|
||||||
Le vector golden v1 de la configuration historique commence par les 84 octets hexadécimaux
|
The current verifier does not add Essential/Homography model competition.
|
||||||
`4c33444756465031...0300000000` et donne le SHA-256
|
|
||||||
`ddb44bb070c62be66c405946e89cbb49c084f8f30a21d6f408dc239225b7bbd0`. Pour un Match File SHA
|
|
||||||
composé de 31 octets nuls puis `01`, cette configuration donne la seed décimale `1910542150`.
|
|
||||||
V2 conserve cet encodage et place `2` au champ `verifier version`; son fingerprint diffère donc
|
|
||||||
obligatoirement même lorsque les sept paramètres numériques sont identiques. La seed dérivée suit
|
|
||||||
ce fingerprint v2 et appartient à cette nouvelle identité. Pour la configuration production, le
|
|
||||||
fingerprint v2 est `7868a893437ee611a10008a093286997212fa8bd80b2afd2bb1d11f04f01c5ae` ;
|
|
||||||
le même Match SHA golden donne la seed décimale `1528046088`.
|
|
||||||
V3 conserve encore exactement les 84 octets et place `3` au champ version. Pour la configuration
|
|
||||||
production, son fingerprint est
|
|
||||||
`6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c` ; le même Match SHA golden
|
|
||||||
donne la seed décimale `188721673`.
|
|
||||||
Les politiques de
|
|
||||||
ressources, hardware, PSI, lot, worker et réservation CPU ne sont ni des champs ni des entrées.
|
|
||||||
|
|
||||||
## Acceptance policy
|
|
||||||
|
|
||||||
Un modèle candidat qui échoue à cette policy publie REJECTED avec son masque et son compte
|
|
||||||
d'inliers, sans matrice. La production exige `inlier_count >= 16` et
|
|
||||||
`inlier_count / match_count >= 0,20`. Les cas 100 % faux produisent 10/64, 14/256, 26/1024 et
|
|
||||||
28/4096 inliers, ratio maximal 0,15625. Les scènes saines produisent 45/64, 129/256 et 297/1024 ;
|
|
||||||
la faible baseline produit 126/256.
|
|
||||||
|
|
||||||
## Fundamental matrix canonicalization
|
|
||||||
|
|
||||||
La production adopte cette canonicalisation version 1. Les neuf valeurs doivent être finies. La
|
|
||||||
norme de Frobenius est calculée avec une accumulation `hypot` résistante au débordement ; zéro est
|
|
||||||
refusé. Le premier coefficient de valeur absolue strictement maximale gagne, donc un tie conserve
|
|
||||||
le plus petit index ligne-major. Après division, le signe rend ce pivot positif et les zéros signés
|
|
||||||
sont normalisés à `+0.0`. Sur 8192/70 %, les singular values sont
|
|
||||||
3,392e-2, 1,374e-4 et 5,915e-24. OpenCV fournit déjà rank-2 à précision numérique. V1 ne calcule
|
|
||||||
aucune SVD en production, n'impose aucun seuil de rang et n'effectue aucune post-projection rank-2.
|
|
||||||
Les validations production portent uniquement sur la forme 3×3 unique, la finitude et la norme.
|
|
||||||
|
|
||||||
## Inlier mask generation
|
|
||||||
|
|
||||||
Le masque OpenCV est validé en type, taille et valeurs, puis converti sans réordonnancement vers
|
|
||||||
le bitset LSB-first du modèle. Les frontières 7/8/9, 63/64/65 et 8191/8192 sont testées.
|
|
||||||
|
|
||||||
Le core conserve strictement l'ordre d'entrée du Match File. Les tests utilisent des indices B
|
|
||||||
permutés et des masques non contigus ; le bit `i` publié reste l'élément `i` du fichier, jamais
|
|
||||||
l'index de feature. Les tailles 1, 2, 7, 8, 9, 63, 64, 65, 8191 et 8192, le padding nul et le
|
|
||||||
popcount sont couverts avec le Model v1 inchangé.
|
|
||||||
|
|
||||||
## Scientific rejection
|
|
||||||
|
|
||||||
En v1, un nombre brut de matches inférieur au minimum réel produit le rejet zéro historique. En
|
|
||||||
v2, moins de sept observations canoniques distinctes sur A ou B produit le rejet zéro décrit dans
|
|
||||||
`Input ordering`. V3 conserve ce test et rejette également quand le nombre brut est strictement
|
|
||||||
inférieur au `min_inlier_count` configuré. L'absence de modèle sur entrée valide ou l'échec de
|
|
||||||
l'acceptance policy produit un résultat scientifique REJECTED cohérent.
|
|
||||||
|
|
||||||
Le minimum USAC observé est sept. Sept à quinze observations supportées peuvent produire une
|
|
||||||
hypothèse mais ne franchissent pas nécessairement le support d'acceptation production.
|
|
||||||
|
|
||||||
## Execution failure
|
|
||||||
|
|
||||||
Match/Feature asset absent ou corrompu, index hors bornes, exception OpenCV, OOM, masque malformé,
|
|
||||||
matrice non finie ou invariant interne invalide échoue dans le Task Runtime. Aucun résultat
|
|
||||||
scientifique n'est publié dans ces cas.
|
|
||||||
|
|
||||||
Le core traduit parent absent/NO_MATCH et Feature Set absent en erreur d'exécution `NOT_FOUND` ;
|
|
||||||
asset absent, tronqué, hash divergent, ownership ou index incohérent en `CORRUPT` ; exception ou
|
|
||||||
sortie estimator malformée/non finie en `ESTIMATOR_ERROR` ; `bad_alloc` en `OUT_OF_MEMORY` ; et
|
|
||||||
échec Model en `DATABASE_ERROR`. Les seams test-only couvrent erreur estimator, mask/matrice
|
|
||||||
malformés, NaN, OOM et publication. Aucun de ces chemins ne crée de résultat scientifique.
|
|
||||||
|
|
||||||
## Resource bounds
|
|
||||||
|
|
||||||
Une unité atomique est un Match Result, au maximum 8192 correspondances. Le Match File est borné
|
|
||||||
à 98 336 octets et le bitset à 1024 octets. Aucun cache global ni préchargement de projet complet
|
|
||||||
n'est utilisé.
|
|
||||||
|
|
||||||
À 8192 matches, les allocations directement contrôlées maximales sont 98 304 octets d'entries,
|
|
||||||
393 216 octets de keypoints A/B, 262 144 octets de Point2d A/B, deux cartes v2 de présence de
|
|
||||||
8192 octets, 1024 octets de bitset, environ 8192 octets de mask OpenCV et 72 octets de modèle, soit
|
|
||||||
environ 761 Kio hors petits objets et scratch OpenCV. Les cartes appartiennent à une paire et sont
|
|
||||||
libérées au retour ; leur borne Feature Store est opérationnelle et n'ajoute aucune limite
|
|
||||||
scientifique. Aucun descriptor ni matrice A×B n'est lu. Massif mesure 2,445 Mio de heap au pic
|
|
||||||
du test E2E complet, incluant SQLite, OpenCV, fixtures Feature Store et toutes les séquences de test.
|
|
||||||
La forme sérielle historique réservait 4 Mio fixes. La Task outer-parallel
|
|
||||||
courante réserve 8 Mio par item admis afin de couvrir aussi la pile enfant
|
|
||||||
bornée de 4 Mio, l'objet préparé, les readers et le scratch opaque. Avec un lot
|
|
||||||
maximal 16, cette charge reste bornée à 128 Mio et ne limite pas la cardinalité
|
|
||||||
du dataset.
|
|
||||||
|
|
||||||
## CPU policy
|
|
||||||
|
|
||||||
Le parallélisme scientifique interne OpenCV reste explicitement désactivé :
|
|
||||||
`UsacParams::isParallel=false` appartient au fingerprint FROZEN. Le verifier ne
|
|
||||||
change pas `cv::setNumThreads()` par paire.
|
|
||||||
|
|
||||||
Le parallélisme courant porte uniquement sur des Match Results indépendants.
|
|
||||||
Le Governor peut admettre CPU1..8 pour une fenêtre/lot d'au plus 16 ; le
|
|
||||||
callback Queue compte comme participant, crée au plus `cpu_threads-1` enfants,
|
|
||||||
les joint, puis publie seul dans l'ordre. La fenêtre participant a été validée
|
|
||||||
sûre jusqu'à 16, mais CPU8 est le maximum utile mesuré. Ce choix opérationnel
|
|
||||||
n'entre ni dans le fingerprint, ni dans le GVR.
|
|
||||||
|
|
||||||
## GPU policy
|
|
||||||
|
|
||||||
Aucun backend Vulkan n'est implémenté avant profil du chemin CPU final. La décision attendue est
|
|
||||||
`NOT_JUSTIFIED` si les unités restent sub-millisecondes ou de quelques millisecondes.
|
|
||||||
|
|
||||||
Verdict Gate A : `NOT_JUSTIFIED`. Les cas usuels prennent 0,3 à 5,6 ms et le pire MAGSAC local
|
|
||||||
mesuré reste à 11,4 ms. Aucun backend Vulkan de vérification n'est implémenté.
|
|
||||||
|
|
||||||
## Task Runtime
|
|
||||||
|
|
||||||
L'audit Gate C conclut que le checkpoint générique v1 est insuffisant : il conserve l'état,
|
|
||||||
la progression, le compteur de séquences et les temps, mais aucun payload propre au kind. Le
|
|
||||||
reconstructeur doit retrouver les paramètres scientifiques immuables et le curseur sans les
|
|
||||||
inventer depuis un fingerprint irréversible.
|
|
||||||
|
|
||||||
`geometric_verifier_tasks` est donc la seule raison de Project DB v13. Elle doit conserver
|
|
||||||
`task_id`, `after_match_result_id`, les sept paramètres de configuration v1 et le fingerprint
|
|
||||||
calculé à la création pour validation à la reconstruction. Aucun `cv::Mat`, buffer, état RNG,
|
|
||||||
paramètre Governor ou donnée hardware n'y appartient. La tâche calcule hors transaction et publie
|
|
||||||
chaque résultat par transaction courte avant avancement du curseur.
|
|
||||||
|
|
||||||
Le payload v22 ne duplique pas `verifier_version`. À la reconstruction, le fingerprint exact est
|
|
||||||
comparé aux encodages supportés v1, v2 et v3 des sept paramètres durables : cela restaure sans
|
|
||||||
ambiguïté chaque policy, sans migration ni nouveau système d'identité. Toute nouvelle tâche
|
|
||||||
sélectionne v3 ; le payload et l'ABI publique de configuration restent inchangés. Une tâche v3
|
|
||||||
démarre avec une identité neuve et ne reprend ni ne ré-étiquette une tâche v1/v2.
|
|
||||||
|
|
||||||
Le Task Kind production est `geometric_verifier.run` version 1. Il pagine les Match Results par ID
|
|
||||||
strictement croissant avec une page de `batch + 1`, et traite des lots Governor
|
|
||||||
1..16 avec CPU utile 1..8. Les préparations éligibles peuvent s'exécuter en
|
|
||||||
parallèle, mais la publication, l'avancement du curseur contigu et le checkpoint
|
|
||||||
restent owner-only et ordonnés. Les parents autres que `MATCHED` avec
|
|
||||||
`match_count > 0` sont seulement traversés par le curseur. Une unité éligible
|
|
||||||
appelle le core, qui reuse l'identité exacte avant toute lecture d'asset.
|
|
||||||
|
|
||||||
WHY GENERIC TASK PERSISTENCE IS INSUFFICIENT: aucun champ de payload métier dans le snapshot v1.
|
|
||||||
|
|
||||||
REQUIRED DURABLE FIELDS: configuration scientifique v1, fingerprint et dernier Match Result
|
|
||||||
publié puis checkpointé.
|
|
||||||
|
|
||||||
WHY EXISTING DB CANNOT STORE THEM: `tasks` et `checkpoints` ne portent que le résumé générique ;
|
|
||||||
aucune table v12 ne possède une ligne 1:1 adaptée à ce Task Kind.
|
|
||||||
|
|
||||||
## Checkpoint/recovery
|
|
||||||
|
|
||||||
La pagination suit `match_result_id` croissant sans supposer des IDs contigus. Le résultat est
|
|
||||||
publié avant que `after_match_result_id` avance en mémoire ; le curseur n'est persisté qu'après le
|
|
||||||
lot. Après chaque lot non terminal, `task_sequence_break()` rend la réservation au Governor.
|
|
||||||
|
|
||||||
Le test de crash publie puis interrompt avant checkpoint du curseur, ferme runtime et DB, recharge
|
|
||||||
le checkpoint antérieur et reconstruit le Task Kind. Le parent est revu, son résultat exact est
|
|
||||||
réutilisé, puis le curseur progresse.
|
|
||||||
|
|
||||||
## Cancellation
|
|
||||||
|
|
||||||
Pause et annulation sont coopératives avant chaque parent et entre lots. Une petite estimation
|
|
||||||
OpenCV engagée finit et publie avant l'arrêt ; aucun résultat scientifique CANCELLED n'est créé.
|
|
||||||
Les résultats déjà publiés restent durables.
|
|
||||||
|
|
||||||
## Backend policy
|
|
||||||
|
|
||||||
Un backend n'est transparent pour l'identité que si ses sorties scientifiques sont équivalentes
|
|
||||||
selon le contrat. V1 possède une seule implémentation CPU de production.
|
|
||||||
|
|
||||||
## Core publication and reuse
|
|
||||||
|
|
||||||
Le core charge les métadonnées DB, relâche les mutex internes après chaque API, lit les assets et
|
|
||||||
calcule sans transaction longue, puis appelle une publication Model v1 courte. Une identité exacte
|
|
||||||
VERIFIED ou REJECTED est retournée avant toute lecture Feature/Match et sans appel estimator. Une
|
|
||||||
contrainte concurrente déclenche un unique `find` de l'identité, jamais un overwrite ou une
|
|
||||||
récursion. Changer un paramètre scientifique produit un autre fingerprint et un autre résultat.
|
|
||||||
|
|
||||||
Les tests E2E utilisent le vrai Project DB (migré séquentiellement jusqu'à v15 à
|
|
||||||
l'ouverture), deux Feature Files à 8192 points, des Match Files hashés, le vrai
|
|
||||||
MAGSAC et le Model v1. VERIFIED est rechargé après close/reopen avec modèle et
|
|
||||||
masque bit-identiques ; REJECTED conserve son support et est également réutilisé.
|
|
||||||
|
|
||||||
## Production algorithm
|
## Production algorithm
|
||||||
|
|
||||||
UsacParams explicites, sampler uniforme, score MAGSAC, non parallèle et seed locale par appel.
|
The production estimator uses explicit OpenCV USAC/MAGSAC parameters rather than a hidden preset.
|
||||||
Les champs LO et polishing effectifs sont encodés explicitement ; aucun preset enum caché.
|
|
||||||
|
|
||||||
## Production parameters
|
Scientific choices include:
|
||||||
|
|
||||||
FUNDAMENTAL version 1 ; seuil 1,5 px ; confiance 0,999 ; 5000 itérations ; 16 inliers ; ratio 0,20 ;
|
```text
|
||||||
seed policy 1 ; canonicalisation 1 ; Point2d. Tous les champs scientifiques appartiennent au
|
model FUNDAMENTAL
|
||||||
fingerprint version 1.
|
algorithm USAC_MAGSAC
|
||||||
|
point representation Point2d
|
||||||
|
threshold 1.5 px
|
||||||
|
confidence 0.999
|
||||||
|
max iterations 5000
|
||||||
|
minimum inlier count 16
|
||||||
|
minimum inlier ratio 0.20
|
||||||
|
sampler uniform
|
||||||
|
score MAGSAC
|
||||||
|
isParallel false
|
||||||
|
LO iterations 5
|
||||||
|
LO sample size 14
|
||||||
|
polisher COV
|
||||||
|
polisher iterations 3
|
||||||
|
```
|
||||||
|
|
||||||
## Validation
|
The internal scientific estimator remains serial:
|
||||||
|
|
||||||
Gate A couvre corpus, comparaison, seed et repeatability. Gate B couvre fingerprint/seed golden,
|
```text
|
||||||
canonicalisation, mapping bit à bit, frontières d'acceptation, E2E DB, reuse, corruption,
|
UsacParams::isParallel=false
|
||||||
publication, 8192 matches et ASan/UBSan. Gate C couvre Task, publication avant curseur et reprise.
|
```
|
||||||
|
|
||||||
La référence A6000 v3 complète contient 37 805 parents `MATCHED`. Le préflight v3 rejette à zéro
|
Outer Task-level concurrency is separate.
|
||||||
9 368 parents avec `N<16`, puis le support distinct A/B rejette 117 parents supplémentaires avec
|
|
||||||
`N>=16`. Les 28 320 autres parents appellent USAC sous leur seed v3 exacte ; ils terminent tous par
|
|
||||||
un modèle ou une absence de modèle, sans exception estimator. Cette exécution démarre une tâche v3
|
|
||||||
neuve et ne reprend ni ne ré-étiquette la tâche v2 historique 1385.
|
|
||||||
|
|
||||||
Gate D a exécuté 1000 parents configurés dans la vraie Task, puis les reprises et variantes de
|
## Random seed
|
||||||
configuration du test : environ 2001 traversées réutilisées en 5,870 s, soit environ 341/s. Ce
|
|
||||||
run valide pagination, checkpoints, Governor et reuse ; il n'est pas une mesure de latence MAGSAC
|
|
||||||
et n'en revendique ni médiane ni p95. Le RSS pic observé est 25 964 Kio pour le processus de test
|
|
||||||
complet. `MemAvailable` passe de 10 702 988 à 10 692 916 Kio ; `pswpin/pswpout` restent 0/0 ; en
|
|
||||||
fin de run, PSI avg10 vaut 0,34 % CPU, 0 % mémoire et 0 % I/O. Le chemin calculé reste couvert par
|
|
||||||
le vrai E2E MAGSAC Gate B et ses bornes, sans campagne scientifique répétée.
|
|
||||||
|
|
||||||
TSan couvre core, Task, sequencing et Governor (4/4), avec uniquement la suppression OpenCV
|
The seed is derived locally from immutable scientific input.
|
||||||
existante. Le build CPU-only couvre la suite normale (31/31). La suite normale ne contient ni
|
|
||||||
benchmark lourd ni stress. Le clean build Clang/Clang++ et la campagne normale finale passent
|
The frozen seed domain is based on:
|
||||||
32/32 avec ORB Vulkan matériel sur Radeon 780M RADV PHOENIX.
|
|
||||||
|
```text
|
||||||
|
L3DGVSE1
|
||||||
|
Match File SHA-256
|
||||||
|
verifier parameter fingerprint
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting seed is supplied to the per-call USAC parameter object.
|
||||||
|
|
||||||
|
Global `cv::theRNG()` mutation is forbidden.
|
||||||
|
|
||||||
|
## Parameter fingerprint
|
||||||
|
|
||||||
|
The verifier fingerprint is SHA-256 over the frozen canonical 84-byte encoding.
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
L3DGVFP1
|
||||||
|
```
|
||||||
|
|
||||||
|
It explicitly encodes:
|
||||||
|
|
||||||
|
- verifier kind;
|
||||||
|
- verifier version;
|
||||||
|
- algorithm;
|
||||||
|
- threshold;
|
||||||
|
- confidence;
|
||||||
|
- iteration bound;
|
||||||
|
- minimum inlier count;
|
||||||
|
- minimum inlier ratio;
|
||||||
|
- seed-policy version;
|
||||||
|
- canonicalization version;
|
||||||
|
- Point2d selection;
|
||||||
|
- sampler;
|
||||||
|
- score;
|
||||||
|
- `isParallel`;
|
||||||
|
- LO settings;
|
||||||
|
- neighbor mode;
|
||||||
|
- polisher settings;
|
||||||
|
- reserved zero byte.
|
||||||
|
|
||||||
|
Integers are little-endian.
|
||||||
|
|
||||||
|
Binary64 values use explicit IEEE-754 bits encoded little-endian.
|
||||||
|
|
||||||
|
No C struct dump participates.
|
||||||
|
|
||||||
|
Current v3 production fingerprint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
```
|
||||||
|
|
||||||
|
Historical v1/v2 fingerprints remain distinct and valid.
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
A candidate is verified only when the frozen support policy is satisfied:
|
||||||
|
|
||||||
|
```text
|
||||||
|
inlier_count >= 16
|
||||||
|
inlier_count / match_count >= 0.20
|
||||||
|
```
|
||||||
|
|
||||||
|
Otherwise the result is scientific `GEOMETRIC_REJECTED`.
|
||||||
|
|
||||||
|
A scientific rejection is a completed valid result.
|
||||||
|
|
||||||
|
Runtime failure publishes no scientific GVR.
|
||||||
|
|
||||||
|
## Fundamental canonicalization
|
||||||
|
|
||||||
|
The nine coefficients must be finite.
|
||||||
|
|
||||||
|
Frobenius norm is computed robustly; zero norm is rejected.
|
||||||
|
|
||||||
|
The pivot is the first row-major coefficient having the strictly greatest absolute value.
|
||||||
|
|
||||||
|
The matrix is normalized and signed so that pivot is positive.
|
||||||
|
|
||||||
|
Signed zeros are normalized to `+0.0`.
|
||||||
|
|
||||||
|
No production SVD/rank-2 post-projection is performed by this verifier version.
|
||||||
|
|
||||||
|
## Inlier mask
|
||||||
|
|
||||||
|
OpenCV output mask is validated for type, length and values.
|
||||||
|
|
||||||
|
It is converted without reordering to the persistent LSB-first GVR bitset.
|
||||||
|
|
||||||
|
Padding bits are zero and popcount matches `inlier_count`.
|
||||||
|
|
||||||
|
## Runtime failure versus rejection
|
||||||
|
|
||||||
|
Scientific rejection includes valid cases such as:
|
||||||
|
|
||||||
|
- insufficient canonical support;
|
||||||
|
- v3 impossible acceptance support;
|
||||||
|
- estimator returns no acceptable model;
|
||||||
|
- inlier support below frozen acceptance.
|
||||||
|
|
||||||
|
Runtime/input failure includes:
|
||||||
|
|
||||||
|
- missing/corrupt Match or Feature asset;
|
||||||
|
- out-of-range Feature index;
|
||||||
|
- malformed estimator mask;
|
||||||
|
- non-finite invalid model;
|
||||||
|
- OOM;
|
||||||
|
- unexpected OpenCV exception;
|
||||||
|
- Project DB publication failure.
|
||||||
|
|
||||||
|
Runtime failure publishes no fake rejected result.
|
||||||
|
|
||||||
|
## Resource bounds
|
||||||
|
|
||||||
|
One scientific atomic item is one Match Result with at most 8192 correspondences.
|
||||||
|
|
||||||
|
Current outer-parallel Task reservation uses approximately:
|
||||||
|
|
||||||
|
```text
|
||||||
|
8 MiB per admitted parent
|
||||||
|
batch/window <= 16
|
||||||
|
useful CPU participants <= 8
|
||||||
|
GPU 0
|
||||||
|
```
|
||||||
|
|
||||||
|
The window is safe to 16; CPU8 is the retained useful maximum from measurement.
|
||||||
|
|
||||||
|
These are operational resource values, not fingerprint fields.
|
||||||
|
|
||||||
|
No descriptors or dense A-by-B matrix are loaded by the normal verifier.
|
||||||
|
|
||||||
|
## Outer parallel execution
|
||||||
|
|
||||||
|
Current validated shape:
|
||||||
|
|
||||||
|
```text
|
||||||
|
one admitted owner Task
|
||||||
|
-> bounded independent Match Result preparation
|
||||||
|
-> up to admitted CPU participants
|
||||||
|
-> join
|
||||||
|
-> owner publishes canonical contiguous prefix
|
||||||
|
-> owner advances cursor
|
||||||
|
-> checkpoint
|
||||||
|
-> sequence_break
|
||||||
|
```
|
||||||
|
|
||||||
|
Participant preparation writes no GVR rows.
|
||||||
|
|
||||||
|
Only the owner publishes after join.
|
||||||
|
|
||||||
|
This preserves deterministic parent ordering and restart semantics.
|
||||||
|
|
||||||
|
The inner USAC solver remains scientifically serial.
|
||||||
|
|
||||||
|
## GPU policy
|
||||||
|
|
||||||
|
Current classification:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GEOMETRIC_VERIFIER_GPU=NOT_JUSTIFIED
|
||||||
|
```
|
||||||
|
|
||||||
|
Measured CPU units remained small enough that no production GPU backend was justified.
|
||||||
|
|
||||||
|
No Vulkan/OpenCL/CUDA verifier backend is currently part of the production identity.
|
||||||
|
|
||||||
|
CPU outer parallelism remains valid and should not be disabled merely because GPU is rejected.
|
||||||
|
|
||||||
|
## Durable Task
|
||||||
|
|
||||||
|
Task Kind:
|
||||||
|
|
||||||
|
```text
|
||||||
|
geometric_verifier.run/1
|
||||||
|
```
|
||||||
|
|
||||||
|
Project DB v13 adds the typed task payload required because generic checkpoint v1 does not contain the
|
||||||
|
scientific verifier parameters/cursor.
|
||||||
|
|
||||||
|
Durable payload includes the immutable scientific configuration and:
|
||||||
|
|
||||||
|
```text
|
||||||
|
after_match_result_id
|
||||||
|
```
|
||||||
|
|
||||||
|
The fingerprint is revalidated on reconstruction.
|
||||||
|
|
||||||
|
The durable payload does not contain:
|
||||||
|
|
||||||
|
- `cv::Mat`;
|
||||||
|
- RNG engine state;
|
||||||
|
- Governor feedback;
|
||||||
|
- hardware identity;
|
||||||
|
- CPU mask;
|
||||||
|
- transient buffers.
|
||||||
|
|
||||||
|
## Restart
|
||||||
|
|
||||||
|
Pagination follows increasing `match_result_id` and does not assume contiguous IDs.
|
||||||
|
|
||||||
|
A GVR is published before the durable cursor advances.
|
||||||
|
|
||||||
|
Crash after publication but before checkpoint may replay that parent.
|
||||||
|
|
||||||
|
Restart finds/revalidates the exact GVR identity and reuses it.
|
||||||
|
|
||||||
|
No overwrite is performed.
|
||||||
|
|
||||||
|
## Historical resource normalization
|
||||||
|
|
||||||
|
The exact historical serial resource shape remains accepted only for restart compatibility.
|
||||||
|
|
||||||
|
It may be normalized ephemerally to the current outer-parallel capability.
|
||||||
|
|
||||||
|
The original checkpoint is not rewritten.
|
||||||
|
|
||||||
|
Neighboring resource shapes are rejected rather than guessed.
|
||||||
|
|
||||||
## Real S21 GV v3
|
## Real S21 GV v3
|
||||||
|
|
||||||
`REAL_S21_GV_V3=PASS/FROZEN` au 31 août 2026. La preuve part d'une copie reflink entière du projet
|
Retained S21 proof:
|
||||||
Matcher S21 gelé à 2 826 Feature Sets, 172 741 Candidate Pairs et 172 741 Match Results. Le SHA-256
|
|
||||||
DB source vaut avant et après
|
|
||||||
`9f5ee4877bca25db3d4929be06d8e6ff4fa1c29e11249e4125266a833f09f3e0` ; le projet source n'est
|
|
||||||
jamais ouvert en écriture. La copie de travail reprend exclusivement à la frontière Match Result,
|
|
||||||
par la Task, la Queue et le Resource Governor AUTO de production, puis s'arrête avant Track
|
|
||||||
Builder. Avant GV, la Task Matcher 2831 est `COMPLETE`, progression 100,
|
|
||||||
`sequence_count=21629`, curseur 172 741 ; son checkpoint SHA-256 vaut
|
|
||||||
`636f4f4a20f27308d90142c495c9f6ffc04b4c0dfcca0fdc75cfeb5366ab50b1`. Le projet contient alors
|
|
||||||
zéro GVR, Track Set, Track ou Sparse Reconstruction.
|
|
||||||
|
|
||||||
La Task 2832 consomme le curseur complet de 172 741 Match Results. Parmi eux, 172 275 parents
|
```text
|
||||||
`MATCHED` applicables produisent exactement 172 275 identités v3 : 24 065
|
REAL_S21_GV_V3=PASS/FROZEN
|
||||||
`GEOMETRIC_VERIFIED` et 148 210 `GEOMETRIC_REJECTED`. Les 466 autres Match Results sont traversés
|
|
||||||
sans GVR conformément au contrat. Le fingerprint est
|
|
||||||
`6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c`. La Task termine
|
|
||||||
`COMPLETE`, progression 100, `sequence_count=21592`, curseur 172 741 et zéro mapping dupliqué. Son
|
|
||||||
checkpoint final SHA-256 vaut
|
|
||||||
`3e6bed97cee9c96f229ef19a3c905d19d4693cdbf43b30319edcdeed6c4e378e`. Le wall propre à
|
|
||||||
l'enqueue/attente GV vaut 3 221,757986763 s ; le wall du runner incluant l'audit intégral amont
|
|
||||||
vaut 3 252,89 s.
|
|
||||||
|
|
||||||
L'audit relit les 172 741 mappings Candidate/Match et les 172 275 Match Files : SHA, taille,
|
Match Results 172,741
|
||||||
header, entrées, ordre et curseur Matcher restent valides. Le digest `L3DMRD1` demeure
|
Applicable MATCHED 172,275
|
||||||
`e5128a2e599ff593c4f79850e067254b1f249d19e8480a44973306b1af250f70`. Feature Sets, Candidate
|
Verified 24,065
|
||||||
Pairs et Match Results gardent respectivement 2 826, 172 741 et 172 741 lignes ; aucune Task
|
Rejected 148,210
|
||||||
Feature, Candidate ou Matcher n'est rejouée. Track Set, Track, Track Builder Task, Sparse SfM Task
|
non-applicable 466
|
||||||
et Sparse Reconstruction restent tous à zéro.
|
duplicate mapping 0
|
||||||
|
```
|
||||||
|
|
||||||
Le Governor enregistre 21 593 admissions, exclusivement backend fixe, sans changement de contrat.
|
The v3 fingerprint is the current production fingerprint.
|
||||||
Le dernier contrat est GREEN, CPU 1, GPU 0, I/O 1, batch 8, hôte 4 Mio et GPU 0. Les masques sont
|
|
||||||
compute `0-5,8-13` et reserve `6,7,14,15`. Sur l'échantillonnage coalescé de 21 590 changements,
|
|
||||||
le minimum `MemAvailable` vaut 8 907 714 560 octets, le RSS/HWM processus maximal 45 690 880
|
|
||||||
octets, le PSI mémoire maximal 0,90 %, le PSI I/O maximal 50,17 % et les deltas swap-in/out sont
|
|
||||||
0/0. Les réserves 3 Gio/2 Gio alors en vigueur pour ce run historique restent
|
|
||||||
respectées ; aucune voie GPU GV n'est créée.
|
|
||||||
|
|
||||||
La seconde reprise complète crée la Task 2833, traverse le même curseur et crée zéro GVR. Les
|
A complete replay produced zero new GVRs.
|
||||||
172 275 lignes avant/après sont égales sur toutes leurs colonnes par `EXCEPT` dans les deux sens,
|
|
||||||
avec zéro différence, les mêmes IDs 1..172275 et les mêmes comptes accepté/rejeté. Sur une copie
|
|
||||||
reflink séparée, SIGKILL interrompt la Task 2834 après un préfixe checkpointé : l'état durable reste
|
|
||||||
`RUNNING/PENDING`, puis la registry de production reprend cette même Task (`inspected=1`,
|
|
||||||
`resumed=1`) jusqu'à `COMPLETE`, progression 100 et curseur 172 741. L'égalité complète des GVR
|
|
||||||
avec le projet terminé reste zéro différence dans les deux sens ; aucun résultat n'est perdu ou
|
|
||||||
dupliqué et aucun travail amont/aval n'est exécuté.
|
|
||||||
|
|
||||||
Les builds normaux Vulkan et portable sans Vulkan passent. Les 14 tests focalisés GV, Task,
|
A SIGKILL/restart proof resumed the same Task and converged to the same complete GVR set.
|
||||||
checkpoint, Project DB/Project, registry, Queue et Governor passent dans chaque configuration ; le
|
|
||||||
test runner ciblé passe aussi sous ASan/UBSan. `REAL_S21_GV_V3`, `RESTART_IDEMPOTENCE`,
|
|
||||||
`DETERMINISM`, `GOVERNOR_ADMISSION` et `DOWNSTREAM_STOP` sont donc `PASS/FROZEN`. Ce gel porte sur
|
|
||||||
la preuve réelle de la policy v3 déjà gelée ; il ne rouvre ni algorithme, seuil, RNG, fingerprint,
|
|
||||||
Project DB v22, Matcher/Governor v2, Track Builder ou Sparse SfM.
|
|
||||||
|
|
||||||
## Maintenance outer-parallel — preuve représentative réelle
|
The run stopped before Track Builder at the original GV-only checkpoint.
|
||||||
|
|
||||||
**IMPLEMENTED / VALIDATED / REVIEWED.** La maintenance sépare la préparation
|
Later S21 Track evidence exists separately.
|
||||||
scientifique de la publication sans modifier la policy v3. Une préparation
|
|
||||||
valide tout l'input immuable et produit un objet opaque borné ; elle n'écrit
|
|
||||||
jamais Project DB. Après jointure, le callback propriétaire publie ces objets
|
|
||||||
en ordre de `match_result_id`, détruit chacun exactement une fois et checkpoint
|
|
||||||
le seul préfixe contigu. Les pannes de création partielle, calcul, publication,
|
|
||||||
annulation et reprise ne peuvent donc ni publier un suffixe devant un trou, ni
|
|
||||||
laisser un enfant/handle vivant à la libération de réservation.
|
|
||||||
|
|
||||||
Le corpus représentatif réel contient 4 113 parents, dont 4 102 applicables,
|
## Real A6000 v3
|
||||||
578 `GEOMETRIC_VERIFIED` et 3 524 `GEOMETRIC_REJECTED`. CPU1/2/4/8/12
|
|
||||||
conservent les mêmes IDs 1..4102, toutes les colonnes scientifiques et le digest
|
|
||||||
`9401ef6168804b6f1d51f4cdf64cd6b33cbebd2934e5294c8feacc87f9c8ce86`.
|
|
||||||
Les walls Task complets sont 67,521078032/48,859141912/39,158236068/
|
|
||||||
35,170176868/34,251675780 s, soit 60,7514/83,9556/104,7545/116,6329/
|
|
||||||
119,7606 parents/s. Le gain CPU8→CPU12 vaut seulement 2,68 %, sous le seuil de
|
|
||||||
5 %. La capacité production est donc CPU utile 8, batch 16 et fenêtre sûre 16.
|
|
||||||
|
|
||||||
Les tests focalisés finaux passent 8/8, les répétitions de stress 60/60,
|
The retained A6000 pre-SfM continuation contains:
|
||||||
ASan/UBSan 3/3 et TSan 3/3, avec contrôles C17 GCC/Clang. La preuve S21
|
|
||||||
historique ci-dessus reste le run complet CPU1/batch8 acquis ; aucun rerun
|
|
||||||
complet de 3 221 s n'est revendiqué pour cette maintenance bornée. Le manifest
|
|
||||||
retenu de cette preuve a le SHA-256
|
|
||||||
`52a4412299c74050a66d5690122a793c9451c79faf47e32b6e65a5958f804856`.
|
|
||||||
Il compare littéralement les 4 102 GVR applicables — ordre/IDs 1..4102,
|
|
||||||
statut, compteur/masque d'inliers, présence et octets binary64 du modèle — et
|
|
||||||
vérifie intégrité DB, clés étrangères, absence de replay amont et absence de
|
|
||||||
travail Tracks/Sparse. Le run S21 complet acquis couvre déjà la policy v3 et
|
|
||||||
sa persistance FROZEN ; la maintenance ne change que la préparation externe et
|
|
||||||
la publication owner-only. Cette combinaison réelle bornée + tests ciblés de
|
|
||||||
panne/checkpoint/reprise discrimine donc le changement sans payer un second run
|
|
||||||
scientifique intégral ni prétendre l'avoir exécuté.
|
|
||||||
|
|
||||||
La validation globale fraîche qui englobe ce delta passe aussi dans le graphe
|
```text
|
||||||
Clang portable Vulkan-off 931/931 et sa suite 64/64, puis le graphe Vulkan-on
|
Match Results 38,420
|
||||||
939/939 et sa suite 65/65. Le TSan global reste volontairement Vulkan-disabled
|
Applicable GVRs 37,805
|
||||||
et couvre les deux cibles GV dans sa matrice 14/14 plus répétitions ; il utilise
|
Verified GVRs 10,952
|
||||||
uniquement les suppressions externes OpenCV/TBB documentées par le projet.
|
Rejected GVRs 26,853
|
||||||
|
duplicate mappings 0
|
||||||
|
```
|
||||||
|
|
||||||
## Out of scope
|
Current fingerprint:
|
||||||
|
|
||||||
Tracks, model competition, classification planaire ou faible parallaxe, Essential, calibration,
|
```text
|
||||||
pose, triangulation, bundle adjustment, SfM et Vulkan RANSAC.
|
6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
```
|
||||||
|
|
||||||
|
The Task completed the full cursor.
|
||||||
|
|
||||||
|
Restart traversed the cursor and created zero new GVRs.
|
||||||
|
|
||||||
|
The continuation then reused/built the frozen Track Set and stopped before real Sparse SfM.
|
||||||
|
|
||||||
|
```text
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation boundaries
|
||||||
|
|
||||||
|
The scientific verifier validation covers:
|
||||||
|
|
||||||
|
- canonical fingerprint/seed;
|
||||||
|
- bit-exact mask mapping;
|
||||||
|
- acceptance boundaries;
|
||||||
|
- corruption;
|
||||||
|
- publication/reuse;
|
||||||
|
- maximum Match File cardinality;
|
||||||
|
- restart;
|
||||||
|
- deterministic canonicalization;
|
||||||
|
- outer-parallel owner publication.
|
||||||
|
|
||||||
|
TSan qualification must preserve the external OpenCV/TBB boundary described by the concurrency/global
|
||||||
|
maintenance documents.
|
||||||
|
|
||||||
|
Do not claim Vulkan verifier validation: there is no production Vulkan verifier backend.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
```text
|
||||||
|
CURRENT_GEOMETRIC_VERIFIER=FUNDAMENTAL_V3
|
||||||
|
CURRENT_VERIFIER_VERSION=3
|
||||||
|
CURRENT_VERIFIER_FINGERPRINT=6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
|
||||||
|
GEOMETRIC_VERIFIER_TASK=geometric_verifier.run/1
|
||||||
|
PROJECT_DB_GEOMETRIC_VERIFICATION=v12
|
||||||
|
PROJECT_DB_GEOMETRIC_VERIFIER_TASK=v13
|
||||||
|
|
||||||
|
INNER_USAC_PARALLEL=false
|
||||||
|
OUTER_PARALLEL=VALIDATED
|
||||||
|
USEFUL_CPU_MAX=8
|
||||||
|
SAFE_WINDOW_MAX=16
|
||||||
|
PER_ITEM_RAM=8_MiB
|
||||||
|
GPU=NOT_JUSTIFIED
|
||||||
|
|
||||||
|
REAL_S21_GV_V3=PASS/FROZEN
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,314 +1,505 @@
|
||||||
# Exécution et runtime Lardon3D
|
# Lardon3D Runtime
|
||||||
|
|
||||||
## Modèle d'exécution
|
## Status
|
||||||
|
|
||||||
### Threads
|
|
||||||
- Thread principal : entrée, modèle de vue et rendu TUI ncursesw (exclusif)
|
|
||||||
- Thread worker Queue : exécution sérielle des tâches métier
|
|
||||||
- Participants internes : uniquement ceux du contrat Task admis, joints par le
|
|
||||||
callback propriétaire avant publication
|
|
||||||
- Opération SSD : au plus un thread joinable, uniquement pendant une opération
|
|
||||||
UDisks bornée ; il ne rend rien et ne devient ni Queue ni scheduler
|
|
||||||
|
|
||||||
### Synchronisation
|
|
||||||
- Mutex pour les accès partagés
|
|
||||||
- Variables de condition pour la coordination
|
|
||||||
- Atomicité des opérations critiques
|
|
||||||
|
|
||||||
## Cycle de vie d'une tâche
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
1. Création (PENDING)
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
2. Soumission à la file
|
CURRENT_PRODUCTION_TASK_KINDS=16
|
||||||
3. Sélection FIFO/adaptative par la Queue
|
|
||||||
4. Réservation obligatoire
|
TASK_QUEUE_WORKERS=1
|
||||||
5. Exécution (RUNNING)
|
INTERNAL_PARALLELISM=BOUNDED
|
||||||
- Pause/reprise coopérative
|
INTER_TASK_PARALLELISM=NOT_IMPLEMENTED
|
||||||
- Annulation coopérative
|
|
||||||
- Séquences adaptatives
|
RUNTIME_OBSERVER=CURRENT/VALIDATED_OPERATIONAL
|
||||||
6. Complétion (COMPLETED) ou Échec (FAILED)
|
RESOURCE_UTILIZATION_POLICY=MAXIMUM_SAFE_USEFUL_THROUGHPUT
|
||||||
7. Nettoyage des ressources
|
SERIALISM_REQUIRES_PROOF=CANONICAL
|
||||||
|
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
```
|
```
|
||||||
|
|
||||||
## Synchronisation
|
The runtime coordinates the main thread, Task Queue, Resource Governor, Project DB lifecycle, bounded
|
||||||
|
Task-internal participants, runtime observation and optional external-SSD controller.
|
||||||
|
|
||||||
### Mutex
|
It does not introduce a second scheduler.
|
||||||
- Protection des données partagées
|
|
||||||
- Accès exclusif aux ressources critiques
|
|
||||||
|
|
||||||
### Variables de condition
|
## Thread model
|
||||||
- Coordination entre threads
|
|
||||||
- Notification de changement d'état
|
|
||||||
- Attente passive ; timeout borné seulement pour réévaluer un `WAIT` ressources
|
|
||||||
|
|
||||||
### Atomicité
|
### Main thread
|
||||||
- Opérations indivisibles
|
|
||||||
- État cohérent garanti
|
|
||||||
|
|
||||||
## Gestion des erreurs
|
Owns:
|
||||||
|
|
||||||
### Rollback
|
- input;
|
||||||
- Rollback des transactions locales avant publication
|
- ncurses;
|
||||||
- Nettoyage complet des ressources possédées par l'opération
|
- TUI model binding;
|
||||||
- Une publication fichier réussie suivie d'un échec DB peut laisser un orphelin
|
- project open/close orchestration;
|
||||||
valide ; aucune transaction distribuée fichier+SQLite n'est revendiquée
|
- bounded polling of runtime/SSD state.
|
||||||
|
|
||||||
### Récupération
|
ncurses remains main-thread-only.
|
||||||
- Reprise à la dernière frontière connue
|
|
||||||
- Ignorance des artefacts partiels
|
|
||||||
- Validation avant publication
|
|
||||||
|
|
||||||
## Limites actuelles
|
### Task Queue worker
|
||||||
|
|
||||||
- Worker Queue unique (pas de pools inter-Tasks multiples)
|
The single Queue worker owns one active heavy Task callback at a time.
|
||||||
- Pas de parallélisme inter-Tasks ; certains kinds possèdent des participants
|
|
||||||
internes bornés, comptés par leur contrat Governor
|
|
||||||
- Reprise automatique limitée aux tâches indépendantes reconstructibles
|
|
||||||
|
|
||||||
## Reprise durable
|
A Task callback may create bounded internal participants only when its admitted Task contract permits
|
||||||
|
them.
|
||||||
|
|
||||||
Un snapshot ne conserve que l'état logique d'une tâche. `RUNNING` et `PAUSED`
|
Those participants join before owner publication.
|
||||||
sont normalisés vers `PENDING`; aucun worker, callback brut, pointeur, contrat
|
|
||||||
ou réservation n'est restauré. Le propriétaire fournit un nouveau callback et
|
|
||||||
resoumet la tâche. Les états terminaux sont conservés.
|
|
||||||
|
|
||||||
`started_at` désigne le début de la tentative d'exécution courante, pas le
|
### SSD operation thread
|
||||||
premier démarrage historique. Un checkpoint `RUNNING` restauré en `PENDING`
|
|
||||||
conserve temporairement l'horodatage de la tentative interrompue pour
|
|
||||||
l'observation ; lors de `lardon3d_task_start()`, `started_at` est remplacé par le
|
|
||||||
nouveau démarrage et `finished_at` est remis à zéro. `finished_at` n'est fixé
|
|
||||||
qu'à la terminaison de cette tentative.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — snapshot, codec v1 et restauration isolée.
|
The SSD controller may own at most one bounded joinable operation thread while executing a synchronous
|
||||||
|
UDisks operation.
|
||||||
|
|
||||||
**IMPLEMENTED** — l'import `import.images` se sauvegarde à chaque fin de lot et
|
It does not become:
|
||||||
se reconstruit explicitement avec un userdata neuf lié au projet rouvert. Son
|
|
||||||
intention durable contient `source_path + scanset_id`; le hash/copie et la
|
|
||||||
transaction catalogue restent hors mutex Task et hors mutex DB pendant l'I/O.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — `project_open()` inventorie par pages de 8, restaure puis
|
- a Task worker;
|
||||||
resoumet automatiquement les tâches production valides. Il retourne après
|
- a Queue;
|
||||||
l'enqueue et n'attend jamais leur terminaison.
|
- a scheduler;
|
||||||
|
- an ncurses owner.
|
||||||
|
|
||||||
L'ordre d'initialisation production est : politique driver, profil matériel,
|
## Task lifecycle
|
||||||
Governor, backend, Queue/worker, contrôleur SSD optionnel et binding
|
|
||||||
Governor, puis TUI. L'ouverture DB/projet et la reprise synchrone sont pilotées
|
|
||||||
ensuite depuis le thread principal. Une fermeture ne peut commencer qu'après le
|
|
||||||
retour de `project_open()`. Le worker peut consommer pendant le scan ; chaque
|
|
||||||
tâche exécutée est néanmoins réadmise normalement.
|
|
||||||
|
|
||||||
**NOT_YET_WIRED** — reprise ordonnée par dépendances/DAG. Les kinds de
|
Conceptual lifecycle:
|
||||||
production reconstructibles checkpointent déjà à leurs frontières métier ;
|
|
||||||
aucun timer autosave générique ne doit avancer devant leur publication durable.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — reprise sélective des kinds reconstructibles via Project DB,
|
```text
|
||||||
Task Kind Registry et Queue. Les dépendances/DAG restent différées ; il
|
create PENDING
|
||||||
n'existe pas de scheduler global distinct à restaurer.
|
-> persist typed intent where required
|
||||||
|
-> enqueue
|
||||||
|
-> Queue selects
|
||||||
|
-> Resource Governor admits/reserves
|
||||||
|
-> RUNNING
|
||||||
|
-> bounded sequence work
|
||||||
|
-> Task-specific durable publication
|
||||||
|
-> generic checkpoint
|
||||||
|
-> optional sequence_break/re-admission
|
||||||
|
-> COMPLETED | FAILED | CANCELLED
|
||||||
|
-> terminal callback
|
||||||
|
-> destruction
|
||||||
|
```
|
||||||
|
|
||||||
## Accès Project Database
|
Pause/cancel are cooperative.
|
||||||
|
|
||||||
**IMPLEMENTED** — une connexion SQLite opaque sérialisée par mutex interne ;
|
A sequence break is not a Task state.
|
||||||
les opérations multi-tables sont transactionnelles et bornées.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — le cycle de vie projet ouvre/crée `project.db`, vérifie
|
## Durable restart
|
||||||
l'identité et ferme la connexion. Ouvrir, fermer ou changer de projet est une
|
|
||||||
frontière exacte : l'observateur et la vue optique libèrent leurs borrows, puis
|
|
||||||
l'unique Queue est annulée, jointe et détruite, callbacks terminaux inclus,
|
|
||||||
avant la fermeture de Project DB. Une seule Queue vide est ensuite recréée et
|
|
||||||
les observateurs sont rebondés. Il n'existe jamais deux schedulers simultanés.
|
|
||||||
L'historique terminal et l'espace d'IDs Queue sont ainsi propres à la session ;
|
|
||||||
les mêmes Task IDs durables de deux projets restent indépendants et aucun
|
|
||||||
historique fourni n'est affiché lorsqu'aucun projet n'est chargé.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — la registry reconstruit explicitement callback/userdata hors
|
A generic snapshot stores logical Task state, not live execution machinery.
|
||||||
mutex DB pour un kind connu ; elle ne soumet aucune tâche.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — la queue accepte un identifiant restauré préassigné s'il
|
On restoration:
|
||||||
n'entre en collision avec aucune tâche connue. L'import production peut donc
|
|
||||||
être reconstruit puis soumis explicitement.
|
|
||||||
|
|
||||||
**IMPLEMENTED** — la resoumission automatique utilise la registry production,
|
```text
|
||||||
conserve le task ID et laisse le worker obtenir une nouvelle réservation.
|
RUNNING -> PENDING
|
||||||
Kinds inconnus, tâches legacy, checkpoints invalides et sources absentes ne
|
PAUSED -> PENDING
|
||||||
bloquent pas l'ouverture.
|
```
|
||||||
|
|
||||||
**IMPLEMENTED** — `visual_index.update` reprend à la dernière membership
|
Terminal states remain terminal.
|
||||||
commitée. Un segment temporaire n'est jamais visible et un rejeu exclut les
|
|
||||||
Feature Sets déjà membres.
|
|
||||||
|
|
||||||
## Durée de vie terminale et fermeture Queue
|
Restart never restores:
|
||||||
|
|
||||||
Une Task terminale reste vivante jusqu'au retour complet de son callback
|
- worker thread;
|
||||||
terminé. Queue la retire alors de la liste active et la détruit hors de son
|
- callback pointer;
|
||||||
mutex ; seule une histoire de 64 snapshots reste observable. Les appels déjà
|
- userdata pointer;
|
||||||
enregistrés avant `task_queue_destroy()` sont attendus. Le propriétaire doit
|
- CPU affinity;
|
||||||
empêcher tout nouvel appel dès le début de la destruction, règle nécessaire à
|
- live reservation;
|
||||||
toute API C adressée par pointeur brut.
|
- GPU handle;
|
||||||
|
- scratch lease;
|
||||||
|
- adaptive feedback history.
|
||||||
|
|
||||||
Un callback terminé peut consulter les vues Queue tant que le propriétaire la
|
Task Kind Registry reconstructs fresh runtime binding from exact durable kind/version and typed payload.
|
||||||
maintient vivante. Il ne peut pas détruire cette Queue, retirer son propre
|
|
||||||
record ni attendre une opération dépendante de son retour.
|
|
||||||
|
|
||||||
## Observatoire TUI actuel
|
Every resumed Task is re-admitted by the Resource Governor.
|
||||||
|
|
||||||
**CURRENT / VALIDATED OPERATIONAL.** Ce statut décrit l'implémentation et ses
|
## Project-open recovery
|
||||||
tests courants. L'audit global qui contient cette frontière est désormais
|
|
||||||
`PASS/FROZEN` après revue indépendante ; le statut TUI reste volontairement
|
|
||||||
opérationnel et n'interdit pas ses évolutions futures sous un ticket distinct.
|
|
||||||
|
|
||||||
### Séparation modèle, observation et rendu
|
`project_open()` discovers durable Tasks in bounded pages, validates their checkpoint/typed identity,
|
||||||
|
reconstructs eligible bindings and submits them to the existing Queue.
|
||||||
|
|
||||||
Le modèle `tui_model` est pur et testable sans terminal. Le renderer reçoit
|
It returns after enqueue; it does not wait for those Tasks to finish.
|
||||||
seulement des copies bornées et n'interroge ni Queue, ni Governor, ni Project
|
|
||||||
DB, ni contrôleur SSD. Toutes les fonctions ncurses, l'entrée clavier et le
|
|
||||||
rendu demeurent sur le thread principal.
|
|
||||||
|
|
||||||
L'observateur runtime emprunte Queue et Governor et conserve une seule copie
|
Unknown kinds, unsupported versions, legacy-untyped Tasks, invalid checkpoints or Task-specific
|
||||||
cohérente. Les captures ordinaires sont coalescées pendant au moins une seconde
|
non-reconstructible input remain inspectable and do not cause guessed execution.
|
||||||
monotone ; un échec conserve la dernière vue bornée en la marquant stale.
|
|
||||||
Il observe au plus 129 Tasks : les 64 pending possibles, l'unique active et les
|
|
||||||
64 snapshots terminaux récents. L'ordre Queue place le travail vivant du plus
|
|
||||||
récent au plus ancien, puis l'histoire par terminaison décroissante ; une Task
|
|
||||||
active ne peut donc pas être masquée par un vieux préfixe historique. Il
|
|
||||||
n'existe ni scan DB par frame, ni lecture `/proc` volumineuse, ni historique
|
|
||||||
non borné.
|
|
||||||
|
|
||||||
Les ABI historiques restent exactes : `Lardon3DTaskSnapshot`,
|
Generic dependency/DAG recovery remains unimplemented.
|
||||||
`Lardon3DResourceSnapshot`, `Lardon3DAppState` et
|
|
||||||
`lardon3d_layout_draw()` ne sont pas étendus en place. Les surfaces additives
|
|
||||||
`Lardon3DTaskObservation`, `lardon3d_task_queue_observe()`,
|
|
||||||
`Lardon3DResourceObservation`, `Lardon3DRuntimeSnapshot` et
|
|
||||||
`lardon3d_layout_draw_runtime()` portent les nouveaux champs. De même,
|
|
||||||
`lardon3d_tui_run()` reste le symbole historique ; l'application utilise
|
|
||||||
`lardon3d_tui_run_with_ssd_operation()` avec un owner SSD conservé hors de
|
|
||||||
`Lardon3DAppState`.
|
|
||||||
|
|
||||||
### Progression et ETA
|
## Initialization order
|
||||||
|
|
||||||
Une Task typée publie `completed/total` seulement après son propre commit
|
Production startup establishes the safe driver/runtime policy before heavy worker/backend activity.
|
||||||
métier durable. Quand ces compteurs sont connus, la TUI les affiche toujours et
|
|
||||||
en dérive le pourcentage sans utiliser le message ou le nom. Une Task marquée
|
|
||||||
`COMPLETED` avec un préfixe durable incomplet est une erreur d'intégrité
|
|
||||||
visible, jamais 100 %. Quand les comptes typés sont inconnus, le lifecycle peut
|
|
||||||
être terminal mais la progression scientifique reste indéterminée. Le
|
|
||||||
pourcentage générique non typé, lorsqu'il est utile, porte explicitement le
|
|
||||||
libellé runtime.
|
|
||||||
|
|
||||||
Le débit est un EWMA borné. La première observation établit seulement le
|
Conceptually:
|
||||||
préfixe de reprise et ne contribue pas au taux ; une reprise de RUNNING remet
|
|
||||||
également la fenêtre temporelle à zéro. Deux intervalles strictement positifs
|
|
||||||
sont nécessaires avant un débit et une ETA connus. Une absence de progrès,
|
|
||||||
une pression Governor, une régression ou une preuve insuffisante produit
|
|
||||||
respectivement `STALLED`, `THROTTLED`, reset ou `INDETERMINATE/CALCULATING`.
|
|
||||||
Seule une complétion cohérente vaut exactement 100 % et ETA zéro ; aucune fausse
|
|
||||||
précision n'est affichée.
|
|
||||||
|
|
||||||
### Pipeline et ressources
|
```text
|
||||||
|
driver policy
|
||||||
|
-> hardware profile
|
||||||
|
-> Resource Governor
|
||||||
|
-> optional backend metadata
|
||||||
|
-> Task Queue / worker
|
||||||
|
-> optional SSD controller + Governor binding
|
||||||
|
-> TUI
|
||||||
|
```
|
||||||
|
|
||||||
La synthèse utilise les étapes Acquisition, RAW, Quality, Features, Visual
|
Project open/recovery is then driven from the main thread.
|
||||||
Index, Candidate, Matcher, GV, Tracks, Sparse SfM et future Dense. Les états
|
|
||||||
sont `NOT_READY`, `READY`, `QUEUED`, `RUNNING`, `THROTTLED`, `BLOCKED`,
|
|
||||||
`COMPLETE`, `FAILED` et `NOT_APPLICABLE`. Dense reste explicitement
|
|
||||||
`NOT_APPLICABLE` tant qu'aucun Task kind de production n'existe ; une étape
|
|
||||||
future n'est jamais devinée active depuis un nom ou un message.
|
|
||||||
|
|
||||||
Le panneau ressources expose CPU actif/admis/disponible et sa raison, GPU
|
The exact source initialization sequence remains authoritative.
|
||||||
présent/mémoire/busy/backend lorsqu'ils sont connus, RAM/MemAvailable/réserve,
|
|
||||||
swap total/utilisé et deltas actifs, lot/inflight/helpers/I/O, scratch et
|
|
||||||
pression Governor GREEN/YELLOW/RED. Le contrat installé de l'exacte Task active
|
|
||||||
est l'autorité pour CPU et lot. Un dernier diagnostic privé seulement indexé
|
|
||||||
par kind peut appartenir à une autre Task ou séquence : backend, inflight,
|
|
||||||
helpers, utilisation ou raison restent donc `UNKNOWN` sans association exacte
|
|
||||||
Task+séquence. La mémoire UMA est comptée une seule fois et ni swap ni scratch
|
|
||||||
ne sont ajoutés à la capacité RAM.
|
|
||||||
|
|
||||||
### Dimensions, couleurs et clavier
|
## Project lifetime boundary
|
||||||
|
|
||||||
Le layout complet demande au moins 100×30. Le layout compact est validé à la
|
Changing/closing project is an exact ownership boundary.
|
||||||
frontière 72×20 et reste supporté jusqu'au minimum 60×15. En dessous, le rendu
|
|
||||||
se réduit au message borné `Terminal trop petit`; un resize recalcule la classe
|
|
||||||
sans faire travailler un worker. Les rôles sémantiques sont healthy vert,
|
|
||||||
warning jaune, error rouge, GPU cyan, CPU bleu, SSD magenta, plus dim/bold.
|
|
||||||
Les libellés textuels demeurent l'autorité lorsqu'il n'y a pas de couleur ou
|
|
||||||
pas assez de paires terminal.
|
|
||||||
|
|
||||||
Les écrans courants sont accueil, projets, import, viewer futur, tâches,
|
Before Project DB close:
|
||||||
ressources, optique, SSD et aide. `F1..F7` naviguent respectivement vers aide,
|
|
||||||
projets, import, viewer, tâches, ressources et optique. Le segment littéral
|
|
||||||
`F10 SSD` est réservé au début du footer et reste visible à 60 colonnes dans
|
|
||||||
tous les modes pertinents. Les footers dérivent du même mode que le handler :
|
|
||||||
|
|
||||||
- saisie active : Enter valide, Échap annule, F10 reste disponible ;
|
```text
|
||||||
- import actif : `X` demande l'annulation et F10 reste disponible ; `q` et
|
views release DB borrows
|
||||||
Échap sont affichés comme désactivés ;
|
-> Queue ingress closes
|
||||||
- mode idle : `q`, Échap/navigation et les commandes propres à l'écran sont
|
-> Queue cancels/joins/destroys
|
||||||
annoncés seulement lorsqu'ils sont réellement traités ;
|
-> terminal callbacks finish
|
||||||
- Tasks : flèches/`j`/`k`, `P` pause, `R` reprise, `C` annulation ;
|
-> Project DB closes
|
||||||
- Optique : Tab change de panneau, flèches/`j`/`k` sélectionnent, `[` revient à
|
```
|
||||||
la première page et `]` charge la suivante ; `B/L/C/V/A/G/K/E` déclenchent
|
|
||||||
les opérations indiquées et `R` retente explicitement un bind/chargement.
|
|
||||||
|
|
||||||
### Workflow optique
|
A fresh empty Queue can then be created for the next project.
|
||||||
|
|
||||||
La TUI consomme les API v23 décrites dans
|
No terminal callback may dereference a closed Project DB.
|
||||||
[Project Database](project_database.md), sans SQL direct ni édition d'une ligne
|
|
||||||
immuable. Elle inspecte une affectation Capture, effectue seulement des lookup
|
|
||||||
metadata exacts, liste les profils de boîtier/objectif/configuration et accepte
|
|
||||||
un objectif manuel sans électronique ni alias — le Meike de test est un cas
|
|
||||||
normal, pas une branche produit. « Modifier » signifie créer un nouveau profil
|
|
||||||
ou une nouvelle configuration immuable, puis l'assigner explicitement à un
|
|
||||||
groupe de campagne encore éligible ou à un Capture non affecté. Les
|
|
||||||
calibrations listées doivent être compatibles avec l'exacte configuration et
|
|
||||||
la sélection reste explicite ; absence, ambiguïté, incompatibilité, BUSY, I/O
|
|
||||||
et corruption sont rendues sans profil fabriqué. Les pages ont 16 lignes,
|
|
||||||
rapportent un compte page-local et un indicateur « suite » exact.
|
|
||||||
|
|
||||||
### SSD F10 et lifetime application
|
Queue terminal history belongs to the current runtime session and does not leak between projects.
|
||||||
|
|
||||||
La TUI affiche les huit états physiques `ABSENT`, `DETECTED`, `ENABLING`,
|
## Project Database
|
||||||
`ENABLED`, `IN_USE`, `DRAINING`, `SAFE_TO_UNPLUG` et `ERROR`, avec identité
|
|
||||||
stable, modèle/télémétrie lorsqu'ils sont connus, swap, scratch, mount, usage,
|
|
||||||
leases, drain et raison. `UNKNOWN` n'est jamais remplacé par zéro ou par une
|
|
||||||
supposition ; `SAFE_TO_UNPLUG` est mis en évidence comme endpoint sûr. F10
|
|
||||||
choisit exclusivement l'une des capacités exactes
|
|
||||||
`can_enable`, `can_disable` ou `can_cancel_drain` publiée par le contrôleur ; un
|
|
||||||
état incomplet, une paire de remplacement ou un résultat malformé n'accorde
|
|
||||||
aucune autorité. L'opération synchrone UDisks s'exécute dans au plus un thread
|
|
||||||
joinable, tandis que le main continue de rendre et de poller sans blocage.
|
|
||||||
|
|
||||||
La validation qui alimente ces capacités est fail-closed par état : toute
|
Project DB uses an opaque serialized SQLite connection with bounded transactional operations.
|
||||||
autorité exige Drive et deux partitions détectés, identités Drive+UUID exactes,
|
|
||||||
extents positifs connus et faits mount/activité/drain cohérents. `ABSENT` ne
|
|
||||||
peut transporter aucun fait actif, `DETECTED` partiel n'a aucune action et un
|
|
||||||
hazard `ERROR` déconnecté ne peut que retenir l'identité originale sans
|
|
||||||
allocation. Seule la reconnexion complète de ce tuple peut autoriser son drain.
|
|
||||||
|
|
||||||
Après chaque observation ou résultat validé, l'adaptateur enregistre une copie
|
Current schema head:
|
||||||
bornée de l'état physique auprès du Governor. Une copie malformée devient
|
|
||||||
`ERROR` et interdit les nouvelles allocations ; l'observation ressources lit
|
|
||||||
cet état Governor-owned, tandis que les détails/permissions F10 restent dans
|
|
||||||
le snapshot physique. La génération source peut saturer à `UINT64_MAX` : une
|
|
||||||
update publique égale ne réaccorde jamais une autorité stale ; seule la
|
|
||||||
complétion du wrapper exact déjà engagé réconcilie son lease adressé. À l'arrêt,
|
|
||||||
l'ordre est : destruction/join de la Queue et
|
|
||||||
libération de chaque lease Task, fermeture du projet/DB, join puis unregister
|
|
||||||
vérifié de l'adaptateur SSD, destruction du contrôleur, puis destruction du
|
|
||||||
Governor. Les tests utilisent un provider factice et n'exécutent aucune vraie
|
|
||||||
mutation SSD.
|
|
||||||
|
|
||||||
## Invariants
|
```text
|
||||||
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
|
```
|
||||||
|
|
||||||
- ncurses appartient exclusivement au thread principal
|
Current additive selected-execution overlays include:
|
||||||
- Aucune tâche ne démarre sans réservation active
|
|
||||||
- Les réservations sont libérées exactement une fois
|
|
||||||
- Les buffers sont strictement bornés
|
|
||||||
- Le Resource Governor reste l'unique propriétaire de l'admission ; ni Queue,
|
|
||||||
ni contrôleur SSD ne constituent un second orchestrateur de ressources
|
|
||||||
|
|
||||||
## Statut : CURRENT / VALIDATED OPERATIONAL
|
```text
|
||||||
|
v24 raw.develop.batch/1
|
||||||
|
v25 features.extract.batch/1
|
||||||
|
```
|
||||||
|
|
||||||
La TUI/runtime et son raccordement SSD sont implémentés, testés et relus dans
|
The v23 optical model remains valid but is no longer the schema head.
|
||||||
leur tranche. Le statut global est
|
|
||||||
`GLOBAL_MAINTENANCE_AUDIT=PASS/FROZEN`. Les builds portables/Vulkan,
|
## Current production Task inventory
|
||||||
sanitizers, contrôles de concurrence et ABI frais sont acquis ; l'unique revue
|
|
||||||
finale indépendante a conclu PASS sans finding bloquant.
|
Production currently has sixteen Task Kinds.
|
||||||
|
|
||||||
|
Important selected-execution additions:
|
||||||
|
|
||||||
|
```text
|
||||||
|
raw.develop.batch/1
|
||||||
|
features.extract.batch/1
|
||||||
|
```
|
||||||
|
|
||||||
|
The Queue still has one active heavy callback; batch Task Kinds obtain throughput from bounded
|
||||||
|
participants inside that callback.
|
||||||
|
|
||||||
|
Per-item atomicity does not require cross-item serial execution.
|
||||||
|
|
||||||
|
## Resource Governor
|
||||||
|
|
||||||
|
Every production Task goes through the Resource Governor, including fixed-resource Tasks.
|
||||||
|
|
||||||
|
The canonical host policy is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
preserve defined interactive reserve
|
||||||
|
then maximize safe useful throughput
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
RESOURCE_UTILIZATION_POLICY=MAXIMUM_SAFE_USEFUL_THROUGHPUT
|
||||||
|
SERIALISM_REQUIRES_PROOF=CANONICAL
|
||||||
|
```
|
||||||
|
|
||||||
|
Reference-host CPU counts are evidence, not portable constants.
|
||||||
|
|
||||||
|
Pressure may reduce a later admission; healthy recovery may ramp useful width again.
|
||||||
|
|
||||||
|
Swap/zram/scratch do not enlarge admitted RAM.
|
||||||
|
|
||||||
|
UMA GPU memory is charged once against host RAM.
|
||||||
|
|
||||||
|
## Internal parallelism
|
||||||
|
|
||||||
|
Validated Task Kinds may execute:
|
||||||
|
|
||||||
|
```text
|
||||||
|
one Queue owner callback
|
||||||
|
-> bounded participants
|
||||||
|
-> join
|
||||||
|
-> deterministic owner publication
|
||||||
|
```
|
||||||
|
|
||||||
|
Current examples include:
|
||||||
|
|
||||||
|
- Feature selected batch;
|
||||||
|
- Visual Index;
|
||||||
|
- Candidate Pair;
|
||||||
|
- Matcher CPU work;
|
||||||
|
- Geometric Verifier outer parallel preparation;
|
||||||
|
- RAW selected batch.
|
||||||
|
|
||||||
|
This is not inter-Task parallelism and does not create another global worker pool.
|
||||||
|
|
||||||
|
## Current Matcher backend policy
|
||||||
|
|
||||||
|
ORB Matcher normal production is Governor-owned AUTO.
|
||||||
|
|
||||||
|
Eligible ORB work prefers the validated Vulkan backend.
|
||||||
|
|
||||||
|
Fallback is complete CPU recomputation.
|
||||||
|
|
||||||
|
Normal Vulkan contract:
|
||||||
|
|
||||||
|
```text
|
||||||
|
inflight = 1
|
||||||
|
helpers = 0
|
||||||
|
useful batch <= 8
|
||||||
|
```
|
||||||
|
|
||||||
|
Depth 2 remains validated private safety/benchmark capacity but was rejected as normal useful policy.
|
||||||
|
|
||||||
|
SIFT/RootSIFT Matcher remains CPU.
|
||||||
|
|
||||||
|
## Runtime observation
|
||||||
|
|
||||||
|
The runtime observer borrows Queue/Governor state and publishes one bounded coherent snapshot for the
|
||||||
|
TUI.
|
||||||
|
|
||||||
|
It does not retain Task userdata.
|
||||||
|
|
||||||
|
Ordinary snapshots are rate-limited/coalesced.
|
||||||
|
|
||||||
|
On observation failure, the previous bounded view may be retained and explicitly marked stale.
|
||||||
|
|
||||||
|
Task observation includes live/pending/recent-terminal entries only within fixed capacity.
|
||||||
|
|
||||||
|
No unbounded Project DB scan is performed per frame.
|
||||||
|
|
||||||
|
## Durable progress and ETA
|
||||||
|
|
||||||
|
Typed Tasks publish exact `completed/total` only after their Task-specific durable prefix is committed.
|
||||||
|
|
||||||
|
The TUI must not infer exact scientific progress from:
|
||||||
|
|
||||||
|
- Task name;
|
||||||
|
- message text;
|
||||||
|
- generic percentage.
|
||||||
|
|
||||||
|
When exact counters exist, they are authoritative.
|
||||||
|
|
||||||
|
Throughput/ETA needs enough positive-time progress observations.
|
||||||
|
|
||||||
|
No-progress/pressure/restart cases become explicit states such as stalled, throttled or indeterminate
|
||||||
|
rather than fabricated precision.
|
||||||
|
|
||||||
|
A terminal Task with inconsistent durable progress is visible as an integrity problem rather than
|
||||||
|
silently forced to 100%.
|
||||||
|
|
||||||
|
## Pipeline observation
|
||||||
|
|
||||||
|
Current observable stages include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Acquisition
|
||||||
|
RAW
|
||||||
|
Quality
|
||||||
|
Features
|
||||||
|
Visual Index
|
||||||
|
Candidate
|
||||||
|
Matcher
|
||||||
|
GV
|
||||||
|
Tracks
|
||||||
|
Sparse SfM
|
||||||
|
Dense
|
||||||
|
```
|
||||||
|
|
||||||
|
Sparse SfM capability exists.
|
||||||
|
|
||||||
|
Dense has no production Task Kind and remains not applicable/unimplemented at the current checkpoint.
|
||||||
|
|
||||||
|
Historical S21/A6000 real campaigns have not executed Sparse SfM because known calibration is
|
||||||
|
unavailable for those campaigns.
|
||||||
|
|
||||||
|
## TUI resource observation
|
||||||
|
|
||||||
|
Resource UI may display known bounded values for:
|
||||||
|
|
||||||
|
- active/admitted/available CPU;
|
||||||
|
- GPU presence/backend/busy/memory;
|
||||||
|
- RAM and `MemAvailable`;
|
||||||
|
- host reserve;
|
||||||
|
- swap state and active deltas;
|
||||||
|
- batch/inflight/helpers;
|
||||||
|
- IO;
|
||||||
|
- scratch;
|
||||||
|
- Governor pressure.
|
||||||
|
|
||||||
|
The installed contract of the exact active Task is authoritative for that sequence.
|
||||||
|
|
||||||
|
A diagnostic indexed only by Task Kind cannot automatically be attributed to another Task/sequence.
|
||||||
|
|
||||||
|
Unknown values remain unknown.
|
||||||
|
|
||||||
|
## TUI layout
|
||||||
|
|
||||||
|
The validated layout classes remain bounded.
|
||||||
|
|
||||||
|
Current thresholds include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
full layout >= 100x30
|
||||||
|
compact boundary = 72x20
|
||||||
|
supported minimum = 60x15
|
||||||
|
```
|
||||||
|
|
||||||
|
Below the supported minimum, the UI uses its too-small-terminal fallback.
|
||||||
|
|
||||||
|
Repository documentation is English. Any remaining non-English executable UI literal is legacy runtime
|
||||||
|
text and must be changed only in the explicitly scoped UI-language remediation pass; documentation does
|
||||||
|
not redefine executable behavior by pretending that source literal has already changed.
|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
The current TUI provides screens for the implemented runtime surfaces, including:
|
||||||
|
|
||||||
|
- home;
|
||||||
|
- projects;
|
||||||
|
- import;
|
||||||
|
- tasks;
|
||||||
|
- resources;
|
||||||
|
- optics;
|
||||||
|
- SSD;
|
||||||
|
- help;
|
||||||
|
- viewer placeholder/future surface.
|
||||||
|
|
||||||
|
Key bindings and exact executable labels remain owned by the TUI source and its tests.
|
||||||
|
|
||||||
|
Documentation should describe behavior rather than preserve stale localized literals as authority.
|
||||||
|
|
||||||
|
## Optical workflow
|
||||||
|
|
||||||
|
The TUI uses the public optical APIs introduced by the v23 overlay.
|
||||||
|
|
||||||
|
It does not write optical SQLite rows directly.
|
||||||
|
|
||||||
|
It supports explicit inspection/selection and immutable profile creation.
|
||||||
|
|
||||||
|
Manual lenses without electronic metadata are valid data.
|
||||||
|
|
||||||
|
No workflow may fabricate:
|
||||||
|
|
||||||
|
- "unknown" lens identity;
|
||||||
|
- calibration compatibility;
|
||||||
|
- metadata match;
|
||||||
|
- focal/lens substitution.
|
||||||
|
|
||||||
|
Calibration selection remains explicit and exact.
|
||||||
|
|
||||||
|
## SSD F10 boundary
|
||||||
|
|
||||||
|
The SSD UI reflects controller capability/state rather than inventing actions.
|
||||||
|
|
||||||
|
The controller owns physical detection, pairing, mount/swap/scratch state and bounded UDisks operations.
|
||||||
|
|
||||||
|
The Resource Governor owns scratch lease admission.
|
||||||
|
|
||||||
|
A state that is incomplete, stale or physically inconsistent grants no control/lease authority.
|
||||||
|
|
||||||
|
Scratch is storage capacity, never RAM.
|
||||||
|
|
||||||
|
## Global shutdown
|
||||||
|
|
||||||
|
Ownership shutdown preserves:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Task Queue / Task leases
|
||||||
|
-> project close
|
||||||
|
-> SSD operation join / Governor unregister
|
||||||
|
-> SSD controller
|
||||||
|
-> Resource Governor
|
||||||
|
```
|
||||||
|
|
||||||
|
A real outstanding scratch lease can block unregister and must remain an observable error.
|
||||||
|
|
||||||
|
Do not abandon a live lease pointer.
|
||||||
|
|
||||||
|
## Error/recovery model
|
||||||
|
|
||||||
|
Runtime operations use local rollback and explicit publication boundaries.
|
||||||
|
|
||||||
|
File asset publication plus SQLite is not treated as one distributed transaction.
|
||||||
|
|
||||||
|
A successfully published physical asset followed by DB failure may leave a valid orphan.
|
||||||
|
|
||||||
|
Recovery validates known durable representations; it does not guess or silently repair scientific
|
||||||
|
identity.
|
||||||
|
|
||||||
|
## Current real checkpoint
|
||||||
|
|
||||||
|
Current retained A6000 checkpoint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
real-a6000-pre-sfm-2026-09-02
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
||||||
|
It exercised current runtime/Queue/Governor behavior through:
|
||||||
|
|
||||||
|
```text
|
||||||
|
selected RAW batch
|
||||||
|
selected Feature batch
|
||||||
|
Visual Index
|
||||||
|
Candidate Pair
|
||||||
|
Matcher
|
||||||
|
Geometric Verifier v3
|
||||||
|
Track Builder
|
||||||
|
```
|
||||||
|
|
||||||
|
The final continuation recorded deterministic restart/reuse and stopped with:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Sparse SfM Tasks 0
|
||||||
|
Sparse Reconstructions 0
|
||||||
|
Dense/MVS 0
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a current real runtime checkpoint, later than the historical global-maintenance checkpoint.
|
||||||
|
|
||||||
|
Both remain valid for the boundaries they prove.
|
||||||
|
|
||||||
|
## Current limits
|
||||||
|
|
||||||
|
Current runtime intentionally does not provide:
|
||||||
|
|
||||||
|
- multiple concurrent heavy Queue callbacks;
|
||||||
|
- generic inter-Task DAG scheduling;
|
||||||
|
- generic Task priorities beyond current Queue policy;
|
||||||
|
- generic autosave ahead of Task-specific durable publication;
|
||||||
|
- Dense/MVS production Task Kind;
|
||||||
|
- live capture/viewer reconstruction loop;
|
||||||
|
- generic scratch-consuming Task Kind.
|
||||||
|
|
||||||
|
Those are future product/implementation decisions, not silently missing state.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
```text
|
||||||
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
|
CURRENT_PRODUCTION_TASK_KINDS=16
|
||||||
|
|
||||||
|
TASK_QUEUE_WORKERS=1
|
||||||
|
ACTIVE_HEAVY_CALLBACKS=1
|
||||||
|
INTER_TASK_PARALLELISM=NOT_IMPLEMENTED
|
||||||
|
INTERNAL_PARALLELISM=BOUNDED
|
||||||
|
|
||||||
|
GENERIC_DAG=NOT_IMPLEMENTED
|
||||||
|
DENSE_TASK_KIND=NOT_IMPLEMENTED
|
||||||
|
CURRENT_SCRATCH_CONSUMING_TASK_KINDS=0
|
||||||
|
|
||||||
|
RESOURCE_UTILIZATION_POLICY=MAXIMUM_SAFE_USEFUL_THROUGHPUT
|
||||||
|
SERIALISM_REQUIRES_PROOF=CANONICAL
|
||||||
|
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,526 +1,450 @@
|
||||||
# Track Model v1
|
# Track Model v1
|
||||||
|
|
||||||
## Scope
|
## Status
|
||||||
|
|
||||||
Track Model v1 est le contrat persistant qui transforme les correspondances
|
```text
|
||||||
géométriquement vérifiées en structures multi-view cohérentes. Il stocke des
|
TRACK_MODEL_V1=FROZEN
|
||||||
ensembles d'observations 2D liées à un même point physique supposé. Il ne
|
TRACK_BUILDER_V1=PASS/FROZEN
|
||||||
calcule rien, ne triangule pas, ne contient aucune coordonnée 3D et ne résout
|
|
||||||
aucun conflit. Le Track Builder, la triangulation, le Sparse SfM et le Bundle
|
CURRENT_PRODUCTION_VERIFIER=FUNDAMENTAL_V3
|
||||||
Adjustment sont des étapes séparées ; Gate E a gelé le Builder v1 sans
|
SPARSE_SFM_CAPABILITY=IMPLEMENTED_THROUGH_GATE_G
|
||||||
implémenter ces étapes 3D.
|
REAL_S21_SPARSE_SFM=NOT_EXECUTED
|
||||||
|
REAL_A6000_SPARSE_SFM=NOT_EXECUTED
|
||||||
|
|
||||||
|
REAL_S21_TRACKS=PASS/FROZEN
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
||||||
|
Track Model v1 is the persistent scientific contract for coherent multi-view 2D observation sets.
|
||||||
|
|
||||||
|
A Track is **not** a 3D point.
|
||||||
|
|
||||||
|
It contains no camera pose, triangulated coordinate, reprojection error or Bundle Adjustment state.
|
||||||
|
|
||||||
|
Track Builder v1 constructs Tracks from verified Geometric Verification Results. Sparse SfM consumes an
|
||||||
|
immutable Track Set later.
|
||||||
|
|
||||||
|
## Pipeline position
|
||||||
|
|
||||||
|
Current pipeline:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Feature Set
|
||||||
|
-> Candidate Pair
|
||||||
|
-> Match Result
|
||||||
|
-> Geometric Verifier v3
|
||||||
|
-> Geometric Verification Result
|
||||||
|
-> Track Builder v1
|
||||||
|
-> Track Model v1
|
||||||
|
-> Sparse SfM capability
|
||||||
|
```
|
||||||
|
|
||||||
|
Sparse SfM Gates C through G are implemented and frozen.
|
||||||
|
|
||||||
|
The retained S21 and A6000 historical campaigns stop before real Sparse SfM because known calibration
|
||||||
|
data is unavailable for those campaigns.
|
||||||
|
|
||||||
|
Older Track Model text that called Sparse SfM "future" describes historical lifecycle, not current
|
||||||
|
implementation status.
|
||||||
|
|
||||||
## Track definition
|
## Track definition
|
||||||
|
|
||||||
Un **Track** est un ensemble d'observations 2D cohérentes d'un même point
|
A Track is a coherent set of 2D observations believed to correspond to the same physical scene point
|
||||||
physique supposé, observé à travers plusieurs images. Chaque observation est
|
across multiple images.
|
||||||
identifiée par `(feature_set_id, feature_index)`.
|
|
||||||
|
|
||||||
Un Track n'est **pas** un point 3D. Il ne contient aucune coordonnée 3D,
|
Observation identity is exactly:
|
||||||
aucune erreur de reprojection, aucun statut de triangulation. La
|
|
||||||
triangulation appartient à une étape ultérieure.
|
|
||||||
|
|
||||||
La chaîne scientifique correcte est :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Matcher → Match Result → Geometric Verification → Track Builder v1
|
|
||||||
→ Track Model → Sparse SfM (futur)
|
|
||||||
```
|
|
||||||
|
|
||||||
Le Matcher ne produit pas les Tracks. Le Track Builder v1 les assemble à partir
|
|
||||||
des Geometric Verification Results.
|
|
||||||
|
|
||||||
## Observation identity
|
|
||||||
|
|
||||||
Une observation est identifiée par :
|
|
||||||
|
|
||||||
```
|
|
||||||
(feature_set_id, feature_index)
|
(feature_set_id, feature_index)
|
||||||
```
|
```
|
||||||
|
|
||||||
- `feature_set_id` : identifiant SQLite AUTOINCREMENT du Feature Set. Le
|
`feature_set_id` identifies one immutable Feature Set.
|
||||||
Feature Set porte directement `image_id` comme colonne NOT NULL FK. L'image
|
|
||||||
est dérivable par `SELECT image_id FROM feature_sets WHERE feature_set_id=?`.
|
|
||||||
- `feature_index` : ordinal zero-based dans le tableau de keypoints du Feature
|
|
||||||
File, stable tant que le Feature Set existe. Un Feature Set publié est
|
|
||||||
immutable : aucune API de production ne modifie ses colonnes après INSERT.
|
|
||||||
|
|
||||||
L'identité `(feature_set_id, feature_index)` est suffisante. Il est inutile
|
`feature_index` is the zero-based keypoint ordinal inside that immutable Feature File.
|
||||||
de porter `image_id` dans la table d'observations car il est dérivable via
|
|
||||||
`feature_sets.image_id`.
|
|
||||||
|
|
||||||
Note : `feature_sets` ne possède pas de colonne d'état. L'existence d'une
|
The Feature Set directly owns `image_id`; image identity is therefore derivable and is not duplicated
|
||||||
ligne publiée dans la table constitue le contrat réel de disponibilité du
|
in Track observation identity.
|
||||||
Feature Set.
|
|
||||||
|
|
||||||
## Scientific inputs
|
## Scientific input
|
||||||
|
|
||||||
Les Tracks sont construits exclusivement à partir de :
|
Track Builder consumes only completed verified geometric results selected by one exact verifier
|
||||||
|
identity.
|
||||||
|
|
||||||
```
|
Current production lineage:
|
||||||
Geometric Verification Result
|
|
||||||
status == GEOMETRIC_VERIFIED (2)
|
|
||||||
```
|
|
||||||
|
|
||||||
correspondant exactement au VERIFICATION_SELECTOR du Track Set.
|
|
||||||
|
|
||||||
Pour chaque résultat vérifié, les entrées du Match File dont le bit
|
|
||||||
correspondant dans le masque d'inliers vaut 1 fournissent les correspondances
|
|
||||||
valides. La chaîne de dérivation est :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
GVR → match_result_id
|
verifier_kind = FUNDAMENTAL
|
||||||
→ candidate_pair + feature_set_id_a + feature_set_id_b
|
verifier_version = 3
|
||||||
→ Match File entry[i] = (feature_index_a, feature_index_b, distance)
|
verifier_fingerprint =
|
||||||
→ bit i du masque d'inliers = 1
|
6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
→ observation A: (feature_set_id_a, feature_index_a)
|
|
||||||
→ observation B: (feature_set_id_b, feature_index_b)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Un `GEOMETRIC_REJECTED` ne produit aucun track. Un Match Result non vérifié
|
Historical Track Sets created from Fundamental verifier v1 or v2 remain valid historical scientific
|
||||||
géométriquement ne suffit pas.
|
objects.
|
||||||
|
|
||||||
## VERIFICATION_SELECTOR
|
They must not be relabelled as v3.
|
||||||
|
|
||||||
Le VERIFICATION_SELECTOR définit la configuration de Geometric Verification
|
For each selected `GEOMETRIC_VERIFIED` result, only Match File entries whose corresponding inlier-mask
|
||||||
éligible pour un Track Set. Il est stocké sur le Track Set et fait partie de
|
bit is one contribute observation edges.
|
||||||
son identité de reuse.
|
|
||||||
|
|
||||||
```
|
A rejected GVR contributes no Track edge.
|
||||||
(
|
|
||||||
verifier_kind INTEGER, -- ex: 1 = FUNDAMENTAL
|
## Verification selector
|
||||||
verifier_version INTEGER,
|
|
||||||
parameter_fingerprint BLOB(32)
|
A Track Set stores the exact verifier selector:
|
||||||
)
|
|
||||||
|
```text
|
||||||
|
verifier_kind
|
||||||
|
verifier_version
|
||||||
|
verifier_fingerprint
|
||||||
```
|
```
|
||||||
|
|
||||||
Le Track Builder ne consomme que les GVR avec `status == GEOMETRIC_VERIFIED`
|
The builder never selects verification evidence using:
|
||||||
correspondant exactement à ce tuple. Aucune sélection par timestamp, "latest"
|
|
||||||
ou ordre d'insertion n'est permise.
|
|
||||||
|
|
||||||
Valeur production : `(1, 1, SHA-256 de l'encodage canonique 84 octets)`.
|
- timestamp;
|
||||||
|
- "latest";
|
||||||
|
- insertion order;
|
||||||
|
- approximate fingerprint match.
|
||||||
|
|
||||||
## INPUT_SCOPE
|
The current default producer is v3, but the Track Model remains version-independent and can store valid
|
||||||
|
sets from explicitly supported historical selectors.
|
||||||
|
|
||||||
L'INPUT_SCOPE représente l'ensemble scientifique réel des entrées consommées
|
## Input scope
|
||||||
par une Track Generation donnée. Il est distinct du VERIFICATION_SELECTOR :
|
|
||||||
le selector dit quels GVR sont admissibles, le scope dit quels GVR ont
|
|
||||||
effectivement été consommés.
|
|
||||||
|
|
||||||
```
|
A Track Set also records the exact consumed GVR scope.
|
||||||
input_scope_hash BLOB(32) -- SHA-256 canonique
|
|
||||||
gvr_count INTEGER -- nombre de GVR consommés
|
Canonical scope identity uses:
|
||||||
|
|
||||||
|
```text
|
||||||
|
domain: L3DTSIS1
|
||||||
|
items: geometric_verification_result_id
|
||||||
|
order: strictly increasing
|
||||||
|
encoding: uint64 little-endian
|
||||||
|
digest: SHA-256
|
||||||
```
|
```
|
||||||
|
|
||||||
### INPUT_SCOPE_HASH
|
Conceptually:
|
||||||
|
|
||||||
| Propriété | Valeur |
|
```text
|
||||||
|-----------|--------|
|
SHA-256(L3DTSIS1 || id_0 || id_1 || ... || id_N)
|
||||||
| Domain/version | `L3DTSIS1` (8 octets ASCII) |
|
```
|
||||||
| Items | `geometric_verification_result_id` des GVR consommés |
|
|
||||||
| Canonical ordering | IDs triés par ordre croissant |
|
|
||||||
| Serialization | Chaque ID : 8 octets little-endian |
|
|
||||||
| Digest | SHA-256 |
|
|
||||||
| DB-local IDs | OUI — le reuse est scoped à une DB projet |
|
|
||||||
| Duplicate handling | Inutile — les IDs sont uniques par construction |
|
|
||||||
| Empty scope | Interdit — un Track Set sans GVR n'a pas de sens |
|
|
||||||
|
|
||||||
Le digest est calculé sur `L3DTSIS1` (8 octets) suivi des IDs sérialisés :
|
The scope is Project-DB-local because SQLite GVR IDs participate directly.
|
||||||
`SHA-256(L3DTSIS1 || id_0 || id_1 || ... || id_N)` où chaque `id_i` est
|
|
||||||
8 octets little-endian et les IDs sont triés par ordre croissant.
|
|
||||||
|
|
||||||
Le `gvr_count` est stocké comme métadonnée de validation. Il permet de
|
`gvr_count` is retained as validation metadata.
|
||||||
détecter un scope incomplet sans re-hasher. Il ne fait pas partie du hash
|
|
||||||
lui-même.
|
|
||||||
|
|
||||||
Le scope_hash est DB-local : il utilise les `geometric_verification_result_id`
|
An empty scope is invalid.
|
||||||
SQLite. Deux DB distinctes avec les mêmes données produiront des IDs
|
|
||||||
différents. Le reuse est donc scoped à une seule DB projet.
|
|
||||||
|
|
||||||
## Track membership invariants
|
## Track membership invariants
|
||||||
|
|
||||||
1. **Minimum structurel** : un Track contient au moins 2 observations.
|
### Minimum size
|
||||||
Une seule observation ne constitue aucune relation multi-view. Le futur
|
|
||||||
Track Builder v1, la triangulation ou le Sparse SfM pourront appliquer des
|
|
||||||
critères plus stricts. Le Model ne fixe pas de plafond de reconstruction.
|
|
||||||
|
|
||||||
2. **One observation per image** : un Track ne contient pas deux observations
|
A Track has at least two observations.
|
||||||
issues de la même image. Cette contrainte est validée par l'API lors de la
|
|
||||||
création. Le schéma v1 ne dénormalise pas `image_id` dans
|
|
||||||
`track_observations` ; l'API vérifie déterministement la relation via
|
|
||||||
`feature_sets.image_id` avant publication sous `BEGIN IMMEDIATE`.
|
|
||||||
|
|
||||||
**SQL** : non protégé (pas de colonne `image_id` dans `track_observations`).
|
### At most one observation per image
|
||||||
**API** : validation par jointure `feature_sets.image_id` avant INSERT.
|
|
||||||
|
|
||||||
3. **Observation unique across tracks** : dans un même Track Set, une
|
One Track cannot contain two observations derived from the same image.
|
||||||
observation `(feature_set_id, feature_index)` n'appartient qu'à un seul
|
|
||||||
Track.
|
|
||||||
|
|
||||||
**SQL** : `PRIMARY KEY(track_set_id, feature_set_id, feature_index)` sur
|
This is validated through `feature_sets.image_id`.
|
||||||
`track_observations`. Le `track_set_id` est dénormalisé depuis `tracks`.
|
|
||||||
**API** : validation que `track_set_id` correspond au `track_set_id` du
|
|
||||||
`track_id` parent.
|
|
||||||
|
|
||||||
4. **Feature Set existence** : chaque `feature_set_id` référencé existe dans
|
### Observation uniqueness inside one Track Set
|
||||||
la table `feature_sets`. La FK SQLite garantit la référence.
|
|
||||||
|
|
||||||
**SQL** : `REFERENCES feature_sets(feature_set_id)`.
|
Within one Track Set:
|
||||||
|
|
||||||
5. **Feature index bounds** : `feature_index < feature_sets.feature_count`
|
```text
|
||||||
pour l'observation correspondante.
|
(feature_set_id, feature_index)
|
||||||
|
```
|
||||||
|
|
||||||
**SQL** : `CHECK(feature_index >= 0)`.
|
belongs to at most one Track.
|
||||||
**API** : validation de la borne supérieure via `feature_sets.feature_count`
|
|
||||||
(SQLite CHECK ne peut pas référencer une autre table).
|
The persistence schema enforces this using the Track Set-scoped primary key.
|
||||||
|
|
||||||
|
### Feature Set existence
|
||||||
|
|
||||||
|
Every referenced Feature Set must exist.
|
||||||
|
|
||||||
|
### Feature index bound
|
||||||
|
|
||||||
|
For every observation:
|
||||||
|
|
||||||
|
```text
|
||||||
|
0 <= feature_index < feature_count
|
||||||
|
```
|
||||||
|
|
||||||
|
The upper bound is validated against the referenced Feature Set.
|
||||||
|
|
||||||
|
### Parent consistency
|
||||||
|
|
||||||
|
The denormalized Track Set ID carried by an observation must equal the Track Set of its parent Track.
|
||||||
|
|
||||||
## Track identity
|
## Track identity
|
||||||
|
|
||||||
Un Track persistant possède un identifiant opaque :
|
Persistent Track identity is the opaque SQLite:
|
||||||
|
|
||||||
```
|
```text
|
||||||
track_id INTEGER PRIMARY KEY AUTOINCREMENT CHECK(track_id > 0)
|
track_id
|
||||||
```
|
```
|
||||||
|
|
||||||
Il n'a pas d'identité scientifique dérivée de son contenu en v1. Les raisons :
|
Track Model v1 does not define a content-derived Track hash.
|
||||||
|
|
||||||
- un hash de membership rendrait les INSERTs dépendants de l'ordre ;
|
Reproducibility and reuse are owned by the Track Set identity, builder configuration and exact input
|
||||||
- le contenu d'un track peut être reconstruit depuis les GVR sources ;
|
scope.
|
||||||
- un `track_id` opaque suffit pour la persistance, le référencement et la
|
|
||||||
pagination ;
|
|
||||||
- la corruption est détectée par cohérence interne (doublons, images
|
|
||||||
manquantes, index hors bornes) plutôt que par re-hash.
|
|
||||||
|
|
||||||
La reproductibilité est assurée au niveau du Track Set (parent), pas du Track
|
## Track Set identity
|
||||||
individuel.
|
|
||||||
|
|
||||||
## Track Set / Generation
|
A Track Set is one complete immutable generation.
|
||||||
|
|
||||||
Un **Track Set** est le parent obligatoire de tout Track persistant. Il
|
Its reuse identity contains:
|
||||||
représente une génération complète de Track Building.
|
|
||||||
|
|
||||||
Champs :
|
```text
|
||||||
|
builder_kind
|
||||||
```
|
builder_version
|
||||||
track_set_id INTEGER PK AUTOINCREMENT
|
builder_parameter_fingerprint
|
||||||
builder_kind TEXT(1..64)
|
verifier_kind
|
||||||
builder_version INTEGER > 0
|
verifier_version
|
||||||
parameter_fingerprint BLOB(32)
|
verifier_fingerprint
|
||||||
verifier_kind INTEGER -- VERIFICATION_SELECTOR
|
|
||||||
verifier_version INTEGER
|
|
||||||
verifier_fingerprint BLOB(32)
|
|
||||||
input_scope_hash BLOB(32)
|
|
||||||
gvr_count INTEGER >= 1
|
|
||||||
track_count INTEGER >= 0
|
|
||||||
created_at INTEGER >= 0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Identité de reuse
|
|
||||||
|
|
||||||
```
|
|
||||||
(
|
|
||||||
builder_kind,
|
|
||||||
builder_version,
|
|
||||||
parameter_fingerprint,
|
|
||||||
verifier_kind,
|
|
||||||
verifier_version,
|
|
||||||
verifier_fingerprint,
|
|
||||||
input_scope_hash
|
input_scope_hash
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`gvr_count` est stocké comme métadonnée de validation mais ne fait pas
|
`gvr_count` validates the scope metadata but is not an independent reuse discriminator.
|
||||||
partie de l'identité de reuse. Le même `input_scope_hash` avec un `gvr_count`
|
|
||||||
différent indiquerait une corruption (hash cohérent mais nombre de sources
|
|
||||||
incohérent).
|
|
||||||
|
|
||||||
Un set existant avec cette identité exacte est réutilisé. `INSERT OR REPLACE`
|
`INSERT OR REPLACE` is forbidden.
|
||||||
est interdit.
|
|
||||||
|
|
||||||
### Immutabilité
|
An exact existing immutable set is reused.
|
||||||
|
|
||||||
Un Track Set publié est **immutable**. Aucune opération d'append, remove ou
|
A scientifically different scope/configuration creates a new Track Set.
|
||||||
merge n'est permise sur un track ou un set existant.
|
|
||||||
|
|
||||||
L'invalidation scientifique (nouvelle entrée, nouveau scope, nouvelle
|
## Immutability
|
||||||
configuration) produit un nouveau Track Set. Le set précédent reste intact.
|
|
||||||
|
|
||||||
La suppression référentielle utilise `ON DELETE CASCADE` : supprimer un
|
A published Track Set is immutable.
|
||||||
Track Set supprime ses tracks et observations.
|
|
||||||
|
|
||||||
### Justification
|
No production operation:
|
||||||
|
|
||||||
- chaque rebuild crée un nouveau set, les anciens restent intacts ;
|
- appends to it;
|
||||||
- plusieurs configurations peuvent coexister (expérimentation) ;
|
- removes observations;
|
||||||
- l'invalidation est simple : supprimer un set supprime ses tracks via
|
- merges existing Tracks;
|
||||||
CASCADE ;
|
- rewrites memberships;
|
||||||
- la reproductibilité est portée par le fingerprint et le scope_hash ;
|
- updates it to a newer verifier version.
|
||||||
- pas d'UPDATE/INSERT/MERGE sur des tracks existants ;
|
|
||||||
- cohérent avec tous les résultats publiés existants (Feature Sets, Match
|
|
||||||
Results, GVRs) qui sont immutables après publication.
|
|
||||||
|
|
||||||
Le Track Builder v1 construit en mémoire, puis publie un set complet
|
New evidence creates a new generation.
|
||||||
dans une transaction. Aucun track n'est visible avant que le set entier soit
|
|
||||||
validé.
|
|
||||||
|
|
||||||
## Immutability / incrementality
|
Historical generations remain queryable until explicitly deleted.
|
||||||
|
|
||||||
Un Track publié dans un set est **immutable**.
|
|
||||||
|
|
||||||
L'incrémentalité est gérée par création de nouveaux sets :
|
|
||||||
|
|
||||||
1. nouvelles images → nouveaux Match Results → nouveaux GVR → nouveau
|
|
||||||
Track Set ;
|
|
||||||
2. le set précédent reste valide et consultable ;
|
|
||||||
3. le futur Sparse SfM choisira quel set consommer.
|
|
||||||
|
|
||||||
Cette approche est cohérente avec la philosophie Lardon3D :
|
|
||||||
|
|
||||||
- résultats atomiques ;
|
|
||||||
- pas de destruction silencieuse ;
|
|
||||||
- reprise à frontière connue ;
|
|
||||||
- conservation de l'historique.
|
|
||||||
|
|
||||||
## Persistence
|
## Persistence
|
||||||
|
|
||||||
### Conceptual schema
|
Track storage was introduced by Project DB v14.
|
||||||
|
|
||||||
```sql
|
Durable Track Builder Task payload persistence was added in Project DB v15.
|
||||||
CREATE TABLE track_sets(
|
|
||||||
track_set_id INTEGER PRIMARY KEY AUTOINCREMENT
|
|
||||||
CHECK(track_set_id > 0),
|
|
||||||
builder_kind TEXT NOT NULL
|
|
||||||
CHECK(length(builder_kind) > 0 AND length(builder_kind) <= 64),
|
|
||||||
builder_version INTEGER NOT NULL CHECK(builder_version > 0),
|
|
||||||
parameter_fingerprint BLOB NOT NULL
|
|
||||||
CHECK(length(parameter_fingerprint) = 32),
|
|
||||||
verifier_kind INTEGER NOT NULL CHECK(verifier_kind > 0),
|
|
||||||
verifier_version INTEGER NOT NULL CHECK(verifier_version > 0),
|
|
||||||
verifier_fingerprint BLOB NOT NULL
|
|
||||||
CHECK(length(verifier_fingerprint) = 32),
|
|
||||||
input_scope_hash BLOB NOT NULL
|
|
||||||
CHECK(length(input_scope_hash) = 32),
|
|
||||||
gvr_count INTEGER NOT NULL CHECK(gvr_count >= 1),
|
|
||||||
track_count INTEGER NOT NULL CHECK(track_count >= 0),
|
|
||||||
created_at INTEGER NOT NULL CHECK(created_at >= 0),
|
|
||||||
UNIQUE(builder_kind, builder_version, parameter_fingerprint,
|
|
||||||
verifier_kind, verifier_version, verifier_fingerprint,
|
|
||||||
input_scope_hash)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE tracks(
|
Later schema migrations through v25 do not reinterpret Track Model v1.
|
||||||
track_id INTEGER PRIMARY KEY AUTOINCREMENT CHECK(track_id > 0),
|
|
||||||
track_set_id INTEGER NOT NULL
|
|
||||||
REFERENCES track_sets(track_set_id) ON DELETE CASCADE,
|
|
||||||
observation_count INTEGER NOT NULL CHECK(observation_count >= 2)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX tracks_set_idx
|
Conceptual tables:
|
||||||
ON tracks(track_set_id, track_id);
|
|
||||||
|
|
||||||
CREATE TABLE track_observations(
|
```text
|
||||||
track_set_id INTEGER NOT NULL,
|
track_sets
|
||||||
track_id INTEGER NOT NULL
|
tracks
|
||||||
REFERENCES tracks(track_id) ON DELETE CASCADE,
|
track_observations
|
||||||
feature_set_id INTEGER NOT NULL
|
|
||||||
REFERENCES feature_sets(feature_set_id),
|
|
||||||
feature_index INTEGER NOT NULL CHECK(feature_index >= 0),
|
|
||||||
position_in_track INTEGER NOT NULL CHECK(position_in_track >= 0),
|
|
||||||
PRIMARY KEY(track_set_id, feature_set_id, feature_index),
|
|
||||||
UNIQUE(track_id, position_in_track)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX track_observations_lookup_idx
|
|
||||||
ON track_observations(feature_set_id, feature_index, track_set_id);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Schema invariants
|
Publication is atomic for the complete Track Set under one transaction.
|
||||||
|
|
||||||
**SQL-enforced :**
|
No Track from that set becomes visible before the complete generation validates and commits.
|
||||||
|
|
||||||
- `track_observations.PRIMARY KEY(track_set_id, feature_set_id, feature_index)`
|
Rollback leaves no partial Track Set.
|
||||||
: dans un Track Set donné, une observation n'apparaît qu'une fois. Cela
|
|
||||||
garantit qu'une observation scientifique appartient à au plus un Track dans
|
|
||||||
ce set.
|
|
||||||
- `REFERENCES tracks(track_id) ON DELETE CASCADE` : l'observation appartient
|
|
||||||
à un track existant ; supprimer le track supprime l'observation.
|
|
||||||
- `REFERENCES feature_sets(feature_set_id)` : le Feature Set existe.
|
|
||||||
- `CHECK(observation_count >= 2)` : minimum structurel.
|
|
||||||
- `UNIQUE(builder_kind, builder_version, parameter_fingerprint,
|
|
||||||
verifier_kind, verifier_version, verifier_fingerprint,
|
|
||||||
input_scope_hash)` sur `track_sets` : identité de reuse, empêche les
|
|
||||||
doublons de set pour une même configuration et un même scope.
|
|
||||||
- `ON DELETE CASCADE` depuis `track_sets` : supprimer un set supprime tout.
|
|
||||||
- `CHECK(feature_index >= 0)` : borne inférieure de l'index.
|
|
||||||
- `UNIQUE(track_id, position_in_track)` : chaque position dans un track est
|
|
||||||
unique. L'ordre est déterminé par le Track Builder lors de la publication.
|
|
||||||
|
|
||||||
**API-enforced :**
|
## Ordering
|
||||||
|
|
||||||
- `track_set_id` dans `track_observations` correspond au `track_set_id` du
|
Track Builder publishes deterministic canonical order.
|
||||||
`track_id` parent. Le schéma ne comporte pas de FK composite (aucun
|
|
||||||
précédent dans le codebase). L'API valide cette cohérence avant INSERT sous
|
|
||||||
`BEGIN IMMEDIATE`.
|
|
||||||
- Une seule observation par image par track. L'API valide via jointure à
|
|
||||||
`feature_sets.image_id`.
|
|
||||||
- `feature_index < feature_sets.feature_count`. L'API valide la borne
|
|
||||||
supérieure.
|
|
||||||
- `observation_count` cohérent avec le nombre réel d'observations insérées.
|
|
||||||
- `track_count` cohérent avec le nombre réel de tracks insérés.
|
|
||||||
- `position_in_track` contigu à partir de 0 pour chaque track.
|
|
||||||
|
|
||||||
### Note sur la dénormalisation
|
`position_in_track` is contiguous from zero.
|
||||||
|
|
||||||
`track_set_id` dans `track_observations` dénormalise une clé grandparent,
|
The exact builder contract owns edge ordering and conflict resolution; Track Model only persists the
|
||||||
après le même pattern utilisé par `visual_index_memberships.visual_index_id`.
|
validated result.
|
||||||
Le pattern parent-key-in-UNIQUE est déjà répandu dans le codebase. La cohérence
|
|
||||||
repose sur le chemin d'écriture unique du Track Builder et la validation API
|
|
||||||
sous transaction.
|
|
||||||
|
|
||||||
`track_observations.track_set_id` n'a pas de FK directe vers `track_sets`
|
No hash-table iteration order may define persistent scientific ordering.
|
||||||
pour éviter un second chemin CASCADE depuis `track_sets` vers
|
|
||||||
`track_observations` (le premier chemin passe par `tracks`). La cohérence
|
|
||||||
est garantie par l'API sous `BEGIN IMMEDIATE`.
|
|
||||||
|
|
||||||
## Provenance
|
## Deletion
|
||||||
|
|
||||||
### Track Set provenance
|
Deleting a Track Set cascades to its Tracks and observations.
|
||||||
|
|
||||||
Chaque Track Set conserve :
|
A Feature Set referenced by a Track observation cannot be silently removed while the reference remains
|
||||||
|
valid.
|
||||||
|
|
||||||
- `builder_kind`, `builder_version`, `parameter_fingerprint` : configuration
|
Deletion semantics do not mutate other immutable Track Sets.
|
||||||
du Track Builder ;
|
|
||||||
- `verifier_kind`, `verifier_version`, `verifier_fingerprint` : configuration
|
|
||||||
du Geometric Verifier consommé ;
|
|
||||||
- `input_scope_hash`, `gvr_count` : ensemble réel des GVR consommés.
|
|
||||||
|
|
||||||
Ces champs suffisent pour identifier la configuration scientifique complète
|
## Pagination and resource bounds
|
||||||
ayant produit le set.
|
|
||||||
|
|
||||||
### Edge provenance (deferred)
|
Track Model storage APIs are paged.
|
||||||
|
|
||||||
En v1, la provenance détaillée (quels GVR spécifiques ont contribué à quel
|
The model does not impose an arbitrary scientific maximum Track length below the number of images that
|
||||||
track individuel) n'est pas persistée. Les raisons :
|
could legitimately observe the same point.
|
||||||
|
|
||||||
- elle peut être reconstruite en comparant les memberships du set aux GVR
|
It does not materialize a dense image-by-image covisibility matrix.
|
||||||
disponibles ;
|
|
||||||
- une table `track_set_sources` volumineuse complexifie la DB sans bénéfice
|
|
||||||
immédiat ;
|
|
||||||
- une future version du Track Builder pourra l'ajouter dans une migration
|
|
||||||
ultérieure.
|
|
||||||
|
|
||||||
## Invalidation
|
Loading one Track loads that Track's observations; project-wide traversal remains paged.
|
||||||
|
|
||||||
### Invalidation scientifique
|
Execution-memory strategy belongs to Track Builder, not Track Model.
|
||||||
|
|
||||||
Un nouveau scope, une nouvelle configuration de verifier ou un nouveau
|
|
||||||
builder produit un **nouveau** Track Set avec une identité différente. Le set
|
|
||||||
précédent reste intact et consultable. Aucune mutation silencieuse n'est
|
|
||||||
permise.
|
|
||||||
|
|
||||||
### Suppression référentielle
|
|
||||||
|
|
||||||
`ON DELETE CASCADE` s'applique :
|
|
||||||
|
|
||||||
- `track_sets` → `tracks` → `track_observations` : supprimer un set supprime
|
|
||||||
tous ses tracks et observations ;
|
|
||||||
- `feature_sets` → (pas de CASCADE vers `track_observations`) : la FK utilise
|
|
||||||
le comportement par défaut (NO ACTION). Supprimer un Feature Set référencé
|
|
||||||
par une observation est interdit tant que l'observation existe.
|
|
||||||
|
|
||||||
## Atomic publication
|
|
||||||
|
|
||||||
L'unité persistante est le Track Set complet. La publication est une seule
|
|
||||||
transaction `BEGIN IMMEDIATE` contenant l'INSERT du set, de tous ses tracks
|
|
||||||
et de toutes ses observations.
|
|
||||||
|
|
||||||
- aucun track n'est visible avant le COMMIT du set entier ;
|
|
||||||
- un rollback ne laisse aucune ligne partielle ;
|
|
||||||
- le `created_at` du set est le timestamp de la transaction ;
|
|
||||||
- le `track_count` et `gvr_count` sont validés contre les INSERTs réels.
|
|
||||||
|
|
||||||
Le Track Builder v1 utilise le Task Runtime pour le checkpoint/reprise et le
|
|
||||||
Resource Governor pour l'admission. Le Model ne contient aucune
|
|
||||||
logique d'exécution.
|
|
||||||
|
|
||||||
## Resource bounds
|
|
||||||
|
|
||||||
- **Pas de plafond de longueur arbitraire** : le Model ne fixe pas de
|
|
||||||
maximum sur le nombre d'observations par Track. Un projet avec N images
|
|
||||||
peut produire des tracks de longueur jusqu'à N.
|
|
||||||
- **Lecture paginée** : `list_tracks` et `list_track_sets` utilisent une
|
|
||||||
page de 64 entrées avec curseur.
|
|
||||||
- **Chargement borné** : load track by id charge les observations du track ;
|
|
||||||
la taille est bornée naturellement par le nombre d'images dans le scope.
|
|
||||||
- **Pas de chargement complet du graphe** : aucune API ne charge tous les
|
|
||||||
tracks et toutes les observations d'un projet en une seule fois.
|
|
||||||
- **Pas de matrice dense** : aucune matrice de co-visibilité N×N n'est
|
|
||||||
matérialisée par le Model.
|
|
||||||
|
|
||||||
## Corruption handling
|
## Corruption handling
|
||||||
|
|
||||||
Le loader doit détecter :
|
A loader returns corruption rather than partial best-effort data when it detects conditions such as:
|
||||||
|
|
||||||
- track absent (`track_id` référencé mais inexistant) ;
|
- missing parent Track or Track Set;
|
||||||
- observation invalide (`feature_set_id` inexistant) ;
|
- missing Feature Set;
|
||||||
- duplicate observation dans un même track set ;
|
- duplicate observation in one Track Set;
|
||||||
- deux observations de la même image dans un même track ;
|
- repeated image inside one Track;
|
||||||
- `feature_index` hors bornes du Feature Set ;
|
- out-of-range feature index;
|
||||||
- `observation_count` incohérent avec le nombre réel d'observations ;
|
- inconsistent observation count;
|
||||||
- `track_set_id` dans `track_observations` ne correspondant pas au
|
- inconsistent Track count;
|
||||||
`track_set_id` du `track_id` parent ;
|
- inconsistent denormalized Track Set ID;
|
||||||
- `track_set` parent absent.
|
- invalid/non-contiguous position ordering.
|
||||||
|
|
||||||
Toute corruption retourne `CORRUPT` sans résultat partiel.
|
No loader repairs scientific identity in place.
|
||||||
|
|
||||||
## API
|
## Provenance
|
||||||
|
|
||||||
L'API publique implémente :
|
Track Set provenance includes:
|
||||||
|
|
||||||
- `lardon3d_project_db_create_track_set()` — INSERT set + ses tracks +
|
```text
|
||||||
observations dans une seule transaction `BEGIN IMMEDIATE`.
|
builder identity
|
||||||
- `lardon3d_project_db_load_track_set()` — SELECT par ID.
|
verifier selector
|
||||||
- `lardon3d_project_db_find_track_set()` — SELECT par identité exacte.
|
input scope hash
|
||||||
- `lardon3d_project_db_list_track_sets()` — SELECT paginé ORDER BY id,
|
gvr count
|
||||||
page 64.
|
```
|
||||||
- `lardon3d_project_db_load_track()` — SELECT par ID avec observations.
|
|
||||||
- `lardon3d_project_db_list_tracks()` — SELECT par set, paginé ORDER BY
|
|
||||||
id, page 64.
|
|
||||||
- `lardon3d_project_db_find_track_by_observation()` — recherche par
|
|
||||||
`(feature_set_id, feature_index)` dans un set donné.
|
|
||||||
|
|
||||||
La création valide en C : existence des Feature Sets, bornes des
|
Detailed per-edge provenance is not persisted by Track Model v1.
|
||||||
`feature_index`, unicité des observations, unicité image par track,
|
|
||||||
`observation_count` cohérent, `track_set_id` cohérent. L'INSERT est
|
|
||||||
transactionnel.
|
|
||||||
|
|
||||||
## Explicitly out of scope
|
Adding such provenance later requires an explicit version/schema decision if persistent representation
|
||||||
|
changes.
|
||||||
|
|
||||||
- Track Builder algorithmique (union-find, connected components) ;
|
## Current production verifier lineage
|
||||||
- triangulation ;
|
|
||||||
- coordonnées 3D ;
|
Fundamental verifier v1 and v2 are historical scientific identities.
|
||||||
- Essential matrix ;
|
|
||||||
|
Current new production verification uses Fundamental v3.
|
||||||
|
|
||||||
|
V3 adds bounded preflight rejection before the unchanged scientific estimator path and has its own
|
||||||
|
fingerprint.
|
||||||
|
|
||||||
|
Track Builder consumes only exact matching GVR identities.
|
||||||
|
|
||||||
|
Therefore:
|
||||||
|
|
||||||
|
```text
|
||||||
|
HISTORICAL_TRACK_SET_VERIFIER_V1=VALID
|
||||||
|
HISTORICAL_TRACK_SET_VERIFIER_V2=VALID
|
||||||
|
CURRENT_TRACK_SET_VERIFIER_V3=PRODUCTION
|
||||||
|
```
|
||||||
|
|
||||||
|
No historical Track Set is upgraded in place.
|
||||||
|
|
||||||
|
## Real S21 evidence
|
||||||
|
|
||||||
|
The retained S21 Track proof is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
REAL_S21_TRACKS=PASS/FROZEN
|
||||||
|
|
||||||
|
Track Set observations = 2,495,768
|
||||||
|
Tracks = 912,447
|
||||||
|
minimum Track length = 2
|
||||||
|
maximum Track length = 42
|
||||||
|
mean Track length = 2.7352470883240341
|
||||||
|
```
|
||||||
|
|
||||||
|
Retained digest:
|
||||||
|
|
||||||
|
```text
|
||||||
|
c30eba192627bf73eaf21ff30d81038d8cc6bbf36a69226f88cdc8c37f7d74a1
|
||||||
|
```
|
||||||
|
|
||||||
|
The compact memory model supersedes the older historical 18.204 GiB envelope.
|
||||||
|
|
||||||
|
That checkpoint did not execute real Sparse SfM.
|
||||||
|
|
||||||
|
## Real A6000 evidence
|
||||||
|
|
||||||
|
The current retained A6000 checkpoint is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
real-a6000-pre-sfm-2026-09-02
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
||||||
|
Track output:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Track Set 1
|
||||||
|
Tracks 130,714
|
||||||
|
Track observations 318,944
|
||||||
|
duplicate obs 0
|
||||||
|
repeated-image 0
|
||||||
|
orphan obs 0
|
||||||
|
```
|
||||||
|
|
||||||
|
The upstream v3 GV scope contained:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Applicable GVRs 37,805
|
||||||
|
Verified GVRs 10,952
|
||||||
|
Rejected GVRs 26,853
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart traversed the retained scope and reused the same Track Set without creating a duplicate
|
||||||
|
scientific generation.
|
||||||
|
|
||||||
|
No Sparse SfM Task or Sparse Reconstruction was created.
|
||||||
|
|
||||||
|
## Sparse SfM relationship
|
||||||
|
|
||||||
|
Track Model does not perform Sparse SfM.
|
||||||
|
|
||||||
|
Sparse SfM capability is nevertheless implemented through Gate G.
|
||||||
|
|
||||||
|
Correct current statement:
|
||||||
|
|
||||||
|
```text
|
||||||
|
TRACK_MODEL_OUTPUT=AVAILABLE
|
||||||
|
SPARSE_SFM_IMPLEMENTATION=AVAILABLE
|
||||||
|
REAL_HISTORICAL_CAMPAIGN_SPARSE_SFM=BLOCKED_BY_KNOWN_CALIBRATION_DATA
|
||||||
|
```
|
||||||
|
|
||||||
|
These are separate lifecycle facts.
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
|
||||||
|
Track Model v1 does not own:
|
||||||
|
|
||||||
|
- Track Builder union/find algorithm;
|
||||||
|
- Fundamental estimation;
|
||||||
|
- Essential estimation;
|
||||||
- camera pose;
|
- camera pose;
|
||||||
- bundle adjustment ;
|
- triangulation;
|
||||||
- sparse reconstruction / Sparse SfM ;
|
- 3D coordinates;
|
||||||
- reprojection error;
|
- reprojection error;
|
||||||
|
- Bundle Adjustment;
|
||||||
- dense reconstruction;
|
- dense reconstruction;
|
||||||
- Track optimization ou merge ;
|
- metric scale;
|
||||||
- mutation de tracks existants ;
|
- Track mutation/merge;
|
||||||
- co-visibilité (matrice ou calcul) ;
|
- selection by "latest".
|
||||||
- sélection par timestamp ou "latest".
|
|
||||||
|
|
||||||
## Track rejected state
|
## Summary
|
||||||
|
|
||||||
Le Model v1 ne persiste pas d'état Track rejected. Le Model représente des
|
```text
|
||||||
Tracks structurellement valides (≥ 2 observations, cohérents). Le Track Builder
|
TRACK_MODEL_V1=FROZEN
|
||||||
v1 décide quels candidats publier. Les candidats non publiés n'existent pas dans
|
TRACK_BUILDER_V1=PASS/FROZEN
|
||||||
le Model ; cette séparation reste la frontière scientifique figée.
|
|
||||||
|
|
||||||
## Versioning
|
CURRENT_PRODUCTION_VERIFIER=FUNDAMENTAL_V3
|
||||||
|
CURRENT_VERIFIER_FINGERPRINT=6944a471d611d8ffc59dac7cf15a5b79b97e2371d4c51785c477d68c1577f74c
|
||||||
|
|
||||||
Project DB v14 introduced the Track storage and v15 adds only durable Track
|
PROJECT_DB_TRACK_MODEL=v14
|
||||||
Builder task payload persistence. `builder_version` et `verifier_version`
|
PROJECT_DB_TRACK_TASK=v15
|
||||||
décrivent indépendamment les contrats scientifiques.
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
Changer un algorithme n'impose une migration DB que si la représentation
|
|
||||||
persistante change.
|
REAL_S21_TRACKS=PASS/FROZEN
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
|
||||||
|
SPARSE_SFM_CAPABILITY=IMPLEMENTED_THROUGH_GATE_G
|
||||||
|
REAL_S21_SPARSE_SFM=NOT_EXECUTED
|
||||||
|
REAL_A6000_SPARSE_SFM=NOT_EXECUTED
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,207 +1,430 @@
|
||||||
# Visual Index v1
|
# Visual Index v1
|
||||||
|
|
||||||
## Problème et frontière
|
## Status
|
||||||
|
|
||||||
Le Visual Index transforme une collection homogène de `FeatureSet` READY en
|
```text
|
||||||
candidats de recherche. Il consomme exclusivement `feature_set_id` et les
|
VISUAL_INDEX_V1=IMPLEMENTED
|
||||||
descripteurs ORB lus par le Feature Reader. Il ne fait ni matching final, ni
|
VISUAL_INDEX_KIND=orb-lsh
|
||||||
ratio test, ni vérification géométrique.
|
VISUAL_INDEX_VERSION=1
|
||||||
|
|
||||||
## Choix algorithmique
|
CANDIDATE_PAIR=IMPLEMENTED
|
||||||
|
MATCHER=IMPLEMENTED
|
||||||
|
|
||||||
La v1 utilise un LSH binaire déterministe à six tables. Chaque table extrait
|
VISUAL_INDEX_GPU=REJECTED_WITH_MEASURED_REASON
|
||||||
24 positions distinctes des 256 bits ORB. La position v1 est
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
`(41*table + 11*bit) mod 256`; 11 étant premier avec 256, les 24 positions
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
d'une table sont distinctes. Une clé est `(table_id, key24)`. Des descripteurs proches en
|
```
|
||||||
Hamming ont une probabilité élevée de collision dans au moins une table, sans
|
|
||||||
conversion flottante.
|
|
||||||
|
|
||||||
Alternatives évaluées :
|
Visual Index turns a homogeneous collection of immutable Feature Sets into bounded image-retrieval
|
||||||
|
candidates.
|
||||||
|
|
||||||
- le hash exact est très compact et déterministe, mais son rappel s'effondre
|
It is a retrieval stage, not a Matcher and not a geometric verifier.
|
||||||
dès qu'un descriptor varie d'un bit ;
|
|
||||||
- le multi-index hashing avec sous-chaînes et multiprobes offre des garanties
|
|
||||||
Hamming intéressantes, mais le nombre de postings/probes nécessaire au
|
|
||||||
rappel utile d'ORB est trop élevé pour une v1 bornée ;
|
|
||||||
- FLANN-LSH masque son format, ses allocations et sa stabilité de
|
|
||||||
sérialisation, ce qui nuit à la reprise et à l'audit ;
|
|
||||||
- BoW/IVF donne un bon retrieval image, mais impose vocabulaire, entraînement,
|
|
||||||
identité et politique de mise à jour avant de pouvoir être incrémental ;
|
|
||||||
- HNSW et FAISS ajoutent une dépendance et un état mutable complexes sans
|
|
||||||
avantage décisif à quelques milliers d'images.
|
|
||||||
|
|
||||||
Ce LSH n'est pas un matcher. Il privilégie une base déterministe, segmentable
|
Current downstream consumers are implemented:
|
||||||
et contrôlable. Une évolution de la sélection de bits exige une nouvelle
|
|
||||||
`visual_index_version`.
|
|
||||||
|
|
||||||
## Identité et configuration
|
```text
|
||||||
|
Feature Store
|
||||||
|
-> Visual Index
|
||||||
|
-> Candidate Pair Generator
|
||||||
|
-> Matcher
|
||||||
|
-> Geometric Verification
|
||||||
|
-> Tracks
|
||||||
|
```
|
||||||
|
|
||||||
Le kind est `orb-lsh`, version 1. Un index contient exclusivement des Feature
|
Older text describing Candidate Pair or Matcher as future consumers is historical design context and is
|
||||||
Sets de même `descriptor_type`, dimension, `extractor_kind`, version et
|
not current status.
|
||||||
`parameter_fingerprint`. Sa configuration v1 contient :
|
|
||||||
|
|
||||||
- `table_count=6` ;
|
## Algorithm
|
||||||
- `key_bits=24` ;
|
|
||||||
- `max_features_per_set` entre 1 et 1024, défaut 512 ;
|
|
||||||
- `max_bucket_postings` entre 1 et 4096, défaut 256 ;
|
|
||||||
- `max_segments=256` ;
|
|
||||||
- `max_feature_sets_per_segment=16`.
|
|
||||||
|
|
||||||
Le fingerprint de paramètres est SHA-256 des 32 octets canoniques
|
Visual Index v1 uses deterministic binary LSH over ORB descriptors.
|
||||||
`L3DVICF1`, version et cinq entiers little-endian. Aucun padding, JSON, locale
|
|
||||||
ou endianness hôte n'intervient. `visual_index_id` est une identité SQLite
|
|
||||||
`AUTOINCREMENT`, jamais réutilisée après publication.
|
|
||||||
|
|
||||||
## Échantillonnage
|
It uses six tables.
|
||||||
|
|
||||||
Au plus `max_features_per_set` features sont indexées. La sélection v1 retient
|
Each table selects 24 distinct positions from the 256 ORB bits.
|
||||||
le préfixe de `feature_index` croissant. Les postings conservent l'indice
|
|
||||||
original. Un Feature Set vide est membre valide sans posting. Le build Task
|
|
||||||
peut lire en parallèle jusqu'à douze Feature Files, avec un reader et une
|
|
||||||
tranche de 256 descripteurs privés par participant effectivement admis. Chaque
|
|
||||||
Feature Set écrit dans une tranche privée de la capacité de postings déjà
|
|
||||||
réservée pour le segment ; le propriétaire compacte ensuite les tranches dans
|
|
||||||
l'ordre de sélection et applique seul l'ordre total persistant.
|
|
||||||
|
|
||||||
## Segments introduits en Project Database v6, conservés en v7
|
The frozen v1 position rule is:
|
||||||
|
|
||||||
Un index logique possède des segments immuables READY. Chaque update publie un
|
```text
|
||||||
segment de un à seize nouveaux Feature Sets, puis ajoute atomiquement segments
|
position = (41 * table + 11 * bit) mod 256
|
||||||
et memberships. `UNIQUE(visual_index_id,feature_set_id)` assure l'idempotence.
|
```
|
||||||
Une recherche copie au début la liste bornée des segments READY, relâche le
|
|
||||||
mutex DB, puis lit ce snapshot. Un segment commité au milieu sera visible à la
|
|
||||||
requête suivante.
|
|
||||||
|
|
||||||
SQLite conserve les tables `visual_indexes`, `visual_index_segments`,
|
A posting key is:
|
||||||
`visual_index_memberships` et `visual_index_update_tasks`. Les gros postings
|
|
||||||
restent hors DB. La configuration et chaque membership sont immuables. La
|
|
||||||
compaction est `NOT_YET_WIRED`; au-delà de 256 segments une update est refusée avec
|
|
||||||
`LARDON3D_VISUAL_INDEX_LIMIT`. Avec seize membres par segment, la capacité v1 est donc
|
|
||||||
exactement 4096 Feature Sets par index. Le refus ne publie ni segment ni membership et
|
|
||||||
l'index existant reste requêtable.
|
|
||||||
|
|
||||||
Le DDL v6 exact est `schema_visual_v6` dans `src/project_db.c`. Il impose
|
```text
|
||||||
`AUTOINCREMENT` aux index/segments, les uniques
|
(table_id, key24)
|
||||||
`(visual_index_id,generation)`, `(visual_index_id,sha256)` et
|
```
|
||||||
`(visual_index_id,feature_set_id)`, ainsi que les FKs vers index, Feature Set,
|
|
||||||
segment et tâche. Les CHECKS bornent tables 1..32, bits 8..32, sampling
|
Changing this bit-selection policy requires a new Visual Index scientific version.
|
||||||
1..1024, bucket 1..4096, membres segment 1..16 et durabilité 0..1. La migration
|
|
||||||
entière reste sous `BEGIN IMMEDIATE` et possède une injection de rollback v6.
|
## Identity and configuration
|
||||||
|
|
||||||
|
Current kind/version:
|
||||||
|
|
||||||
|
```text
|
||||||
|
orb-lsh / 1
|
||||||
|
```
|
||||||
|
|
||||||
|
One index contains Feature Sets with homogeneous:
|
||||||
|
|
||||||
|
- descriptor type;
|
||||||
|
- descriptor dimension;
|
||||||
|
- extractor kind;
|
||||||
|
- extractor version;
|
||||||
|
- extractor parameter fingerprint.
|
||||||
|
|
||||||
|
Frozen v1 configuration contains:
|
||||||
|
|
||||||
|
```text
|
||||||
|
table_count = 6
|
||||||
|
key_bits = 24
|
||||||
|
max_features_per_set = 1..1024, default 512
|
||||||
|
max_bucket_postings = 1..4096, default 256
|
||||||
|
max_segments = 256
|
||||||
|
max_feature_sets_per_segment = 16
|
||||||
|
```
|
||||||
|
|
||||||
|
The canonical parameter fingerprint uses domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
L3DVICF1
|
||||||
|
```
|
||||||
|
|
||||||
|
with explicit little-endian fields.
|
||||||
|
|
||||||
|
No C struct padding, locale or host endianness enters the fingerprint.
|
||||||
|
|
||||||
|
## Sampling
|
||||||
|
|
||||||
|
At most `max_features_per_set` Feature entries are indexed.
|
||||||
|
|
||||||
|
V1 selects the increasing `feature_index` prefix.
|
||||||
|
|
||||||
|
Postings retain the original Feature index.
|
||||||
|
|
||||||
|
An empty Feature Set is a valid member and contributes no posting.
|
||||||
|
|
||||||
|
## Segment persistence
|
||||||
|
|
||||||
|
Project DB v6 introduced Visual Index persistence. v7 retained the model.
|
||||||
|
|
||||||
|
Later schema versions through v25 do not reinterpret Visual Index v1.
|
||||||
|
|
||||||
|
A logical index owns immutable READY segments.
|
||||||
|
|
||||||
|
One update publishes one segment containing between one and sixteen new Feature Sets.
|
||||||
|
|
||||||
|
Membership uniqueness is enforced on:
|
||||||
|
|
||||||
|
```text
|
||||||
|
(visual_index_id, feature_set_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
A query snapshots the bounded READY segment list before asset reads.
|
||||||
|
|
||||||
|
A segment committed after that snapshot is visible to the next query, not retroactively injected into
|
||||||
|
the running query.
|
||||||
|
|
||||||
|
## Capacity
|
||||||
|
|
||||||
|
V1 currently allows:
|
||||||
|
|
||||||
|
```text
|
||||||
|
max_segments = 256
|
||||||
|
max_feature_sets_per_segment = 16
|
||||||
|
```
|
||||||
|
|
||||||
|
Therefore one v1 index can contain exactly up to:
|
||||||
|
|
||||||
|
```text
|
||||||
|
4096 Feature Sets
|
||||||
|
```
|
||||||
|
|
||||||
|
before another update returns the Visual Index limit.
|
||||||
|
|
||||||
|
This is an index-v1 capacity bound, not a project-wide image-count limit.
|
||||||
|
|
||||||
|
Compaction/base-delta redesign remains deferred.
|
||||||
|
|
||||||
## Segment File v1
|
## Segment File v1
|
||||||
|
|
||||||
Le fichier est little-endian et ne sérialise aucune structure C. Layout :
|
Segment File v1 is explicitly little-endian and does not serialize C structs.
|
||||||
|
|
||||||
| Offset | Taille | Champ |
|
Magic:
|
||||||
|---:|---:|---|
|
|
||||||
| 0 | 8 | magic `L3DVIDX\0` |
|
|
||||||
| 8 | 4 | format version 1 |
|
|
||||||
| 12 | 4 | header size 128 |
|
|
||||||
| 16 | 4 | table count |
|
|
||||||
| 20 | 4 | key bits |
|
|
||||||
| 24 | 8 | posting count |
|
|
||||||
| 32 | 8 | member count |
|
|
||||||
| 40 | 8 | postings offset, 128 |
|
|
||||||
| 48 | 8 | total size |
|
|
||||||
| 56 | 32 | index parameter fingerprint |
|
|
||||||
| 88 | 32 | feature parameter fingerprint |
|
|
||||||
| 120 | 8 | réservés, zéro |
|
|
||||||
|
|
||||||
Chaque posting fait 24 octets : `table_id:u32`, `key24:u32`,
|
```text
|
||||||
`feature_set_id:u64`, `feature_index:u32`, réservé zéro `u32`. L'ordre est
|
L3DVIDX\0
|
||||||
`table_id`, clé, Feature Set, feature index. Le fichier exact est SHA-256 et
|
```
|
||||||
vit sous `assets/visual-index/<2 hex>/<sha256 lowercase>`.
|
|
||||||
|
|
||||||
Publication : temporaire local, écriture, `fsync`, hash, `link` sans
|
A posting contains:
|
||||||
écrasement, validation d'une adoption concurrente, `fsync` du répertoire, puis
|
|
||||||
transaction DB. Un échec après publication peut laisser un orphelin mais jamais
|
|
||||||
un segment READY partiel. La durabilité distingue `DURABLE` et
|
|
||||||
`PUBLISHED_NOT_DURABLE`.
|
|
||||||
|
|
||||||
Le reader vérifie le SHA avant le parsing. Un fichier au SHA et aux métadonnées cohérents
|
```text
|
||||||
mais portant une version future produit `UNSUPPORTED_VERSION`; les comptes et produits
|
table_id:u32
|
||||||
d'offset invalides produisent `CORRUPT` avant allocation, conversion ou lecture de posting.
|
key24:u32
|
||||||
|
feature_set_id:u64
|
||||||
|
feature_index:u32
|
||||||
|
reserved_zero:u32
|
||||||
|
```
|
||||||
|
|
||||||
## Recherche, score et bornes
|
Canonical persistent ordering is:
|
||||||
|
|
||||||
L'API est centrée sur `(visual_index_id, query_feature_set_id)`. Elle accepte
|
```text
|
||||||
`ANY_SCANSET`, `SAME_SCANSET` ou `OTHER_SCANSETS`, l'exclusion du même asset,
|
table_id
|
||||||
un minimum de preuves et `top_k` entre 1 et 256. Elle ne retourne jamais le
|
key24
|
||||||
Feature Set ni l'image de requête.
|
feature_set_id
|
||||||
|
feature_index
|
||||||
|
```
|
||||||
|
|
||||||
Une preuve est un `feature_index` de requête distinct ayant au moins une
|
The complete Segment File is content-addressed by SHA-256 under the Visual Index asset tree.
|
||||||
collision avec le candidat. Plusieurs tables, postings ou descriptors du
|
|
||||||
candidat ne multiplient pas cette preuve. Le score final vaut
|
|
||||||
`evidence_count / sampled_query_feature_count` dans `[0,1]`. Le volume du
|
|
||||||
candidat ne peut donc pas augmenter le score sans preuve distincte. L'ordre est
|
|
||||||
score décroissant, preuves décroissantes, `image_id`, puis `feature_set_id`.
|
|
||||||
|
|
||||||
La burstiness est bornée par une contribution maximum par feature de requête
|
## Publication
|
||||||
et candidat. Une première passe additionne la fréquence d'un bucket sur tous
|
|
||||||
les segments du snapshot. Au-delà de `max_bucket_postings`, il est ignoré : un motif
|
|
||||||
très commun ne peut ni allouer une liste géante ni dominer le score. Le reader
|
|
||||||
lit au plus 256 postings par appel. L'accumulateur contient au plus 4096
|
|
||||||
candidats ; les nouveaux candidats sont ignorés après saturation, de manière
|
|
||||||
déterministe par l'ordre des postings. Aucun cache global n'existe et un seul
|
|
||||||
segment est ouvert à la fois.
|
|
||||||
|
|
||||||
Deux updates concurrentes peuvent sélectionner le même lot et construire le même asset.
|
Publication follows the normal immutable-asset pattern:
|
||||||
La transaction SQLite et les contraintes uniques ne laissent publier qu'un segment et
|
|
||||||
un membership par Feature Set; l'autre update échoue/rejoue en no-op. Une query prend son
|
|
||||||
snapshot de métadonnées avant les lectures et ouvre/ferme un seul segment à la fois, y
|
|
||||||
compris avec 250 à 256 segments : le nombre de descripteurs de fichier reste borné.
|
|
||||||
|
|
||||||
## Tâche, reprise et ressources
|
```text
|
||||||
|
local temp
|
||||||
|
-> write
|
||||||
|
-> fsync
|
||||||
|
-> hash
|
||||||
|
-> no-overwrite publication/adoption validation
|
||||||
|
-> fsync directory
|
||||||
|
-> short Project DB transaction
|
||||||
|
```
|
||||||
|
|
||||||
`visual_index.update`, version 1, persiste `visual_index_id` et un curseur
|
A physical file may remain orphaned if DB publication fails after the file is published.
|
||||||
`after_feature_set_id`. Une séquence traite au plus seize Feature Sets non
|
|
||||||
indexés, publie et commit un segment, puis checkpoint. Pause et annulation sont
|
|
||||||
coopératives entre lectures et avant publication ; un segment déjà READY reste
|
|
||||||
valide. La reprise recommence au dernier curseur commité et l'unicité des
|
|
||||||
memberships rend le rejeu idempotent.
|
|
||||||
|
|
||||||
**IMPLEMENTED — parallélisme interne borné.** La Queue exécute toujours un seul
|
No partially committed READY segment is invented.
|
||||||
callback. L'estimation demande jusqu'à seize threads CPU, un slot I/O, GPU zéro,
|
|
||||||
8 Mio fixes et 2 Mio par Feature Set, lot 1..16. Le callback compte comme un
|
|
||||||
participant et crée au plus `cpu_threads - 1` enfants. Chaque enfant lit
|
|
||||||
exclusivement des Feature Files immuables et écrit une tranche privée ; il ne
|
|
||||||
touche ni au handle Project DB partagé, ni au fichier de segment, ni au curseur.
|
|
||||||
Tous les enfants sont joints avant tri, sérialisation, publication asset et
|
|
||||||
transaction SQLite.
|
|
||||||
|
|
||||||
La réduction emploie l'ordre total v1
|
Durability distinguishes:
|
||||||
`table_id,key24,feature_set_id,feature_index`. Le fichier, son SHA-256, le
|
|
||||||
chemin, les memberships, la génération, le fingerprint et les résultats de
|
|
||||||
requête sont donc exactement identiques à un build avec un participant. Une
|
|
||||||
erreur de lecture dans une tranche interdit toute publication ; une création
|
|
||||||
de thread refusée est remplacée par le calcul de cette tranche sur le callback,
|
|
||||||
sans changer la réduction. Le curseur n'avance qu'après la publication
|
|
||||||
transactionnelle du segment, puis le checkpoint existant reste le seul point
|
|
||||||
de reprise Task. `record_batch` reçoit le nombre de Feature Sets réellement
|
|
||||||
commités, la durée réelle et `peak_memory_bytes=0` (inconnue).
|
|
||||||
|
|
||||||
## Complexité et limites
|
```text
|
||||||
|
DURABLE
|
||||||
|
PUBLISHED_NOT_DURABLE
|
||||||
|
```
|
||||||
|
|
||||||
Pour `D` descriptors échantillonnés, construction et disque sont `O(6D)`.
|
## Reader validation
|
||||||
Une requête effectue `O(6Q log P + H)` par segment (`Q<=1024`, `H` hits bornés),
|
|
||||||
pas `O(images²)`. La mémoire build est bornée par les métadonnées, les tranches
|
|
||||||
de 256 descripteurs privées des participants et les postings d'un segment ; les
|
|
||||||
tranches privées partitionnent le buffer de postings existant et ne le
|
|
||||||
dupliquent pas. Chaque participant garde au plus un reader/FD de Feature File.
|
|
||||||
La mémoire query est bornée par 4096 candidats, 256 postings et 256 résultats.
|
|
||||||
À 3700 images et 512 features, environ 11,4
|
|
||||||
millions de postings sont produits. Un test structurel persiste 50 000 Feature Sets puis
|
|
||||||
confirme la pagination par 16 et le refus propre après 4096 memberships. Un index unique
|
|
||||||
ne couvre donc pas encore 50 000 images : le risque principal est le nombre de segments
|
|
||||||
et les seeks. Une compaction/base+delta ou une évolution v2 sera nécessaire, sans changer
|
|
||||||
les identités durables; elle est `NOT_YET_WIRED`.
|
|
||||||
|
|
||||||
Les fixtures de validation incluent un Feature Set vide, un crop réel, une rotation de
|
The reader validates the asset SHA before trusting the format.
|
||||||
8 degrés, deux campagnes, un asset source partagé et une attaque de motif répétitif. Ces
|
|
||||||
tests valident le classement de candidats LSH, jamais une compatibilité géométrique.
|
|
||||||
|
|
||||||
## Frontière future
|
It rejects:
|
||||||
|
|
||||||
Le Candidate Pair Generator pourra filtrer sur score et `evidence_count`, puis
|
- invalid counts;
|
||||||
transmettre `feature_set_id + feature_index` au futur matcher. Le score Visual
|
- invalid offsets;
|
||||||
Index ne constitue jamais une preuve géométrique.
|
- overflow;
|
||||||
|
- malformed reserved fields;
|
||||||
|
- inconsistent DB metadata;
|
||||||
|
- unsupported future version.
|
||||||
|
|
||||||
|
A coherent future format version is `UNSUPPORTED_VERSION`, not generic corruption.
|
||||||
|
|
||||||
|
## Query
|
||||||
|
|
||||||
|
Query identity is centered on:
|
||||||
|
|
||||||
|
```text
|
||||||
|
(visual_index_id, query_feature_set_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
Options include:
|
||||||
|
|
||||||
|
- ScanSet filter;
|
||||||
|
- same/other ScanSet policy;
|
||||||
|
- source-asset exclusion;
|
||||||
|
- minimum evidence count;
|
||||||
|
- `top_k` in `1..256`.
|
||||||
|
|
||||||
|
The source Feature Set/image is never returned as its own candidate.
|
||||||
|
|
||||||
|
## Evidence and score
|
||||||
|
|
||||||
|
One evidence unit is one distinct query `feature_index` that collides with the candidate.
|
||||||
|
|
||||||
|
Multiple tables or candidate postings do not multiply the same query-feature evidence.
|
||||||
|
|
||||||
|
Score:
|
||||||
|
|
||||||
|
```text
|
||||||
|
evidence_count / sampled_query_feature_count
|
||||||
|
```
|
||||||
|
|
||||||
|
Range:
|
||||||
|
|
||||||
|
```text
|
||||||
|
0..1
|
||||||
|
```
|
||||||
|
|
||||||
|
Canonical result order:
|
||||||
|
|
||||||
|
```text
|
||||||
|
score descending
|
||||||
|
evidence_count descending
|
||||||
|
image_id ascending
|
||||||
|
feature_set_id ascending
|
||||||
|
```
|
||||||
|
|
||||||
|
Visual Index score is retrieval evidence only.
|
||||||
|
|
||||||
|
It is not descriptor-match evidence and not geometric evidence.
|
||||||
|
|
||||||
|
## Burstiness bound
|
||||||
|
|
||||||
|
Bucket frequency is bounded across the retained query snapshot.
|
||||||
|
|
||||||
|
A bucket above `max_bucket_postings` is ignored.
|
||||||
|
|
||||||
|
This prevents common patterns from dominating score or creating unbounded posting accumulation.
|
||||||
|
|
||||||
|
The query accumulator is bounded to 4096 candidates and 256 returned results.
|
||||||
|
|
||||||
|
No global query cache is required.
|
||||||
|
|
||||||
|
## Durable Task
|
||||||
|
|
||||||
|
Task Kind:
|
||||||
|
|
||||||
|
```text
|
||||||
|
visual_index.update/1
|
||||||
|
```
|
||||||
|
|
||||||
|
Durable cursor:
|
||||||
|
|
||||||
|
```text
|
||||||
|
after_feature_set_id
|
||||||
|
```
|
||||||
|
|
||||||
|
One sequence handles a bounded admitted set of new Feature Sets, publishes a complete segment, commits
|
||||||
|
memberships, advances the cursor/checkpoint and returns through `sequence_break()` if more work remains.
|
||||||
|
|
||||||
|
Restart resumes from the durable cursor and membership uniqueness makes replay idempotent.
|
||||||
|
|
||||||
|
## Internal parallelism
|
||||||
|
|
||||||
|
The Queue owns one active heavy callback.
|
||||||
|
|
||||||
|
Visual Index may use bounded internal CPU participants inside that callback.
|
||||||
|
|
||||||
|
Current validated shape:
|
||||||
|
|
||||||
|
```text
|
||||||
|
CPU up to 16
|
||||||
|
batch/window 1..16
|
||||||
|
GPU 0
|
||||||
|
fixed RAM approximately 8 MiB
|
||||||
|
per-item RAM approximately 2 MiB
|
||||||
|
```
|
||||||
|
|
||||||
|
Each participant reads immutable Feature data into private work.
|
||||||
|
|
||||||
|
Participants do not publish the segment.
|
||||||
|
|
||||||
|
After join, the owner performs canonical total ordering, serialization, asset publication and Project DB
|
||||||
|
commit.
|
||||||
|
|
||||||
|
Thread-creation failure may fall back to owner computation of that slice without changing output.
|
||||||
|
|
||||||
|
## Determinism
|
||||||
|
|
||||||
|
The following must match the serial scientific result:
|
||||||
|
|
||||||
|
- posting set;
|
||||||
|
- posting order;
|
||||||
|
- Segment File bytes;
|
||||||
|
- SHA-256;
|
||||||
|
- membership set;
|
||||||
|
- generation ordering;
|
||||||
|
- query results.
|
||||||
|
|
||||||
|
Operational CPU width does not enter scientific identity.
|
||||||
|
|
||||||
|
## GPU policy
|
||||||
|
|
||||||
|
Current GPU classification:
|
||||||
|
|
||||||
|
```text
|
||||||
|
VISUAL_INDEX_GPU=REJECTED_WITH_MEASURED_REASON
|
||||||
|
```
|
||||||
|
|
||||||
|
The stage is dominated by posting construction, total ordering, hashing and deterministic publication,
|
||||||
|
and there is no validated production GPU seam that preserves the full contract with useful measured
|
||||||
|
benefit.
|
||||||
|
|
||||||
|
This does not authorize avoidable CPU serialism.
|
||||||
|
|
||||||
|
```text
|
||||||
|
RESOURCE_UTILIZATION_POLICY=MAXIMUM_SAFE_USEFUL_THROUGHPUT
|
||||||
|
SERIALISM_REQUIRES_PROOF=CANONICAL
|
||||||
|
```
|
||||||
|
|
||||||
|
## Current downstream relationship
|
||||||
|
|
||||||
|
Candidate Pair Generator is implemented and consumes Visual Index queries.
|
||||||
|
|
||||||
|
Matcher is implemented and consumes persisted Candidate Pairs.
|
||||||
|
|
||||||
|
Therefore current relationship is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Visual Index
|
||||||
|
-> Candidate Pair Generator
|
||||||
|
-> Candidate Pair persistence
|
||||||
|
-> Matcher
|
||||||
|
```
|
||||||
|
|
||||||
|
Visual Index does not pass raw `feature_set_id + feature_index` pairs directly into a hypothetical
|
||||||
|
future Matcher.
|
||||||
|
|
||||||
|
The persisted Candidate Pair boundary remains explicit.
|
||||||
|
|
||||||
|
## Real A6000 evidence
|
||||||
|
|
||||||
|
The retained A6000 proof contains:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Feature Sets 689
|
||||||
|
Candidate Pairs 38,420
|
||||||
|
Match Results 38,420
|
||||||
|
```
|
||||||
|
|
||||||
|
Final continuation replayed no new Visual Index work.
|
||||||
|
|
||||||
|
Checkpoint:
|
||||||
|
|
||||||
|
```text
|
||||||
|
real-a6000-pre-sfm-2026-09-02
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
||||||
|
This confirms the current Visual Index path was already durably reusable before downstream GV/Tracks
|
||||||
|
continuation.
|
||||||
|
|
||||||
|
## Limits
|
||||||
|
|
||||||
|
Current v1 limits/non-goals include:
|
||||||
|
|
||||||
|
- no segment compaction;
|
||||||
|
- one index limited to 4096 Feature Sets;
|
||||||
|
- no GPU backend;
|
||||||
|
- no geometric meaning assigned to retrieval score;
|
||||||
|
- no dense project-wide pair matrix.
|
||||||
|
|
||||||
|
A future index version may change capacity or data structure only through an explicit versioned
|
||||||
|
scientific/persistence decision.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
```text
|
||||||
|
VISUAL_INDEX_V1=IMPLEMENTED
|
||||||
|
VISUAL_INDEX_KIND=orb-lsh
|
||||||
|
VISUAL_INDEX_VERSION=1
|
||||||
|
VISUAL_INDEX_CAPACITY=4096_FEATURE_SETS
|
||||||
|
VISUAL_INDEX_SEGMENT_MEMBERS=16
|
||||||
|
VISUAL_INDEX_TOP_K_MAX=256
|
||||||
|
|
||||||
|
VISUAL_INDEX_TASK=visual_index.update/1
|
||||||
|
VISUAL_INDEX_GPU=REJECTED_WITH_MEASURED_REASON
|
||||||
|
|
||||||
|
CANDIDATE_PAIR=IMPLEMENTED
|
||||||
|
MATCHER=IMPLEMENTED
|
||||||
|
|
||||||
|
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||||
|
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue