feat: add calibration v2 autofocus foundation
This commit is contained in:
parent
038cc64032
commit
34c6a82b35
22 changed files with 903 additions and 82 deletions
12
AGENTS.md
12
AGENTS.md
|
|
@ -81,13 +81,19 @@ Detailed subcontracts remain defined by their canonical documents. This file
|
||||||
must not duplicate every S3 substage, scientific threshold, migration detail,
|
must not duplicate every S3 substage, scientific threshold, migration detail,
|
||||||
or persistence format.
|
or persistence format.
|
||||||
|
|
||||||
Project DB v25 is the current additive operational schema. It preserves v24 RAW batch, the v23
|
Project DB v25 is an additive operational schema in the retained lineage. It preserves v24 RAW batch, the v23
|
||||||
optical overlay and the v22 scientific/persistence foundation. Its additive purpose is typed durable
|
optical overlay and the v22 scientific/persistence foundation. Its additive purpose is typed durable
|
||||||
persistence for `features.extract.batch/1` through `feature_extract_batch_tasks`; it adds no
|
persistence for `features.extract.batch/1` through `feature_extract_batch_tasks`; it adds no
|
||||||
scientific identity and must not reinterpret historical rows. The v25 Feature-batch path has completed
|
scientific identity and must not reinterpret historical rows. The v25 Feature-batch path has completed
|
||||||
its retained real A6000 proof. Historical references to older Project DB versions remain valid where
|
its retained real A6000 proof. Historical references to older Project DB versions remain valid where
|
||||||
they describe the actual historical contract or migration path.
|
they describe the actual historical contract or migration path.
|
||||||
|
|
||||||
|
Project DB v27 is the current additive operational schema. It preserves the v22 scientific/
|
||||||
|
persistence foundation, v23 optical overlay, v24 RAW batch, v25 Feature batch and v26 exact
|
||||||
|
Capture geometric-state/applicability foundation. Its v27 focus-domain rows are generic bounded
|
||||||
|
exact-token machinery with no historical backfill and no device-specific physical applicability
|
||||||
|
claim. Future schema changes beyond v27 require explicit human authorization.
|
||||||
|
|
||||||
The global maintenance implementation, fresh portable/Vulkan/sanitizer/
|
The global maintenance implementation, fresh portable/Vulkan/sanitizer/
|
||||||
concurrency validation and independent final review are acquired. Its lifecycle
|
concurrency validation and independent final review are acquired. Its lifecycle
|
||||||
is `GLOBAL_MAINTENANCE_AUDIT=PASS/FROZEN`. The review independently passed the
|
is `GLOBAL_MAINTENANCE_AUDIT=PASS/FROZEN`. The review independently passed the
|
||||||
|
|
@ -802,7 +808,7 @@ For Project DB:
|
||||||
must not reinterpret scientific history;
|
must not reinterpret scientific history;
|
||||||
- v25 is the additive Feature-batch migration for `features.extract.batch/1` and
|
- v25 is the additive Feature-batch migration for `features.extract.batch/1` and
|
||||||
must preserve v22/v23/v24 identities, rows and semantics;
|
must preserve v22/v23/v24 identities, rows and semantics;
|
||||||
- future schema-version changes beyond the current v25 head require
|
- future schema-version changes beyond the current v27 head require
|
||||||
explicit human authorization;
|
explicit human authorization;
|
||||||
- migrations must be additive unless a different migration is explicitly
|
- migrations must be additive unless a different migration is explicitly
|
||||||
authorized;
|
authorized;
|
||||||
|
|
@ -1020,7 +1026,7 @@ Every completed ticket report must include:
|
||||||
STOP and request a human decision only when resolution requires:
|
STOP and request a human decision only when resolution requires:
|
||||||
|
|
||||||
- changing a FROZEN scientific contract;
|
- changing a FROZEN scientific contract;
|
||||||
- changing Project DB schema/version beyond the current v25 head without
|
- changing Project DB schema/version beyond the current v27 head without
|
||||||
prior authorization;
|
prior authorization;
|
||||||
- introducing a genuinely new subsystem outside authorized scope;
|
- introducing a genuinely new subsystem outside authorized scope;
|
||||||
- files outside the authorized scope;
|
- files outside the authorized scope;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ progressive observations and constraints
|
||||||
|
|
||||||
### Current Project Database
|
### Current Project Database
|
||||||
|
|
||||||
The current Project DB schema is **v26**.
|
The current Project DB schema is **v27**.
|
||||||
|
|
||||||
The current head is additive:
|
The current head is additive:
|
||||||
|
|
||||||
|
|
@ -40,6 +40,7 @@ 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
|
v26 Capture geometric state and exact calibration applicability
|
||||||
|
v27 Generic bounded exact-token focus domains
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
||||||
|
|
@ -121,7 +122,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/v26 operational overlays — IMPLEMENTED / VALIDATED**
|
- **Project DB v24/v25/v26/v27 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
```text
|
```text
|
||||||
DOCUMENTATION_INDEX=CURRENT
|
DOCUMENTATION_INDEX=CURRENT
|
||||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
CURRENT_PROJECT_DB_SCHEMA=v27
|
||||||
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=AUTOFOCUS_V2_FOUNDATION
|
CURRENT_NEXT=PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||||
```
|
```
|
||||||
|
|
||||||
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,7 +35,7 @@ quote an exact API, DDL or constant.
|
||||||
## Current repository state
|
## Current repository state
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Project DB head v26
|
Project DB head v27
|
||||||
Production Task kinds 16
|
Production Task kinds 16
|
||||||
|
|
||||||
v22 selected scientific execution foundation
|
v22 selected scientific execution foundation
|
||||||
|
|
@ -43,6 +43,7 @@ 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
|
v26 Capture geometric state/applicability
|
||||||
|
v27 generic bounded exact-token focus domains
|
||||||
```
|
```
|
||||||
|
|
||||||
Canonical resource objective:
|
Canonical resource objective:
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,36 @@ Historical EXIF/MakerNote values such as Sony `FocusPosition2` or derived
|
||||||
`FocusDistance2` may inform experiment design. They are not by themselves
|
`FocusDistance2` may inform experiment design. They are not by themselves
|
||||||
physical calibration evidence.
|
physical calibration evidence.
|
||||||
|
|
||||||
|
The implemented generic Stage E foundation represents a validated discrete
|
||||||
|
domain as:
|
||||||
|
|
||||||
|
```text
|
||||||
|
existing exact calibration applicability
|
||||||
|
+ positive domain format/version
|
||||||
|
+ nonzero retained-evidence/provenance SHA-256
|
||||||
|
+ exact complete exemplar state for every non-focus geometry field
|
||||||
|
+ 1..64 explicit opaque observed focus tokens
|
||||||
|
```
|
||||||
|
|
||||||
|
The 64-token limit is an operational persistence/API bound, not a scientific
|
||||||
|
focus range. Domain membership is exact token equality. Tokens have no numeric
|
||||||
|
distance, order, magnitude, adjacency or EXIF interpretation, and the generic
|
||||||
|
machinery performs no interpolation or extrapolation. The target configuration
|
||||||
|
and every non-focus geometric-state and provenance field must exactly match the
|
||||||
|
exemplar. Unknown/incomplete focus remains `CALIBRATION_REQUIRED`.
|
||||||
|
|
||||||
|
An exact applicability and its attached domain retain one applicability and
|
||||||
|
calibration identity. Candidate enumeration deduplicates that identity if both
|
||||||
|
the exact exemplar state and a domain member match. Distinct overlapping
|
||||||
|
applicabilities remain ambiguous and produce `SELECTION_REQUIRED`.
|
||||||
|
|
||||||
|
This generic representation does not itself validate a real device domain.
|
||||||
|
In particular:
|
||||||
|
|
||||||
|
```text
|
||||||
|
A6000_E_PZ_16_50_AF_APPLICABILITY=BLOCKED_BY_PHYSICAL_VALIDATION
|
||||||
|
```
|
||||||
|
|
||||||
### 9.3 Discrete focus bands
|
### 9.3 Discrete focus bands
|
||||||
|
|
||||||
If one calibration is not valid across the complete autofocus range, v2 may
|
If one calibration is not valid across the complete autofocus range, v2 may
|
||||||
|
|
|
||||||
|
|
@ -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=v26
|
CURRENT_PROJECT_DB_SCHEMA=v27
|
||||||
```
|
```
|
||||||
|
|
||||||
The current head is additive:
|
The current head is additive:
|
||||||
|
|
@ -18,10 +18,11 @@ v23 Generic optical-context overlay IMPLEMENTED / VALI
|
||||||
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
|
v26 Capture geometric state and exact calibration applicability PASS / FROZEN
|
||||||
|
v27 Generic exact-token focus-domain applicability PASS / FROZEN
|
||||||
```
|
```
|
||||||
|
|
||||||
Project DB v26 preserves the scientific and persistence meaning of every earlier retained row. No
|
Project DB v27 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
|
migration from v22 through v27 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
|
||||||
|
|
@ -233,6 +234,37 @@ 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
|
The v26 tables are a separate additive foundation; they do not attach a Sparse
|
||||||
calibration scope or transition a selected execution to `READY`.
|
calibration scope or transition a selected execution to `READY`.
|
||||||
|
|
||||||
|
### Project DB v27 - generic validated focus domains
|
||||||
|
|
||||||
|
**PASS / FROZEN.**
|
||||||
|
|
||||||
|
The v26 -> v27 migration is transactional, additive and DDL-only. It creates
|
||||||
|
empty `optical_focus_domains_v2` and `optical_focus_domain_tokens_v2` tables.
|
||||||
|
Historical focus observations are not physical validation, so migration
|
||||||
|
creates no inferred domain, token member, applicability, selection or
|
||||||
|
calibration identity.
|
||||||
|
|
||||||
|
A v27 domain attaches to one existing v26 applicability. It durably retains a
|
||||||
|
positive version, a nonzero 32-byte retained-evidence/provenance digest and a
|
||||||
|
bounded set of 1..64 distinct opaque focus tokens. Tokens are stored in
|
||||||
|
deterministic lexical order, but scientific matching is exact byte-for-byte
|
||||||
|
token membership; there is no numeric distance/range comparison, EXIF
|
||||||
|
assumption, interpolation or extrapolation. The operational 64-token capacity
|
||||||
|
is not a scientific dataset or focus-range limit.
|
||||||
|
|
||||||
|
Resolution preserves the v26 zero/one/many contract while enumerating the
|
||||||
|
distinct union of exact v26 matches and eligible domain matches. A domain match
|
||||||
|
requires the exact configuration, exact complete exemplar state for every
|
||||||
|
non-focus geometry/provenance field, observed target focus and exact token
|
||||||
|
membership. Exact and domain paths for the same applicability are deduplicated;
|
||||||
|
different overlapping applicabilities produce `SELECTION_REQUIRED`. The
|
||||||
|
existing v2 selection API remains immutable/idempotent and accepts a domain
|
||||||
|
applicability only while it is exactly eligible.
|
||||||
|
|
||||||
|
This schema is generic machinery, not device-specific autofocus evidence.
|
||||||
|
`A6000_E_PZ_16_50_AF_APPLICABILITY=BLOCKED_BY_PHYSICAL_VALIDATION` remains in
|
||||||
|
force.
|
||||||
|
|
||||||
## 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:
|
||||||
|
|
@ -893,6 +925,7 @@ 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
|
v25 -> v26 Capture geometric state + exact calibration applicability
|
||||||
|
v26 -> v27 generic bounded exact-token focus domains
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
||||||
|
|
@ -900,9 +933,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 v26.
|
An empty Project DB is created and migrated through the complete known chain to v27.
|
||||||
|
|
||||||
A supported historical DB is migrated sequentially to v26. Each migration is transactional. A
|
A supported historical DB is migrated sequentially to v27. 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.
|
||||||
|
|
||||||
|
|
@ -913,7 +946,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 v26. It must not
|
The migration implementation must recognize only the known sequential range through v27. 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:
|
||||||
|
|
@ -927,6 +960,7 @@ Important rollback properties retained from historical tests include:
|
||||||
- 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.
|
- v26 failure leaves no partial geometric-state/applicability tables or marker and a true v25.
|
||||||
|
- v27 failure leaves no partial focus-domain tables or marker and a true v26.
|
||||||
|
|
||||||
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.
|
||||||
|
|
@ -1089,20 +1123,21 @@ must not be silently reinterpreted as a scientific dataset limit.
|
||||||
## Status summary
|
## Status summary
|
||||||
|
|
||||||
```text
|
```text
|
||||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
CURRENT_PROJECT_DB_SCHEMA=v27
|
||||||
|
|
||||||
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
|
v26 Capture geometric state/applicability PASS/FROZEN
|
||||||
|
v27 generic exact-token focus domains 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 v26.
|
chain to v27.
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -1119,4 +1154,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 v26 require explicit human authorization.
|
Future schema changes beyond v27 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:
|
The following existing boundaries are consumed as-is:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Project DB head v26
|
Project DB head v27
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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 v26
|
Project DB current schema v27
|
||||||
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 AUTOFOCUS_V2_FOUNDATION
|
CURRENT_NEXT PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||||
```
|
```
|
||||||
|
|
||||||
The current Project DB head is additive:
|
The current Project DB head is additive:
|
||||||
|
|
@ -35,6 +35,7 @@ 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
|
v26 Capture geometric state + exact calibration applicability
|
||||||
|
v27 generic bounded exact-token focus domains
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -539,8 +540,10 @@ additive L3DCALB2/Tooling/Bootstrap v2 now retains independent group-local prove
|
||||||
complete exact selected-image coverage, and attaches one existing per-image scope only after complete
|
complete exact selected-image coverage, and attaches one existing per-image scope only after complete
|
||||||
publication. `CALIBRATION_WORKFLOW_V2=PASS/FROZEN`: the workflow now proves exact Capture/state
|
publication. `CALIBRATION_WORKFLOW_V2=PASS/FROZEN`: the workflow now proves exact Capture/state
|
||||||
applicability and matching per-image calibration IDs before its sole final scope attachment. The next
|
applicability and matching per-image calibration IDs before its sole final scope attachment. The next
|
||||||
dependency is the generic adaptive-settings/autofocus foundation. Device-specific autofocus envelopes
|
dependency is physical autofocus/optical applicability validation and a dedicated calibrated real
|
||||||
remain blocked until physical evidence validates them.
|
campaign. The generic adaptive-settings audit and bounded exact-token autofocus foundation are
|
||||||
|
PASS/FROZEN. 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.
|
||||||
|
|
@ -934,12 +937,16 @@ SOURCE_COMMENT_AUDIT PASS
|
||||||
SOURCE_COMMENT_REMEDIATION PASS
|
SOURCE_COMMENT_REMEDIATION PASS
|
||||||
PRODUCT_DEFINITION_V1 PASS/FROZEN
|
PRODUCT_DEFINITION_V1 PASS/FROZEN
|
||||||
PROMPT_TREE CURRENT
|
PROMPT_TREE CURRENT
|
||||||
CALIBRATION_EVIDENCE_SOLVER_V1 IMPLEMENTED/VALIDATED
|
CALIBRATION_SCIENCE_V2 PASS/FROZEN
|
||||||
CALIBRATION_TOOLING_ALIGNMENT PASS/FROZEN
|
CALIBRATION_V2_HETEROGENEOUS_OPTICS PASS/FROZEN
|
||||||
CURRENT_NEXT DEDICATED_PHYSICAL_CALIBRATED_REAL_CAMPAIGN
|
CALIBRATION_WORKFLOW_V2 PASS/FROZEN
|
||||||
|
ADAPTIVE_CAPTURE_SETTINGS_CONTRACT PASS/FROZEN
|
||||||
|
AUTOFOCUS_V2_FOUNDATION PASS/FROZEN
|
||||||
|
CURRENT_NEXT PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||||
```
|
```
|
||||||
|
|
||||||
Implementation proceeds only through explicitly human-authorized tranches under `prompt.md` and the
|
Implementation proceeds only through explicitly human-authorized tranches under `prompt.md` and the
|
||||||
numbered `prompt/` execution contract. The current authorized dependency is the final usable
|
numbered `prompt/` execution contract. The current dependency is physical autofocus/optical
|
||||||
calibration workflow; its next missing sub-boundary composes the FROZEN Tooling
|
applicability validation for real equipment, followed by a dedicated calibrated real campaign.
|
||||||
and Bootstrap importer to reach truthful READY from the validated binding.
|
Generic autofocus applicability machinery is available, but the real
|
||||||
|
A6000 + E PZ 16-50 autofocus applicability remains blocked until physical evidence validates it.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ enum {
|
||||||
LARDON3D_OPTICAL_TEXT_CAPACITY = 128,
|
LARDON3D_OPTICAL_TEXT_CAPACITY = 128,
|
||||||
LARDON3D_OPTICAL_PROVENANCE_CAPACITY = 256,
|
LARDON3D_OPTICAL_PROVENANCE_CAPACITY = 256,
|
||||||
LARDON3D_OPTICAL_PAGE_MAX = 128,
|
LARDON3D_OPTICAL_PAGE_MAX = 128,
|
||||||
|
LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE = 32,
|
||||||
|
/* This is an operational persistence/API bound, not a scientific focus
|
||||||
|
* range. Every member remains one opaque exact observation token. */
|
||||||
|
LARDON3D_OPTICAL_FOCUS_DOMAIN_TOKEN_MAX = 64,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
@ -171,6 +175,19 @@ typedef struct {
|
||||||
uint64_t exemplar_capture_id;
|
uint64_t exemplar_capture_id;
|
||||||
} Lardon3DOpticalCalibrationApplicabilityV2;
|
} Lardon3DOpticalCalibrationApplicabilityV2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t focus_domain_id;
|
||||||
|
/* The v26 applicability retains calibration/configuration identity and its
|
||||||
|
* exemplar retains the exact complete non-focus geometric tuple. */
|
||||||
|
uint64_t applicability_id;
|
||||||
|
uint64_t calibration_profile_id;
|
||||||
|
uint64_t optical_configuration_id;
|
||||||
|
uint64_t exemplar_capture_id;
|
||||||
|
uint32_t domain_version;
|
||||||
|
unsigned char evidence_sha256[LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE];
|
||||||
|
uint32_t token_count;
|
||||||
|
} Lardon3DOpticalFocusDomainV2;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Lardon3DOpticalCalibrationResolutionKind kind;
|
Lardon3DOpticalCalibrationResolutionKind kind;
|
||||||
uint64_t applicability_id;
|
uint64_t applicability_id;
|
||||||
|
|
@ -333,15 +350,35 @@ Lardon3DProjectDbResult lardon3d_optical_calibration_applicability_v2_create(
|
||||||
uint64_t exemplar_capture_id,
|
uint64_t exemplar_capture_id,
|
||||||
Lardon3DOpticalCalibrationApplicabilityV2 *output);
|
Lardon3DOpticalCalibrationApplicabilityV2 *output);
|
||||||
|
|
||||||
/* Resolution counts exact valid applicability rows. NONE is CALIBRATION_REQUIRED,
|
/* Attach one physically validated discrete focus domain to an existing exact
|
||||||
* ONE is RESOLVED, and MANY is SELECTION_REQUIRED. All are successful outcomes. */
|
* v26 applicability. evidence_sha256 must be a nonzero retained-evidence or
|
||||||
|
* provenance digest. focus_tokens contains 1..FOCUS_DOMAIN_TOKEN_MAX distinct,
|
||||||
|
* nonempty, NUL-terminated opaque tokens; the call borrows the array and
|
||||||
|
* strings only for its duration. Members are stored as a deterministic exact
|
||||||
|
* set: order has no meaning, exact retry is idempotent, and conflicting reuse
|
||||||
|
* of the applicability is CONSTRAINT. The API performs no numeric conversion,
|
||||||
|
* EXIF interpretation, interpolation, extrapolation, or physical validation.
|
||||||
|
* output is mandatory. On OK, it receives the durable focus domain and its
|
||||||
|
* attached applicability identity; for valid calls it is zeroed on non-OK. */
|
||||||
|
Lardon3DProjectDbResult lardon3d_optical_focus_domain_v2_create(
|
||||||
|
Lardon3DProjectDb *database, uint64_t applicability_id,
|
||||||
|
uint32_t domain_version,
|
||||||
|
const unsigned char evidence_sha256[LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE],
|
||||||
|
const char *const *focus_tokens, size_t token_count,
|
||||||
|
Lardon3DOpticalFocusDomainV2 *output);
|
||||||
|
|
||||||
|
/* Resolution counts distinct eligible applicability rows: exact v26 state
|
||||||
|
* matches plus v27 domains whose non-focus geometry is exact and whose focus
|
||||||
|
* token is an exact member. NONE is CALIBRATION_REQUIRED, ONE is RESOLVED, and
|
||||||
|
* MANY is SELECTION_REQUIRED. All are successful outcomes. */
|
||||||
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_resolve_v2(
|
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
Lardon3DProjectDb *database, uint64_t capture_id,
|
Lardon3DProjectDb *database, uint64_t capture_id,
|
||||||
Lardon3DOpticalCalibrationResolutionV2 *output);
|
Lardon3DOpticalCalibrationResolutionV2 *output);
|
||||||
/* Selection requires a complete observed geometric-state tuple and an exactly
|
/* Selection requires a complete observed geometric-state tuple and an
|
||||||
* compatible applicability; UNKNOWN in any geometry-relevant field is a
|
* applicability currently eligible by exact v26 match or exact v27 domain
|
||||||
* CONSTRAINT. The first selection is immutable, exact retry is idempotent, and
|
* membership; UNKNOWN in any geometry-relevant field is a CONSTRAINT. The
|
||||||
* a conflicting applicability is rejected without changing the selection. */
|
* 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(
|
Lardon3DProjectDbResult lardon3d_optical_capture_calibration_select_v2(
|
||||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t applicability_id);
|
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t applicability_id);
|
||||||
/* Loads the Capture's durable v2 selection without creating or changing it.
|
/* Loads the Capture's durable v2 selection without creating or changing it.
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@
|
||||||
#include <lardon3d/sparse_sfm_incremental.h>
|
#include <lardon3d/sparse_sfm_incremental.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* v26 additively stores Capture-owned observed geometric state and exact
|
/* v27 additively stores validated focus domains as bounded sets of exact
|
||||||
* calibration applicability. Migration does not infer state from v23
|
* observed tokens attached to v26 applicability. Migration creates no
|
||||||
* configuration or historical calibration selections. */
|
* domain or token from historical geometric state. */
|
||||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 26,
|
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 27,
|
||||||
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,
|
||||||
|
|
|
||||||
|
|
@ -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=v26
|
CURRENT_PROJECT_DB_SCHEMA=v27
|
||||||
PRODUCTION_TASK_KINDS=16
|
PRODUCTION_TASK_KINDS=16
|
||||||
PRODUCT_DEFINITION_V1=PASS/FROZEN
|
PRODUCT_DEFINITION_V1=PASS/FROZEN
|
||||||
PROMPT_TREE=NEXT
|
PROMPT_TREE=NEXT
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
```text
|
```text
|
||||||
CURRENT_PROJECT_DB_SCHEMA=v26
|
CURRENT_PROJECT_DB_SCHEMA=v27
|
||||||
PRODUCTION_TASK_KINDS=16
|
PRODUCTION_TASK_KINDS=16
|
||||||
USER_FACING_UI_LANGUAGE_NORMALIZATION=PASS
|
USER_FACING_UI_LANGUAGE_NORMALIZATION=PASS
|
||||||
CURRENT_IMPLEMENTATION_CURSOR=ADAPTIVE_CAPTURE_SETTINGS_AND_AUTOFOCUS_V2_FOUNDATION
|
CURRENT_IMPLEMENTATION_CURSOR=PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||||
```
|
```
|
||||||
|
|
||||||
## Authority
|
## Authority
|
||||||
|
|
@ -16,7 +16,7 @@ CURRENT_IMPLEMENTATION_CURSOR=ADAPTIVE_CAPTURE_SETTINGS_AND_AUTOFOCUS_V2_FOUNDAT
|
||||||
## CURRENT
|
## CURRENT
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Project DB head v26
|
Project DB head v27
|
||||||
Production Task kinds 16
|
Production Task kinds 16
|
||||||
Feature Store IMPLEMENTED
|
Feature Store IMPLEMENTED
|
||||||
Visual Index IMPLEMENTED
|
Visual Index IMPLEMENTED
|
||||||
|
|
@ -39,8 +39,8 @@ Calibration Science v2 heterogeneous optics PASS/FROZEN
|
||||||
Calibration v2 optical-state foundation PASS/FROZEN
|
Calibration v2 optical-state foundation PASS/FROZEN
|
||||||
Calibration v2 heterogeneous publication PASS/FROZEN
|
Calibration v2 heterogeneous publication PASS/FROZEN
|
||||||
Calibration Workflow v2 PASS/FROZEN
|
Calibration Workflow v2 PASS/FROZEN
|
||||||
Adaptive capture settings semantics PLANNED
|
Adaptive capture settings semantics PASS/FROZEN
|
||||||
Autofocus v2 foundation PLANNED
|
Autofocus v2 foundation PASS/FROZEN
|
||||||
Calibration Tooling planarity alignment PASS/FROZEN
|
Calibration Tooling planarity alignment PASS/FROZEN
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ CALIBRATION_SCIENCE_V2=PASS/FROZEN
|
||||||
CALIBRATION_V2_HETEROGENEOUS_OPTICS=PASS/FROZEN
|
CALIBRATION_V2_HETEROGENEOUS_OPTICS=PASS/FROZEN
|
||||||
CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION=PASS/FROZEN
|
CALIBRATION_V2_HETEROGENEOUS_CALIBRATION_PUBLICATION=PASS/FROZEN
|
||||||
CALIBRATION_V2_WORKFLOW_READY=PASS/FROZEN
|
CALIBRATION_V2_WORKFLOW_READY=PASS/FROZEN
|
||||||
ADAPTIVE_CAPTURE_SETTINGS_CONTRACT=PLANNED
|
ADAPTIVE_CAPTURE_SETTINGS_CONTRACT=PASS/FROZEN
|
||||||
AUTOFOCUS_V2_FOUNDATION=PLANNED
|
AUTOFOCUS_V2_FOUNDATION=PASS/FROZEN
|
||||||
CURRENT_CALIBRATION_NEXT=AUTOFOCUS_V2_FOUNDATION
|
CURRENT_CALIBRATION_NEXT=PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||||
```
|
```
|
||||||
|
|
||||||
## Authority
|
## Authority
|
||||||
|
|
|
||||||
|
|
@ -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=AUTOFOCUS_V2_FOUNDATION
|
CURRENT_NEXT=PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||||
```
|
```
|
||||||
|
|
||||||
## Authority
|
## Authority
|
||||||
|
|
@ -25,8 +25,8 @@ Default dependency order:
|
||||||
3. Calibration v2 heterogeneous-optics persistence foundation — PASS/FROZEN;
|
3. Calibration v2 heterogeneous-optics persistence foundation — PASS/FROZEN;
|
||||||
4. Heterogeneous calibration publication / Tooling / Bootstrap evolution — PASS/FROZEN;
|
4. Heterogeneous calibration publication / Tooling / Bootstrap evolution — PASS/FROZEN;
|
||||||
5. Heterogeneous Workflow v2 truthful READY proof — PASS/FROZEN;
|
5. Heterogeneous Workflow v2 truthful READY proof — PASS/FROZEN;
|
||||||
6. Adaptive capture settings / generic autofocus foundation — CURRENT;
|
6. Adaptive capture settings / generic autofocus foundation — PASS/FROZEN;
|
||||||
7. physical autofocus/optical applicability validation and dedicated calibrated real campaign;
|
7. physical autofocus/optical applicability validation and dedicated calibrated real campaign — CURRENT;
|
||||||
8. real Sparse SfM proof;
|
8. real Sparse SfM proof;
|
||||||
9. durable Dense/OpenMVS orchestration;
|
9. durable Dense/OpenMVS orchestration;
|
||||||
10. mesh / refinement / texturing / export;
|
10. mesh / refinement / texturing / export;
|
||||||
|
|
|
||||||
|
|
@ -2338,6 +2338,21 @@ static const char exact_state_predicate[] =
|
||||||
"t.decoded_geometry_state=e.decoded_geometry_state AND "
|
"t.decoded_geometry_state=e.decoded_geometry_state AND "
|
||||||
"t.decoded_width=e.decoded_width AND t.decoded_height=e.decoded_height";
|
"t.decoded_width=e.decoded_width AND t.decoded_height=e.decoded_height";
|
||||||
|
|
||||||
|
/* A discrete focus domain varies only the exact opaque focus token. Every
|
||||||
|
other geometry and observation-provenance field remains exemplar-exact. */
|
||||||
|
static const char exact_nonfocus_state_predicate[] =
|
||||||
|
"t.optical_configuration_id=e.optical_configuration_id AND "
|
||||||
|
"t.state_version=e.state_version AND t.provenance=e.provenance 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(
|
Lardon3DProjectDbResult lardon3d_optical_calibration_applicability_v2_create(
|
||||||
Lardon3DProjectDb *database, uint64_t calibration_profile_id,
|
Lardon3DProjectDb *database, uint64_t calibration_profile_id,
|
||||||
uint64_t exemplar_capture_id,
|
uint64_t exemplar_capture_id,
|
||||||
|
|
@ -2429,11 +2444,233 @@ Lardon3DProjectDbResult lardon3d_optical_calibration_applicability_v2_create(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool focus_domain_digest_valid(
|
||||||
|
const unsigned char digest[LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE]) {
|
||||||
|
if (!digest)
|
||||||
|
return false;
|
||||||
|
for (size_t index = 0; index < LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE;
|
||||||
|
++index)
|
||||||
|
if (digest[index] != 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool focus_domain_tokens_valid(const char *const *tokens, size_t count) {
|
||||||
|
if (!tokens || count == 0 ||
|
||||||
|
count > LARDON3D_OPTICAL_FOCUS_DOMAIN_TOKEN_MAX)
|
||||||
|
return false;
|
||||||
|
for (size_t index = 0; index < count; ++index) {
|
||||||
|
if (!optical_text(tokens[index], LARDON3D_OPTICAL_TEXT_CAPACITY, false))
|
||||||
|
return false;
|
||||||
|
for (size_t previous = 0; previous < index; ++previous)
|
||||||
|
if (strcmp(tokens[index], tokens[previous]) == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lardon3DProjectDbResult lardon3d_optical_focus_domain_v2_create(
|
||||||
|
Lardon3DProjectDb *database, uint64_t applicability_id,
|
||||||
|
uint32_t domain_version,
|
||||||
|
const unsigned char evidence_sha256[LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE],
|
||||||
|
const char *const *focus_tokens, size_t token_count,
|
||||||
|
Lardon3DOpticalFocusDomainV2 *output) {
|
||||||
|
if (output)
|
||||||
|
memset(output, 0, sizeof(*output));
|
||||||
|
if (!database || !optical_id(applicability_id) || domain_version == 0 ||
|
||||||
|
!focus_domain_digest_valid(evidence_sha256) ||
|
||||||
|
!focus_domain_tokens_valid(focus_tokens, token_count) || !output)
|
||||||
|
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
/* Canonical lexical order makes a domain's durable representation
|
||||||
|
independent of caller ordering while retaining tokens byte-for-byte. */
|
||||||
|
const char *ordered[LARDON3D_OPTICAL_FOCUS_DOMAIN_TOKEN_MAX];
|
||||||
|
for (size_t index = 0; index < token_count; ++index) {
|
||||||
|
size_t position = index;
|
||||||
|
while (position > 0 && strcmp(focus_tokens[index], ordered[position - 1]) < 0) {
|
||||||
|
ordered[position] = ordered[position - 1];
|
||||||
|
--position;
|
||||||
|
}
|
||||||
|
ordered[position] = focus_tokens[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)pthread_mutex_lock(&database->mutex);
|
||||||
|
Lardon3DProjectDbResult result = execute(
|
||||||
|
database, "BEGIN IMMEDIATE", "begin optical focus domain v2");
|
||||||
|
sqlite3_stmt *statement = NULL;
|
||||||
|
uint64_t calibration_profile_id = 0;
|
||||||
|
uint64_t optical_configuration_id = 0;
|
||||||
|
uint64_t exemplar_capture_id = 0;
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK)
|
||||||
|
result = prepare(
|
||||||
|
database,
|
||||||
|
"SELECT calibration_profile_id,optical_configuration_id,"
|
||||||
|
"exemplar_capture_id FROM optical_calibration_applicabilities_v2 "
|
||||||
|
"WHERE applicability_id=?1",
|
||||||
|
&statement);
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
sqlite3_bind_int64(statement, 1, (sqlite3_int64)applicability_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 focus domain applicability");
|
||||||
|
else 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;
|
||||||
|
else {
|
||||||
|
calibration_profile_id = (uint64_t)sqlite3_column_int64(statement, 0);
|
||||||
|
optical_configuration_id = (uint64_t)sqlite3_column_int64(statement, 1);
|
||||||
|
exemplar_capture_id = (uint64_t)sqlite3_column_int64(statement, 2);
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE)
|
||||||
|
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)sqlite3_finalize(statement);
|
||||||
|
statement = NULL;
|
||||||
|
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK)
|
||||||
|
result = prepare(
|
||||||
|
database,
|
||||||
|
"INSERT OR IGNORE INTO optical_focus_domains_v2(applicability_id,"
|
||||||
|
"domain_version,evidence_sha256,token_count) VALUES(?1,?2,?3,?4)",
|
||||||
|
&statement);
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
sqlite3_bind_int64(statement, 1, (sqlite3_int64)applicability_id);
|
||||||
|
sqlite3_bind_int64(statement, 2, (sqlite3_int64)domain_version);
|
||||||
|
sqlite3_bind_blob(statement, 3, evidence_sha256,
|
||||||
|
LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE,
|
||||||
|
SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_int64(statement, 4, (sqlite3_int64)token_count);
|
||||||
|
result = step_done(database, statement, "insert optical focus domain v2");
|
||||||
|
statement = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t focus_domain_id = 0;
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK)
|
||||||
|
result = prepare(
|
||||||
|
database,
|
||||||
|
"SELECT focus_domain_id,domain_version,evidence_sha256,token_count FROM "
|
||||||
|
"optical_focus_domains_v2 WHERE applicability_id=?1",
|
||||||
|
&statement);
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
sqlite3_bind_int64(statement, 1, (sqlite3_int64)applicability_id);
|
||||||
|
int code = sqlite3_step(statement);
|
||||||
|
if (code != SQLITE_ROW)
|
||||||
|
result = code == SQLITE_DONE
|
||||||
|
? LARDON3D_PROJECT_DB_CORRUPT
|
||||||
|
: sqlite_result(database, code, "load optical focus domain v2");
|
||||||
|
else {
|
||||||
|
sqlite3_int64 stored_id = sqlite3_column_int64(statement, 0);
|
||||||
|
sqlite3_int64 stored_version = sqlite3_column_int64(statement, 1);
|
||||||
|
sqlite3_int64 stored_count = sqlite3_column_int64(statement, 3);
|
||||||
|
const unsigned char *stored_digest = sqlite3_column_blob(statement, 2);
|
||||||
|
if (sqlite3_column_type(statement, 0) != SQLITE_INTEGER ||
|
||||||
|
sqlite3_column_type(statement, 1) != SQLITE_INTEGER ||
|
||||||
|
sqlite3_column_type(statement, 2) != SQLITE_BLOB ||
|
||||||
|
sqlite3_column_type(statement, 3) != SQLITE_INTEGER || stored_id <= 0 ||
|
||||||
|
stored_version <= 0 || stored_version > UINT32_MAX ||
|
||||||
|
sqlite3_column_bytes(statement, 2) !=
|
||||||
|
LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE ||
|
||||||
|
!focus_domain_digest_valid(stored_digest) || stored_count <= 0 ||
|
||||||
|
stored_count > LARDON3D_OPTICAL_FOCUS_DOMAIN_TOKEN_MAX) {
|
||||||
|
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||||
|
} else if (stored_version != (sqlite3_int64)domain_version ||
|
||||||
|
memcmp(stored_digest, evidence_sha256,
|
||||||
|
LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE) != 0 ||
|
||||||
|
stored_count != (sqlite3_int64)token_count) {
|
||||||
|
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||||
|
} else {
|
||||||
|
focus_domain_id = (uint64_t)stored_id;
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE)
|
||||||
|
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)sqlite3_finalize(statement);
|
||||||
|
statement = NULL;
|
||||||
|
|
||||||
|
for (size_t index = 0; index < token_count &&
|
||||||
|
result == LARDON3D_PROJECT_DB_OK;
|
||||||
|
++index) {
|
||||||
|
result = prepare(
|
||||||
|
database,
|
||||||
|
"INSERT OR IGNORE INTO optical_focus_domain_tokens_v2 "
|
||||||
|
"VALUES(?1,?2,?3)",
|
||||||
|
&statement);
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
sqlite3_bind_int64(statement, 1, (sqlite3_int64)focus_domain_id);
|
||||||
|
sqlite3_bind_int64(statement, 2, (sqlite3_int64)index);
|
||||||
|
sqlite3_bind_text(statement, 3, ordered[index], -1, SQLITE_TRANSIENT);
|
||||||
|
result = step_done(database, statement, "insert focus domain token v2");
|
||||||
|
statement = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK)
|
||||||
|
result = prepare(
|
||||||
|
database,
|
||||||
|
"SELECT token_ordinal,focus_token FROM optical_focus_domain_tokens_v2 "
|
||||||
|
"WHERE focus_domain_id=?1 ORDER BY token_ordinal",
|
||||||
|
&statement);
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
sqlite3_bind_int64(statement, 1, (sqlite3_int64)focus_domain_id);
|
||||||
|
for (size_t index = 0; index < token_count; ++index) {
|
||||||
|
int code = sqlite3_step(statement);
|
||||||
|
if (code != SQLITE_ROW) {
|
||||||
|
result = code == SQLITE_DONE ? LARDON3D_PROJECT_DB_CORRUPT
|
||||||
|
: sqlite_result(database, code,
|
||||||
|
"load focus domain token v2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sqlite3_column_type(statement, 0) != SQLITE_INTEGER ||
|
||||||
|
sqlite3_column_int64(statement, 0) != (sqlite3_int64)index ||
|
||||||
|
sqlite3_column_type(statement, 1) != SQLITE_TEXT ||
|
||||||
|
sqlite3_column_bytes(statement, 1) <= 0 ||
|
||||||
|
sqlite3_column_bytes(statement, 1) >= LARDON3D_OPTICAL_TEXT_CAPACITY) {
|
||||||
|
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!optical_column_equals(statement, 1, ordered[index])) {
|
||||||
|
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||||
|
sqlite3_step(statement) != SQLITE_DONE)
|
||||||
|
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||||
|
}
|
||||||
|
(void)sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
result = optical_commit_or_rollback(database, result,
|
||||||
|
"commit optical focus domain v2",
|
||||||
|
"rollback optical focus domain v2");
|
||||||
|
(void)pthread_mutex_unlock(&database->mutex);
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
output->focus_domain_id = focus_domain_id;
|
||||||
|
output->applicability_id = applicability_id;
|
||||||
|
output->calibration_profile_id = calibration_profile_id;
|
||||||
|
output->optical_configuration_id = optical_configuration_id;
|
||||||
|
output->exemplar_capture_id = exemplar_capture_id;
|
||||||
|
output->domain_version = domain_version;
|
||||||
|
memcpy(output->evidence_sha256, evidence_sha256,
|
||||||
|
LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE);
|
||||||
|
output->token_count = (uint32_t)token_count;
|
||||||
|
} else {
|
||||||
|
memset(output, 0, sizeof(*output));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static Lardon3DProjectDbResult
|
static Lardon3DProjectDbResult
|
||||||
exact_candidates_locked(Lardon3DProjectDb *database, uint64_t capture_id,
|
applicability_candidates_locked(Lardon3DProjectDb *database,
|
||||||
uint64_t required_applicability,
|
uint64_t capture_id,
|
||||||
Lardon3DOpticalCalibrationResolutionV2 *output,
|
uint64_t required_applicability,
|
||||||
size_t *count) {
|
Lardon3DOpticalCalibrationResolutionV2 *output,
|
||||||
|
size_t *count) {
|
||||||
/* A broken v2 dependency is corruption, not evidence that calibration is
|
/* A broken v2 dependency is corruption, not evidence that calibration is
|
||||||
required. Validate the target configuration before exact-state filtering. */
|
required. Validate the target configuration before exact-state filtering. */
|
||||||
sqlite3_stmt *validation = NULL;
|
sqlite3_stmt *validation = NULL;
|
||||||
|
|
@ -2461,13 +2698,58 @@ exact_candidates_locked(Lardon3DProjectDb *database, uint64_t capture_id,
|
||||||
(void)sqlite3_finalize(validation);
|
(void)sqlite3_finalize(validation);
|
||||||
if (result != LARDON3D_PROJECT_DB_OK)
|
if (result != LARDON3D_PROJECT_DB_OK)
|
||||||
return result;
|
return result;
|
||||||
|
validation = NULL;
|
||||||
|
|
||||||
char query[1800];
|
/* Domain rows are retained scientific evidence. Broken dependencies,
|
||||||
|
incomplete exemplars or token-set corruption must fail closed before
|
||||||
|
enumeration; a domain never supplies evidence missing from its exemplar. */
|
||||||
|
result = prepare(
|
||||||
|
database,
|
||||||
|
"SELECT d.focus_domain_id FROM optical_focus_domains_v2 d LEFT JOIN "
|
||||||
|
"optical_calibration_applicabilities_v2 a ON "
|
||||||
|
"a.applicability_id=d.applicability_id LEFT JOIN capture_geometric_states e "
|
||||||
|
"ON e.capture_id=a.exemplar_capture_id AND "
|
||||||
|
"e.optical_configuration_id=a.optical_configuration_id WHERE "
|
||||||
|
"a.applicability_id IS NULL OR (a.optical_configuration_id=(SELECT "
|
||||||
|
"optical_configuration_id FROM capture_geometric_states WHERE capture_id=?1) "
|
||||||
|
"AND (e.capture_id IS NULL OR e.focus_state!=2 OR e.aperture_state!=2 OR "
|
||||||
|
"e.stabilization=0 OR e.crop_state!=2 OR e.pipeline_state!=2 OR "
|
||||||
|
"e.representation_state!=2 OR e.decoded_geometry_state!=2 OR "
|
||||||
|
"typeof(d.domain_version)!='integer' OR d.domain_version<=0 OR "
|
||||||
|
"typeof(d.evidence_sha256)!='blob' OR length(d.evidence_sha256)!=32 OR "
|
||||||
|
"d.evidence_sha256=zeroblob(32) OR typeof(d.token_count)!='integer' OR "
|
||||||
|
"d.token_count<=0 OR d.token_count>64 OR d.token_count!=(SELECT COUNT(*) "
|
||||||
|
"FROM optical_focus_domain_tokens_v2 k WHERE "
|
||||||
|
"k.focus_domain_id=d.focus_domain_id) OR (SELECT MIN(k.token_ordinal) FROM "
|
||||||
|
"optical_focus_domain_tokens_v2 k WHERE k.focus_domain_id=d.focus_domain_id)"
|
||||||
|
"!=0 OR (SELECT MAX(k.token_ordinal) FROM optical_focus_domain_tokens_v2 k "
|
||||||
|
"WHERE k.focus_domain_id=d.focus_domain_id)!=d.token_count-1 OR EXISTS("
|
||||||
|
"SELECT 1 FROM optical_focus_domain_tokens_v2 k WHERE "
|
||||||
|
"k.focus_domain_id=d.focus_domain_id AND (typeof(k.token_ordinal)!='integer' "
|
||||||
|
"OR k.token_ordinal<0 OR k.token_ordinal>=64 OR "
|
||||||
|
"typeof(k.focus_token)!='text' OR length(k.focus_token)=0 OR "
|
||||||
|
"length(k.focus_token)>=128)))) 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 optical focus domain v2");
|
||||||
|
}
|
||||||
|
(void)sqlite3_finalize(validation);
|
||||||
|
if (result != LARDON3D_PROJECT_DB_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
char query[4096];
|
||||||
int length = snprintf(
|
int length = snprintf(
|
||||||
query, sizeof(query),
|
query, sizeof(query),
|
||||||
"SELECT "
|
"SELECT applicability_id,calibration_profile_id,sparse_calibration_id "
|
||||||
"a.applicability_id,a.calibration_profile_id,p.sparse_calibration_id "
|
"FROM (SELECT a.applicability_id AS applicability_id,"
|
||||||
"FROM capture_geometric_states t JOIN "
|
"a.calibration_profile_id AS calibration_profile_id,"
|
||||||
|
"p.sparse_calibration_id AS sparse_calibration_id FROM "
|
||||||
|
"capture_geometric_states t JOIN "
|
||||||
"optical_calibration_applicabilities_v2 a ON "
|
"optical_calibration_applicabilities_v2 a ON "
|
||||||
"a.optical_configuration_id=t.optical_configuration_id JOIN "
|
"a.optical_configuration_id=t.optical_configuration_id JOIN "
|
||||||
"capture_geometric_states e ON e.capture_id=a.exemplar_capture_id JOIN "
|
"capture_geometric_states e ON e.capture_id=a.exemplar_capture_id JOIN "
|
||||||
|
|
@ -2475,17 +2757,29 @@ exact_candidates_locked(Lardon3DProjectDb *database, uint64_t capture_id,
|
||||||
"p.calibration_profile_id=a.calibration_profile_id AND "
|
"p.calibration_profile_id=a.calibration_profile_id AND "
|
||||||
"p.optical_configuration_id=a.optical_configuration_id JOIN "
|
"p.optical_configuration_id=a.optical_configuration_id JOIN "
|
||||||
"sparse_calibrations s ON s.calibration_id=p.sparse_calibration_id WHERE "
|
"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",
|
"t.capture_id=?1 AND %s UNION SELECT a.applicability_id,"
|
||||||
exact_state_predicate,
|
"a.calibration_profile_id,p.sparse_calibration_id FROM "
|
||||||
required_applicability ? " AND a.applicability_id=?2" : "");
|
"capture_geometric_states t JOIN optical_focus_domains_v2 d ON "
|
||||||
|
"1=1 JOIN optical_calibration_applicabilities_v2 a ON "
|
||||||
|
"a.applicability_id=d.applicability_id AND "
|
||||||
|
"a.optical_configuration_id=t.optical_configuration_id JOIN "
|
||||||
|
"capture_geometric_states e ON e.capture_id=a.exemplar_capture_id JOIN "
|
||||||
|
"optical_focus_domain_tokens_v2 k ON "
|
||||||
|
"k.focus_domain_id=d.focus_domain_id AND "
|
||||||
|
"k.focus_token=t.focus_observation 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 t.focus_state=2 AND %s) candidates WHERE "
|
||||||
|
"(?2=0 OR applicability_id=?2) ORDER BY applicability_id LIMIT 2",
|
||||||
|
exact_state_predicate, exact_nonfocus_state_predicate);
|
||||||
sqlite3_stmt *statement = NULL;
|
sqlite3_stmt *statement = NULL;
|
||||||
result = length < 0 || (size_t)length >= sizeof(query)
|
result = length < 0 || (size_t)length >= sizeof(query)
|
||||||
? LARDON3D_PROJECT_DB_IO_ERROR
|
? LARDON3D_PROJECT_DB_IO_ERROR
|
||||||
: prepare(database, query, &statement);
|
: prepare(database, query, &statement);
|
||||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||||
if (required_applicability)
|
sqlite3_bind_int64(statement, 2, (sqlite3_int64)required_applicability);
|
||||||
sqlite3_bind_int64(statement, 2, (sqlite3_int64)required_applicability);
|
|
||||||
int code;
|
int code;
|
||||||
*count = 0;
|
*count = 0;
|
||||||
while (*count < 2 && (code = sqlite3_step(statement)) == SQLITE_ROW) {
|
while (*count < 2 && (code = sqlite3_step(statement)) == SQLITE_ROW) {
|
||||||
|
|
@ -2556,7 +2850,8 @@ Lardon3DProjectDbResult lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
return result;
|
return result;
|
||||||
(void)pthread_mutex_lock(&database->mutex);
|
(void)pthread_mutex_lock(&database->mutex);
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
result = exact_candidates_locked(database, capture_id, 0, output, &count);
|
result = applicability_candidates_locked(database, capture_id, 0, output,
|
||||||
|
&count);
|
||||||
(void)pthread_mutex_unlock(&database->mutex);
|
(void)pthread_mutex_unlock(&database->mutex);
|
||||||
if (result != LARDON3D_PROJECT_DB_OK) {
|
if (result != LARDON3D_PROJECT_DB_OK) {
|
||||||
memset(output, 0, sizeof(*output));
|
memset(output, 0, sizeof(*output));
|
||||||
|
|
@ -2585,8 +2880,9 @@ lardon3d_optical_capture_calibration_select_v2(Lardon3DProjectDb *database,
|
||||||
Lardon3DProjectDbResult result = execute(
|
Lardon3DProjectDbResult result = execute(
|
||||||
database, "BEGIN IMMEDIATE", "begin Capture calibration selection v2");
|
database, "BEGIN IMMEDIATE", "begin Capture calibration selection v2");
|
||||||
if (result == LARDON3D_PROJECT_DB_OK)
|
if (result == LARDON3D_PROJECT_DB_OK)
|
||||||
result = exact_candidates_locked(database, capture_id, applicability_id,
|
result = applicability_candidates_locked(database, capture_id,
|
||||||
&candidate, &count);
|
applicability_id, &candidate,
|
||||||
|
&count);
|
||||||
if (result == LARDON3D_PROJECT_DB_OK && count != 1)
|
if (result == LARDON3D_PROJECT_DB_OK && count != 1)
|
||||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||||
Lardon3DOpticalCaptureGeometricState state = {0};
|
Lardon3DOpticalCaptureGeometricState state = {0};
|
||||||
|
|
@ -2688,7 +2984,7 @@ Lardon3DProjectDbResult lardon3d_optical_capture_calibration_selection_load_v2(
|
||||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
Lardon3DOpticalCalibrationResolutionV2 candidate = {0};
|
Lardon3DOpticalCalibrationResolutionV2 candidate = {0};
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
result = exact_candidates_locked(
|
result = applicability_candidates_locked(
|
||||||
database, capture_id, output->applicability_id, &candidate, &count);
|
database, capture_id, output->applicability_id, &candidate, &count);
|
||||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||||
(count != 1 ||
|
(count != 1 ||
|
||||||
|
|
|
||||||
|
|
@ -960,6 +960,29 @@ static const char schema_optical_geometric_state_v26[] =
|
||||||
"optical_calibration_applicabilities_v2(applicability_id,calibration_"
|
"optical_calibration_applicabilities_v2(applicability_id,calibration_"
|
||||||
"profile_id,optical_configuration_id));";
|
"profile_id,optical_configuration_id));";
|
||||||
|
|
||||||
|
/* PERSISTENCE CONTRACT v27: a focus domain is evidence attached to one v26
|
||||||
|
applicability, not a numeric focus interval or a new calibration identity.
|
||||||
|
Token order is canonical insertion order only; matching is exact text
|
||||||
|
equality. DDL-only migration cannot infer a domain from historical tokens. */
|
||||||
|
static const char schema_optical_focus_domains_v27[] =
|
||||||
|
"CREATE TABLE optical_focus_domains_v2("
|
||||||
|
"focus_domain_id INTEGER PRIMARY KEY AUTOINCREMENT CHECK(focus_domain_id>0),"
|
||||||
|
"applicability_id INTEGER NOT NULL UNIQUE REFERENCES "
|
||||||
|
"optical_calibration_applicabilities_v2(applicability_id),"
|
||||||
|
"domain_version INTEGER NOT NULL CHECK(domain_version>0 "
|
||||||
|
"AND domain_version<=4294967295),evidence_sha256 BLOB NOT NULL "
|
||||||
|
"CHECK(typeof(evidence_sha256)='blob' AND length(evidence_sha256)=32 AND "
|
||||||
|
"evidence_sha256!=zeroblob(32)),token_count INTEGER NOT NULL "
|
||||||
|
"CHECK(token_count>0 AND token_count<=64));"
|
||||||
|
"CREATE TABLE optical_focus_domain_tokens_v2(focus_domain_id INTEGER NOT NULL "
|
||||||
|
"REFERENCES optical_focus_domains_v2(focus_domain_id) ON DELETE CASCADE,"
|
||||||
|
"token_ordinal INTEGER NOT NULL CHECK(token_ordinal>=0 AND token_ordinal<64),"
|
||||||
|
"focus_token TEXT NOT NULL CHECK(typeof(focus_token)='text' AND "
|
||||||
|
"length(focus_token)>0 AND length(focus_token)<128),PRIMARY KEY(focus_domain_id,"
|
||||||
|
"token_ordinal),UNIQUE(focus_domain_id,focus_token));"
|
||||||
|
"CREATE INDEX optical_focus_domain_tokens_v2_token_idx ON "
|
||||||
|
"optical_focus_domain_tokens_v2(focus_token,focus_domain_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 : "");
|
||||||
|
|
@ -1053,7 +1076,8 @@ 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 != 25) {
|
from_version != 23 && from_version != 24 && from_version != 25 &&
|
||||||
|
from_version != 26) {
|
||||||
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");
|
||||||
|
|
@ -1579,6 +1603,27 @@ 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 < 27) {
|
||||||
|
/* A v26 focus token is only an observation. It is never sufficient
|
||||||
|
physical evidence to manufacture an applicability domain. */
|
||||||
|
result = execute(database, schema_optical_focus_domains_v27,
|
||||||
|
"migrate optical focus domains v26 to v27");
|
||||||
|
#ifdef LARDON3D_PROJECT_DB_TESTING
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||||
|
getenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V27"))
|
||||||
|
result = execute(database, "INSERT INTO missing_v27_test_table VALUES(1)",
|
||||||
|
"forced migration v27 failure");
|
||||||
|
#endif
|
||||||
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
|
result = execute(database,
|
||||||
|
"UPDATE metadata SET value=27 WHERE "
|
||||||
|
"key='schema_version' AND value=26",
|
||||||
|
"finish schema v27 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");
|
||||||
}
|
}
|
||||||
|
|
@ -1736,7 +1781,9 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
||||||
"capture_calibration_selections"};
|
"capture_calibration_selections"};
|
||||||
const char *required_v26[] = {"capture_geometric_states",
|
const char *required_v26[] = {"capture_geometric_states",
|
||||||
"optical_calibration_applicabilities_v2",
|
"optical_calibration_applicabilities_v2",
|
||||||
"capture_calibration_selections_v2"};
|
"capture_calibration_selections_v2",
|
||||||
|
"optical_focus_domains_v2",
|
||||||
|
"optical_focus_domain_tokens_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) {
|
||||||
|
|
@ -1751,7 +1798,7 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
||||||
++index) {
|
++index) {
|
||||||
if (!table_exists(database->connection, required_v26[index])) {
|
if (!table_exists(database->connection, required_v26[index])) {
|
||||||
copy_error(database->error,
|
copy_error(database->error,
|
||||||
"Current Project DB v26 schema is incomplete.");
|
"Current Project DB v27 optical schema is incomplete.");
|
||||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,11 @@ static bool create_v11_database(const char *path) {
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
return execute_sql(path,
|
return execute_sql(path,
|
||||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domains_v2;"
|
||||||
|
"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 IF EXISTS raw_development_batch_tasks;"
|
"DROP TABLE IF EXISTS raw_development_batch_tasks;"
|
||||||
"DROP TABLE IF EXISTS capture_calibration_selections;"
|
"DROP TABLE IF EXISTS capture_calibration_selections;"
|
||||||
|
|
|
||||||
|
|
@ -878,6 +878,11 @@ static bool run_task_test(void) {
|
||||||
CHECK(exec_sql(
|
CHECK(exec_sql(
|
||||||
database_path,
|
database_path,
|
||||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domains_v2;"
|
||||||
|
"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 IF EXISTS raw_development_batch_tasks;"
|
"DROP TABLE IF EXISTS raw_development_batch_tasks;"
|
||||||
"DROP TABLE IF EXISTS capture_calibration_selections;"
|
"DROP TABLE IF EXISTS capture_calibration_selections;"
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,12 @@ static bool create_v9_database(const char *path) {
|
||||||
static const char sql[] =
|
static const char sql[] =
|
||||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||||
/* This database is a true v9 fixture, not a current database whose
|
/* This database is a true v9 fixture, not a current database whose
|
||||||
metadata alone was relabelled while additive v20-v25 objects survived. */
|
metadata alone was relabelled while later additive objects survived. */
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domains_v2;"
|
||||||
|
"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 IF EXISTS raw_development_batch_tasks;"
|
"DROP TABLE IF EXISTS raw_development_batch_tasks;"
|
||||||
"DROP TABLE IF EXISTS capture_calibration_selections;"
|
"DROP TABLE IF EXISTS capture_calibration_selections;"
|
||||||
|
|
|
||||||
|
|
@ -360,6 +360,11 @@ static bool downgrade_project_to_historical_v10(const char *database_path) {
|
||||||
}
|
}
|
||||||
static const char sql[] =
|
static const char sql[] =
|
||||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domains_v2;"
|
||||||
|
"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 IF EXISTS raw_development_batch_tasks;"
|
"DROP TABLE IF EXISTS raw_development_batch_tasks;"
|
||||||
"DROP TABLE IF EXISTS selected_execution_items;"
|
"DROP TABLE IF EXISTS selected_execution_items;"
|
||||||
|
|
|
||||||
|
|
@ -1147,6 +1147,8 @@ 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 optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domains_v2;"
|
||||||
"DROP TABLE IF EXISTS capture_calibration_selections_v2;"
|
"DROP TABLE IF EXISTS capture_calibration_selections_v2;"
|
||||||
"DROP TABLE IF EXISTS optical_calibration_applicabilities_v2;"
|
"DROP TABLE IF EXISTS optical_calibration_applicabilities_v2;"
|
||||||
"DROP TABLE IF EXISTS capture_geometric_states;"
|
"DROP TABLE IF EXISTS capture_geometric_states;"
|
||||||
|
|
@ -1407,6 +1409,8 @@ static bool test_v26_exact_geometric_applicability(void) {
|
||||||
*/
|
*/
|
||||||
CHECK(raw_sql(
|
CHECK(raw_sql(
|
||||||
path, "PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
path, "PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||||
|
"DROP TABLE optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE optical_focus_domains_v2;"
|
||||||
"DROP TABLE capture_calibration_selections_v2;"
|
"DROP TABLE capture_calibration_selections_v2;"
|
||||||
"DROP TABLE optical_calibration_applicabilities_v2;"
|
"DROP TABLE optical_calibration_applicabilities_v2;"
|
||||||
"DROP TABLE capture_geometric_states;"
|
"DROP TABLE capture_geometric_states;"
|
||||||
|
|
@ -1432,6 +1436,296 @@ static bool test_v26_exact_geometric_applicability(void) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Lardon3DOpticalCaptureGeometricState complete_focus_state(
|
||||||
|
uint64_t capture_id, uint64_t configuration_id, const char *focus_token) {
|
||||||
|
Lardon3DOpticalCaptureGeometricState state = {
|
||||||
|
.capture_id = capture_id,
|
||||||
|
.optical_configuration_id = 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,
|
||||||
|
};
|
||||||
|
(void)snprintf(state.focus_observation, sizeof(state.focus_observation),
|
||||||
|
"%s", focus_token);
|
||||||
|
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"));
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool test_v27_discrete_focus_domains(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));
|
||||||
|
|
||||||
|
Lardon3DOpticalConfiguration base_configuration;
|
||||||
|
CHECK(lardon3d_optical_configuration_load(
|
||||||
|
database, fixture.configuration_id, &base_configuration) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
Lardon3DOpticalCameraBodyProfile other_body_input = {0};
|
||||||
|
memcpy(other_body_input.manufacturer, "Generic", sizeof("Generic"));
|
||||||
|
memcpy(other_body_input.model, "Other body", sizeof("Other body"));
|
||||||
|
memcpy(other_body_input.name, "Other body profile",
|
||||||
|
sizeof("Other body profile"));
|
||||||
|
Lardon3DOpticalCameraBodyProfile other_body;
|
||||||
|
CHECK(lardon3d_optical_camera_body_create(database, &other_body_input,
|
||||||
|
&other_body) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
Lardon3DOpticalLensProfile other_lens_input = {
|
||||||
|
.interface_kind = LARDON3D_OPTICAL_LENS_ELECTRONIC,
|
||||||
|
.focal_range_kind = LARDON3D_OPTICAL_FOCAL_RANGE_PRIME,
|
||||||
|
.minimum_focal_um = 16000,
|
||||||
|
.maximum_focal_um = 16000,
|
||||||
|
};
|
||||||
|
memcpy(other_lens_input.manufacturer, "Generic", sizeof("Generic"));
|
||||||
|
memcpy(other_lens_input.model, "Other lens", sizeof("Other lens"));
|
||||||
|
memcpy(other_lens_input.name, "Other lens profile",
|
||||||
|
sizeof("Other lens profile"));
|
||||||
|
Lardon3DOpticalLensProfile other_lens;
|
||||||
|
CHECK(lardon3d_optical_lens_create(database, &other_lens_input, &other_lens) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
Lardon3DOpticalConfiguration configuration_input = {
|
||||||
|
.camera_body_profile_id = other_body.camera_body_profile_id,
|
||||||
|
.lens_profile_id = base_configuration.lens_profile_id,
|
||||||
|
.has_focal_length = true,
|
||||||
|
.focal_length_um = 16000,
|
||||||
|
};
|
||||||
|
Lardon3DOpticalConfiguration other_body_configuration;
|
||||||
|
CHECK(lardon3d_optical_configuration_create(
|
||||||
|
database, &configuration_input, &other_body_configuration) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
configuration_input.camera_body_profile_id =
|
||||||
|
base_configuration.camera_body_profile_id;
|
||||||
|
configuration_input.lens_profile_id = other_lens.lens_profile_id;
|
||||||
|
Lardon3DOpticalConfiguration other_lens_configuration;
|
||||||
|
CHECK(lardon3d_optical_configuration_create(
|
||||||
|
database, &configuration_input, &other_lens_configuration) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
|
||||||
|
enum { TARGET_COUNT = 5 };
|
||||||
|
Lardon3DProjectDbCapture targets[TARGET_COUNT];
|
||||||
|
for (size_t index = 0; index < TARGET_COUNT; ++index)
|
||||||
|
CHECK(lardon3d_project_db_create_capture(database, fixture.scanset_id,
|
||||||
|
(uint32_t)(index + 2),
|
||||||
|
&targets[index]) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||||
|
database, fixture.capture_id, fixture.configuration_id) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||||
|
database, targets[0].capture_id, fixture.configuration_id) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||||
|
database, targets[1].capture_id, fixture.configuration_id) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||||
|
database, targets[2].capture_id,
|
||||||
|
fixture.alternate_configuration_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||||
|
database, targets[3].capture_id,
|
||||||
|
other_body_configuration.optical_configuration_id) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_assign_explicit(
|
||||||
|
database, targets[4].capture_id,
|
||||||
|
other_lens_configuration.optical_configuration_id) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
|
||||||
|
Lardon3DOpticalCaptureGeometricState state = complete_focus_state(
|
||||||
|
fixture.capture_id, fixture.configuration_id, "synthetic-focus-a");
|
||||||
|
Lardon3DOpticalCaptureGeometricState stored;
|
||||||
|
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||||
|
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
state = complete_focus_state(
|
||||||
|
targets[3].capture_id,
|
||||||
|
other_body_configuration.optical_configuration_id, "synthetic-focus-b");
|
||||||
|
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||||
|
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
state = complete_focus_state(
|
||||||
|
targets[4].capture_id,
|
||||||
|
other_lens_configuration.optical_configuration_id, "synthetic-focus-b");
|
||||||
|
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||||
|
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
state = complete_focus_state(targets[0].capture_id, fixture.configuration_id,
|
||||||
|
"synthetic-focus-b");
|
||||||
|
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||||
|
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
state = complete_focus_state(targets[1].capture_id, fixture.configuration_id,
|
||||||
|
"synthetic-focus-outside");
|
||||||
|
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||||
|
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
/* The identical focus token at another focal configuration must not cross
|
||||||
|
the exact body/lens/focal applicability boundary. */
|
||||||
|
state = complete_focus_state(targets[2].capture_id,
|
||||||
|
fixture.alternate_configuration_id,
|
||||||
|
"synthetic-focus-b");
|
||||||
|
CHECK(lardon3d_optical_capture_geometric_state_create(
|
||||||
|
database, &state, &stored) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
|
||||||
|
Lardon3DSparseCalibration calibration;
|
||||||
|
CHECK(create_sparse_calibration(database, 0xd1, 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 = 200,
|
||||||
|
};
|
||||||
|
memcpy(profile_input.name, "focus domain A", sizeof("focus domain A"));
|
||||||
|
memcpy(profile_input.provenance, "synthetic physical evidence",
|
||||||
|
sizeof("synthetic physical evidence"));
|
||||||
|
Lardon3DOpticalCalibrationProfile profile_a;
|
||||||
|
CHECK(lardon3d_optical_calibration_profile_create(
|
||||||
|
database, &profile_input, &profile_a) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
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);
|
||||||
|
|
||||||
|
const char *tokens[] = {"synthetic-focus-b", "synthetic-focus-a"};
|
||||||
|
unsigned char evidence[LARDON3D_OPTICAL_FOCUS_DOMAIN_DIGEST_SIZE] = {0};
|
||||||
|
evidence[0] = 0x71;
|
||||||
|
Lardon3DOpticalFocusDomainV2 domain_a;
|
||||||
|
CHECK(lardon3d_optical_focus_domain_v2_create(
|
||||||
|
database, applicability_a.applicability_id, 1, evidence, tokens,
|
||||||
|
2, &domain_a) == LARDON3D_PROJECT_DB_OK &&
|
||||||
|
domain_a.token_count == 2);
|
||||||
|
const char *retry_tokens[] = {"synthetic-focus-a", "synthetic-focus-b"};
|
||||||
|
Lardon3DOpticalFocusDomainV2 domain_retry;
|
||||||
|
CHECK(lardon3d_optical_focus_domain_v2_create(
|
||||||
|
database, applicability_a.applicability_id, 1, evidence,
|
||||||
|
retry_tokens, 2, &domain_retry) == LARDON3D_PROJECT_DB_OK &&
|
||||||
|
domain_retry.focus_domain_id == domain_a.focus_domain_id);
|
||||||
|
evidence[1] = 1;
|
||||||
|
CHECK(lardon3d_optical_focus_domain_v2_create(
|
||||||
|
database, applicability_a.applicability_id, 1, evidence,
|
||||||
|
retry_tokens, 2, &domain_retry) == LARDON3D_PROJECT_DB_CONSTRAINT &&
|
||||||
|
domain_retry.focus_domain_id == 0);
|
||||||
|
evidence[1] = 0;
|
||||||
|
|
||||||
|
Lardon3DOpticalCalibrationResolutionV2 resolution;
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[0].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_RESOLVED &&
|
||||||
|
resolution.applicability_id == applicability_a.applicability_id);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[1].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[2].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[3].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[4].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_REQUIRED);
|
||||||
|
|
||||||
|
/* A domain cannot repair incomplete exemplar evidence. Corrupting the
|
||||||
|
schema-valid focus state must fail closed before candidate enumeration. */
|
||||||
|
lardon3d_project_db_close(database);
|
||||||
|
database = NULL;
|
||||||
|
char corruption[512];
|
||||||
|
int corruption_bytes = snprintf(
|
||||||
|
corruption, sizeof(corruption),
|
||||||
|
"UPDATE capture_geometric_states SET focus_state=1,"
|
||||||
|
"focus_observation='' WHERE capture_id=%llu;",
|
||||||
|
(unsigned long long)fixture.capture_id);
|
||||||
|
CHECK(corruption_bytes > 0 &&
|
||||||
|
(size_t)corruption_bytes < sizeof(corruption) &&
|
||||||
|
raw_sql(path, corruption));
|
||||||
|
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
memset(&resolution, 0x7f, sizeof(resolution));
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[0].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_CORRUPT &&
|
||||||
|
resolution.kind == 0 &&
|
||||||
|
resolution.applicability_id == 0);
|
||||||
|
lardon3d_project_db_close(database);
|
||||||
|
database = NULL;
|
||||||
|
corruption_bytes = snprintf(
|
||||||
|
corruption, sizeof(corruption),
|
||||||
|
"UPDATE capture_geometric_states SET focus_state=2,"
|
||||||
|
"focus_observation='synthetic-focus-a' WHERE capture_id=%llu;",
|
||||||
|
(unsigned long long)fixture.capture_id);
|
||||||
|
CHECK(corruption_bytes > 0 &&
|
||||||
|
(size_t)corruption_bytes < sizeof(corruption) &&
|
||||||
|
raw_sql(path, corruption));
|
||||||
|
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
|
||||||
|
memcpy(profile_input.name, "focus domain B", sizeof("focus domain B"));
|
||||||
|
Lardon3DOpticalCalibrationProfile profile_b;
|
||||||
|
CHECK(lardon3d_optical_calibration_profile_create(
|
||||||
|
database, &profile_input, &profile_b) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
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);
|
||||||
|
evidence[0] = 0x72;
|
||||||
|
const char *overlap_tokens[] = {"synthetic-focus-b"};
|
||||||
|
Lardon3DOpticalFocusDomainV2 domain_b;
|
||||||
|
CHECK(lardon3d_optical_focus_domain_v2_create(
|
||||||
|
database, applicability_b.applicability_id, 1, evidence,
|
||||||
|
overlap_tokens, 1, &domain_b) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_resolve_v2(
|
||||||
|
database, targets[0].capture_id, &resolution) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
resolution.kind == LARDON3D_OPTICAL_CALIBRATION_SELECTION_REQUIRED);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||||
|
database, targets[0].capture_id,
|
||||||
|
applicability_a.applicability_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_optical_capture_calibration_select_v2(
|
||||||
|
database, targets[0].capture_id,
|
||||||
|
applicability_a.applicability_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
|
||||||
|
lardon3d_project_db_close(database);
|
||||||
|
/* v26 contains observations but no retained physical-domain evidence. The
|
||||||
|
additive migration must recreate empty domain tables without inference. */
|
||||||
|
CHECK(raw_sql(path, "PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||||
|
"DROP TABLE optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE optical_focus_domains_v2;"
|
||||||
|
"UPDATE metadata SET value=26 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 count = -1;
|
||||||
|
CHECK(raw_integer(path, "SELECT COUNT(*) FROM optical_focus_domains_v2",
|
||||||
|
&count) &&
|
||||||
|
count == 0);
|
||||||
|
CHECK(raw_integer(path,
|
||||||
|
"SELECT COUNT(*) FROM optical_focus_domain_tokens_v2",
|
||||||
|
&count) &&
|
||||||
|
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];
|
||||||
|
|
@ -1507,6 +1801,8 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
|
||||||
"capture_geometric_states",
|
"capture_geometric_states",
|
||||||
"optical_calibration_applicabilities_v2",
|
"optical_calibration_applicabilities_v2",
|
||||||
"capture_calibration_selections_v2",
|
"capture_calibration_selections_v2",
|
||||||
|
"optical_focus_domains_v2",
|
||||||
|
"optical_focus_domain_tokens_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]);
|
||||||
|
|
@ -1543,6 +1839,9 @@ static bool test_migration_rollback_retry_and_equivalence(void) {
|
||||||
"optical_calibration_applicabilities_v2",
|
"optical_calibration_applicabilities_v2",
|
||||||
"optical_calibration_applicabilities_v2_config_idx",
|
"optical_calibration_applicabilities_v2_config_idx",
|
||||||
"capture_calibration_selections_v2",
|
"capture_calibration_selections_v2",
|
||||||
|
"optical_focus_domains_v2",
|
||||||
|
"optical_focus_domain_tokens_v2",
|
||||||
|
"optical_focus_domain_tokens_v2_token_idx",
|
||||||
};
|
};
|
||||||
char migrated_sql[8192];
|
char migrated_sql[8192];
|
||||||
char fresh_sql[8192];
|
char fresh_sql[8192];
|
||||||
|
|
@ -1564,6 +1863,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_v26_exact_geometric_applicability() &&
|
||||||
|
test_v27_discrete_focus_domains() &&
|
||||||
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() &&
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,14 @@
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Historical migration fixtures are produced from a temporary current DB.
|
/* Historical migration fixtures are produced from a temporary current DB.
|
||||||
* Remove every additive v23/v24/v25 object first so the fixture really is historical
|
* Remove every additive v23..v27 object first so the fixture really is
|
||||||
* rather than a lower version number with future tables left behind. */
|
* historical rather than a lower version number with future tables left behind. */
|
||||||
#define DROP_OPTICAL_V23_SQL \
|
#define DROP_OPTICAL_V23_SQL \
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domain_tokens_v2;" \
|
||||||
|
"DROP TABLE IF EXISTS optical_focus_domains_v2;" \
|
||||||
|
"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 IF EXISTS raw_development_batch_tasks;" \
|
"DROP TABLE IF EXISTS raw_development_batch_tasks;" \
|
||||||
"DROP TABLE IF EXISTS capture_calibration_selections;" \
|
"DROP TABLE IF EXISTS capture_calibration_selections;" \
|
||||||
|
|
@ -129,12 +134,12 @@ static bool create_future_database(const char *path) {
|
||||||
if (sqlite3_open(path, &connection) != SQLITE_OK) {
|
if (sqlite3_open(path, &connection) != SQLITE_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool ok =
|
char *sql = sqlite3_mprintf(
|
||||||
sqlite3_exec(
|
"CREATE TABLE metadata(key TEXT PRIMARY KEY,value INTEGER NOT NULL);"
|
||||||
connection,
|
"INSERT INTO metadata VALUES('schema_version',%u);",
|
||||||
"CREATE TABLE metadata(key TEXT PRIMARY KEY,value INTEGER NOT NULL);"
|
LARDON3D_PROJECT_DB_SCHEMA_VERSION + 1U);
|
||||||
"INSERT INTO metadata VALUES('schema_version',26);",
|
bool ok = sql && sqlite3_exec(connection, sql, NULL, NULL, NULL) == SQLITE_OK;
|
||||||
NULL, NULL, NULL) == SQLITE_OK;
|
sqlite3_free(sql);
|
||||||
return sqlite3_close(connection) == SQLITE_OK && ok;
|
return sqlite3_close(connection) == SQLITE_OK && ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -963,12 +968,18 @@ static bool run_test(void) {
|
||||||
|
|
||||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
||||||
Lardon3DProjectDb *database = NULL;
|
Lardon3DProjectDb *database = NULL;
|
||||||
/* v25 is DDL-only: an injected failure rolls back table and marker, and a
|
/* Remove later empty overlays to form a true v24 fixture. The v25 injected
|
||||||
* retry creates no fabricated association or historical cursor. */
|
* failure must roll back its table/marker, and retry through current head
|
||||||
|
* creates no fabricated association, observation, domain, or cursor. */
|
||||||
CHECK(lardon3d_project_db_open(v24_path, &database, error) == LARDON3D_PROJECT_DB_OK);
|
CHECK(lardon3d_project_db_open(v24_path, &database, error) == LARDON3D_PROJECT_DB_OK);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(execute_test_sql(v24_path,
|
CHECK(execute_test_sql(v24_path,
|
||||||
|
"DROP TABLE optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE optical_focus_domains_v2;"
|
||||||
|
"DROP TABLE capture_calibration_selections_v2;"
|
||||||
|
"DROP TABLE optical_calibration_applicabilities_v2;"
|
||||||
|
"DROP TABLE capture_geometric_states;"
|
||||||
"DROP TABLE feature_extract_batch_tasks;"
|
"DROP TABLE feature_extract_batch_tasks;"
|
||||||
"UPDATE metadata SET value=24 WHERE key='schema_version';"));
|
"UPDATE metadata SET value=24 WHERE key='schema_version';"));
|
||||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V25", "1", 1) == 0);
|
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V25", "1", 1) == 0);
|
||||||
|
|
@ -987,6 +998,26 @@ static bool run_test(void) {
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(v24_path, "SELECT count(*) FROM feature_extract_batch_tasks", 0));
|
CHECK(query_integer(v24_path, "SELECT count(*) FROM feature_extract_batch_tasks", 0));
|
||||||
|
CHECK(execute_test_sql(v24_path,
|
||||||
|
"DROP TABLE optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE optical_focus_domains_v2;"
|
||||||
|
"UPDATE metadata SET value=26 WHERE key='schema_version';"));
|
||||||
|
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V27", "1", 1) == 0);
|
||||||
|
CHECK(lardon3d_project_db_open(v24_path, &database, error) !=
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(database == NULL);
|
||||||
|
CHECK(unsetenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V27") == 0);
|
||||||
|
CHECK(query_integer(v24_path,
|
||||||
|
"SELECT value FROM metadata WHERE key='schema_version'", 26));
|
||||||
|
CHECK(query_integer(v24_path,
|
||||||
|
"SELECT count(*) FROM sqlite_master WHERE type='table' AND name IN "
|
||||||
|
"('optical_focus_domains_v2','optical_focus_domain_tokens_v2')", 0));
|
||||||
|
CHECK(lardon3d_project_db_open(v24_path, &database, error) ==
|
||||||
|
LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_schema_version(database) ==
|
||||||
|
LARDON3D_PROJECT_DB_SCHEMA_VERSION);
|
||||||
|
lardon3d_project_db_close(database);
|
||||||
|
database = NULL;
|
||||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
LARDON3D_PROJECT_DB_OK);
|
||||||
CHECK(database && lardon3d_project_db_schema_version(database) ==
|
CHECK(database && lardon3d_project_db_schema_version(database) ==
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,11 @@ static bool seed_v21(const char *path) {
|
||||||
"INSERT INTO sparse_calibration_scope_images VALUES(1,1,1);"
|
"INSERT INTO sparse_calibration_scope_images VALUES(1,1,1);"
|
||||||
/* This fixture is a true v21 database; future additive objects must not
|
/* This fixture is a true v21 database; future additive objects must not
|
||||||
remain merely because it was generated from a temporary current DB. */
|
remain merely because it was generated from a temporary current DB. */
|
||||||
|
"DROP TABLE optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE optical_focus_domains_v2;"
|
||||||
|
"DROP TABLE capture_calibration_selections_v2;"
|
||||||
|
"DROP TABLE optical_calibration_applicabilities_v2;"
|
||||||
|
"DROP TABLE capture_geometric_states;"
|
||||||
"DROP TABLE feature_extract_batch_tasks;"
|
"DROP TABLE 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;"
|
||||||
|
|
@ -110,7 +115,12 @@ static bool run(void) {
|
||||||
CHECK(sql(path, "SELECT 1 FROM raw_development_batch_tasks WHERE 0;"));
|
CHECK(sql(path, "SELECT 1 FROM raw_development_batch_tasks WHERE 0;"));
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(sql(path, "DROP TABLE feature_extract_batch_tasks;"
|
CHECK(sql(path, "DROP TABLE optical_focus_domain_tokens_v2;"
|
||||||
|
"DROP TABLE optical_focus_domains_v2;"
|
||||||
|
"DROP TABLE capture_calibration_selections_v2;"
|
||||||
|
"DROP TABLE optical_calibration_applicabilities_v2;"
|
||||||
|
"DROP TABLE capture_geometric_states;"
|
||||||
|
"DROP TABLE feature_extract_batch_tasks;"
|
||||||
"DROP TABLE raw_development_batch_tasks;"
|
"DROP TABLE raw_development_batch_tasks;"
|
||||||
"UPDATE metadata SET value=23 WHERE key='schema_version';"));
|
"UPDATE metadata SET value=23 WHERE key='schema_version';"));
|
||||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V24", "1", 1) == 0);
|
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V24", "1", 1) == 0);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue