feat: bridge calibration workflow to autofocus study
This commit is contained in:
parent
524f08d1b3
commit
1a96bcce1f
9 changed files with 517 additions and 3 deletions
|
|
@ -147,3 +147,44 @@ This v1 boundary does not:
|
|||
|
||||
The future physical study supplies the evidence needed to decide whether the
|
||||
A6000 + E PZ 16-50 supports one domain, discrete domains, or exact focus only.
|
||||
|
||||
## Materialized Workflow bridge v1
|
||||
|
||||
**Status: PASS / FROZEN.**
|
||||
|
||||
`CALIBRATION_AF_STUDY_WORKFLOW_BRIDGE_V1` is the additive conversion boundary
|
||||
between the already-FROZEN Calibration Workflow materializer and AF-study
|
||||
samples.
|
||||
|
||||
It accepts a `Lardon3DCalibrationWorkflowExternalEvidence` that has already
|
||||
passed the existing immutable-file, solver-bundle and provenance checks. It
|
||||
does not parse `solve.json` or any other solver file again.
|
||||
|
||||
The bridge:
|
||||
|
||||
```text
|
||||
materialized Calibration Workflow evidence
|
||||
+ caller-supplied exact focus token
|
||||
+ caller-supplied FIT/HOLDOUT role
|
||||
-> Lardon3DCalibrationAfStudySample
|
||||
```
|
||||
|
||||
The sample publishes `repeated_parameters[0]` only after checking that all three
|
||||
retained full solves remain exactly equal.
|
||||
|
||||
Its `calibration_evidence_sha256` is independent of the focus token and
|
||||
FIT/HOLDOUT role and binds:
|
||||
|
||||
- target identity;
|
||||
- optical-state identity;
|
||||
- solver executable/configuration identity;
|
||||
- initialization evidence;
|
||||
- validation evidence;
|
||||
- exact oriented dimensions;
|
||||
- exact published binary64 intrinsics.
|
||||
|
||||
Therefore relabelling one calibration result cannot manufacture independent
|
||||
calibration evidence.
|
||||
|
||||
The bridge performs no DB access, metadata interpretation, physical AF decision,
|
||||
thresholding, interpolation or extrapolation.
|
||||
|
|
|
|||
|
|
@ -950,5 +950,7 @@ CURRENT_NEXT PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VAL
|
|||
Implementation proceeds only through explicitly human-authorized tranches under `prompt.md` and the
|
||||
numbered `prompt/` execution contract. The current dependency is physical autofocus/optical
|
||||
applicability validation for real equipment, followed by a dedicated calibrated real campaign.
|
||||
Generic autofocus applicability machinery is available, but the real
|
||||
A6000 + E PZ 16-50 autofocus applicability remains blocked until physical evidence validates it.
|
||||
Generic autofocus applicability machinery is available. AF-study evidence can now be produced from
|
||||
already-materialized Calibration Workflow results without a second solver parser, while focus tokens
|
||||
remain explicit study annotations. The real A6000 + E PZ 16-50 autofocus applicability remains
|
||||
blocked until physical evidence validates it.
|
||||
|
|
|
|||
51
include/lardon3d/calibration_af_study_workflow.h
Normal file
51
include/lardon3d/calibration_af_study_workflow.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_H
|
||||
#define LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_H
|
||||
|
||||
#include <lardon3d/calibration_af_study.h>
|
||||
#include <lardon3d/calibration_workflow.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK = 0,
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_ARGUMENT,
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE,
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_CRYPTO_ERROR,
|
||||
} Lardon3DCalibrationAfStudyWorkflowResult;
|
||||
|
||||
/* Convert one already validated/materialized Calibration Workflow result into
|
||||
* one AF-study sample without re-parsing any solver file.
|
||||
*
|
||||
* `focus_token` and FIT/HOLDOUT role are study annotations. They are
|
||||
* deliberately excluded from calibration_evidence_sha256, so relabelling the
|
||||
* same calibration result cannot manufacture a new calibration-evidence
|
||||
* identity.
|
||||
*
|
||||
* calibration_evidence_sha256 is domain-separated and binds:
|
||||
* - target identity;
|
||||
* - optical-state identity;
|
||||
* - solver executable/configuration identity;
|
||||
* - initialization and validation evidence;
|
||||
* - exact oriented dimensions;
|
||||
* - exact published binary64 fx,fy,cx,cy,k1,k2,p1,p2.
|
||||
*
|
||||
* The bridge checks the materialization invariants it consumes, including
|
||||
* deterministic validation-evidence binding and equality of all three repeated
|
||||
* full solves. It publishes repeated_parameters[0].
|
||||
*
|
||||
* No Project DB access, metadata interpretation, physical AF applicability
|
||||
* decision, interpolation, extrapolation, solver execution or thresholding
|
||||
* occurs here. */
|
||||
Lardon3DCalibrationAfStudyWorkflowResult
|
||||
lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
const Lardon3DCalibrationWorkflowExternalEvidence *external,
|
||||
Lardon3DCalibrationAfStudySampleRole role, const char *focus_token,
|
||||
Lardon3DCalibrationAfStudySample *output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
17
meson.build
17
meson.build
|
|
@ -184,6 +184,7 @@ lardon3d_app = executable(
|
|||
'src/calibration_tooling.c',
|
||||
'src/calibration_tooling_v2.c',
|
||||
'src/calibration_af_study.c',
|
||||
'src/calibration_af_study_workflow.c',
|
||||
'src/calibration_workflow.cpp',
|
||||
'src/calibration_workflow_materialize.cpp',
|
||||
'src/calibration_workflow_bind.cpp',
|
||||
|
|
@ -930,6 +931,22 @@ calibration_af_study_test = executable(
|
|||
|
||||
test('calibration-af-study', calibration_af_study_test, timeout: 30)
|
||||
|
||||
calibration_af_study_workflow_test = executable(
|
||||
'test-calibration-af-study-workflow',
|
||||
sources: [
|
||||
'tests/test_calibration_af_study_workflow.c',
|
||||
'src/calibration_af_study_workflow.c',
|
||||
],
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: [openssl, cc.find_library('m')],
|
||||
)
|
||||
|
||||
test(
|
||||
'calibration-af-study-workflow',
|
||||
calibration_af_study_workflow_test,
|
||||
timeout: 30,
|
||||
)
|
||||
|
||||
calibration_workflow_v2_test = executable(
|
||||
'test-calibration-workflow-v2',
|
||||
sources: [
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ Calibration Workflow v2 PASS/FROZEN
|
|||
Adaptive capture settings semantics PASS/FROZEN
|
||||
Autofocus v2 foundation PASS/FROZEN
|
||||
Calibration AF study evidence v1 PASS/FROZEN
|
||||
Calibration AF study Workflow bridge v1 PASS/FROZEN
|
||||
Calibration Tooling planarity alignment PASS/FROZEN
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ CALIBRATION_V2_WORKFLOW_READY=PASS/FROZEN
|
|||
ADAPTIVE_CAPTURE_SETTINGS_CONTRACT=PASS/FROZEN
|
||||
AUTOFOCUS_V2_FOUNDATION=PASS/FROZEN
|
||||
CALIBRATION_AF_STUDY_EVIDENCE_V1=PASS/FROZEN
|
||||
CALIBRATION_AF_STUDY_WORKFLOW_BRIDGE_V1=PASS/FROZEN
|
||||
CURRENT_CALIBRATION_NEXT=PHYSICAL_AUTOFOCUS_OPTICAL_APPLICABILITY_VALIDATION
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Default dependency order:
|
|||
4. Heterogeneous calibration publication / Tooling / Bootstrap evolution — PASS/FROZEN;
|
||||
5. Heterogeneous Workflow v2 truthful READY proof — PASS/FROZEN;
|
||||
6. Adaptive capture settings / generic autofocus foundation — PASS/FROZEN;
|
||||
7. physical autofocus/optical applicability validation and dedicated calibrated real campaign — CURRENT; `CALIBRATION_AF_STUDY_EVIDENCE_V1=PASS/FROZEN` supplies deterministic measurement evidence but makes no physical applicability decision;
|
||||
7. physical autofocus/optical applicability validation and dedicated calibrated real campaign — CURRENT; `CALIBRATION_AF_STUDY_EVIDENCE_V1=PASS/FROZEN` supplies deterministic measurement evidence and `CALIBRATION_AF_STUDY_WORKFLOW_BRIDGE_V1=PASS/FROZEN` converts already-materialized Calibration Workflow evidence into AF-study samples without reparsing solver artifacts; neither makes a physical applicability decision;
|
||||
8. real Sparse SfM proof;
|
||||
9. durable Dense/OpenMVS orchestration;
|
||||
10. mesh / refinement / texturing / export;
|
||||
|
|
|
|||
211
src/calibration_af_study_workflow.c
Normal file
211
src/calibration_af_study_workflow.c
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
#include <lardon3d/calibration_af_study_workflow.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool nonzero_digest(const unsigned char value[32]) {
|
||||
unsigned char any = 0;
|
||||
for (size_t index = 0; index < 32; ++index) any |= value[index];
|
||||
return any != 0;
|
||||
}
|
||||
|
||||
static bool token_copy(
|
||||
const char *input,
|
||||
char output[LARDON3D_CALIBRATION_AF_STUDY_FOCUS_TOKEN_CAPACITY]) {
|
||||
if (!input) return false;
|
||||
size_t length = 0;
|
||||
while (length < LARDON3D_CALIBRATION_AF_STUDY_FOCUS_TOKEN_CAPACITY &&
|
||||
input[length] != '\0')
|
||||
++length;
|
||||
if (length == 0 ||
|
||||
length >= LARDON3D_CALIBRATION_AF_STUDY_FOCUS_TOKEN_CAPACITY)
|
||||
return false;
|
||||
memset(output, 0, LARDON3D_CALIBRATION_AF_STUDY_FOCUS_TOKEN_CAPACITY);
|
||||
memcpy(output, input, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool digest_begin(EVP_MD_CTX **ctx, const char *domain) {
|
||||
*ctx = EVP_MD_CTX_new();
|
||||
return *ctx &&
|
||||
EVP_DigestInit_ex(*ctx, EVP_sha256(), NULL) == 1 &&
|
||||
EVP_DigestUpdate(*ctx, domain, strlen(domain)) == 1;
|
||||
}
|
||||
|
||||
static bool digest_add(EVP_MD_CTX *ctx, const void *bytes, size_t size) {
|
||||
return EVP_DigestUpdate(ctx, bytes, size) == 1;
|
||||
}
|
||||
|
||||
static bool digest_finish(EVP_MD_CTX *ctx, unsigned char output[32]) {
|
||||
unsigned int output_size = 0;
|
||||
const bool ok =
|
||||
EVP_DigestFinal_ex(ctx, output, &output_size) == 1 && output_size == 32;
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void encode_u32_le(uint32_t value, unsigned char output[4]) {
|
||||
for (size_t index = 0; index < 4; ++index)
|
||||
output[index] = (unsigned char)(value >> (8u * index));
|
||||
}
|
||||
|
||||
static void encode_f64_le(double value, unsigned char output[8]) {
|
||||
uint64_t bits = 0;
|
||||
if (value == 0.0) value = 0.0;
|
||||
memcpy(&bits, &value, sizeof(bits));
|
||||
for (size_t index = 0; index < 8; ++index)
|
||||
output[index] = (unsigned char)(bits >> (8u * index));
|
||||
}
|
||||
|
||||
static bool validation_binding(
|
||||
const Lardon3DCalibrationWorkflowInputBoundary *boundary,
|
||||
unsigned char output[32]) {
|
||||
static const char domain[] = "L3DCAL_WORKFLOW_VALIDATION_V1\n";
|
||||
EVP_MD_CTX *ctx = NULL;
|
||||
if (!digest_begin(&ctx, domain)) {
|
||||
if (ctx) EVP_MD_CTX_free(ctx);
|
||||
return false;
|
||||
}
|
||||
const bool ok =
|
||||
digest_add(ctx, boundary->detection_sha256, 32) &&
|
||||
digest_add(ctx, boundary->solve_sha256, 32) &&
|
||||
digest_add(ctx, boundary->evidence_sha256, 32) &&
|
||||
digest_add(ctx, boundary->producer_sha256, 32);
|
||||
if (!ok) {
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return false;
|
||||
}
|
||||
return digest_finish(ctx, output);
|
||||
}
|
||||
|
||||
static bool sample_identity(
|
||||
const Lardon3DCalibrationWorkflowExternalEvidence *external,
|
||||
unsigned char output[32]) {
|
||||
static const char domain[] = "L3DAF_CALIBRATION_SAMPLE_V1\n";
|
||||
EVP_MD_CTX *ctx = NULL;
|
||||
if (!digest_begin(&ctx, domain)) {
|
||||
if (ctx) EVP_MD_CTX_free(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok =
|
||||
digest_add(ctx, external->target_sha256, 32) &&
|
||||
digest_add(ctx, external->optical_state_sha256, 32) &&
|
||||
digest_add(ctx, external->solver_executable_sha256, 32) &&
|
||||
digest_add(ctx, external->solver_configuration_sha256, 32) &&
|
||||
digest_add(ctx, external->initialization_evidence_sha256, 32) &&
|
||||
digest_add(ctx, external->validation_evidence_sha256, 32);
|
||||
|
||||
unsigned char encoded_u32[4];
|
||||
encode_u32_le(external->oriented_width, encoded_u32);
|
||||
ok = ok && digest_add(ctx, encoded_u32, sizeof(encoded_u32));
|
||||
encode_u32_le(external->oriented_height, encoded_u32);
|
||||
ok = ok && digest_add(ctx, encoded_u32, sizeof(encoded_u32));
|
||||
|
||||
for (size_t parameter = 0; parameter < 8 && ok; ++parameter) {
|
||||
unsigned char encoded_f64[8];
|
||||
encode_f64_le(external->repeated_parameters[0][parameter], encoded_f64);
|
||||
ok = digest_add(ctx, encoded_f64, sizeof(encoded_f64));
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return false;
|
||||
}
|
||||
return digest_finish(ctx, output);
|
||||
}
|
||||
|
||||
static bool boundary_provenance_valid(
|
||||
const Lardon3DCalibrationWorkflowExternalEvidence *external) {
|
||||
const Lardon3DCalibrationWorkflowInputBoundary *boundary =
|
||||
&external->boundary;
|
||||
|
||||
if (!nonzero_digest(boundary->session_sha256) ||
|
||||
!nonzero_digest(boundary->detection_sha256) ||
|
||||
!nonzero_digest(boundary->solve_sha256) ||
|
||||
!nonzero_digest(boundary->evidence_sha256) ||
|
||||
!nonzero_digest(boundary->producer_sha256) ||
|
||||
!nonzero_digest(boundary->optical_state_sha256) ||
|
||||
!nonzero_digest(boundary->solver_executable_sha256) ||
|
||||
!nonzero_digest(boundary->solver_configuration_sha256))
|
||||
return false;
|
||||
|
||||
return memcmp(external->optical_state_sha256,
|
||||
boundary->optical_state_sha256, 32) == 0 &&
|
||||
memcmp(external->solver_executable_sha256,
|
||||
boundary->solver_executable_sha256, 32) == 0 &&
|
||||
memcmp(external->solver_configuration_sha256,
|
||||
boundary->solver_configuration_sha256, 32) == 0 &&
|
||||
memcmp(external->initialization_evidence_sha256,
|
||||
boundary->session_sha256, 32) == 0;
|
||||
}
|
||||
|
||||
static bool published_parameters_valid(
|
||||
const Lardon3DCalibrationWorkflowExternalEvidence *external) {
|
||||
const double *published = external->repeated_parameters[0];
|
||||
for (size_t parameter = 0; parameter < 8; ++parameter) {
|
||||
if (!isfinite(published[parameter])) return false;
|
||||
if (external->repeated_parameters[1][parameter] != published[parameter] ||
|
||||
external->repeated_parameters[2][parameter] != published[parameter])
|
||||
return false;
|
||||
}
|
||||
|
||||
return published[0] > 0.0 && published[1] > 0.0 &&
|
||||
published[2] >= 0.0 && published[3] >= 0.0 &&
|
||||
published[2] < (double)external->oriented_width &&
|
||||
published[3] < (double)external->oriented_height;
|
||||
}
|
||||
|
||||
Lardon3DCalibrationAfStudyWorkflowResult
|
||||
lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
const Lardon3DCalibrationWorkflowExternalEvidence *external,
|
||||
Lardon3DCalibrationAfStudySampleRole role, const char *focus_token,
|
||||
Lardon3DCalibrationAfStudySample *output) {
|
||||
if (output) memset(output, 0, sizeof(*output));
|
||||
|
||||
if (!external || !focus_token || !output ||
|
||||
(role != LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT &&
|
||||
role != LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_HOLDOUT))
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_ARGUMENT;
|
||||
|
||||
Lardon3DCalibrationAfStudySample sample = {0};
|
||||
if (!token_copy(focus_token, sample.focus_token))
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_ARGUMENT;
|
||||
|
||||
if (external->oriented_width == 0 || external->oriented_height == 0 ||
|
||||
!nonzero_digest(external->target_sha256) ||
|
||||
!nonzero_digest(external->optical_state_sha256) ||
|
||||
!nonzero_digest(external->solver_executable_sha256) ||
|
||||
!nonzero_digest(external->solver_configuration_sha256) ||
|
||||
!nonzero_digest(external->initialization_evidence_sha256) ||
|
||||
!nonzero_digest(external->validation_evidence_sha256) ||
|
||||
!boundary_provenance_valid(external) ||
|
||||
!published_parameters_valid(external))
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE;
|
||||
|
||||
unsigned char expected_validation[32] = {0};
|
||||
if (!validation_binding(&external->boundary, expected_validation))
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_CRYPTO_ERROR;
|
||||
if (memcmp(external->validation_evidence_sha256,
|
||||
expected_validation, 32) != 0)
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE;
|
||||
|
||||
sample.role = role;
|
||||
if (!sample_identity(external, sample.calibration_evidence_sha256))
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_CRYPTO_ERROR;
|
||||
|
||||
sample.fx = external->repeated_parameters[0][0];
|
||||
sample.fy = external->repeated_parameters[0][1];
|
||||
sample.cx = external->repeated_parameters[0][2];
|
||||
sample.cy = external->repeated_parameters[0][3];
|
||||
sample.k1 = external->repeated_parameters[0][4];
|
||||
sample.k2 = external->repeated_parameters[0][5];
|
||||
sample.p1 = external->repeated_parameters[0][6];
|
||||
sample.p2 = external->repeated_parameters[0][7];
|
||||
|
||||
*output = sample;
|
||||
return LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK;
|
||||
}
|
||||
190
tests/test_calibration_af_study_workflow.c
Normal file
190
tests/test_calibration_af_study_workflow.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
#include <lardon3d/calibration_af_study_workflow.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHECK(expression) \
|
||||
do { \
|
||||
if (!(expression)) { \
|
||||
fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #expression); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void fill_digest(unsigned char output[32], unsigned char value) {
|
||||
memset(output, value, 32);
|
||||
}
|
||||
|
||||
static int sha256_validation(
|
||||
const Lardon3DCalibrationWorkflowInputBoundary *boundary,
|
||||
unsigned char output[32]) {
|
||||
static const char domain[] = "L3DCAL_WORKFLOW_VALIDATION_V1\n";
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||
if (!ctx) return 0;
|
||||
int ok = EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) == 1 &&
|
||||
EVP_DigestUpdate(ctx, domain, sizeof(domain) - 1) == 1 &&
|
||||
EVP_DigestUpdate(ctx, boundary->detection_sha256, 32) == 1 &&
|
||||
EVP_DigestUpdate(ctx, boundary->solve_sha256, 32) == 1 &&
|
||||
EVP_DigestUpdate(ctx, boundary->evidence_sha256, 32) == 1 &&
|
||||
EVP_DigestUpdate(ctx, boundary->producer_sha256, 32) == 1;
|
||||
unsigned int length = 0;
|
||||
ok = ok && EVP_DigestFinal_ex(ctx, output, &length) == 1 && length == 32;
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static Lardon3DCalibrationWorkflowExternalEvidence fixture(void) {
|
||||
Lardon3DCalibrationWorkflowExternalEvidence value = {0};
|
||||
|
||||
fill_digest(value.boundary.session_sha256, 0x11);
|
||||
fill_digest(value.boundary.detection_sha256, 0x22);
|
||||
fill_digest(value.boundary.solve_sha256, 0x33);
|
||||
fill_digest(value.boundary.evidence_sha256, 0x44);
|
||||
fill_digest(value.boundary.producer_sha256, 0x55);
|
||||
fill_digest(value.boundary.campaign_state_sha256, 0x66);
|
||||
fill_digest(value.boundary.optical_state_sha256, 0x77);
|
||||
fill_digest(value.boundary.solver_executable_sha256, 0x88);
|
||||
fill_digest(value.boundary.solver_configuration_sha256, 0x99);
|
||||
|
||||
fill_digest(value.target_sha256, 0xA1);
|
||||
memcpy(value.optical_state_sha256, value.boundary.optical_state_sha256, 32);
|
||||
memcpy(value.solver_executable_sha256,
|
||||
value.boundary.solver_executable_sha256, 32);
|
||||
memcpy(value.solver_configuration_sha256,
|
||||
value.boundary.solver_configuration_sha256, 32);
|
||||
memcpy(value.initialization_evidence_sha256,
|
||||
value.boundary.session_sha256, 32);
|
||||
|
||||
(void)sha256_validation(&value.boundary, value.validation_evidence_sha256);
|
||||
|
||||
value.oriented_width = 6000;
|
||||
value.oriented_height = 4000;
|
||||
const double params[8] = {
|
||||
4000.0, 4002.0, 3000.0, 2000.0, -0.1, 0.01, 0.001, -0.001,
|
||||
};
|
||||
for (size_t run = 0; run < 3; ++run)
|
||||
memcpy(value.repeated_parameters[run], params, sizeof(params));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int test_happy_path_and_identity_stability(void) {
|
||||
Lardon3DCalibrationWorkflowExternalEvidence external = fixture();
|
||||
Lardon3DCalibrationAfStudySample fit = {0};
|
||||
Lardon3DCalibrationAfStudySample holdout = {0};
|
||||
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT,
|
||||
"sony-focus:137", &fit) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK);
|
||||
CHECK(fit.role == LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT);
|
||||
CHECK(strcmp(fit.focus_token, "sony-focus:137") == 0);
|
||||
CHECK(fit.fx == 4000.0 && fit.fy == 4002.0);
|
||||
CHECK(fit.cx == 3000.0 && fit.cy == 2000.0);
|
||||
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_HOLDOUT,
|
||||
"different-focus-label", &holdout) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK);
|
||||
|
||||
CHECK(memcmp(fit.calibration_evidence_sha256,
|
||||
holdout.calibration_evidence_sha256, 32) == 0);
|
||||
unsigned char zero[32] = {0};
|
||||
CHECK(memcmp(fit.calibration_evidence_sha256, zero, 32) != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_identity_binds_provenance_and_parameters(void) {
|
||||
Lardon3DCalibrationWorkflowExternalEvidence a = fixture();
|
||||
Lardon3DCalibrationWorkflowExternalEvidence b = fixture();
|
||||
Lardon3DCalibrationAfStudySample sample_a = {0};
|
||||
Lardon3DCalibrationAfStudySample sample_b = {0};
|
||||
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&a, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample_a) == LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK);
|
||||
|
||||
b.target_sha256[0] ^= 1;
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&b, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample_b) == LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK);
|
||||
CHECK(memcmp(sample_a.calibration_evidence_sha256,
|
||||
sample_b.calibration_evidence_sha256, 32) != 0);
|
||||
|
||||
b = fixture();
|
||||
for (size_t run = 0; run < 3; ++run)
|
||||
b.repeated_parameters[run][0] += 1.0;
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&b, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample_b) == LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_OK);
|
||||
CHECK(memcmp(sample_a.calibration_evidence_sha256,
|
||||
sample_b.calibration_evidence_sha256, 32) != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_invalid_materialization_rejected(void) {
|
||||
Lardon3DCalibrationWorkflowExternalEvidence external = fixture();
|
||||
Lardon3DCalibrationAfStudySample sample;
|
||||
memset(&sample, 0xA5, sizeof(sample));
|
||||
|
||||
external.validation_evidence_sha256[0] ^= 1;
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE);
|
||||
Lardon3DCalibrationAfStudySample zero = {0};
|
||||
CHECK(memcmp(&sample, &zero, sizeof(sample)) == 0);
|
||||
|
||||
external = fixture();
|
||||
external.repeated_parameters[1][0] += 1.0;
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE);
|
||||
|
||||
external = fixture();
|
||||
external.repeated_parameters[0][0] = NAN;
|
||||
external.repeated_parameters[1][0] = NAN;
|
||||
external.repeated_parameters[2][0] = NAN;
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE);
|
||||
|
||||
external = fixture();
|
||||
external.optical_state_sha256[0] ^= 1;
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_EVIDENCE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_invalid_arguments(void) {
|
||||
Lardon3DCalibrationWorkflowExternalEvidence external = fixture();
|
||||
Lardon3DCalibrationAfStudySample sample = {0};
|
||||
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
NULL, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "focus:a",
|
||||
&sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_ARGUMENT);
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, 0, "focus:a", &sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_ARGUMENT);
|
||||
CHECK(lardon3d_calibration_af_study_sample_from_materialized_evidence(
|
||||
&external, LARDON3D_CALIBRATION_AF_STUDY_SAMPLE_FIT, "",
|
||||
&sample) ==
|
||||
LARDON3D_CALIBRATION_AF_STUDY_WORKFLOW_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
CHECK(test_happy_path_and_identity_stability() == 0);
|
||||
CHECK(test_identity_binds_provenance_and_parameters() == 0);
|
||||
CHECK(test_invalid_materialization_rejected() == 0);
|
||||
CHECK(test_invalid_arguments() == 0);
|
||||
puts("CALIBRATION_AF_STUDY_WORKFLOW_BRIDGE_V1=PASS");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue