feat: add calibration v2 optical state foundation

This commit is contained in:
fy59 2026-09-03 12:51:15 +02:00
parent 72375078df
commit 8fee775586
14 changed files with 1225 additions and 49 deletions

View file

@ -30,7 +30,7 @@ progressive observations and constraints
### Current Project Database ### Current Project Database
The current Project DB schema is **v25**. The current Project DB schema is **v26**.
The current head is additive: The current head is additive:
@ -39,6 +39,7 @@ v22 Selected scientific execution foundation
v23 Generic optical-context overlay v23 Generic optical-context overlay
v24 raw.develop.batch/1 persistence v24 raw.develop.batch/1 persistence
v25 features.extract.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. 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 Solver Preflight v1 — PASS**
- **Calibration Evidence Solver v1 — IMPLEMENTED / VALIDATED** - **Calibration Evidence Solver v1 — IMPLEMENTED / VALIDATED**
- **Calibration Tooling planarity alignment — PASS / FROZEN** - **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 - raw.develop.batch/1 durable selected-execution path
- features.extract.batch/1 durable selected-execution path - features.extract.batch/1 durable selected-execution path

View file

@ -4,14 +4,14 @@
```text ```text
DOCUMENTATION_INDEX=CURRENT DOCUMENTATION_INDEX=CURRENT
CURRENT_PROJECT_DB_SCHEMA=v25 CURRENT_PROJECT_DB_SCHEMA=v26
CURRENT_PRODUCTION_TASK_KINDS=16 CURRENT_PRODUCTION_TASK_KINDS=16
REAL_S21_TRACKS=PASS/FROZEN REAL_S21_TRACKS=PASS/FROZEN
REAL_A6000_PRE_SFM=PASS/FROZEN REAL_A6000_PRE_SFM=PASS/FROZEN
PRODUCT_DEFINITION_V1=PASS/FROZEN PRODUCT_DEFINITION_V1=PASS/FROZEN
PROMPT_TREE=CURRENT 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. 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 ## Current repository state
```text ```text
Project DB head v25 Project DB head v26
Production Task kinds 16 Production Task kinds 16
v22 selected scientific execution foundation v22 selected scientific execution foundation
v23 generic optical-context overlay v23 generic optical-context overlay
v24 raw.develop.batch/1 persistence v24 raw.develop.batch/1 persistence
v25 features.extract.batch/1 persistence v25 features.extract.batch/1 persistence
v26 Capture geometric state/applicability
``` ```
Canonical resource objective: Canonical resource objective:

View file

