test_projector_loop_stub

This commit is contained in:
Carl Niklas Rydberg 2026-02-21 20:07:57 +01:00
parent baa4794918
commit 7b3ef3eab4
2 changed files with 180 additions and 0 deletions

View file

@ -121,6 +121,21 @@ for (;;) {
* Cursor paging boundaries MUST NOT affect results. * Cursor paging boundaries MUST NOT affect results.
* A checkpoint MUST allow resume without changing derived outcomes. * A checkpoint MUST allow resume without changing derived outcomes.
### 4.3 Implementation Slice (Checklist + Stub)
**Checklist (minimal, repo-aligned):**
* Choose a stable `projection_name`, `projection_schema_version`, and `builder_id`.
* Read authoritative head state via `amduat_asl_index_current_state`.
* Page log records with `amduat_asl_log_read_since` (cursor-driven).
* Apply a deterministic projection step (even if it is just a counter in the stub).
* Encode a checkpoint via `amduat_asl_projection_checkpoint_encode_v1`.
* Store the checkpoint as an ASL record with schema `projection/checkpoint`.
* Verify the stored checkpoint decodes and matches the last processed `log_position`.
**Repo stub:** `tests/asl/test_asl_projection_replay.c` includes
`test_projector_loop_stub()` that runs the minimal loop and persists a checkpoint.
--- ---
## 5. Projection Checkpoint Records ## 5. Projection Checkpoint Records

View file

@ -351,6 +351,168 @@ cleanup_root:
return exit_code; return exit_code;
} }
static int test_projector_loop_stub(void) {
amduat_asl_store_config_t config;
amduat_asl_store_index_fs_t fs;
amduat_asl_store_t store;
amduat_asl_index_state_t state;
amduat_asl_log_record_t *page = NULL;
size_t page_len = 0u;
amduat_asl_log_position_t after = 0u;
amduat_asl_log_position_t next = 0u;
bool end = false;
amduat_reference_t checkpoint_ref;
amduat_asl_record_t checkpoint_record;
amduat_asl_projection_checkpoint_v1_t checkpoint;
amduat_asl_projection_checkpoint_v1_t decoded;
amduat_octets_t checkpoint_bytes = amduat_octets(NULL, 0u);
size_t projected_count = 0u;
char *root;
int exit_code = 1;
root = make_temp_root();
if (root == NULL) {
fprintf(stderr, "temp root failed\n");
return 1;
}
memset(&config, 0, sizeof(config));
config.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1;
config.hash_id = AMDUAT_HASH_ASL1_ID_SHA256;
if (!amduat_asl_store_index_fs_init(&fs, config, root)) {
fprintf(stderr, "index fs init failed\n");
goto cleanup_root;
}
amduat_asl_store_init(&store, config, amduat_asl_store_index_fs_ops(), &fs);
{
uint8_t payload_a[2] = {0x10, 0x20};
uint8_t payload_b[2] = {0x30, 0x40};
amduat_reference_t ref = amduat_reference(0u, amduat_octets(NULL, 0u));
amduat_artifact_t artifact = amduat_artifact(amduat_octets(payload_a, sizeof(payload_a)));
if (amduat_asl_store_put_indexed(&store, artifact, &ref, &state) !=
AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "put_indexed A failed\n");
amduat_reference_free(&ref);
goto cleanup_root;
}
amduat_reference_free(&ref);
artifact = amduat_artifact(amduat_octets(payload_b, sizeof(payload_b)));
ref = amduat_reference(0u, amduat_octets(NULL, 0u));
if (amduat_asl_store_put_indexed(&store, artifact, &ref, &state) !=
AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "put_indexed B failed\n");
amduat_reference_free(&ref);
goto cleanup_root;
}
amduat_reference_free(&ref);
}
if (!amduat_asl_index_current_state(&store, &state)) {
fprintf(stderr, "current_state failed\n");
goto cleanup_root;
}
checkpoint_ref = amduat_reference(0u, amduat_octets(NULL, 0u));
while (!end) {
if (!amduat_asl_log_read_since(&store,
after,
0u,
&page,
&page_len,
&next,
&end)) {
fprintf(stderr, "projector log read failed\n");
goto cleanup_checkpoint_ref;
}
projected_count += page_len;
memset(&checkpoint, 0, sizeof(checkpoint));
checkpoint.checkpoint_version = AMDUAT_ASL_PROJECTION_CHECKPOINT_VERSION_V1;
checkpoint.projection_name =
amduat_octets("projector-stub", strlen("projector-stub"));
checkpoint.projection_schema_version = 1u;
checkpoint.has_snapshot_id = true;
checkpoint.snapshot_id = state.snapshot_id;
checkpoint.log_position = next;
checkpoint.created_at = 0u;
checkpoint.builder_id =
amduat_octets("test-projector", strlen("test-projector"));
checkpoint.has_artifact_count = true;
checkpoint.artifact_count = projected_count;
if (!amduat_asl_projection_checkpoint_encode_v1(&checkpoint,
&checkpoint_bytes)) {
fprintf(stderr, "checkpoint encode failed\n");
amduat_enc_asl_log_free(page, page_len);
goto cleanup_checkpoint_ref;
}
amduat_reference_free(&checkpoint_ref);
if (amduat_asl_record_store_put(
&store,
amduat_octets("projection/checkpoint",
strlen("projection/checkpoint")),
checkpoint_bytes,
&checkpoint_ref) != AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "checkpoint store failed\n");
amduat_octets_free(&checkpoint_bytes);
amduat_enc_asl_log_free(page, page_len);
goto cleanup_checkpoint_ref;
}
amduat_octets_free(&checkpoint_bytes);
amduat_enc_asl_log_free(page, page_len);
after = next;
}
if (amduat_asl_record_store_get(&store, checkpoint_ref, &checkpoint_record) !=
AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "checkpoint record get failed\n");
goto cleanup_checkpoint_ref;
}
if (!amduat_octets_eq(
checkpoint_record.schema,
amduat_octets("projection/checkpoint",
strlen("projection/checkpoint")))) {
fprintf(stderr, "checkpoint schema mismatch\n");
amduat_asl_record_free(&checkpoint_record);
goto cleanup_checkpoint_ref;
}
if (!amduat_asl_projection_checkpoint_decode_v1(
checkpoint_record.payload, &decoded)) {
fprintf(stderr, "checkpoint decode failed\n");
amduat_asl_record_free(&checkpoint_record);
goto cleanup_checkpoint_ref;
}
if (decoded.log_position != state.log_position) {
fprintf(stderr, "checkpoint log position mismatch\n");
amduat_asl_projection_checkpoint_free(&decoded);
amduat_asl_record_free(&checkpoint_record);
goto cleanup_checkpoint_ref;
}
amduat_asl_projection_checkpoint_free(&decoded);
amduat_asl_record_free(&checkpoint_record);
exit_code = 0;
cleanup_checkpoint_ref:
amduat_octets_free(&checkpoint_bytes);
amduat_reference_free(&checkpoint_ref);
cleanup_root:
if (!remove_tree(root)) {
fprintf(stderr, "cleanup failed\n");
exit_code = 1;
}
free(root);
return exit_code;
}
int main(void) { int main(void) {
if (test_cursor_deterministic_replay() != 0) { if (test_cursor_deterministic_replay() != 0) {
return 1; return 1;
@ -358,5 +520,8 @@ int main(void) {
if (test_checkpoint_resume() != 0) { if (test_checkpoint_resume() != 0) {
return 1; return 1;
} }
if (test_projector_loop_stub() != 0) {
return 1;
}
return 0; return 0;
} }