fix(store): bump the graph digest stream to version 2

The canonical graph digest now streams index_unresolved_candidates when
the table exists and binds the unresolved_calls_complete column of
index_coverage_meta, but its version word was still 1. A holder of an
older digest, such as the test-impact receipt's graph_sha256, would then
compare two different stream definitions under one version number.

Bump CBM_STORE_GRAPH_DIGEST_VERSION to 2 and document what each version
streams. The golden fixture has neither the table nor the column, so its
stream differs from version 1 only in the version word: still 17 rows and
4038 framed bytes, with a new golden SHA-256, and the test now asserts
version 2.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-10-25 22:30:47 +01:00
1 parent 3b37d9e230
commit 24bd38c4bf
3 files changed
+17 -5

No files matched your search

+2 -1
View File
@@ -706,7 +706,8 @@ static bool gd_table_rows(gd_context_t *g, int index, bool present) {
static bool gd_stream_tables(gd_context_t *g, const bool present[GD_TABLE_COUNT]) {
for (int i = 0; i < GD_TABLE_COUNT; i++) {
/* Legacy stores retain their byte-for-byte canonical stream. */
/* A store without the candidate table streams the same tables as
* version 1; only the version word differs. */
if (i == GD_UNRESOLVED_CANDIDATES && !present[i]) {
continue;
}
+9 -2
View File
@@ -7,7 +7,14 @@
#include <stddef.h>
#include <stdint.h>
#define CBM_STORE_GRAPH_DIGEST_VERSION 1u
/* Canonical stream version, hashed right after the domain string. A bump
* changes every digest, so a holder of an older digest (the test-impact
* receipt's graph_sha256) sees a mismatch instead of comparing two different
* stream definitions.
* 1 The nine tables projects .. store_meta.
* 2 #2265: also index_unresolved_candidates (streamed only when present) and
* index_coverage_meta.unresolved_calls_complete (bound when present). */
#define CBM_STORE_GRAPH_DIGEST_VERSION 2u
#define CBM_STORE_GRAPH_DIGEST_BYTES 32u
typedef enum {
@@ -32,7 +39,7 @@ typedef struct {
uint64_t framed_bytes;
} cbm_store_graph_digest_t;
/* Borrow a live, exclusive D5 scope. Hash the version-1 canonical stream of
/* Borrow a live, exclusive D5 scope. Hash the version-2 canonical stream of
* the nine legacy tables and the unresolved candidate index when present,
* including their exact CREATE SQL and explicit project
* identity. The database must use UTF-8. No new handler or transaction is used.
+6 -2
View File
@@ -38,7 +38,11 @@ static const char *const gd_inserts[] = {
"INSERT INTO index_coverage(project,rel_path,kind,detail) VALUES(CAST(X'70' AS TEXT),CAST(X'62' AS TEXT),CAST(X'736b6970' AS TEXT),CAST(X'' AS TEXT));",
"INSERT INTO index_coverage_meta(project,generation,index_mode,recorded_at,recording_status,ignored_files_stored,ignored_files_total,coverage_version,hash_records_complete) VALUES(CAST(X'70' AS TEXT),CAST(X'67656e' AS TEXT),CAST(X'66756c6c' AS TEXT),CAST(X'74' AS TEXT),CAST(X'636f6d706c657465' AS TEXT),-1,0,1,1);",
};
static const unsigned char gd_golden_sha[32] = { 0x46, 0x44, 0x71, 0x72, 0xdc, 0x9b, 0x2d, 0xa8, 0xda, 0xc8, 0x54, 0x5a, 0x56, 0x88, 0xab, 0x59, 0x1d, 0xad, 0x39, 0xe2, 0x9b, 0xe6, 0x33, 0x9c, 0x3d, 0x26, 0x49, 0x27, 0xd0, 0x94, 0xe9, 0x3e };
/* Stream version 2: the oracle's version-1 stream (4038 framed bytes, golden
* 46447172dc9b2da8...) with only its version word set to 2. This fixture has
* no index_unresolved_candidates table and no unresolved_calls_complete
* column, so nothing else in its stream changes. */
static const unsigned char gd_golden_sha[32] = { 0xd0, 0x51, 0xc4, 0x56, 0x11, 0x5c, 0xf7, 0x3c, 0x75, 0xe2, 0x89, 0xb5, 0xc3, 0x92, 0xa2, 0x56, 0xa5, 0x66, 0xe6, 0x62, 0xfd, 0x56, 0x66, 0x35, 0x05, 0xc6, 0x1e, 0xa5, 0x49, 0x7d, 0xa1, 0x30 };
#define GD_GOLDEN_ROWS UINT64_C(17)
#define GD_GOLDEN_BYTES UINT64_C(4038)
@@ -190,7 +194,7 @@ TEST(store_graph_digest_independent_canonical_golden) {
gd_int(cbm_store_get_db(s),"SELECT length(CAST(properties AS BLOB)) FROM nodes WHERE id=-7",4) &&
gd_int(cbm_store_get_db(s),"SELECT count(*) FROM lsp_surface WHERE typeof(ref_bloom)='blob'",2);
bool got=setup && gd_p(s,&out); cbm_store_close(s);
ASSERT_TRUE(setup); ASSERT_TRUE(got); ASSERT_EQ(out.version,1);
ASSERT_TRUE(setup); ASSERT_TRUE(got); ASSERT_EQ(out.version,2);
ASSERT_TRUE(out.rows==GD_GOLDEN_ROWS); ASSERT_TRUE(out.framed_bytes==GD_GOLDEN_BYTES);
ASSERT_TRUE(memcmp(out.sha256,gd_golden_sha,32)==0); PASS();
}