@ -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. present-tense statements in this document use the current schema head.
```text ```text
CURRENT_PROJECT_DB_SCHEMA=v25 CURRENT_PROJECT_DB_SCHEMA=v26
``` ```
The current head is additive: The current head is additive:
@ -17,10 +17,11 @@ v22 Selected scientific execution foundation PASS / FROZEN
v23 Generic optical-context overlay IMPLEMENTED / VALIDATED / REVIEWED v23 Generic optical-context overlay IMPLEMENTED / VALIDATED / REVIEWED
v24 raw.develop.batch/1 persistence IMPLEMENTED / VALIDATED v24 raw.develop.batch/1 persistence IMPLEMENTED / VALIDATED
v25 features.extract.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 Project DB v26 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 migration from v22 through v26 backfills scientific identity, infers camera/lens identity, invents
calibration, rewrites Capture identity, or changes historical Task payload interpretation. 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 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 No acquisition, RAW development, Candidate generation or Matcher replay was required during the
final A6000 GV/Tracks continuation. 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 ## Optical TUI workflow
The optical TUI uses bounded public APIs and does not write SQLite directly. It can: 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 v22 -> v23 generic optical-context overlay
v23 -> v24 selected RAW-batch Task persistence v23 -> v24 selected RAW-batch Task persistence
v24 -> v25 selected Feature-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. 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 ## 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, migration failure rolls back both newly created objects and the schema-version marker for that step,
leaving the prior version complete and retryable. leaving the prior version complete and retryable.
@ -880,7 +913,7 @@ The implementation rejects:
- impossible version/storage-class combinations; - impossible version/storage-class combinations;
- malformed required durable relationships. - 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. skip an intermediate contract.
Important rollback properties retained from historical tests include: 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; - v23 failure leaves no partial optical overlay and a true v22;
- v24 failure leaves no partial RAW-batch table/marker and a true v23; - 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. - 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 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. 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 ## Status summary
```text ```text
CURRENT_PROJECT_DB_SCHEMA=v25 CURRENT_PROJECT_DB_SCHEMA=v26
v22 selected scientific execution foundation PASS/FROZEN v22 selected scientific execution foundation PASS/FROZEN
v23 generic optical-context overlay IMPLEMENTED/VALIDATED/REVIEWED v23 generic optical-context overlay IMPLEMENTED/VALIDATED/REVIEWED
v24 raw.develop.batch/1 persistence IMPLEMENTED/VALIDATED v24 raw.develop.batch/1 persistence IMPLEMENTED/VALIDATED
v25 features.extract.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_S21_TRACKS PASS/FROZEN
REAL_A6000_PRE_SFM PASS/FROZEN REAL_A6000_PRE_SFM PASS/FROZEN
``` ```
Current Project DB opens and migrates supported historical databases through the sequential known 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, Historical contracts for Candidate Pair, Matcher, Geometric Verification, Tracks, Sparse SfM,
Phase H, Capture/Asset Provenance, campaign execution, Photo Quality and selected scientific 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; - creates a generic dependency DAG;
- persists active Resource Governor reservations. - persists active Resource Governor reservations.
Future schema changes beyond v25 require explicit human authorization. Future schema changes beyond v26 require explicit human authorization.

View file

@ -111,7 +111,7 @@ This document may freeze a product requirement while its implementation remains
The following existing boundaries are consumed as-is: The following existing boundaries are consumed as-is:
```text ```text
Project DB head v25 Project DB head v26
Production Task kinds 16 Production Task kinds 16
Capture / Asset Provenance PASS/FROZEN Capture / Asset Provenance PASS/FROZEN
Acquisition / campaign execution PASS/FROZEN Acquisition / campaign execution PASS/FROZEN

View file

