fix(reconstruction): finalize track builder v1 freeze

This commit is contained in:
fy59 2026-08-10 00:25:00 +02:00
parent f1a139e3c1
commit cd6ad105a6
6 changed files with 71 additions and 43 deletions

View file

@ -547,8 +547,8 @@ CREATE INDEX track_observations_lookup_idx
**Statut** : les tables sont créées par la migration et validées par les
tests. L'API C (`create_track_set`, `load_track_set`, `find_track_set`,
`list_track_sets`, `load_track`, `list_tracks`, `find_track_by_observation`)
est exposée et implémentée. Les limites réelles restent l'absence de Track
Builder algorithmique, de tâche dédiée et de triangulation.
est exposée et implémentée. Le Track Builder algorithmique et sa tâche durable
sont implémentés par les Gates AE ; la triangulation reste hors périmètre.
## Schéma v15 — payload durable Track Builder

View file

@ -122,9 +122,9 @@ USAC/MAGSAC avec configuration, seed et fingerprint déterministes.
| **Lien avec le catalogue** | Les tracks référenceront les images par `image_id`, jamais par nom ou chemin. |
| **Persistance** | Les tracks sont persistés entre les sessions de traitement. Un track ne peut être détruit que par une action explicite de l'utilisateur. |
**Statut :** PARTIAL — le Track Model v1 (persistance) est implémenté dans
Project DB v15 (`track_sets`, `tracks`, `track_observations`). Le Track
Builder, la triangulation et le Sparse SfM restent PLANNED.
**Statut :** COMPLETED/FROZEN — le Track Builder v1 direct et durable est
implémenté dans Project DB v15 (`track_sets`, `tracks`, `track_observations` et
le payload de tâche). La triangulation et le Sparse SfM restent PLANNED.
---

View file

@ -2,9 +2,11 @@
## Status
**GATE A — PASS.** This document is the scientific and algorithmic contract
for the future Track Builder. It specifies no implementation, migration or
Task. `FACT`, `DECISION` and `FROZEN` are intentionally distinguished below.
**GATE A — PASS. GATE B — PASS. GATE C — PASS. GATE D — PASS. GATE E — PASS.**
This document is the frozen scientific and algorithmic contract for Track
Builder v1. `FACT`, `DECISION` and `FROZEN` remain distinguished below. Runtime
freeze is limited to the Track Builder v1 task contract; generic Task Runtime
and Resource Governor evolution remains separate.
## Scope
@ -561,14 +563,14 @@ different-scope identity and late matching-GVR exclusion. The test-only phase
seam is compiled only into the Gate C test executable.
Normal and AddressSanitizer/UndefinedBehaviorSanitizer targeted runs pass for
the core and project executables. The 106,496-edge synthetic resource case
completed in 0.281 seconds with a 26,564 KiB process high-water RSS and one
Match File live at a time. C26 has no clean fault injection in the frozen DB
API and C27 belongs to the future concurrency gate.
the core and project executables. The historical 106,496-edge synthetic
resource case completed in 0.281 seconds with a 26,564 KiB fresh-process RSS
and one Match File live at a time. C26 has no clean fault injection in the
frozen DB API; C27 was closed by Gate D.
Gate C status: **PASS**. Gate A: **PASS**. Gate B: **PASS**. Gate D:
**NOT_IMPLEMENTED**. Gate E: **NOT_DONE**. Track Builder v1 is not marked
fully frozen by this document; the future runtime gates remain separate.
Gate C status: **PASS**. Gate D status: **PASS**. Gate E status: **PASS**.
Track Builder v1 is **FROZEN** by this Gate E closure. Future scientific changes
require a new Builder version and explicit identity decision.
## Gate D — durable runtime contract
@ -591,8 +593,7 @@ the task ID, payload format version, scope path, byte size and SHA-256, exact
selector, builder identity, scope hash and count. The scope asset stores field-
by-field little-endian uint64 GVR IDs with explicit magic/version/count/size and
checksum. No native struct dump, SQL text list or arbitrary small ID limit is
allowed. A v14 database remains readable and is upgraded transactionally only
when this payload is actually implemented.
allowed. A v14 database remains readable and is upgraded transactionally to v15.
### Recovery and publication
@ -611,7 +612,7 @@ Pause and cancellation are cooperative at task boundaries and between bounded
GVR units. Gate B is non-preemptible: an active invocation finishes, then pause
or cancellation is observed before publication. Prepublication cancellation
publishes no Track Set; a committed publication remains valid even if a late
cancellation is requested. A deterministic test seam will exercise the Gate C
cancellation is requested. A deterministic test seam exercised the Gate C
late-identity collision: an exact identity conflict is re-looked-up and reused;
an unrelated constraint remains an error.
@ -645,4 +646,4 @@ apparent 1,079,972 KiB result was contaminated cumulative RUSAGE from the
persistent shell that launched direct runs; it was not Track Builder memory.
A normal 250k hardware run completed in 0.368 seconds with 33,228 KiB peak RSS,
MemAvailable loss of 14,108 KiB, no swap delta and zero PSI averages. Gate D
is **PASS**; Gate E remains responsible for final full-suite freeze.
is **PASS**; Gate E final validation and freeze are complete.

