feat: add calibration v2 optical state foundation
This commit is contained in:
parent
72375078df
commit
8fee775586
14 changed files with 1225 additions and 49 deletions
|
|
@ -30,7 +30,7 @@ progressive observations and constraints
|
|||
|
||||
### Current Project Database
|
||||
|
||||
The current Project DB schema is **v25**.
|
||||
The current Project DB schema is **v26**.
|
||||
|
||||
The current head is additive:
|
||||
|
||||
|
|
@ -39,6 +39,7 @@ v22 Selected scientific execution foundation
|
|||
v23 Generic optical-context overlay
|
||||
v24 raw.develop.batch/1 persistence
|
||||
v25 features.extract.batch/1 persistence
|
||||
v26 Capture geometric state and exact calibration applicability
|
||||
```
|
||||
|
||||
Earlier schema versions remain valid historical contracts where their own documentation says so.
|
||||
|
|
@ -120,7 +121,7 @@ The following major foundations are implemented and validated at their documente
|
|||
- **Calibration Solver Preflight v1 — PASS**
|
||||
- **Calibration Evidence Solver v1 — IMPLEMENTED / VALIDATED**
|
||||
- **Calibration Tooling planarity alignment — PASS / FROZEN**
|
||||
- **Project DB v24/v25 operational overlays — IMPLEMENTED / VALIDATED**
|
||||
- **Project DB v24/v25/v26 operational overlays — IMPLEMENTED / VALIDATED**
|
||||
- raw.develop.batch/1 durable selected-execution path
|
||||
- features.extract.batch/1 durable selected-execution path
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
|
||||
```text
|
||||
DOCUMENTATION_INDEX=CURRENT
|
||||
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
||||
CURRENT_PRODUCTION_TASK_KINDS=16
|
||||
|
||||
REAL_S21_TRACKS=PASS/FROZEN
|
||||
REAL_A6000_PRE_SFM=PASS/FROZEN
|
||||
PRODUCT_DEFINITION_V1=PASS/FROZEN
|
||||
PROMPT_TREE=CURRENT
|
||||
CURRENT_NEXT=CALIBRATION_WORKFLOW_COORDINATOR
|
||||
CURRENT_NEXT=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
|
||||
```
|
||||
|
||||
This index separates current authority, historical evidence and future product-definition work.
|
||||
|
|
@ -35,13 +35,14 @@ quote an exact API, DDL or constant.
|
|||
## Current repository state
|
||||
|
||||
```text
|
||||
Project DB head v25
|
||||
Project DB head v26
|
||||
Production Task kinds 16
|
||||
|
||||
v22 selected scientific execution foundation
|
||||
v23 generic optical-context overlay
|
||||
v24 raw.develop.batch/1 persistence
|
||||
v25 features.extract.batch/1 persistence
|
||||
v26 Capture geometric state/applicability
|
||||
```
|
||||
|
||||
Canonical resource objective:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ span schema versions. Historical sections remain authoritative for the version t
|
|||
present-tense statements in this document use the current schema head.
|
||||
|
||||
```text
|
||||
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
||||
```
|
||||
|
||||
The current head is additive:
|
||||
|
|
@ -17,10 +17,11 @@ v22 Selected scientific execution foundation PASS / FROZEN
|
|||
v23 Generic optical-context overlay IMPLEMENTED / VALIDATED / REVIEWED
|
||||
v24 raw.develop.batch/1 persistence IMPLEMENTED / VALIDATED
|
||||
v25 features.extract.batch/1 persistence IMPLEMENTED / VALIDATED
|
||||
v26 Capture geometric state and exact calibration applicability PASS / FROZEN
|
||||
```
|
||||
|
||||
Project DB v25 preserves the scientific and persistence meaning of every earlier retained row. No
|
||||
migration from v22 through v25 backfills scientific identity, infers camera/lens identity, invents
|
||||
Project DB v26 preserves the scientific and persistence meaning of every earlier retained row. No
|
||||
migration from v22 through v26 backfills scientific identity, infers camera/lens identity, invents
|
||||
calibration, rewrites Capture identity, or changes historical Task payload interpretation.
|
||||
|
||||
The current real A6000 pre-SfM proof completed the v24 RAW-batch and v25 Feature-batch paths before
|
||||
|
|
@ -201,6 +202,37 @@ Match Results 38,420
|
|||
No acquisition, RAW development, Candidate generation or Matcher replay was required during the
|
||||
final A6000 GV/Tracks continuation.
|
||||
|
||||
### Project DB v26 - Capture geometric state and exact calibration applicability
|
||||
|
||||
**PASS / FROZEN.**
|
||||
|
||||
The v25 -> v26 migration is transactional and additive. It creates empty
|
||||
`capture_geometric_states`, `optical_calibration_applicabilities_v2` and
|
||||
`capture_calibration_selections_v2` tables. It creates no observed state,
|
||||
applicability, selection, calibration profile or scientific identity for a
|
||||
historical row.
|
||||
|
||||
`capture_geometric_states` is Capture-owned evidence, not Capture identity. It
|
||||
references the existing exact v23 body/lens/focal configuration and stores a
|
||||
bounded, versioned tuple of geometry-relevant observations: focus, aperture,
|
||||
stabilization, crop, geometric pipeline, representation and decoded geometry,
|
||||
with explicit metadata or caller-explicit provenance. Unknown is durable but
|
||||
never a default or a compatible value.
|
||||
|
||||
A v26 applicability binds an existing immutable calibration profile to one
|
||||
complete exemplar state. A target Capture is compatible only when its exact
|
||||
configuration and every state field match the exemplar. There is no
|
||||
cross-body/lens/focal substitution, nearby-focus borrowing, interpolation or
|
||||
extrapolation. An incomplete target is `CALIBRATION_REQUIRED`; zero, one and
|
||||
multiple complete candidates resolve respectively to `CALIBRATION_REQUIRED`,
|
||||
resolved and `SELECTION_REQUIRED`. An explicit v26 selection is immutable,
|
||||
idempotent on exact retry, and rejected unless the selected applicability is
|
||||
exactly compatible.
|
||||
|
||||
The v1 optical-profile and calibration-selection APIs/tables remain unchanged.
|
||||
The v26 tables are a separate additive foundation; they do not attach a Sparse
|
||||
calibration scope or transition a selected execution to `READY`.
|
||||
|
||||
## Optical TUI workflow
|
||||
|
||||
The optical TUI uses bounded public APIs and does not write SQLite directly. It can:
|
||||
|
|
@ -860,6 +892,7 @@ v21 -> v22 selected scientific execution + single RAW Task
|
|||
v22 -> v23 generic optical-context overlay
|
||||
v23 -> v24 selected RAW-batch Task persistence
|
||||
v24 -> v25 selected Feature-batch Task persistence
|
||||
v25 -> v26 Capture geometric state + exact calibration applicability
|
||||
```
|
||||
|
||||
Historical version-specific contracts remain valid for the rows and checkpoints they describe.
|
||||
|
|
@ -867,9 +900,9 @@ An older version number is not stale when the text explicitly describes historic
|
|||
|
||||
## Opening and migration
|
||||
|
||||
An empty Project DB is created and migrated through the complete known chain to v25.
|
||||
An empty Project DB is created and migrated through the complete known chain to v26.
|
||||
|
||||
A supported historical DB is migrated sequentially to v25. Each migration is transactional. A
|
||||
A supported historical DB is migrated sequentially to v26. Each migration is transactional. A
|
||||
migration failure rolls back both newly created objects and the schema-version marker for that step,
|
||||
leaving the prior version complete and retryable.
|
||||
|
||||
|
|
@ -880,7 +913,7 @@ The implementation rejects:
|
|||
- impossible version/storage-class combinations;
|
||||
- malformed required durable relationships.
|
||||
|
||||
The migration implementation must recognize only the known sequential range through v25. It must not
|
||||
The migration implementation must recognize only the known sequential range through v26. It must not
|
||||
skip an intermediate contract.
|
||||
|
||||
Important rollback properties retained from historical tests include:
|
||||
|
|
@ -893,6 +926,7 @@ Important rollback properties retained from historical tests include:
|
|||
- v23 failure leaves no partial optical overlay and a true v22;
|
||||
- v24 failure leaves no partial RAW-batch table/marker and a true v23;
|
||||
- v25 failure leaves no partial Feature-batch table/marker and a true v24.
|
||||
- v26 failure leaves no partial geometric-state/applicability tables or marker and a true v25.
|
||||
|
||||
Exact executable migration SQL is owned by `src/project_db.c`. Documentation may summarize it, but
|
||||
must not contradict the source or the FROZEN migration tests.
|
||||
|
|
@ -1055,19 +1089,20 @@ must not be silently reinterpreted as a scientific dataset limit.
|
|||
## Status summary
|
||||
|
||||
```text
|
||||
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
||||
|
||||
v22 selected scientific execution foundation PASS/FROZEN
|
||||
v23 generic optical-context overlay IMPLEMENTED/VALIDATED/REVIEWED
|
||||
v24 raw.develop.batch/1 persistence IMPLEMENTED/VALIDATED
|
||||
v25 features.extract.batch/1 persistence IMPLEMENTED/VALIDATED
|
||||
v26 Capture geometric state/applicability PASS/FROZEN
|
||||
|
||||
REAL_S21_TRACKS PASS/FROZEN
|
||||
REAL_A6000_PRE_SFM PASS/FROZEN
|
||||
```
|
||||
|
||||
Current Project DB opens and migrates supported historical databases through the sequential known
|
||||
chain to v25.
|
||||
chain to v26.
|
||||
|
||||
Historical contracts for Candidate Pair, Matcher, Geometric Verification, Tracks, Sparse SfM,
|
||||
Phase H, Capture/Asset Provenance, campaign execution, Photo Quality and selected scientific
|
||||
|
|
@ -1084,4 +1119,4 @@ No current Project DB migration:
|
|||
- creates a generic dependency DAG;
|
||||
- persists active Resource Governor reservations.
|
||||
|
||||
Future schema changes beyond v25 require explicit human authorization.
|
||||
Future schema changes beyond v26 require explicit human authorization.
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ This document may freeze a product requirement while its implementation remains
|
|||
The following existing boundaries are consumed as-is:
|
||||
|
||||
```text
|
||||
Project DB head v25
|
||||
Project DB head v26
|
||||
Production Task kinds 16
|
||||
Capture / Asset Provenance PASS/FROZEN
|
||||
Acquisition / campaign execution PASS/FROZEN
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ It must not be used to reinterpret FROZEN scientific evidence.
|
|||
## Current repository state
|
||||
|
||||
```text
|
||||
Project DB current schema v25
|
||||
Project DB current schema v26
|
||||
Production Task kinds 16
|
||||
GLOBAL_MAINTENANCE_AUDIT PASS/FROZEN
|
||||
REAL_S21_TRACKS PASS/FROZEN
|
||||
|
|
@ -24,7 +24,7 @@ SOURCE_COMMENT_AUDIT PASS
|
|||
PRODUCT_DEFINITION PASS/FROZEN
|
||||
PROMPT_TREE CURRENT
|
||||
USER_FACING_UI_LANGUAGE_NORMALIZATION PASS
|
||||
CURRENT_NEXT CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION
|
||||
CURRENT_NEXT CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
|
||||
```
|
||||
|
||||
The current Project DB head is additive:
|
||||
|
|
@ -34,6 +34,7 @@ v22 selected scientific execution foundation
|
|||
v23 generic optical-context overlay
|
||||
v24 raw.develop.batch/1 persistence
|
||||
v25 features.extract.batch/1 persistence
|
||||
v26 Capture geometric state + exact calibration applicability
|
||||
```
|
||||
|
||||
Historical references to earlier versions remain valid when they describe the state of their own
|
||||
|
|
@ -529,9 +530,12 @@ silent calibration substitution remains forbidden
|
|||
```
|
||||
|
||||
The current Sparse calibration scope already models membership as `image_id -> calibration_id`; the
|
||||
next dependency is the additive durable heterogeneous-optics/applicability foundation, which must
|
||||
reuse that capability where it proves sufficient. Device-specific autofocus envelopes remain blocked
|
||||
until physical evidence validates them.
|
||||
v26 heterogeneous-optics foundation now durably records Capture geometric state and exact
|
||||
applicability while retaining that per-image scope model. Unknown state remains retained but
|
||||
`CALIBRATION_REQUIRED`, and exact compatibility resolves none/one/many candidates to
|
||||
`CALIBRATION_REQUIRED`/resolved/`SELECTION_REQUIRED`. The next dependency is heterogeneous
|
||||
calibration publication. Device-specific autofocus envelopes remain blocked until physical evidence
|
||||
validates them.
|
||||
|
||||
Calibration Tooling v1 consumes an already acquired Science v1 evidence bundle, validates the bounded
|
||||
contract and produces deterministic `L3DCALB1` v1.
|
||||
|
|
|
|||
|
|
@ -119,6 +119,73 @@ typedef struct {
|
|||
uint64_t sparse_calibration_id;
|
||||
} Lardon3DOpticalCaptureCalibrationSelection;
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_OPTICAL_OBSERVATION_UNKNOWN = 1,
|
||||
LARDON3D_OPTICAL_OBSERVATION_OBSERVED = 2,
|
||||
} Lardon3DOpticalObservationState;
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_OPTICAL_STABILIZATION_UNKNOWN = 1,
|
||||
LARDON3D_OPTICAL_STABILIZATION_OFF = 2,
|
||||
LARDON3D_OPTICAL_STABILIZATION_ON = 3,
|
||||
} Lardon3DOpticalStabilizationState;
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_OPTICAL_GEOMETRIC_STATE_METADATA = 1,
|
||||
LARDON3D_OPTICAL_GEOMETRIC_STATE_CALLER_EXPLICIT = 2,
|
||||
} Lardon3DOpticalGeometricStateProvenance;
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_OPTICAL_CALIBRATION_REQUIRED = 1,
|
||||
LARDON3D_OPTICAL_CALIBRATION_RESOLVED = 2,
|
||||
LARDON3D_OPTICAL_CALIBRATION_SELECTION_REQUIRED = 3,
|
||||
} Lardon3DOpticalCalibrationResolutionKind;
|
||||
|
||||
typedef struct {
|
||||
uint64_t capture_id;
|
||||
uint64_t optical_configuration_id;
|
||||
uint32_t state_version;
|
||||
Lardon3DOpticalGeometricStateProvenance provenance;
|
||||
Lardon3DOpticalObservationState focus_state;
|
||||
/* Focus is an exact, bounded observation token, not a physical-distance or
|
||||
* autofocus domain. Empty is required when focus is explicitly unknown. */
|
||||
char focus_observation[LARDON3D_OPTICAL_TEXT_CAPACITY];
|
||||
Lardon3DOpticalObservationState aperture_state;
|
||||
uint32_t aperture_x1000;
|
||||
Lardon3DOpticalStabilizationState stabilization;
|
||||
Lardon3DOpticalObservationState crop_state;
|
||||
char crop_observation[LARDON3D_OPTICAL_TEXT_CAPACITY];
|
||||
Lardon3DOpticalObservationState pipeline_state;
|
||||
char pipeline_observation[LARDON3D_OPTICAL_TEXT_CAPACITY];
|
||||
Lardon3DOpticalObservationState representation_state;
|
||||
char representation_observation[LARDON3D_OPTICAL_TEXT_CAPACITY];
|
||||
Lardon3DOpticalObservationState decoded_geometry_state;
|
||||
uint32_t decoded_width;
|
||||
uint32_t decoded_height;
|
||||
} Lardon3DOpticalCaptureGeometricState;
|
||||
|
||||
typedef struct {
|
||||
uint64_t applicability_id;
|
||||
uint64_t calibration_profile_id;
|
||||
uint64_t optical_configuration_id;
|
||||
uint64_t exemplar_capture_id;
|
||||
} Lardon3DOpticalCalibrationApplicabilityV2;
|
||||
|
||||
typedef struct {
|
||||
Lardon3DOpticalCalibrationResolutionKind kind;
|
||||
uint64_t applicability_id;
|
||||
uint64_t calibration_profile_id;
|
||||
uint64_t sparse_calibration_id;
|
||||
} Lardon3DOpticalCalibrationResolutionV2;
|
||||
|
||||
typedef struct {
|
||||
uint64_t capture_id;
|
||||
uint64_t applicability_id;
|
||||
uint64_t calibration_profile_id;
|
||||
uint64_t optical_configuration_id;
|
||||
uint64_t sparse_calibration_id;
|
||||
} Lardon3DOpticalCaptureCalibrationSelectionV2;
|
||||
|
||||
/* All profile/config creation calls borrow input only for the call and return a
|
||||
* caller-owned, NUL-terminated copy; input and output storage must not overlap.
|
||||
* The generated row-ID field in a create input must be zero; referenced IDs
|
||||
|
|
@ -247,6 +314,44 @@ Lardon3DProjectDbResult lardon3d_optical_capture_calibration_selection_load(
|
|||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCaptureCalibrationSelection *output);
|
||||
|
||||
/* v26 state is Capture-owned and separate from both Capture identity and the
|
||||
* v23 body/lens/focal configuration. Unknown values remain explicit. Create is
|
||||
* immutable: an exact retry is idempotent and any differing tuple conflicts. */
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_geometric_state_create(
|
||||
Lardon3DProjectDb *database,
|
||||
const Lardon3DOpticalCaptureGeometricState *input,
|
||||
Lardon3DOpticalCaptureGeometricState *output);
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_geometric_state_load(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCaptureGeometricState *output);
|
||||
|
||||
/* Applicability binds an existing v1 calibration profile to the exemplar's
|
||||
* exact configuration and complete observed-state tuple. It authorizes no
|
||||
* body/lens/focal substitution, unknown default, interpolation or extrapolation. */
|
||||
Lardon3DProjectDbResult lardon3d_optical_calibration_applicability_v2_create(
|
||||
Lardon3DProjectDb *database, uint64_t calibration_profile_id,
|
||||
uint64_t exemplar_capture_id,
|
||||
Lardon3DOpticalCalibrationApplicabilityV2 *output);
|
||||
|
||||
/* Resolution counts exact valid applicability rows. NONE is CALIBRATION_REQUIRED,
|
||||
* ONE is RESOLVED, and MANY is SELECTION_REQUIRED. All are successful outcomes. */
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_resolve_v2(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCalibrationResolutionV2 *output);
|
||||
/* Selection requires a complete observed geometric-state tuple and an exactly
|
||||
* compatible applicability; UNKNOWN in any geometry-relevant field is a
|
||||
* CONSTRAINT. The first selection is immutable, exact retry is idempotent, and
|
||||
* a conflicting applicability is rejected without changing the selection. */
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_select_v2(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t applicability_id);
|
||||
/* Loads the Capture's durable v2 selection without creating or changing it.
|
||||
* NOT_FOUND means no selection exists. OK returns the complete stored tuple
|
||||
* only when its applicability remains exactly compatible with the Capture's
|
||||
* complete observed geometric state; broken dependencies are CORRUPT. */
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_selection_load_v2(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCaptureCalibrationSelectionV2 *output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
#include <lardon3d/sparse_sfm_incremental.h>
|
||||
|
||||
enum {
|
||||
/* v25 adds only durable features.extract.batch/1 operational state. The
|
||||
* selected execution remains the immutable ordered image domain; migration
|
||||
* creates no batch association, cursor, Feature Set, or inferred identity. */
|
||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 25,
|
||||
/* v26 additively stores Capture-owned observed geometric state and exact
|
||||
* calibration applicability. Migration does not infer state from v23
|
||||
* configuration or historical calibration selections. */
|
||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 26,
|
||||
LARDON3D_PROJECT_DB_ID_CAPACITY = 65,
|
||||
LARDON3D_PROJECT_DB_KIND_CAPACITY = 65,
|
||||
LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096,
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ Do not return after each file. Do not repeat global A-to-Z audits when unchanged
|
|||
This contract was prepared against the repository state that declares:
|
||||
|
||||
```text
|
||||
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
||||
PRODUCTION_TASK_KINDS=16
|
||||
PRODUCT_DEFINITION_V1=PASS/FROZEN
|
||||
PROMPT_TREE=NEXT
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
## Status
|
||||
|
||||
```text
|
||||
CURRENT_PROJECT_DB_SCHEMA=v25
|
||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
||||
PRODUCTION_TASK_KINDS=16
|
||||
USER_FACING_UI_LANGUAGE_NORMALIZATION=PASS
|
||||
CURRENT_IMPLEMENTATION_CURSOR=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION
|
||||
CURRENT_IMPLEMENTATION_CURSOR=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
|
||||
```
|
||||
|
||||
## Authority
|
||||
|
|
@ -16,7 +16,7 @@ CURRENT_IMPLEMENTATION_CURSOR=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION
|
|||
## CURRENT
|
||||
|
||||
```text
|
||||
Project DB head v25
|
||||
Project DB head v26
|
||||
Production Task kinds 16
|
||||
Feature Store IMPLEMENTED
|
||||
Visual Index IMPLEMENTED
|
||||
|
|
@ -36,6 +36,7 @@ Calibration workflow evidence materialization PASS/FROZEN
|
|||
Calibration workflow selected-execution binding PASS/FROZEN
|
||||
Calibration workflow Tooling/Bootstrap READY PASS/FROZEN
|
||||
Calibration Science v2 heterogeneous optics PASS/FROZEN
|
||||
Calibration v2 optical-state foundation PASS/FROZEN
|
||||
Adaptive capture settings semantics PLANNED
|
||||
Autofocus v2 foundation PLANNED
|
||||
Calibration Tooling planarity alignment PASS/FROZEN
|
||||
|
|
@ -48,6 +49,7 @@ v22 selected scientific execution foundation
|
|||
v23 generic optical-context overlay
|
||||
v24 raw.develop.batch/1
|
||||
v25 features.extract.batch/1
|
||||
v26 Capture geometric state/applicability
|
||||
```
|
||||
|
||||
## FROZEN
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@ CALIBRATION_WORKFLOW_EVIDENCE_MATERIALIZATION_V1=PASS/FROZEN
|
|||
CALIBRATION_WORKFLOW_SELECTED_EXECUTION_BINDING_V1=PASS/FROZEN
|
||||
CALIBRATION_WORKFLOW_TOOLING_BOOTSTRAP_READY_V1=PASS/FROZEN
|
||||
CALIBRATION_SCIENCE_V2=PASS/FROZEN
|
||||
CALIBRATION_V2_HETEROGENEOUS_OPTICS=PLANNED
|
||||
CALIBRATION_V2_HETEROGENEOUS_OPTICS=PASS/FROZEN
|
||||
CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION=PLANNED
|
||||
ADAPTIVE_CAPTURE_SETTINGS_CONTRACT=PLANNED
|
||||
AUTOFOCUS_V2_FOUNDATION=PLANNED
|
||||
CURRENT_CALIBRATION_NEXT=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION
|
||||
CURRENT_CALIBRATION_NEXT=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
|
||||
```
|
||||
|
||||
## Authority
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
IMPLEMENTATION_ORDER=DEPENDENCY_DRIVEN
|
||||
IMPLEMENTATION_AUTHORIZATION=NO
|
||||
STEP_0_USER_FACING_LANGUAGE_NORMALIZATION=PASS
|
||||
CURRENT_NEXT=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION
|
||||
CURRENT_NEXT=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
|
||||
```
|
||||
|
||||
## Authority
|
||||
|
|
@ -22,23 +22,24 @@ Default dependency order:
|
|||
0. user-facing repository/UI language normalization where appropriate — PASS;
|
||||
1. final usable Calibration Science/Tooling/Bootstrap/Workflow v1 compatibility path — PASS/FROZEN;
|
||||
2. Calibration Science v2 design for heterogeneous cameras/lenses/focals, adaptive capture settings and autofocus — PASS/FROZEN;
|
||||
3. Calibration v2 heterogeneous-optics persistence / Tooling / Bootstrap / workflow foundation — CURRENT;
|
||||
4. physical autofocus/optical applicability validation and dedicated calibrated real campaign;
|
||||
5. real Sparse SfM proof;
|
||||
6. durable Dense/OpenMVS orchestration;
|
||||
7. mesh / refinement / texturing / export;
|
||||
8. viewer foundation;
|
||||
9. offline Coverage Analysis scientific contract and implementation;
|
||||
10. multi-campaign registration / fusion;
|
||||
11. generic live acquisition adapter foundation;
|
||||
12. A6000 HDMI integration;
|
||||
13. S21 integration;
|
||||
14. live camera localization;
|
||||
15. live coverage overlay;
|
||||
16. actionable Capture Guidance;
|
||||
17. video ingestion / deterministic keyframes;
|
||||
18. final integration, UX, restart and performance proof;
|
||||
19. Product Definition v1 Definition-of-Done closure.
|
||||
3. Calibration v2 heterogeneous-optics persistence foundation — PASS/FROZEN;
|
||||
4. Heterogeneous calibration publication / Tooling / Bootstrap evolution — CURRENT;
|
||||
5. physical autofocus/optical applicability validation and dedicated calibrated real campaign;
|
||||
6. real Sparse SfM proof;
|
||||
7. durable Dense/OpenMVS orchestration;
|
||||
8. mesh / refinement / texturing / export;
|
||||
9. viewer foundation;
|
||||
10. offline Coverage Analysis scientific contract and implementation;
|
||||
11. multi-campaign registration / fusion;
|
||||
12. generic live acquisition adapter foundation;
|
||||
13. A6000 HDMI integration;
|
||||
14. S21 integration;
|
||||
15. live camera localization;
|
||||
16. live coverage overlay;
|
||||
17. actionable Capture Guidance;
|
||||
18. video ingestion / deterministic keyframes;
|
||||
19. final integration, UX, restart and performance proof;
|
||||
20. Product Definition v1 Definition-of-Done closure.
|
||||
|
||||
## Adjustment rule
|
||||
|
||||
|
|
|
|||
|
|
@ -2062,3 +2062,642 @@ lardon3d_optical_capture_calibration_selection_load(
|
|||
memset(output, 0, sizeof(*output));
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
geometric_state_input_valid(const Lardon3DOpticalCaptureGeometricState *value) {
|
||||
if (!value || !optical_id(value->capture_id) ||
|
||||
!optical_id(value->optical_configuration_id) ||
|
||||
value->state_version == 0 ||
|
||||
(value->provenance != LARDON3D_OPTICAL_GEOMETRIC_STATE_METADATA &&
|
||||
value->provenance != LARDON3D_OPTICAL_GEOMETRIC_STATE_CALLER_EXPLICIT) ||
|
||||
value->focus_state < LARDON3D_OPTICAL_OBSERVATION_UNKNOWN ||
|
||||
value->focus_state > LARDON3D_OPTICAL_OBSERVATION_OBSERVED ||
|
||||
value->aperture_state < LARDON3D_OPTICAL_OBSERVATION_UNKNOWN ||
|
||||
value->aperture_state > LARDON3D_OPTICAL_OBSERVATION_OBSERVED ||
|
||||
value->crop_state < LARDON3D_OPTICAL_OBSERVATION_UNKNOWN ||
|
||||
value->crop_state > LARDON3D_OPTICAL_OBSERVATION_OBSERVED ||
|
||||
value->pipeline_state < LARDON3D_OPTICAL_OBSERVATION_UNKNOWN ||
|
||||
value->pipeline_state > LARDON3D_OPTICAL_OBSERVATION_OBSERVED ||
|
||||
value->representation_state < LARDON3D_OPTICAL_OBSERVATION_UNKNOWN ||
|
||||
value->representation_state > LARDON3D_OPTICAL_OBSERVATION_OBSERVED ||
|
||||
value->decoded_geometry_state < LARDON3D_OPTICAL_OBSERVATION_UNKNOWN ||
|
||||
value->decoded_geometry_state > LARDON3D_OPTICAL_OBSERVATION_OBSERVED ||
|
||||
value->stabilization < LARDON3D_OPTICAL_STABILIZATION_UNKNOWN ||
|
||||
value->stabilization > LARDON3D_OPTICAL_STABILIZATION_ON)
|
||||
return false;
|
||||
const char *tokens[] = {value->focus_observation, value->crop_observation,
|
||||
value->pipeline_observation,
|
||||
value->representation_observation};
|
||||
const Lardon3DOpticalObservationState states[] = {
|
||||
value->focus_state, value->crop_state, value->pipeline_state,
|
||||
value->representation_state};
|
||||
for (size_t index = 0; index < 4; ++index)
|
||||
if (!optical_text(tokens[index], LARDON3D_OPTICAL_TEXT_CAPACITY,
|
||||
states[index] == LARDON3D_OPTICAL_OBSERVATION_UNKNOWN) ||
|
||||
((states[index] == LARDON3D_OPTICAL_OBSERVATION_UNKNOWN) !=
|
||||
(tokens[index][0] == '\0')))
|
||||
return false;
|
||||
return ((value->aperture_state == LARDON3D_OPTICAL_OBSERVATION_UNKNOWN &&
|
||||
value->aperture_x1000 == 0) ||
|
||||
(value->aperture_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->aperture_x1000 > 0)) &&
|
||||
((value->decoded_geometry_state ==
|
||||
LARDON3D_OPTICAL_OBSERVATION_UNKNOWN &&
|
||||
value->decoded_width == 0 && value->decoded_height == 0) ||
|
||||
(value->decoded_geometry_state ==
|
||||
LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->decoded_width > 0 && value->decoded_height > 0));
|
||||
}
|
||||
|
||||
static bool geometric_state_complete(
|
||||
const Lardon3DOpticalCaptureGeometricState *value) {
|
||||
/* UNKNOWN remains valid durable evidence, but it cannot prove geometric
|
||||
compatibility or authorize publication/selection of an applicability. */
|
||||
return value->focus_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->aperture_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->stabilization != LARDON3D_OPTICAL_STABILIZATION_UNKNOWN &&
|
||||
value->crop_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->pipeline_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->representation_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
value->decoded_geometry_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED;
|
||||
}
|
||||
|
||||
static bool read_geometric_state(sqlite3_stmt *statement,
|
||||
Lardon3DOpticalCaptureGeometricState *output) {
|
||||
memset(output, 0, sizeof(*output));
|
||||
for (int column = 0; column < 18; ++column) {
|
||||
bool text = column == 5 || column == 10 || column == 12 || column == 14;
|
||||
if (sqlite3_column_type(statement, column) !=
|
||||
(text ? SQLITE_TEXT : SQLITE_INTEGER))
|
||||
return false;
|
||||
}
|
||||
sqlite3_int64 capture_id = sqlite3_column_int64(statement, 0);
|
||||
sqlite3_int64 configuration_id = sqlite3_column_int64(statement, 1);
|
||||
sqlite3_int64 version = sqlite3_column_int64(statement, 2);
|
||||
sqlite3_int64 aperture = sqlite3_column_int64(statement, 7);
|
||||
sqlite3_int64 decoded_width = sqlite3_column_int64(statement, 16);
|
||||
sqlite3_int64 decoded_height = sqlite3_column_int64(statement, 17);
|
||||
if (capture_id <= 0 || configuration_id <= 0 || version <= 0 ||
|
||||
(uint64_t)version > UINT32_MAX || aperture < 0 ||
|
||||
(uint64_t)aperture > UINT32_MAX || decoded_width < 0 ||
|
||||
(uint64_t)decoded_width > UINT32_MAX || decoded_height < 0 ||
|
||||
(uint64_t)decoded_height > UINT32_MAX)
|
||||
return false;
|
||||
output->capture_id = (uint64_t)capture_id;
|
||||
output->optical_configuration_id = (uint64_t)configuration_id;
|
||||
output->state_version = (uint32_t)version;
|
||||
output->provenance =
|
||||
(Lardon3DOpticalGeometricStateProvenance)sqlite3_column_int64(statement,
|
||||
3);
|
||||
output->focus_state =
|
||||
(Lardon3DOpticalObservationState)sqlite3_column_int64(statement, 4);
|
||||
output->aperture_state =
|
||||
(Lardon3DOpticalObservationState)sqlite3_column_int64(statement, 6);
|
||||
output->aperture_x1000 = (uint32_t)aperture;
|
||||
output->stabilization =
|
||||
(Lardon3DOpticalStabilizationState)sqlite3_column_int64(statement, 8);
|
||||
output->crop_state =
|
||||
(Lardon3DOpticalObservationState)sqlite3_column_int64(statement, 9);
|
||||
output->pipeline_state =
|
||||
(Lardon3DOpticalObservationState)sqlite3_column_int64(statement, 11);
|
||||
output->representation_state =
|
||||
(Lardon3DOpticalObservationState)sqlite3_column_int64(statement, 13);
|
||||
output->decoded_geometry_state =
|
||||
(Lardon3DOpticalObservationState)sqlite3_column_int64(statement, 15);
|
||||
output->decoded_width = (uint32_t)decoded_width;
|
||||
output->decoded_height = (uint32_t)decoded_height;
|
||||
if (!optical_copy_text(statement, 5, output->focus_observation,
|
||||
sizeof(output->focus_observation), true) ||
|
||||
!optical_copy_text(statement, 10, output->crop_observation,
|
||||
sizeof(output->crop_observation), true) ||
|
||||
!optical_copy_text(statement, 12, output->pipeline_observation,
|
||||
sizeof(output->pipeline_observation), true) ||
|
||||
!optical_copy_text(statement, 14, output->representation_observation,
|
||||
sizeof(output->representation_observation), true))
|
||||
return false;
|
||||
return geometric_state_input_valid(output);
|
||||
}
|
||||
|
||||
static const char geometric_state_columns[] =
|
||||
"capture_id,optical_configuration_id,state_version,provenance,focus_state,"
|
||||
"focus_observation,"
|
||||
"aperture_state,aperture_x1000,stabilization,crop_state,crop_observation,"
|
||||
"pipeline_state,"
|
||||
"pipeline_observation,representation_state,representation_observation,"
|
||||
"decoded_geometry_state,"
|
||||
"decoded_width,decoded_height";
|
||||
|
||||
static bool
|
||||
geometric_states_equal(const Lardon3DOpticalCaptureGeometricState *a,
|
||||
const Lardon3DOpticalCaptureGeometricState *b) {
|
||||
return a->capture_id == b->capture_id &&
|
||||
a->optical_configuration_id == b->optical_configuration_id &&
|
||||
a->state_version == b->state_version &&
|
||||
a->provenance == b->provenance && a->focus_state == b->focus_state &&
|
||||
strcmp(a->focus_observation, b->focus_observation) == 0 &&
|
||||
a->aperture_state == b->aperture_state &&
|
||||
a->aperture_x1000 == b->aperture_x1000 &&
|
||||
a->stabilization == b->stabilization &&
|
||||
a->crop_state == b->crop_state &&
|
||||
strcmp(a->crop_observation, b->crop_observation) == 0 &&
|
||||
a->pipeline_state == b->pipeline_state &&
|
||||
strcmp(a->pipeline_observation, b->pipeline_observation) == 0 &&
|
||||
a->representation_state == b->representation_state &&
|
||||
strcmp(a->representation_observation, b->representation_observation) ==
|
||||
0 &&
|
||||
a->decoded_geometry_state == b->decoded_geometry_state &&
|
||||
a->decoded_width == b->decoded_width &&
|
||||
a->decoded_height == b->decoded_height;
|
||||
}
|
||||
|
||||
static Lardon3DProjectDbResult
|
||||
geometric_state_load_locked(Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCaptureGeometricState *output) {
|
||||
char query[768];
|
||||
int length =
|
||||
snprintf(query, sizeof(query),
|
||||
"SELECT %s FROM capture_geometric_states WHERE capture_id=?1",
|
||||
geometric_state_columns);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = length < 0 || (size_t)length >= sizeof(query)
|
||||
? LARDON3D_PROJECT_DB_IO_ERROR
|
||||
: prepare(database, query, &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE)
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
else if (code != SQLITE_ROW)
|
||||
result = sqlite_result(database, code, "load Capture geometric state");
|
||||
else if (!read_geometric_state(statement, output) ||
|
||||
output->capture_id != capture_id ||
|
||||
sqlite3_step(statement) != SQLITE_DONE)
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_geometric_state_load(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCaptureGeometricState *output) {
|
||||
if (output)
|
||||
memset(output, 0, sizeof(*output));
|
||||
if (!database || !optical_id(capture_id) || !output)
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
Lardon3DProjectDbResult result =
|
||||
geometric_state_load_locked(database, capture_id, output);
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
memset(output, 0, sizeof(*output));
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_geometric_state_create(
|
||||
Lardon3DProjectDb *database,
|
||||
const Lardon3DOpticalCaptureGeometricState *input,
|
||||
Lardon3DOpticalCaptureGeometricState *output) {
|
||||
if (output)
|
||||
memset(output, 0, sizeof(*output));
|
||||
if (!database || !output || input == output ||
|
||||
!geometric_state_input_valid(input))
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
Lardon3DProjectDbResult result =
|
||||
execute(database, "BEGIN IMMEDIATE", "begin Capture geometric state");
|
||||
Lardon3DOpticalCaptureAssignment assignment = {0};
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = capture_assignment_load_locked(database, input->capture_id,
|
||||
&assignment);
|
||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||
assignment.optical_configuration_id != input->optical_configuration_id)
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
sqlite3_stmt *statement = NULL;
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = prepare(database,
|
||||
"INSERT OR IGNORE INTO capture_geometric_states "
|
||||
"VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?"
|
||||
"15,?16,?17,?18)",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)input->capture_id);
|
||||
sqlite3_bind_int64(statement, 2,
|
||||
(sqlite3_int64)input->optical_configuration_id);
|
||||
sqlite3_bind_int64(statement, 3, input->state_version);
|
||||
sqlite3_bind_int64(statement, 4, input->provenance);
|
||||
sqlite3_bind_int64(statement, 5, input->focus_state);
|
||||
sqlite3_bind_text(statement, 6, input->focus_observation, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int64(statement, 7, input->aperture_state);
|
||||
sqlite3_bind_int64(statement, 8, input->aperture_x1000);
|
||||
sqlite3_bind_int64(statement, 9, input->stabilization);
|
||||
sqlite3_bind_int64(statement, 10, input->crop_state);
|
||||
sqlite3_bind_text(statement, 11, input->crop_observation, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int64(statement, 12, input->pipeline_state);
|
||||
sqlite3_bind_text(statement, 13, input->pipeline_observation, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int64(statement, 14, input->representation_state);
|
||||
sqlite3_bind_text(statement, 15, input->representation_observation, -1,
|
||||
SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int64(statement, 16, input->decoded_geometry_state);
|
||||
sqlite3_bind_int64(statement, 17, input->decoded_width);
|
||||
sqlite3_bind_int64(statement, 18, input->decoded_height);
|
||||
result = step_done(database, statement, "insert Capture geometric state");
|
||||
statement = NULL;
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
Lardon3DOpticalCaptureGeometricState stored = {0};
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = geometric_state_load_locked(database, input->capture_id, &stored);
|
||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||
!geometric_states_equal(&stored, input))
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
result = optical_commit_or_rollback(database, result,
|
||||
"commit Capture geometric state",
|
||||
"rollback Capture geometric state");
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
*output = stored;
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char exact_state_predicate[] =
|
||||
"t.optical_configuration_id=e.optical_configuration_id AND "
|
||||
"t.state_version=e.state_version AND t.provenance=e.provenance AND "
|
||||
"t.focus_state=e.focus_state AND "
|
||||
"t.focus_observation=e.focus_observation AND "
|
||||
"t.aperture_state=e.aperture_state AND t.aperture_x1000=e.aperture_x1000 "
|
||||
"AND t.stabilization=e.stabilization AND t.crop_state=e.crop_state AND "
|
||||
"t.crop_observation=e.crop_observation AND "
|
||||
"t.pipeline_state=e.pipeline_state AND "
|
||||
"t.pipeline_observation=e.pipeline_observation AND "
|
||||
"t.representation_state=e.representation_state AND "
|
||||
"t.representation_observation=e.representation_observation AND "
|
||||
"t.decoded_geometry_state=e.decoded_geometry_state AND "
|
||||
"t.decoded_width=e.decoded_width AND t.decoded_height=e.decoded_height";
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_optical_calibration_applicability_v2_create(
|
||||
Lardon3DProjectDb *database, uint64_t calibration_profile_id,
|
||||
uint64_t exemplar_capture_id,
|
||||
Lardon3DOpticalCalibrationApplicabilityV2 *output) {
|
||||
if (output)
|
||||
memset(output, 0, sizeof(*output));
|
||||
if (!database || !optical_id(calibration_profile_id) ||
|
||||
!optical_id(exemplar_capture_id) || !output)
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
Lardon3DOpticalCalibrationProfile profile;
|
||||
Lardon3DProjectDbResult result = lardon3d_optical_calibration_profile_load(
|
||||
database, calibration_profile_id, &profile);
|
||||
Lardon3DOpticalCaptureGeometricState state;
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = lardon3d_optical_capture_geometric_state_load(
|
||||
database, exemplar_capture_id, &state);
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
return result;
|
||||
if (profile.optical_configuration_id != state.optical_configuration_id ||
|
||||
!geometric_state_complete(&state))
|
||||
return LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
result = execute(database, "BEGIN IMMEDIATE",
|
||||
"begin calibration applicability v2");
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = prepare(
|
||||
database,
|
||||
"INSERT OR IGNORE INTO "
|
||||
"optical_calibration_applicabilities_v2(calibration_profile_id,optical_"
|
||||
"configuration_id,exemplar_capture_id) VALUES(?1,?2,?3)",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)calibration_profile_id);
|
||||
sqlite3_bind_int64(statement, 2,
|
||||
(sqlite3_int64)state.optical_configuration_id);
|
||||
sqlite3_bind_int64(statement, 3, (sqlite3_int64)exemplar_capture_id);
|
||||
result =
|
||||
step_done(database, statement, "insert calibration applicability v2");
|
||||
statement = NULL;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = prepare(
|
||||
database,
|
||||
"SELECT "
|
||||
"applicability_id,calibration_profile_id,optical_configuration_id,"
|
||||
"exemplar_capture_id FROM optical_calibration_applicabilities_v2 WHERE "
|
||||
"calibration_profile_id=?1 AND exemplar_capture_id=?2",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)calibration_profile_id);
|
||||
sqlite3_bind_int64(statement, 2, (sqlite3_int64)exemplar_capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code != SQLITE_ROW)
|
||||
result = code == SQLITE_DONE
|
||||
? LARDON3D_PROJECT_DB_CORRUPT
|
||||
: sqlite_result(database, code,
|
||||
"load calibration applicability v2");
|
||||
else {
|
||||
sqlite3_int64 applicability_id = sqlite3_column_int64(statement, 0);
|
||||
bool valid = true;
|
||||
for (int column = 0; column < 4; ++column)
|
||||
if (sqlite3_column_type(statement, column) != SQLITE_INTEGER)
|
||||
valid = false;
|
||||
if (!valid || applicability_id <= 0 ||
|
||||
sqlite3_column_int64(statement, 1) !=
|
||||
(sqlite3_int64)calibration_profile_id ||
|
||||
sqlite3_column_int64(statement, 2) !=
|
||||
(sqlite3_int64)state.optical_configuration_id ||
|
||||
sqlite3_column_int64(statement, 3) !=
|
||||
(sqlite3_int64)exemplar_capture_id ||
|
||||
sqlite3_step(statement) != SQLITE_DONE) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
} else {
|
||||
output->applicability_id = (uint64_t)applicability_id;
|
||||
output->calibration_profile_id = calibration_profile_id;
|
||||
output->optical_configuration_id = state.optical_configuration_id;
|
||||
output->exemplar_capture_id = exemplar_capture_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
result = optical_commit_or_rollback(database, result,
|
||||
"commit calibration applicability v2",
|
||||
"rollback calibration applicability v2");
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
memset(output, 0, sizeof(*output));
|
||||
return result;
|
||||
}
|
||||
|
||||
static Lardon3DProjectDbResult
|
||||
exact_candidates_locked(Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
uint64_t required_applicability,
|
||||
Lardon3DOpticalCalibrationResolutionV2 *output,
|
||||
size_t *count) {
|
||||
/* A broken v2 dependency is corruption, not evidence that calibration is
|
||||
required. Validate the target configuration before exact-state filtering. */
|
||||
sqlite3_stmt *validation = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database,
|
||||
"SELECT a.applicability_id FROM optical_calibration_applicabilities_v2 a "
|
||||
"LEFT JOIN capture_geometric_states e ON e.capture_id=a.exemplar_capture_id "
|
||||
"AND e.optical_configuration_id=a.optical_configuration_id LEFT JOIN "
|
||||
"optical_calibration_profiles p ON p.calibration_profile_id=a.calibration_profile_id "
|
||||
"AND p.optical_configuration_id=a.optical_configuration_id LEFT JOIN "
|
||||
"sparse_calibrations s ON s.calibration_id=p.sparse_calibration_id WHERE "
|
||||
"a.optical_configuration_id=(SELECT optical_configuration_id FROM "
|
||||
"capture_geometric_states WHERE capture_id=?1) AND (e.capture_id IS NULL OR "
|
||||
"p.calibration_profile_id IS NULL OR s.calibration_id IS NULL) LIMIT 1",
|
||||
&validation);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(validation, 1, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(validation);
|
||||
if (code == SQLITE_ROW)
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
else if (code != SQLITE_DONE)
|
||||
result = sqlite_result(database, code,
|
||||
"validate calibration applicability v2");
|
||||
}
|
||||
(void)sqlite3_finalize(validation);
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
return result;
|
||||
|
||||
char query[1800];
|
||||
int length = snprintf(
|
||||
query, sizeof(query),
|
||||
"SELECT "
|
||||
"a.applicability_id,a.calibration_profile_id,p.sparse_calibration_id "
|
||||
"FROM capture_geometric_states t JOIN "
|
||||
"optical_calibration_applicabilities_v2 a ON "
|
||||
"a.optical_configuration_id=t.optical_configuration_id JOIN "
|
||||
"capture_geometric_states e ON e.capture_id=a.exemplar_capture_id JOIN "
|
||||
"optical_calibration_profiles p ON "
|
||||
"p.calibration_profile_id=a.calibration_profile_id AND "
|
||||
"p.optical_configuration_id=a.optical_configuration_id JOIN "
|
||||
"sparse_calibrations s ON s.calibration_id=p.sparse_calibration_id WHERE "
|
||||
"t.capture_id=?1 AND %s%s ORDER BY a.applicability_id LIMIT 2",
|
||||
exact_state_predicate,
|
||||
required_applicability ? " AND a.applicability_id=?2" : "");
|
||||
sqlite3_stmt *statement = NULL;
|
||||
result = length < 0 || (size_t)length >= sizeof(query)
|
||||
? LARDON3D_PROJECT_DB_IO_ERROR
|
||||
: prepare(database, query, &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
if (required_applicability)
|
||||
sqlite3_bind_int64(statement, 2, (sqlite3_int64)required_applicability);
|
||||
int code;
|
||||
*count = 0;
|
||||
while (*count < 2 && (code = sqlite3_step(statement)) == SQLITE_ROW) {
|
||||
if (sqlite3_column_type(statement, 0) != SQLITE_INTEGER ||
|
||||
sqlite3_column_type(statement, 1) != SQLITE_INTEGER ||
|
||||
sqlite3_column_type(statement, 2) != SQLITE_INTEGER ||
|
||||
sqlite3_column_int64(statement, 0) <= 0 ||
|
||||
sqlite3_column_int64(statement, 1) <= 0 ||
|
||||
sqlite3_column_int64(statement, 2) <= 0) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
break;
|
||||
}
|
||||
if (*count == 0) {
|
||||
output->applicability_id = (uint64_t)sqlite3_column_int64(statement, 0);
|
||||
output->calibration_profile_id =
|
||||
(uint64_t)sqlite3_column_int64(statement, 1);
|
||||
output->sparse_calibration_id =
|
||||
(uint64_t)sqlite3_column_int64(statement, 2);
|
||||
}
|
||||
++*count;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && code != SQLITE_DONE && *count < 2)
|
||||
result =
|
||||
sqlite_result(database, code, "resolve calibration applicability v2");
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_resolve_v2(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCalibrationResolutionV2 *output) {
|
||||
if (output)
|
||||
memset(output, 0, sizeof(*output));
|
||||
if (!database || !optical_id(capture_id) || !output)
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
Lardon3DOpticalCaptureGeometricState state;
|
||||
Lardon3DProjectDbResult result =
|
||||
lardon3d_optical_capture_geometric_state_load(database, capture_id,
|
||||
&state);
|
||||
if (result == LARDON3D_PROJECT_DB_NOT_FOUND) {
|
||||
/* A real Capture with no observed tuple has no valid applicability. Absence
|
||||
is not permission to fabricate an unknown/default tuple. */
|
||||
Lardon3DProjectDbCapture capture;
|
||||
result = lardon3d_project_db_load_capture(database, capture_id, &capture);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
output->kind = LARDON3D_OPTICAL_CALIBRATION_REQUIRED;
|
||||
return LARDON3D_PROJECT_DB_OK;
|
||||
}
|
||||
}
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
return result;
|
||||
if (!geometric_state_complete(&state)) {
|
||||
output->kind = LARDON3D_OPTICAL_CALIBRATION_REQUIRED;
|
||||
return LARDON3D_PROJECT_DB_OK;
|
||||
}
|
||||
Lardon3DOpticalCaptureCalibrationSelectionV2 selection;
|
||||
result = lardon3d_optical_capture_calibration_selection_load_v2(
|
||||
database, capture_id, &selection);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
output->kind = LARDON3D_OPTICAL_CALIBRATION_RESOLVED;
|
||||
output->applicability_id = selection.applicability_id;
|
||||
output->calibration_profile_id = selection.calibration_profile_id;
|
||||
output->sparse_calibration_id = selection.sparse_calibration_id;
|
||||
return LARDON3D_PROJECT_DB_OK;
|
||||
}
|
||||
if (result != LARDON3D_PROJECT_DB_NOT_FOUND)
|
||||
return result;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
size_t count = 0;
|
||||
result = exact_candidates_locked(database, capture_id, 0, output, &count);
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
if (result != LARDON3D_PROJECT_DB_OK) {
|
||||
memset(output, 0, sizeof(*output));
|
||||
return result;
|
||||
}
|
||||
if (count == 0)
|
||||
output->kind = LARDON3D_OPTICAL_CALIBRATION_REQUIRED;
|
||||
else if (count == 1)
|
||||
output->kind = LARDON3D_OPTICAL_CALIBRATION_RESOLVED;
|
||||
else {
|
||||
memset(output, 0, sizeof(*output));
|
||||
output->kind = LARDON3D_OPTICAL_CALIBRATION_SELECTION_REQUIRED;
|
||||
}
|
||||
return LARDON3D_PROJECT_DB_OK;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult
|
||||
lardon3d_optical_capture_calibration_select_v2(Lardon3DProjectDb *database,
|
||||
uint64_t capture_id,
|
||||
uint64_t applicability_id) {
|
||||
if (!database || !optical_id(capture_id) || !optical_id(applicability_id))
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
Lardon3DOpticalCalibrationResolutionV2 candidate = {0};
|
||||
size_t count = 0;
|
||||
Lardon3DProjectDbResult result = execute(
|
||||
database, "BEGIN IMMEDIATE", "begin Capture calibration selection v2");
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = exact_candidates_locked(database, capture_id, applicability_id,
|
||||
&candidate, &count);
|
||||
if (result == LARDON3D_PROJECT_DB_OK && count != 1)
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
Lardon3DOpticalCaptureGeometricState state = {0};
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = geometric_state_load_locked(database, capture_id, &state);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = prepare(database,
|
||||
"INSERT OR IGNORE INTO capture_calibration_selections_v2 "
|
||||
"VALUES(?1,?2,?3,?4)",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
sqlite3_bind_int64(statement, 2, (sqlite3_int64)applicability_id);
|
||||
sqlite3_bind_int64(statement, 3,
|
||||
(sqlite3_int64)candidate.calibration_profile_id);
|
||||
sqlite3_bind_int64(statement, 4,
|
||||
(sqlite3_int64)state.optical_configuration_id);
|
||||
result = step_done(database, statement,
|
||||
"insert Capture calibration selection v2");
|
||||
statement = NULL;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result =
|
||||
prepare(database,
|
||||
"SELECT "
|
||||
"applicability_id,calibration_profile_id,optical_configuration_"
|
||||
"id FROM capture_calibration_selections_v2 WHERE capture_id=?1",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code != SQLITE_ROW)
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
else if (sqlite3_column_int64(statement, 0) !=
|
||||
(sqlite3_int64)applicability_id ||
|
||||
sqlite3_column_int64(statement, 1) !=
|
||||
(sqlite3_int64)candidate.calibration_profile_id ||
|
||||
sqlite3_column_int64(statement, 2) !=
|
||||
(sqlite3_int64)state.optical_configuration_id)
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
result = optical_commit_or_rollback(
|
||||
database, result, "commit Capture calibration selection v2",
|
||||
"rollback Capture calibration selection v2");
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_selection_load_v2(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||
Lardon3DOpticalCaptureCalibrationSelectionV2 *output) {
|
||||
if (output)
|
||||
memset(output, 0, sizeof(*output));
|
||||
if (!database || !optical_id(capture_id) || !output)
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database,
|
||||
"SELECT "
|
||||
"x.capture_id,x.applicability_id,x.calibration_profile_id,x.optical_"
|
||||
"configuration_id,p.sparse_calibration_id FROM "
|
||||
"capture_calibration_selections_v2 x LEFT JOIN "
|
||||
"optical_calibration_applicabilities_v2 a ON "
|
||||
"a.applicability_id=x.applicability_id AND "
|
||||
"a.calibration_profile_id=x.calibration_profile_id AND "
|
||||
"a.optical_configuration_id=x.optical_configuration_id LEFT JOIN "
|
||||
"optical_calibration_profiles p ON "
|
||||
"p.calibration_profile_id=x.calibration_profile_id WHERE x.capture_id=?1",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE)
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
else if (code != SQLITE_ROW)
|
||||
result = sqlite_result(database, code,
|
||||
"load Capture calibration selection v2");
|
||||
else {
|
||||
for (int i = 0; i < 5; ++i)
|
||||
if (sqlite3_column_type(statement, i) != SQLITE_INTEGER ||
|
||||
sqlite3_column_int64(statement, i) <= 0)
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
output->capture_id = (uint64_t)sqlite3_column_int64(statement, 0);
|
||||
output->applicability_id = (uint64_t)sqlite3_column_int64(statement, 1);
|
||||
output->calibration_profile_id =
|
||||
(uint64_t)sqlite3_column_int64(statement, 2);
|
||||
output->optical_configuration_id =
|
||||
(uint64_t)sqlite3_column_int64(statement, 3);
|
||||
output->sparse_calibration_id =
|
||||
(uint64_t)sqlite3_column_int64(statement, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
Lardon3DOpticalCalibrationResolutionV2 candidate = {0};
|
||||
size_t count = 0;
|
||||
result = exact_candidates_locked(
|
||||
database, capture_id, output->applicability_id, &candidate, &count);
|
||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||
(count != 1 ||
|
||||
candidate.calibration_profile_id != output->calibration_profile_id ||
|
||||
candidate.sparse_calibration_id != output->sparse_calibration_id))
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
memset(output, 0, sizeof(*output));
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
108
src/project_db.c
108
src/project_db.c
|
|
@ -882,6 +882,84 @@ static const char schema_feature_extract_batch_v25[] =
|
|||
"parameter_fingerprint BLOB NOT NULL CHECK(typeof(parameter_fingerprint)='blob' AND "
|
||||
"length(parameter_fingerprint)=32));";
|
||||
|
||||
/* PERSISTENCE CONTRACT v26: state is immutable Capture-owned evidence. An
|
||||
applicability uses an exemplar only as the exact tuple source; the Capture
|
||||
ID is not calibration identity. DDL-only migration fabricates no evidence. */
|
||||
static const char schema_optical_geometric_state_v26[] =
|
||||
"CREATE TABLE capture_geometric_states("
|
||||
"capture_id INTEGER PRIMARY KEY REFERENCES captures(capture_id) ON DELETE "
|
||||
"CASCADE,"
|
||||
"optical_configuration_id INTEGER NOT NULL,state_version INTEGER NOT NULL "
|
||||
"CHECK(state_version>0 AND state_version<=4294967295),"
|
||||
"provenance INTEGER NOT NULL CHECK(provenance IN(1,2)),focus_state INTEGER "
|
||||
"NOT NULL CHECK(focus_state IN(1,2)),"
|
||||
"focus_observation TEXT NOT NULL CHECK(typeof(focus_observation)='text' "
|
||||
"AND length(focus_observation)<128 AND ((focus_state=1 AND "
|
||||
"length(focus_observation)=0) OR (focus_state=2 AND "
|
||||
"length(focus_observation)>0))),"
|
||||
"aperture_state INTEGER NOT NULL CHECK(aperture_state "
|
||||
"IN(1,2)),aperture_x1000 INTEGER NOT NULL CHECK(aperture_x1000>=0 AND "
|
||||
"aperture_x1000<=4294967295 AND ((aperture_state=1 AND aperture_x1000=0) "
|
||||
"OR (aperture_state=2 AND aperture_x1000>0))),"
|
||||
"stabilization INTEGER NOT NULL CHECK(stabilization IN(1,2,3)),crop_state "
|
||||
"INTEGER NOT NULL CHECK(crop_state IN(1,2)),"
|
||||
"crop_observation TEXT NOT NULL CHECK(typeof(crop_observation)='text' AND "
|
||||
"length(crop_observation)<128 AND ((crop_state=1 AND "
|
||||
"length(crop_observation)=0) OR (crop_state=2 AND "
|
||||
"length(crop_observation)>0))),"
|
||||
"pipeline_state INTEGER NOT NULL CHECK(pipeline_state "
|
||||
"IN(1,2)),pipeline_observation TEXT NOT NULL "
|
||||
"CHECK(typeof(pipeline_observation)='text' AND "
|
||||
"length(pipeline_observation)<128 AND ((pipeline_state=1 AND "
|
||||
"length(pipeline_observation)=0) OR (pipeline_state=2 AND "
|
||||
"length(pipeline_observation)>0))),"
|
||||
"representation_state INTEGER NOT NULL CHECK(representation_state "
|
||||
"IN(1,2)),representation_observation TEXT NOT NULL "
|
||||
"CHECK(typeof(representation_observation)='text' AND "
|
||||
"length(representation_observation)<128 AND ((representation_state=1 AND "
|
||||
"length(representation_observation)=0) OR (representation_state=2 AND "
|
||||
"length(representation_observation)>0))),"
|
||||
"decoded_geometry_state INTEGER NOT NULL CHECK(decoded_geometry_state "
|
||||
"IN(1,2)),decoded_width INTEGER NOT NULL CHECK(decoded_width>=0 AND "
|
||||
"decoded_width<=4294967295),decoded_height INTEGER NOT NULL "
|
||||
"CHECK(decoded_height>=0 AND decoded_height<=4294967295),"
|
||||
"CHECK((decoded_geometry_state=1 AND decoded_width=0 AND decoded_height=0) "
|
||||
"OR (decoded_geometry_state=2 AND decoded_width>0 AND decoded_height>0)),"
|
||||
"UNIQUE(capture_id,optical_configuration_id),FOREIGN "
|
||||
"KEY(capture_id,optical_configuration_id) REFERENCES "
|
||||
"capture_optical_configurations(capture_id,optical_configuration_id));"
|
||||
"CREATE INDEX capture_geometric_states_exact_idx ON "
|
||||
"capture_geometric_states(optical_configuration_id,state_version,focus_"
|
||||
"state,focus_observation,aperture_state,aperture_x1000,stabilization,crop_"
|
||||
"state,crop_observation,pipeline_state,pipeline_observation,representation_"
|
||||
"state,representation_observation,decoded_geometry_state,decoded_width,"
|
||||
"decoded_height);"
|
||||
"CREATE TABLE optical_calibration_applicabilities_v2(applicability_id "
|
||||
"INTEGER PRIMARY KEY AUTOINCREMENT "
|
||||
"CHECK(applicability_id>0),calibration_profile_id INTEGER NOT "
|
||||
"NULL,optical_configuration_id INTEGER NOT NULL,exemplar_capture_id "
|
||||
"INTEGER NOT NULL,"
|
||||
"UNIQUE(calibration_profile_id,exemplar_capture_id),UNIQUE(applicability_"
|
||||
"id,calibration_profile_id,optical_configuration_id),"
|
||||
"FOREIGN KEY(calibration_profile_id,optical_configuration_id) REFERENCES "
|
||||
"optical_calibration_profiles(calibration_profile_id,optical_configuration_"
|
||||
"id),"
|
||||
"FOREIGN KEY(exemplar_capture_id,optical_configuration_id) REFERENCES "
|
||||
"capture_geometric_states(capture_id,optical_configuration_id));"
|
||||
"CREATE INDEX optical_calibration_applicabilities_v2_config_idx ON "
|
||||
"optical_calibration_applicabilities_v2(optical_configuration_id,"
|
||||
"applicability_id);"
|
||||
"CREATE TABLE capture_calibration_selections_v2(capture_id INTEGER PRIMARY "
|
||||
"KEY,applicability_id INTEGER NOT NULL,calibration_profile_id INTEGER NOT "
|
||||
"NULL,optical_configuration_id INTEGER NOT NULL,"
|
||||
"FOREIGN KEY(capture_id,optical_configuration_id) REFERENCES "
|
||||
"capture_geometric_states(capture_id,optical_configuration_id),"
|
||||
"FOREIGN "
|
||||
"KEY(applicability_id,calibration_profile_id,optical_configuration_id) "
|
||||
"REFERENCES "
|
||||
"optical_calibration_applicabilities_v2(applicability_id,calibration_"
|
||||
"profile_id,optical_configuration_id));";
|
||||
|
||||
static void copy_error(char destination[LARDON3D_PROJECT_DB_ERROR_CAPACITY], const char *text) {
|
||||
if (destination) {
|
||||
(void)snprintf(destination, LARDON3D_PROJECT_DB_ERROR_CAPACITY, "%s", text ? text : "");
|
||||
|
|
@ -975,7 +1053,7 @@ static Lardon3DProjectDbResult migrate(Lardon3DProjectDb *database, unsigned int
|
|||
from_version != 12 && from_version != 13 && from_version != 14 &&
|
||||
from_version != 15 && from_version != 16 && from_version != 17 && from_version != 18 &&
|
||||
from_version != 19 && from_version != 20 && from_version != 21 && from_version != 22 &&
|
||||
from_version != 23 && from_version != 24) {
|
||||
from_version != 23 && from_version != 24 && from_version != 25) {
|
||||
return LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
Lardon3DProjectDbResult result = execute(database, "BEGIN IMMEDIATE", "begin migration");
|
||||
|
|
@ -1486,6 +1564,21 @@ static Lardon3DProjectDbResult migrate(Lardon3DProjectDb *database, unsigned int
|
|||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && from_version < 26) {
|
||||
/* Historical rows do not contain focus/pipeline/decode observations, so
|
||||
migration is strictly additive DDL and leaves every v2 table empty. */
|
||||
result = execute(database, schema_optical_geometric_state_v26,
|
||||
"migrate optical geometric state v25 to v26");
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(database,
|
||||
"UPDATE metadata SET value=26 WHERE "
|
||||
"key='schema_version' AND value=25",
|
||||
"finish schema v26 migration");
|
||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||
sqlite3_changes(database->connection) != 1)
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(database, "COMMIT", "commit migration");
|
||||
}
|
||||
|
|
@ -1641,6 +1734,9 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
|||
"capture_optical_configurations",
|
||||
"optical_calibration_profiles",
|
||||
"capture_calibration_selections"};
|
||||
const char *required_v26[] = {"capture_geometric_states",
|
||||
"optical_calibration_applicabilities_v2",
|
||||
"capture_calibration_selections_v2"};
|
||||
for (size_t index = 0; index < sizeof(required) / sizeof(required[0]) &&
|
||||
result == LARDON3D_PROJECT_DB_OK;
|
||||
++index) {
|
||||
|
|
@ -1649,6 +1745,16 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
|||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
}
|
||||
for (size_t index = 0;
|
||||
index < sizeof(required_v26) / sizeof(required_v26[0]) &&
|
||||
result == LARDON3D_PROJECT_DB_OK;
|
||||
++index) {
|
||||
if (!table_exists(database->connection, required_v26[index])) {
|
||||
copy_error(database->error,
|
||||
"Current Project DB v26 schema is incomplete.");
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != LARDON3D_PROJECT_DB_OK) {
|
||||
copy_error(error, database->error);
|
||||
|
|
|
|||
|
|
@ -1147,6 +1147,9 @@ static bool downgrade_to_v22_fixture(const char *path) {
|
|||
return raw_sql(
|
||||
path,
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE IF EXISTS capture_calibration_selections_v2;"
|
||||
"DROP TABLE IF EXISTS optical_calibration_applicabilities_v2;"
|
||||
"DROP TABLE IF EXISTS capture_geometric_states;"
|
||||
"DROP TABLE IF EXISTS feature_extract_batch_tasks;"
|
||||
"DROP TABLE raw_development_batch_tasks;"
|
||||
"DROP TABLE capture_calibration_selections;"
|
||||
|
|
@ -1160,6 +1163,275 @@ static bool downgrade_to_v22_fixture(const char *path) {
|
|||
"UPDATE metadata SET value=22 WHERE key='schema_version';COMMIT;");
|
||||
}
|
||||
|
||||
static bool test_v26_exact_geometric_applicability(void) {
|
||||
char directory[64];
|
||||
char path[256];
|
||||
CHECK(make_database_path(directory, path));
|
||||
Lardon3DProjectDb *database = NULL;
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
||||
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
RepairOpticalFixture fixture;
|
||||
CHECK(seed_repair_optical_fixture(database, &fixture));
|
||||
CHECK(lardon3d_optical_capture_assign_explicit(database, fixture.capture_id,
|
||||
fixture.configuration_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
|
||||
Lardon3DProjectDbCapture peer;
|
||||
Lardon3DProjectDbCapture alternate;
|
||||
CHECK(lardon3d_project_db_create_capture(database, fixture.scanset_id, 2,
|
||||
&peer) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_create_capture(database, fixture.scanset_id, 3,
|
||||
&alternate) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_assign_explicit(database, peer.capture_id,
|
||||
fixture.configuration_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||
database, alternate.capture_id,
|
||||
fixture.alternate_configuration_id) == LARDON3D_PROJECT_DB_OK);
|
||||
|
||||
Lardon3DOpticalCalibrationResolutionV2 resolution;
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, fixture.capture_id, &resolution) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||
|
||||
/* Positive applicability fixtures must fully observe every field capable of
|
||||
changing geometry; UNKNOWN is exercised separately below. */
|
||||
Lardon3DOpticalCaptureGeometricState state = {
|
||||
.capture_id = fixture.capture_id,
|
||||
.optical_configuration_id = fixture.configuration_id,
|
||||
.state_version = 1,
|
||||
.provenance = LARDON3D_OPTICAL_GEOMETRIC_STATE_METADATA,
|
||||
.focus_state = LARDON3D_OPTICAL_OBSERVATION_OBSERVED,
|
||||
.aperture_state = LARDON3D_OPTICAL_OBSERVATION_OBSERVED,
|
||||
.aperture_x1000 = 5600,
|
||||
.stabilization = LARDON3D_OPTICAL_STABILIZATION_OFF,
|
||||
.crop_state = LARDON3D_OPTICAL_OBSERVATION_OBSERVED,
|
||||
.pipeline_state = LARDON3D_OPTICAL_OBSERVATION_OBSERVED,
|
||||
.representation_state = LARDON3D_OPTICAL_OBSERVATION_OBSERVED,
|
||||
.decoded_geometry_state = LARDON3D_OPTICAL_OBSERVATION_OBSERVED,
|
||||
.decoded_width = 6000,
|
||||
.decoded_height = 4000,
|
||||
};
|
||||
memcpy(state.focus_observation, "af-s", sizeof("af-s"));
|
||||
memcpy(state.crop_observation, "full-sensor", sizeof("full-sensor"));
|
||||
memcpy(state.pipeline_observation, "raw-policy-v1", sizeof("raw-policy-v1"));
|
||||
memcpy(state.representation_observation, "L3DRAWD1-png",
|
||||
sizeof("L3DRAWD1-png"));
|
||||
Lardon3DOpticalCaptureGeometricState stored;
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(stored.focus_state == LARDON3D_OPTICAL_OBSERVATION_OBSERVED &&
|
||||
strcmp(stored.focus_observation, "af-s") == 0);
|
||||
Lardon3DOpticalCaptureGeometricState retry;
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &state, &retry) == LARDON3D_PROJECT_DB_OK &&
|
||||
retry.capture_id == state.capture_id);
|
||||
state.decoded_width = 5999;
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &state, &retry) == LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
state.decoded_width = 6000;
|
||||
|
||||
state.capture_id = peer.capture_id;
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||
state.capture_id = alternate.capture_id;
|
||||
state.optical_configuration_id = fixture.alternate_configuration_id;
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||
state.optical_configuration_id = fixture.configuration_id;
|
||||
|
||||
Lardon3DSparseCalibration calibration;
|
||||
CHECK(create_sparse_calibration(database, 0xa6, 6000, 4000, &calibration));
|
||||
Lardon3DOpticalCalibrationProfile profile_input = {
|
||||
.optical_configuration_id = fixture.configuration_id,
|
||||
.sparse_calibration_id = calibration.calibration_id,
|
||||
.profile_version = 2,
|
||||
.applicability = LARDON3D_OPTICAL_CALIBRATION_EXACT_CONFIGURATION,
|
||||
.created_at = 100,
|
||||
};
|
||||
memcpy(profile_input.name, "v26 exact A", sizeof("v26 exact A"));
|
||||
memcpy(profile_input.provenance, "v26 test", sizeof("v26 test"));
|
||||
Lardon3DOpticalCalibrationProfile profile_a;
|
||||
CHECK(lardon3d_optical_calibration_profile_create(
|
||||
database, &profile_input, &profile_a) == LARDON3D_PROJECT_DB_OK);
|
||||
memcpy(profile_input.name, "v26 exact B", sizeof("v26 exact B"));
|
||||
Lardon3DOpticalCalibrationProfile profile_b;
|
||||
CHECK(lardon3d_optical_calibration_profile_create(
|
||||
database, &profile_input, &profile_b) == LARDON3D_PROJECT_DB_OK);
|
||||
|
||||
Lardon3DProjectDbCapture incomplete_exemplar;
|
||||
CHECK(lardon3d_project_db_create_capture(database, fixture.scanset_id, 11,
|
||||
&incomplete_exemplar) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_optical_capture_assign_explicit(
|
||||
database, incomplete_exemplar.capture_id,
|
||||
fixture.configuration_id) == LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DOpticalCaptureGeometricState incomplete_state = state;
|
||||
incomplete_state.capture_id = incomplete_exemplar.capture_id;
|
||||
incomplete_state.focus_state = LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
incomplete_state.focus_observation[0] = '\0';
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &incomplete_state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DOpticalCalibrationApplicabilityV2 rejected_applicability;
|
||||
CHECK(lardon3d_optical_calibration_applicability_v2_create(
|
||||
database, profile_a.calibration_profile_id,
|
||||
incomplete_exemplar.capture_id, &rejected_applicability) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT &&
|
||||
rejected_applicability.applicability_id == 0);
|
||||
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, peer.capture_id, &resolution) == LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||
Lardon3DOpticalCalibrationApplicabilityV2 applicability_a;
|
||||
CHECK(lardon3d_optical_calibration_applicability_v2_create(
|
||||
database, profile_a.calibration_profile_id, fixture.capture_id,
|
||||
&applicability_a) == LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DOpticalCalibrationApplicabilityV2 applicability_retry;
|
||||
CHECK(lardon3d_optical_calibration_applicability_v2_create(
|
||||
database, profile_a.calibration_profile_id, fixture.capture_id,
|
||||
&applicability_retry) == LARDON3D_PROJECT_DB_OK &&
|
||||
applicability_retry.applicability_id ==
|
||||
applicability_a.applicability_id);
|
||||
|
||||
for (uint32_t unknown_field = 0; unknown_field < 7; ++unknown_field) {
|
||||
Lardon3DProjectDbCapture unresolved;
|
||||
CHECK(lardon3d_project_db_create_capture(
|
||||
database, fixture.scanset_id, 4 + unknown_field, &unresolved) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_optical_capture_assign_explicit(
|
||||
database, unresolved.capture_id, fixture.configuration_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DOpticalCaptureGeometricState unresolved_state = state;
|
||||
unresolved_state.capture_id = unresolved.capture_id;
|
||||
if (unknown_field == 0) {
|
||||
unresolved_state.focus_state = LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
unresolved_state.focus_observation[0] = '\0';
|
||||
} else if (unknown_field == 1) {
|
||||
unresolved_state.aperture_state = LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
unresolved_state.aperture_x1000 = 0;
|
||||
} else if (unknown_field == 2) {
|
||||
unresolved_state.stabilization = LARDON3D_OPTICAL_STABILIZATION_UNKNOWN;
|
||||
} else if (unknown_field == 3) {
|
||||
unresolved_state.crop_state = LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
unresolved_state.crop_observation[0] = '\0';
|
||||
} else if (unknown_field == 4) {
|
||||
unresolved_state.pipeline_state = LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
unresolved_state.pipeline_observation[0] = '\0';
|
||||
} else if (unknown_field == 5) {
|
||||
unresolved_state.representation_state =
|
||||
LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
unresolved_state.representation_observation[0] = '\0';
|
||||
} else {
|
||||
unresolved_state.decoded_geometry_state =
|
||||
LARDON3D_OPTICAL_OBSERVATION_UNKNOWN;
|
||||
unresolved_state.decoded_width = 0;
|
||||
unresolved_state.decoded_height = 0;
|
||||
}
|
||||
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||
database, &unresolved_state, &stored) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, unresolved.capture_id, &resolution) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||
database, unresolved.capture_id,
|
||||
applicability_a.applicability_id) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
Lardon3DOpticalCaptureCalibrationSelectionV2 unresolved_selection;
|
||||
CHECK(lardon3d_optical_capture_calibration_selection_load_v2(
|
||||
database, unresolved.capture_id, &unresolved_selection) ==
|
||||
LARDON3D_PROJECT_DB_NOT_FOUND &&
|
||||
unresolved_selection.capture_id == 0);
|
||||
}
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, peer.capture_id, &resolution) == LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_RESOLVED &&
|
||||
resolution.calibration_profile_id == profile_a.calibration_profile_id);
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, alternate.capture_id, &resolution) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||
|
||||
Lardon3DOpticalCalibrationApplicabilityV2 applicability_b;
|
||||
CHECK(lardon3d_optical_calibration_applicability_v2_create(
|
||||
database, profile_b.calibration_profile_id, fixture.capture_id,
|
||||
&applicability_b) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, peer.capture_id, &resolution) == LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_SELECTION_REQUIRED);
|
||||
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||
database, peer.capture_id, applicability_a.applicability_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||
database, peer.capture_id, applicability_a.applicability_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||
database, peer.capture_id, applicability_b.applicability_id) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||
database, alternate.capture_id, applicability_a.applicability_id) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
Lardon3DOpticalCaptureCalibrationSelectionV2 selection;
|
||||
CHECK(lardon3d_optical_capture_calibration_selection_load_v2(
|
||||
database, peer.capture_id, &selection) == LARDON3D_PROJECT_DB_OK &&
|
||||
selection.calibration_profile_id == profile_a.calibration_profile_id &&
|
||||
selection.sparse_calibration_id == calibration.calibration_id);
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, peer.capture_id, &resolution) == LARDON3D_PROJECT_DB_OK &&
|
||||
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_RESOLVED &&
|
||||
resolution.applicability_id == applicability_a.applicability_id);
|
||||
|
||||
lardon3d_project_db_close(database);
|
||||
char corruption[256];
|
||||
int corruption_bytes = snprintf(
|
||||
corruption, sizeof(corruption),
|
||||
"PRAGMA foreign_keys=OFF;DELETE FROM capture_geometric_states WHERE "
|
||||
"capture_id=%llu;",
|
||||
(unsigned long long)fixture.capture_id);
|
||||
CHECK(corruption_bytes > 0 &&
|
||||
(size_t)corruption_bytes < sizeof(corruption) &&
|
||||
raw_sql(path, corruption));
|
||||
database = NULL;
|
||||
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||
database, peer.capture_id, &resolution) ==
|
||||
LARDON3D_PROJECT_DB_CORRUPT);
|
||||
lardon3d_project_db_close(database);
|
||||
/* A v25 project contains no durable observation from which v26 state could
|
||||
be inferred. Re-migration therefore recreates only empty additive tables.
|
||||
*/
|
||||
CHECK(raw_sql(
|
||||
path, "PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE capture_calibration_selections_v2;"
|
||||
"DROP TABLE optical_calibration_applicabilities_v2;"
|
||||
"DROP TABLE capture_geometric_states;"
|
||||
"UPDATE metadata SET value=25 WHERE key='schema_version';COMMIT;"));
|
||||
database = NULL;
|
||||
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
lardon3d_project_db_close(database);
|
||||
sqlite3_int64 migrated_count = -1;
|
||||
CHECK(raw_integer(path, "SELECT COUNT(*) FROM capture_geometric_states",
|
||||
&migrated_count) &&
|
||||
migrated_count == 0);
|
||||
CHECK(raw_integer(
|
||||
path, "SELECT COUNT(*) FROM optical_calibration_applicabilities_v2",
|
||||
&migrated_count) &&
|
||||
migrated_count == 0);
|
||||
CHECK(raw_integer(path,
|
||||
"SELECT COUNT(*) FROM capture_calibration_selections_v2",
|
||||
&migrated_count) &&
|
||||
migrated_count == 0);
|
||||
CHECK(unlink(path) == 0);
|
||||
CHECK(rmdir(directory) == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_migration_rollback_retry_and_equivalence(void) {
|
||||
char migrated_directory[64];
|
||||
char migrated_path[256];
|
||||
|
|
@ -1232,6 +1504,9 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
|
|||
"capture_optical_configurations",
|
||||
"optical_calibration_profiles",
|
||||
"capture_calibration_selections",
|
||||
"capture_geometric_states",
|
||||
"optical_calibration_applicabilities_v2",
|
||||
"capture_calibration_selections_v2",
|
||||
};
|
||||
char query[256];
|
||||
for (size_t index = 0; index < sizeof(empty_tables) / sizeof(empty_tables[0]);
|
||||
|
|
@ -1263,6 +1538,11 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
|
|||
"optical_calibration_profiles_config_idx",
|
||||
"optical_calibration_profiles_sparse_idx",
|
||||
"capture_calibration_selections",
|
||||
"capture_geometric_states",
|
||||
"capture_geometric_states_exact_idx",
|
||||
"optical_calibration_applicabilities_v2",
|
||||
"optical_calibration_applicabilities_v2_config_idx",
|
||||
"capture_calibration_selections_v2",
|
||||
};
|
||||
char migrated_sql[8192];
|
||||
char fresh_sql[8192];
|
||||
|
|
@ -1283,6 +1563,7 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
|
|||
|
||||
int main(void) {
|
||||
return test_profiles_assignments_and_calibrations() &&
|
||||
test_v26_exact_geometric_applicability() &&
|
||||
test_calibration_conflict_result_contract() &&
|
||||
test_calibration_dependency_corruption_precedence() &&
|
||||
test_campaign_request_corruption_prevents_optics_mutation() &&
|
||||
|
|
|
|||
Loading…
Reference in a new issue