@ -11,7 +11,7 @@ It must not be used to reinterpret FROZEN scientific evidence.
## Current repository state ## Current repository state
```text ```text
Project DB current schema v25 Project DB current schema v26
Production Task kinds 16 Production Task kinds 16
GLOBAL_MAINTENANCE_AUDIT PASS/FROZEN GLOBAL_MAINTENANCE_AUDIT PASS/FROZEN
REAL_S21_TRACKS PASS/FROZEN REAL_S21_TRACKS PASS/FROZEN
@ -24,7 +24,7 @@ SOURCE_COMMENT_AUDIT PASS
PRODUCT_DEFINITION PASS/FROZEN PRODUCT_DEFINITION PASS/FROZEN
PROMPT_TREE CURRENT PROMPT_TREE CURRENT
USER_FACING_UI_LANGUAGE_NORMALIZATION PASS 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: The current Project DB head is additive:
@ -34,6 +34,7 @@ v22 selected scientific execution foundation
v23 generic optical-context overlay v23 generic optical-context overlay
v24 raw.develop.batch/1 persistence v24 raw.develop.batch/1 persistence
v25 features.extract.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 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 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 v26 heterogeneous-optics foundation now durably records Capture geometric state and exact
reuse that capability where it proves sufficient. Device-specific autofocus envelopes remain blocked applicability while retaining that per-image scope model. Unknown state remains retained but
until physical evidence validates them. `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 Calibration Tooling v1 consumes an already acquired Science v1 evidence bundle, validates the bounded
contract and produces deterministic `L3DCALB1` v1. contract and produces deterministic `L3DCALB1` v1.

View file

@ -119,6 +119,73 @@ typedef struct {
uint64_t sparse_calibration_id; uint64_t sparse_calibration_id;
} Lardon3DOpticalCaptureCalibrationSelection; } 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 /* 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. * 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 * 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, Lardon3DProjectDb *database, uint64_t capture_id,
Lardon3DOpticalCaptureCalibrationSelection *output); 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -11,10 +11,10 @@
#include <lardon3d/sparse_sfm_incremental.h> #include <lardon3d/sparse_sfm_incremental.h>
enum { enum {
/* v25 adds only durable features.extract.batch/1 operational state. The /* v26 additively stores Capture-owned observed geometric state and exact
* selected execution remains the immutable ordered image domain; migration * calibration applicability. Migration does not infer state from v23
* creates no batch association, cursor, Feature Set, or inferred identity. */ * configuration or historical calibration selections. */
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 25, LARDON3D_PROJECT_DB_SCHEMA_VERSION = 26,
LARDON3D_PROJECT_DB_ID_CAPACITY = 65, LARDON3D_PROJECT_DB_ID_CAPACITY = 65,
LARDON3D_PROJECT_DB_KIND_CAPACITY = 65, LARDON3D_PROJECT_DB_KIND_CAPACITY = 65,
LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096, LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096,

View file

@ -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: This contract was prepared against the repository state that declares:
```text ```text
CURRENT_PROJECT_DB_SCHEMA=v25 CURRENT_PROJECT_DB_SCHEMA=v26
PRODUCTION_TASK_KINDS=16 PRODUCTION_TASK_KINDS=16
PRODUCT_DEFINITION_V1=PASS/FROZEN PRODUCT_DEFINITION_V1=PASS/FROZEN
PROMPT_TREE=NEXT PROMPT_TREE=NEXT

View file

@ -3,10 +3,10 @@
## Status ## Status
```text ```text
CURRENT_PROJECT_DB_SCHEMA=v25 CURRENT_PROJECT_DB_SCHEMA=v26
PRODUCTION_TASK_KINDS=16 PRODUCTION_TASK_KINDS=16
USER_FACING_UI_LANGUAGE_NORMALIZATION=PASS USER_FACING_UI_LANGUAGE_NORMALIZATION=PASS
CURRENT_IMPLEMENTATION_CURSOR=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION CURRENT_IMPLEMENTATION_CURSOR=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
``` ```
## Authority ## Authority
@ -16,7 +16,7 @@ CURRENT_IMPLEMENTATION_CURSOR=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION
## CURRENT ## CURRENT
```text ```text
Project DB head v25 Project DB head v26
Production Task kinds 16 Production Task kinds 16
Feature Store IMPLEMENTED Feature Store IMPLEMENTED
Visual Index IMPLEMENTED Visual Index IMPLEMENTED
@ -36,6 +36,7 @@ Calibration workflow evidence materialization PASS/FROZEN
Calibration workflow selected-execution binding PASS/FROZEN Calibration workflow selected-execution binding PASS/FROZEN
Calibration workflow Tooling/Bootstrap READY PASS/FROZEN Calibration workflow Tooling/Bootstrap READY PASS/FROZEN
Calibration Science v2 heterogeneous optics PASS/FROZEN Calibration Science v2 heterogeneous optics PASS/FROZEN
Calibration v2 optical-state foundation PASS/FROZEN
Adaptive capture settings semantics PLANNED Adaptive capture settings semantics PLANNED
Autofocus v2 foundation PLANNED Autofocus v2 foundation PLANNED
Calibration Tooling planarity alignment PASS/FROZEN Calibration Tooling planarity alignment PASS/FROZEN
@ -48,6 +49,7 @@ v22 selected scientific execution foundation
v23 generic optical-context overlay v23 generic optical-context overlay
v24 raw.develop.batch/1 v24 raw.develop.batch/1
v25 features.extract.batch/1 v25 features.extract.batch/1
v26 Capture geometric state/applicability
``` ```
## FROZEN ## FROZEN

View file

@ -18,10 +18,11 @@ CALIBRATION_WORKFLOW_EVIDENCE_MATERIALIZATION_V1=PASS/FROZEN
CALIBRATION_WORKFLOW_SELECTED_EXECUTION_BINDING_V1=PASS/FROZEN CALIBRATION_WORKFLOW_SELECTED_EXECUTION_BINDING_V1=PASS/FROZEN
CALIBRATION_WORKFLOW_TOOLING_BOOTSTRAP_READY_V1=PASS/FROZEN CALIBRATION_WORKFLOW_TOOLING_BOOTSTRAP_READY_V1=PASS/FROZEN
CALIBRATION_SCIENCE_V2=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 ADAPTIVE_CAPTURE_SETTINGS_CONTRACT=PLANNED
AUTOFOCUS_V2_FOUNDATION=PLANNED AUTOFOCUS_V2_FOUNDATION=PLANNED
CURRENT_CALIBRATION_NEXT=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION CURRENT_CALIBRATION_NEXT=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
``` ```
## Authority ## Authority

View file

@ -6,7 +6,7 @@
IMPLEMENTATION_ORDER=DEPENDENCY_DRIVEN IMPLEMENTATION_ORDER=DEPENDENCY_DRIVEN
IMPLEMENTATION_AUTHORIZATION=NO IMPLEMENTATION_AUTHORIZATION=NO
STEP_0_USER_FACING_LANGUAGE_NORMALIZATION=PASS STEP_0_USER_FACING_LANGUAGE_NORMALIZATION=PASS
CURRENT_NEXT=CALIBRATION_V2_HETEROGENEOUS_OPTICS_FOUNDATION CURRENT_NEXT=CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION
``` ```
## Authority ## Authority
@ -22,23 +22,24 @@ Default dependency order:
0. user-facing repository/UI language normalization where appropriate — PASS; 0. user-facing repository/UI language normalization where appropriate — PASS;
1. final usable Calibration Science/Tooling/Bootstrap/Workflow v1 compatibility path — PASS/FROZEN; 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; 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; 3. Calibration v2 heterogeneous-optics persistence foundation — PASS/FROZEN;
4. physical autofocus/optical applicability validation and dedicated calibrated real campaign; 4. Heterogeneous calibration publication / Tooling / Bootstrap evolution — CURRENT;
5. real Sparse SfM proof; 5. physical autofocus/optical applicability validation and dedicated calibrated real campaign;
6. durable Dense/OpenMVS orchestration; 6. real Sparse SfM proof;
7. mesh / refinement / texturing / export; 7. durable Dense/OpenMVS orchestration;
8. viewer foundation; 8. mesh / refinement / texturing / export;
9. offline Coverage Analysis scientific contract and implementation; 9. viewer foundation;
10. multi-campaign registration / fusion; 10. offline Coverage Analysis scientific contract and implementation;
11. generic live acquisition adapter foundation; 11. multi-campaign registration / fusion;
12. A6000 HDMI integration; 12. generic live acquisition adapter foundation;
13. S21 integration; 13. A6000 HDMI integration;
14. live camera localization; 14. S21 integration;
15. live coverage overlay; 15. live camera localization;
16. actionable Capture Guidance; 16. live coverage overlay;
17. video ingestion / deterministic keyframes; 17. actionable Capture Guidance;
18. final integration, UX, restart and performance proof; 18. video ingestion / deterministic keyframes;
19. Product Definition v1 Definition-of-Done closure. 19. final integration, UX, restart and performance proof;
20. Product Definition v1 Definition-of-Done closure.
## Adjustment rule ## Adjustment rule

View file

@ -2062,3 +2062,642 @@ lardon3d_optical_capture_calibration_selection_load(
memset(output, 0, sizeof(*output)); memset(output, 0, sizeof(*output));
return result; 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;
}

View file

@ -882,6 +882,84 @@ static const char schema_feature_extract_batch_v25[] =
"parameter_fingerprint BLOB NOT NULL CHECK(typeof(parameter_fingerprint)='blob' AND " "parameter_fingerprint BLOB NOT NULL CHECK(typeof(parameter_fingerprint)='blob' AND "
"length(parameter_fingerprint)=32));"; "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) { static void copy_error(char destination[LARDON3D_PROJECT_DB_ERROR_CAPACITY], const char *text) {
if (destination) { if (destination) {
(void)snprintf(destination, LARDON3D_PROJECT_DB_ERROR_CAPACITY, "%s", text ? text : ""); (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 != 12 && from_version != 13 && from_version != 14 &&
from_version != 15 && from_version != 16 && from_version != 17 && from_version != 18 && 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 != 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; return LARDON3D_PROJECT_DB_CORRUPT;
} }
Lardon3DProjectDbResult result = execute(database, "BEGIN IMMEDIATE", "begin migration"); Lardon3DProjectDbResult result = execute(database, "BEGIN IMMEDIATE", "begin migration");
@ -1486,6 +1564,21 @@ static Lardon3DProjectDbResult migrate(Lardon3DProjectDb *database, unsigned int
result = LARDON3D_PROJECT_DB_CORRUPT; 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) { if (result == LARDON3D_PROJECT_DB_OK) {
result = execute(database, "COMMIT", "commit migration"); result = execute(database, "COMMIT", "commit migration");
} }
@ -1641,6 +1734,9 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
"capture_optical_configurations", "capture_optical_configurations",
"optical_calibration_profiles", "optical_calibration_profiles",
"capture_calibration_selections"}; "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]) && for (size_t index = 0; index < sizeof(required) / sizeof(required[0]) &&
result == LARDON3D_PROJECT_DB_OK; result == LARDON3D_PROJECT_DB_OK;
++index) { ++index) {
@ -1649,6 +1745,16 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
result = LARDON3D_PROJECT_DB_CORRUPT; 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) { if (result != LARDON3D_PROJECT_DB_OK) {
copy_error(error, database->error); copy_error(error, database->error);

View file

@ -1147,6 +1147,9 @@ static bool downgrade_to_v22_fixture(const char *path) {
return raw_sql( return raw_sql(
path, path,
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;" "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 IF EXISTS feature_extract_batch_tasks;"
"DROP TABLE raw_development_batch_tasks;" "DROP TABLE raw_development_batch_tasks;"
"DROP TABLE capture_calibration_selections;" "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;"); "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) { static bool test_migration_rollback_retry_and_equivalence(void) {
char migrated_directory[64]; char migrated_directory[64];
char migrated_path[256]; char migrated_path[256];
@ -1232,6 +1504,9 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
"capture_optical_configurations", "capture_optical_configurations",
"optical_calibration_profiles", "optical_calibration_profiles",
"capture_calibration_selections", "capture_calibration_selections",
"capture_geometric_states",
"optical_calibration_applicabilities_v2",
"capture_calibration_selections_v2",
}; };
char query[256]; char query[256];
for (size_t index = 0; index < sizeof(empty_tables) / sizeof(empty_tables[0]); 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_config_idx",
"optical_calibration_profiles_sparse_idx", "optical_calibration_profiles_sparse_idx",
"capture_calibration_selections", "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 migrated_sql[8192];
char fresh_sql[8192]; char fresh_sql[8192];
@ -1283,6 +1563,7 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
int main(void) { int main(void) {
return test_profiles_assignments_and_calibrations() && return test_profiles_assignments_and_calibrations() &&
test_v26_exact_geometric_applicability() &&
test_calibration_conflict_result_contract() && test_calibration_conflict_result_contract() &&
test_calibration_dependency_corruption_precedence() && test_calibration_dependency_corruption_precedence() &&
test_campaign_request_corruption_prevents_optics_mutation() && test_campaign_request_corruption_prevents_optics_mutation() &&