View file

@ -7,7 +7,8 @@ géométriquement vérifiées en structures multi-view cohérentes. Il stocke de
ensembles d'observations 2D liées à un même point physique supposé. Il ne
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
Adjustment sont des étapes ultérieures séparées.
Adjustment sont des étapes séparées ; Gate E a gelé le Builder v1 sans
implémenter ces étapes 3D.
## Track definition
@ -22,12 +23,12 @@ triangulation appartient à une étape ultérieure.
La chaîne scientifique correcte est :
```text
Matcher → Match Result → Geometric Verification → Track Builder (futur)
Matcher → Match Result → Geometric Verification → Track Builder v1
→ Track Model → Sparse SfM (futur)
```
Le Matcher ne produit pas les Tracks. Le Track Builder futur les
assemblera à partir des Geometric Verification Results.
Le Matcher ne produit pas les Tracks. Le Track Builder v1 les assemble à partir
des Geometric Verification Results.
## Observation identity
@ -140,7 +141,7 @@ différents. Le reuse est donc scoped à une seule DB projet.
1. **Minimum structurel** : un Track contient au moins 2 observations.
Une seule observation ne constitue aucune relation multi-view. Le futur
Track Builder, la triangulation ou le Sparse SfM pourront appliquer des
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
@ -258,7 +259,7 @@ Track Set supprime ses tracks et observations.
- cohérent avec tous les résultats publiés existants (Feature Sets, Match
Results, GVRs) qui sont immutables après publication.
Le Track Builder futur construira en mémoire, puis publiera un set complet
Le Track Builder v1 construit en mémoire, puis publie un set complet
dans une transaction. Aucun track n'est visible avant que le set entier soit
validé.
@ -405,7 +406,8 @@ track individuel) n'est pas persistée. Les raisons :
disponibles ;
- une table `track_set_sources` volumineuse complexifie la DB sans bénéfice
immédiat ;
- le Track Builder futur pourra l'ajouter dans une migration ultérieure.
- une future version du Track Builder pourra l'ajouter dans une migration
ultérieure.
## Invalidation
@ -437,8 +439,8 @@ et de toutes ses observations.
- 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 futur utilisera le Task Runtime pour le checkpoint/reprise
et le Resource Governor pour l'admission. Le Model ne contient aucune
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
@ -511,13 +513,14 @@ transactionnel.
## Track rejected state
Le Model v1 ne persiste pas d'état Track rejected. Le Model représente des
Tracks structurellement valides (≥ 2 observations, cohérents). Le futur
Track Builder décidera quels candidats publier. Les candidats non publiés
n'existent pas dans le Model.
Tracks structurellement valides (≥ 2 observations, cohérents). Le Track Builder
v1 décide quels candidats publier. Les candidats non publiés n'existent pas dans
le Model ; cette séparation reste la frontière scientifique figée.
## Versioning
Project DB schema version future décrira le stockage Track. `builder_version`
et `verifier_version` décrivent indépendamment les contrats scientifiques.
Project DB v14 introduced the Track storage and v15 adds only durable Track
Builder task payload persistence. `builder_version` et `verifier_version`
décrivent indépendamment les contrats scientifiques.
Changer un algorithme n'impose une migration DB que si la représentation
persistante change.

View file

@ -10,6 +10,10 @@
#include <lardon3d/task_kind_registry.h>
#include <lardon3d/track_builder_project.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LARDON3D_TRACK_BUILDER_TASK_KIND "track_builder.run"
enum {
@ -40,4 +44,8 @@ bool lardon3d_track_builder_task_reconstruct(
const Lardon3DTaskDurableSnapshot *snapshot, void *context,
Lardon3DTaskKindBinding *binding);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -207,18 +207,34 @@ static bool create_v13_database(const char *path) {
}
static bool create_v14_database(const char *path) {
Lardon3DProjectDb *database = NULL;
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
if (lardon3d_project_db_open(path, &database, error) != LARDON3D_PROJECT_DB_OK) return false;
lardon3d_project_db_close(database);
if (!create_v13_database(path)) return false;
sqlite3 *connection = NULL;
if (sqlite3_open(path, &connection) != SQLITE_OK) return false;
bool ok = sqlite3_exec(connection,
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
"DROP TABLE track_builder_tasks;"
"UPDATE metadata SET value=14 WHERE key='schema_version';"
"COMMIT;PRAGMA foreign_keys=ON;",
NULL, NULL, NULL) == SQLITE_OK;
static const char sql[] =
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
"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(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 ON tracks(track_set_id,track_id);"
"CREATE TABLE track_observations(track_set_id INTEGER NOT NULL,track_id INTEGER NOT NULL "
"REFERENCES tracks(track_id) ON DELETE CASCADE,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);UPDATE metadata SET value=14 WHERE key='schema_version';COMMIT;"
"PRAGMA foreign_keys=ON;";
bool ok = sqlite3_exec(connection, sql, NULL, NULL, NULL) == SQLITE_OK;
return sqlite3_close(connection) == SQLITE_OK && ok;
}