Skip to content

feat(core/oid): migrate edge/cache to gm helpers - #173

Merged
flyingrobots merged 8 commits into
mainfrom
feat/edge-port-followup
Sep 29, 2025
Merged

flyingrobots merged 8 commits into
mainfrom
feat/edge-port-followup

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Sep 29, 2025 •

Copy link
Copy Markdown
Owner

Summary

  • add gm_oid_from_raw/from_hex/equal/is_zero utils and update edge, cache, hooks, journal to use them
  • zero-initialize cache metadata to eliminate flaky oid comparisons
  • migrate unit tests to gm helpers and log activity updates

Testing

  • make ci-local

Summary by CodeRabbit

  • New Features

    • Added public OID utilities (raw/hex parsing, equality, zero-check) and exposed them via the public header.
  • Bug Fixes

    • Zero-initialize cache metadata to prevent cache-query assertions.
    • Hardened OID parsing with explicit length validation and clear error returns.
  • Refactor

    • Replaced legacy external OID helpers with unified internal utilities across the codebase.
  • Documentation

    • Updated activity log; removed/added archived code-review artifacts.
  • Tests

    • Updated unit tests to use new OID utilities and assert explicit success.

@coderabbitai

coderabbitai Bot commented Sep 29, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a new gm_oid utility API (gm_oid_equal, gm_oid_is_zero, gm_oid_from_raw, gm_oid_from_hex, and related helpers), migrates core modules and many unit tests from libgit2 git_oid_* to the gm_oid_* API, tightens cache/journal OID handling and init, removes multiple archived PR172 code-review artifacts, and adds PR173 review artifacts and activity docs updates.

Changes

Cohort / File(s) Summary
OID utilities API
core/include/gitmind/util/oid.h, core/src/util/oid.c
Add public gm_oid_* APIs: gm_oid_equal, gm_oid_is_zero, gm_oid_from_raw, gm_oid_from_hex; add internal hex parser, defensive checks, and preserve gm_oid_to_hex.
Cache & query
core/src/cache/query.c
Remove local hex/oid helpers; use gm_memset_safe for meta init; use gm_oid_is_zero, gm_oid_from_hex, gm_oid_equal in stale checks and comparisons.
Journal writer
core/src/journal/writer.c
Replace git2 OID helpers with gm_oid_from_hex/gm_oid_to_hex; narrow internal commit OID param to gm_oid_t; maintain commit/parent flow with new OID helpers.
Edge & attributed handling
core/src/edge/edge.c, core/src/edge/attributed.c
Replace git_oid_* usage with gm_oid_* for encode/decode, backfill, and comparisons; add error handling when parsing OIDs from raw/hex.
Domain / edge map
core/src/domain/cache/edge_map.c
Validate bucket_count != 0; replace git_oid_cmp with gm_oid_equal; remove git2/oid.h include and add gitmind/util/oid.h.
Hooks / augment
core/src/hooks/augment.c
Use gm_oid_equal for comparisons; adopt GM_CALLBACK_STOP and GM_OK sentinel checks; add oid util include and stdlib.h.
Adapters
core/src/adapters/git/libgit2_repository_port.c
Include gitmind/util/oid.h; switch git_oid_equal → gm_oid_equal in reference update logic.
Public umbrella header
include/gitmind.h
Expose gitmind/util/oid.h via the public umbrella header.
Unit tests (many files)
core/tests/unit/* (e.g., test_cache_query.c, test_cache_edge_map.c, test_edge_cbor_oid.c, test_journal_*, test_cache_*, ...)
Replace git_oid_fromraw/git_oid_fromstr/git_oid_cmp with gm_oid_from_raw/gm_oid_from_hex/gm_oid_equal/gm_oid_is_zero; add GM_OK assertions; add safe string ops and new header includes.
Docs — activity & agents
docs/activity/2025-09.md, AGENTS.md
Add 2025‑09‑29 activity entry describing gm_oid utilities and migration; update AGENTS.md narrative and next steps.
Docs — code review artifacts
docs/code-reviews/PR172/*, docs/code-reviews/PR173/*
Remove multiple archived PR172 review artifact files; add PR173 review artifact markdown.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller as CacheUser
  participant CQ as cache/query.c
  participant OID as gm_oid utils
  participant Meta as CacheMeta

  Caller->>CQ: gm_cache_is_stale(repo, branch)
  CQ->>Meta: read meta (tip oids)
  alt binary tip present
    CQ->>OID: gm_oid_is_zero(meta.journal_tip_oid_bin)
    alt not zero
      CQ->>OID: gm_oid_equal(meta.journal_tip_oid_bin, current_tip.oid)
      OID-->>CQ: equal?/not
    else zero
      CQ->>OID: gm_oid_from_hex(&cached_tip, meta.journal_tip_oid)
      OID-->>CQ: GM_OK/ERR
    end
  else no binary tip
    CQ->>OID: gm_oid_from_hex(&cached_tip, meta.journal_tip_oid)
    OID-->>CQ: GM_OK/ERR
  end
  CQ-->>Caller: stale?/fresh status
Loading
sequenceDiagram
  autonumber
  actor Producer as EdgeEncoder
  participant EDGE as edge/edge.c
  participant OID as gm_oid utils

  Producer->>EDGE: encode/decode edge
  EDGE->>OID: gm_oid_is_zero(src_oid/tgt_oid)
  alt OIDs present
    EDGE->>OID: gm_oid_equal(...) for comparisons
    OID-->>EDGE: equal?/not
  else fallback
    EDGE->>OID: gm_oid_from_raw(&oid, sha_raw, GM_OID_RAWSZ)
    OID-->>EDGE: GM_OK/ERR
  end
  EDGE-->>Producer: result (edge state)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Poem

I hop through hex and tidy bytes,
I nibble zeros on quiet nights,
From raw to oid I parse and test,
I whisper "GM_OK" and then rest.
Thump-thump — the cache sleeps tight. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description includes a summary and testing instructions but is missing required template sections such as Change Areas, Risk assessment, and Code Review Guidance, and it introduces a Testing section not defined by the repository template. Please update the description to follow the repository template by adding the Change Areas checklist, Risk assessment categories, and a Code Review Guidance section, and relocate or remove the Testing section under its appropriate heading if necessary.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title follows the conventional commit style by specifying the feature area and indicates migrating edge and cache modules to the new gm-OID helpers, which accurately reflects a significant portion of the changes; although it omits hooks and journal updates, it still refers to real aspects of the change.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/edge-port-followup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (12)
docs/activity/2025-09.md (1)

1-12: Add SPDX header, H1, and Table of Contents

Conform this activity log to house style: SPDX after front matter, single H1 matching title, and a ToC.

As per coding guidelines

 ---
 title: Activity 2025-09
 description: Archived agent activity logs.
 audience: [contributors]
 domain: [quality]
 tags: [activity]
 status: archive
 last_updated: 2025-09-29
 ---
 
-## 2025-09-29
+<!-- SPDX-License-Identifier: LicenseRef-MIND-UCAL-1.0 -->
+
+# Activity 2025-09
+
+## Table of Contents
+- 2025-09-29
+- 2025-09-20
+- 2025-09-19
+- 2025-09-14
+
+## 2025-09-29
core/tests/unit/test_edge_oid_fallback.c (1)

23-25: Replace strcpy with safe gm string API and check return codes

Tests must use gm_strcpy_safe/gm_snprintf per guidelines; also check return codes.

As per coding guidelines

 #include "gitmind/edge.h"
 #include "gitmind/util/oid.h"
 #include "gitmind/error.h"
+#include "gitmind/util/strings.h"
 
@@
-    strcpy(a.src_path, "A"); strcpy(a.tgt_path, "B");
-    strcpy(b.src_path, "A"); strcpy(b.tgt_path, "B");
+    assert(gm_strcpy_safe(a.src_path, sizeof a.src_path, "A") == 0);
+    assert(gm_strcpy_safe(a.tgt_path, sizeof a.tgt_path, "B") == 0);
+    assert(gm_strcpy_safe(b.src_path, sizeof b.src_path, "A") == 0);
+    assert(gm_strcpy_safe(b.tgt_path, sizeof b.tgt_path, "B") == 0);
core/src/domain/cache/edge_map.c (1)

79-99: Disallow bucket_count == 0 to prevent OOB access in add

With zero buckets, gm_edge_map_add computes index 0 and dereferences map->buckets[0], which is OOB. Reject zero at creation.

 gm_result_void_t gm_edge_map_create(size_t bucket_count, gm_edge_map_t **out_map) {
     if (out_map == NULL) {
         return gm_err_void(
             GM_ERROR(GM_ERR_INVALID_ARGUMENT, "edge map output pointer required"));
     }
 
+    if (bucket_count == 0U) {
+        return gm_err_void(
+            GM_ERROR(GM_ERR_INVALID_ARGUMENT, "bucket_count must be > 0"));
+    }
+
     gm_edge_map_t *map = calloc(1, sizeof(gm_edge_map_t));
     if (map == NULL) {
         return gm_err_void(GM_ERROR(GM_ERR_OUT_OF_MEMORY, "edge map alloc failed"));
     }
core/src/hooks/augment.c (2)

181-186: Replace magic number with GM_CALLBACK_STOP consistently.

Return GM_CALLBACK_STOP from the callback and check for it at the call site; relying on literal 1 is brittle.

-    if (ctx->scanned > LOOKBACK_LIMIT) {
-        return 1; /* Stop iteration */
+    if (ctx->scanned > LOOKBACK_LIMIT) {
+        return GM_CALLBACK_STOP; /* Stop iteration */
     }
...
-    if (error < 0 && error != 1) { /* 1 means we stopped early */
+    if (error < 0 && error != GM_CALLBACK_STOP) { /* stopped early */
         free(search_ctx.edges);
         return error;
     }

Also applies to: 223-226


4-18: Missing <stdlib.h> for malloc/realloc/free under C23 (warnings-as-errors).

malloc/realloc/free are used below without including <stdlib.h>; this will fail our C23 + Werror build.

 #include "gitmind/hooks/augment.h"
 
 #include <ctype.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
core/tests/unit/test_cache_branch_limits.c (1)

82-85: Replace unsafe strcpy with gm_strcpy_safe and check return codes.

Tests follow the same safety rules: use gm_strcpy_safe and fail on truncation.

-    strcpy(edge.src_path, "A");
-    strcpy(edge.tgt_path, "B");
+    assert(gm_strcpy_safe(edge.src_path, GM_PATH_MAX, "A") == GM_OK);
+    assert(gm_strcpy_safe(edge.tgt_path, GM_PATH_MAX, "B") == GM_OK);

Add the needed include if not present:

+#include "gitmind/util/memory.h"

As per coding guidelines

core/tests/unit/test_edge_cbor_oid.c (1)

24-27: Use gm_strcpy_safe for paths and ULID; fail on truncation.

Bring test in line with string safety rules.

-    strcpy(e.src_path, "src/A.c");
-    strcpy(e.tgt_path, "src/B.c");
-    strcpy(e.ulid, "01ARZ3NDEKTSV4RRFFQ69G5FAV");
+    assert(gm_strcpy_safe(e.src_path, GM_PATH_MAX, "src/A.c") == GM_OK);
+    assert(gm_strcpy_safe(e.tgt_path, GM_PATH_MAX, "src/B.c") == GM_OK);
+    assert(gm_strcpy_safe(e.ulid, sizeof e.ulid, "01ARZ3NDEKTSV4RRFFQ69G5FAV") == GM_OK);

Add header if missing:

+#include "gitmind/util/memory.h"

As per coding guidelines

core/tests/unit/test_cache_query.c (1)

37-39: Prefer gm_snprintf and check truncation

Replace raw snprintf with gm_snprintf and assert the result for determinism.

-    char refname[128];
-    snprintf(refname, sizeof refname, "refs/heads/%s", branch);
+    char refname[128];
+    int wn = gm_snprintf(refname, sizeof refname, "refs/heads/%s", branch);
+    assert(wn >= 0 && (size_t)wn < sizeof refname);

Include:

#include "gitmind/security/string.h"

As per coding guidelines.

core/tests/unit/test_journal_safety.c (1)

4-8: Missing stdlib.h for malloc/free — will fail under C23 with Werror.

Add the header to satisfy prototypes and avoid implicit declarations.

 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 #include <sodium.h>
+#include <stdlib.h>
core/include/gitmind/util/oid.h (1)

4-76: Remove lingering direct libgit2 OID helper calls

  • Replace the call to git_oid_equal at core/src/adapters/git/libgit2_repository_port.c:926 with gm_oid_equal.
core/src/cache/query.c (1)

169-172: Fix unsigned underflow in staleness age check

If meta.journal_tip_time > now, (uint64_t)now - meta.journal_tip_time underflows, marking fresh caches as stale. Guard and only subtract when now_u > journal_tip_time.

-    time_t now = time(NULL);
-    if ((uint64_t)now - meta.journal_tip_time > CACHE_MAX_AGE_SECONDS) {
-        return true;
-    }
+    time_t now = time(NULL);
+    if (now <= 0) {
+        return true;
+    }
+    uint64_t now_u = (uint64_t)now;
+    if (now_u > meta.journal_tip_time &&
+        (now_u - meta.journal_tip_time) > CACHE_MAX_AGE_SECONDS) {
+        return true;
+    }
core/tests/unit/test_journal_mixed_cbor.c (1)

56-57: Replace unsafe strcpy with gm_strcpy_safe and check results

Tests must follow the same safe string/memory rules. Replace strcpy, assert GM_OK, and keep buffers zero‑initialized on failure paths.

-    strcpy(e.src_path, "src/A.c"); strcpy(e.tgt_path, "src/B.c");
+    assert(gm_strcpy_safe(e.src_path, sizeof e.src_path, "src/A.c") == GM_OK);
+    assert(gm_strcpy_safe(e.tgt_path, sizeof e.tgt_path, "src/B.c") == GM_OK);
@@
-    strcpy(ae.src_path, "docs/A.md"); strcpy(ae.tgt_path, "src/C.c");
+    assert(gm_strcpy_safe(ae.src_path, sizeof ae.src_path, "docs/A.md") == GM_OK);
+    assert(gm_strcpy_safe(ae.tgt_path, sizeof ae.tgt_path, "src/C.c") == GM_OK);
@@
-    strcpy(ae.attribution.author, "claude@local");
-    strcpy(ae.attribution.session_id, "s1");
+    assert(gm_strcpy_safe(ae.attribution.author, sizeof ae.attribution.author, "claude@local") == GM_OK);
+    assert(gm_strcpy_safe(ae.attribution.session_id, sizeof ae.attribution.session_id, "s1") == GM_OK);

As per coding guidelines

Also applies to: 66-67, 71-73

🧹 Nitpick comments (15)
docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md (1)

82-99: Remove template-only “finishing touches” block from archival artifact

This checkbox block is a workflow scaffold, not archival content. Consider removing to keep the record concise.

core/src/util/oid.c (1)

94-112: Unify error on copy failure

If gm_memcpy_span ever fails here (after length check), treating it as invalid argument is clearer than BUFFER_TOO_SMALL.

-    if (gm_memcpy_span(oid->id, GM_OID_RAWSZ, raw, raw_len) != 0) {
+    if (gm_memcpy_span(oid->id, GM_OID_RAWSZ, raw, raw_len) != 0) {
         gm_memset_safe(oid, sizeof(*oid), 0, sizeof(*oid));
-        return GM_ERR_BUFFER_TOO_SMALL;
+        return GM_ERR_INVALID_ARGUMENT;
     }
core/tests/unit/test_edge_oid_fallback.c (1)

18-21: Prefer gm_memset_safe for deterministic zero/nonzero fills

For consistency with security APIs used elsewhere, switch to gm_memset_safe.

As per coding guidelines

-    memset(a.src_sha, 0x11, GM_SHA1_SIZE);
-    memset(a.tgt_sha, 0x22, GM_SHA1_SIZE);
-    memset(b.src_sha, 0x11, GM_SHA1_SIZE);
-    memset(b.tgt_sha, 0x22, GM_SHA1_SIZE);
+    gm_memset_safe(a.src_sha, sizeof a.src_sha, 0x11, GM_SHA1_SIZE);
+    gm_memset_safe(a.tgt_sha, sizeof a.tgt_sha, 0x22, GM_SHA1_SIZE);
+    gm_memset_safe(b.src_sha, sizeof b.src_sha, 0x11, GM_SHA1_SIZE);
+    gm_memset_safe(b.tgt_sha, sizeof b.tgt_sha, 0x22, GM_SHA1_SIZE);

Note: add #include "gitmind/security/memory.h".

core/src/hooks/augment.c (1)

191-199: *Guard realloc growth against size_t overflow; prefer sizeof(ptr).

Add an overflow check before realloc and use sizeof(*ctx->edges) to avoid type drift.

-            size_t new_capacity = ctx->capacity * ARRAY_GROWTH_FACTOR;
-            gm_edge_t *new_edges =
-                realloc(ctx->edges, new_capacity * sizeof(gm_edge_t));
+            size_t new_capacity = ctx->capacity * ARRAY_GROWTH_FACTOR;
+            if (new_capacity < ctx->capacity ||
+                new_capacity > SIZE_MAX / sizeof(*ctx->edges)) {
+                return GM_ERR_OUT_OF_MEMORY;
+            }
+            gm_edge_t *new_edges =
+                realloc(ctx->edges, new_capacity * sizeof(*ctx->edges));
core/tests/unit/test_cache_shard_distribution.c (1)

21-24: Minor: prefer size_t for byte loops.

Small nit to avoid signed/unsigned mix.

-    for (int i = 0; i < GM_OID_RAWSZ; i++) raw[i] = (uint8_t)(lcg_next() & 0xFF);
+    for (size_t i = 0; i < GM_OID_RAWSZ; i++) raw[i] = (uint8_t)(lcg_next() & 0xFF);
core/tests/unit/test_cache_query.c (2)

10-10: Avoid internal libgit2 headers in unit tests

Use the public commit header instead of git2/sys/commit.h to reduce brittleness.

-#include <git2/sys/commit.h>
+#include <git2/commit.h>

69-73: Use temp FS port for per-test repo dir

Hardcoding ./.gm_cache_query_tmp can leave artifacts and cause cross-run interference. Prefer a unique temp dir from the fs temp port, then pass it to git_repository_init.

I can sketch a small helper to obtain a temp dir via ctx.fs_temp_port if helpful. Based on learnings.

core/src/edge/attributed.c (1)

155-166: Make OID encoding consistent with edge.c (avoid dead fallback)

src_raw is always non-null, so the ternary never picks e->src_sha. Prefer building fixed-size arrays and padding from SHA when OID is zero (mirrors core/src/edge/edge.c).

-    const uint8_t *src_raw = (const uint8_t *)e->src_oid.id;
-    const uint8_t *tgt_raw = (const uint8_t *)e->tgt_oid.id;
+    uint8_t src_raw[GM_OID_RAWSZ] = {0};
+    uint8_t tgt_raw[GM_OID_RAWSZ] = {0};
+    if (!gm_oid_is_zero(&e->src_oid)) {
+        gm_memcpy_span(src_raw, sizeof src_raw, e->src_oid.id, GM_OID_RAWSZ);
+    } else {
+        gm_memcpy_span(src_raw, sizeof src_raw, e->src_sha, GM_SHA1_SIZE);
+    }
+    if (!gm_oid_is_zero(&e->tgt_oid)) {
+        gm_memcpy_span(tgt_raw, sizeof tgt_raw, e->tgt_oid.id, GM_OID_RAWSZ);
+    } else {
+        gm_memcpy_span(tgt_raw, sizeof tgt_raw, e->tgt_sha, GM_SHA1_SIZE);
+    }
@@
-    r = gm_cbor_write_bytes(buffer + offset, avail - offset, src_raw ? src_raw : e->src_sha, GM_OID_RAWSZ);
+    r = gm_cbor_write_bytes(buffer + offset, avail - offset, src_raw, GM_OID_RAWSZ);
@@
-    r = gm_cbor_write_bytes(buffer + offset, avail - offset, tgt_raw ? tgt_raw : e->tgt_sha, GM_OID_RAWSZ);
+    r = gm_cbor_write_bytes(buffer + offset, avail - offset, tgt_raw, GM_OID_RAWSZ);

Keeps OID-first while ensuring deterministic encoding.

core/include/gitmind/util/oid.h (1)

57-66: Doc nit: clarify zeroing semantics on failure for gm_oid_from_raw.

Implementation clears *oid before validation and leaves it zeroed on error. Mirror that in the doc for consistency with gm_oid_from_hex.

 /**
  * Populate an OID from raw bytes.
  *
  * @param oid      Destination OID (must not be NULL)
  * @param raw      Source byte buffer
  * @param raw_len  Number of bytes provided in `raw`
- * @return GM_OK on success, GM_ERR_INVALID_ARGUMENT when parameters are invalid
+ * On entry, the destination is cleared. On failure, it remains all‑zero.
+ * @return GM_OK on success; GM_ERR_INVALID_ARGUMENT when parameters are invalid
core/tests/unit/test_edge_attributed_cbor.c (1)

23-25: Use gm_snprintf or gm_strcpy_safe instead of strcpy in tests.

Tests must use project‑safe string APIs and check truncation. Replace the strcpy calls and include the right header. As per coding guidelines

 #include <string.h>
 
 #include "gitmind/edge_attributed.h"
 #include "gitmind/cbor/cbor.h"
 #include "gitmind/cbor/keys.h"
 #include "gitmind/types.h"
+#include "gitmind/security/string.h"
 #include "gitmind/util/oid.h"
 #include "gitmind/error.h"
@@
-    strcpy(e.src_path, "docs/A.md");
-    strcpy(e.tgt_path, "src/A.c");
-    strcpy(e.ulid, "01ARZ3NDEKTSV4RRFFQ69G5FAV");
+    int n = gm_snprintf(e.src_path, sizeof e.src_path, "%s", "docs/A.md");
+    assert(n >= 0 && (size_t)n < sizeof e.src_path);
+    n = gm_snprintf(e.tgt_path, sizeof e.tgt_path, "%s", "src/A.c");
+    assert(n >= 0 && (size_t)n < sizeof e.tgt_path);
+    n = gm_snprintf(e.ulid, sizeof e.ulid, "%s", "01ARZ3NDEKTSV4RRFFQ69G5FAV");
+    assert(n >= 0 && (size_t)n < sizeof e.ulid);
@@
-    strcpy(e.attribution.author, "claude@local");
-    strcpy(e.attribution.session_id, "sess-1");
+    n = gm_snprintf(e.attribution.author, sizeof e.attribution.author, "%s", "claude@local");
+    assert(n >= 0 && (size_t)n < sizeof e.attribution.author);
+    n = gm_snprintf(e.attribution.session_id, sizeof e.attribution.session_id, "%s", "sess-1");
+    assert(n >= 0 && (size_t)n < sizeof e.attribution.session_id);

Also applies to: 31-32

core/src/cache/query.c (2)

163-164: Minor: redundant local zero‑init before gm_cache_load_meta

gm_cache_load_meta already zero‑initializes meta. Keeping this memset is harmless but redundant. Consider removing for clarity.

-    gm_cache_meta_t meta;
-    gm_memset_safe(&meta, sizeof(meta), 0, sizeof(meta));
+    gm_cache_meta_t meta;

211-211: Prefer OID‑sized hex buffer to avoid accidental mismatch

Use GM_OID_HEX_CHARS+1 instead of SHA_HEX_SIZE to couple the buffer to the encoded OID length.

-    char sha_hex[SHA_HEX_SIZE];
+    char sha_hex[GM_OID_HEX_CHARS + 1];
core/tests/unit/test_journal_mixed_cbor.c (3)

88-89: Build refs via gm_build_ref instead of hard‑coding "refs/"

Avoid double‑prefix and ensure normalization by constructing refs with gm_build_ref.

-    rc = gm_journal_create_commit(&ctx, "refs/gitmind/edges/test", payload, len1 + len2);
+    #include "gitmind/util/ref.h"
+    char ref_name[REF_NAME_BUFFER_SIZE];
+    assert(gm_build_ref(ref_name, sizeof ref_name, GITMIND_EDGES_REF_PREFIX, "test") == GM_OK);
+    rc = gm_journal_create_commit(&ctx, ref_name, payload, len1 + len2);

As per coding guidelines


10-14: Remove duplicate include of gitmind/error.h

gitmind/error.h is included twice; drop one to keep includes clean.

-#include "gitmind/error.h"

39-41: Optional: ensure test repo is isolated and cleaned up

Creating a fixed ./.gm_journal_tmp can leave artifacts. Prefer a mkdtemp‑style unique dir and delete it after.

Also applies to: 97-104

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 069ff59 and ebd9f75.

📒 Files selected for processing (29)
  • AGENTS.md (1 hunks)
  • core/include/gitmind/util/oid.h (2 hunks)
  • core/src/cache/query.c (4 hunks)
  • core/src/domain/cache/edge_map.c (2 hunks)
  • core/src/edge/attributed.c (3 hunks)
  • core/src/edge/edge.c (7 hunks)
  • core/src/hooks/augment.c (2 hunks)
  • core/src/journal/writer.c (4 hunks)
  • core/src/util/oid.c (2 hunks)
  • core/tests/unit/test_cache_branch_limits.c (2 hunks)
  • core/tests/unit/test_cache_edge_map.c (2 hunks)
  • core/tests/unit/test_cache_query.c (3 hunks)
  • core/tests/unit/test_cache_shard_distribution.c (2 hunks)
  • core/tests/unit/test_edge_attributed_cbor.c (4 hunks)
  • core/tests/unit/test_edge_cbor_oid.c (3 hunks)
  • core/tests/unit/test_edge_equal_semantics.c (2 hunks)
  • core/tests/unit/test_edge_oid_fallback.c (2 hunks)
  • core/tests/unit/test_journal_mixed_cbor.c (2 hunks)
  • core/tests/unit/test_journal_safety.c (2 hunks)
  • docs/activity/2025-09.md (1 hunks)
  • docs/code-reviews/PR172/203f4e3539b1d8fc73b641e94b0a420f2e592a14.md (0 hunks)
  • docs/code-reviews/PR172/5402cadb5e7a3f71e0bee7a1e05a1f5034d4fc3c.md (0 hunks)
  • docs/code-reviews/PR172/5add14fcdabafff59a99ea484d691140afdb68c3.md (0 hunks)
  • docs/code-reviews/PR172/7b7b5f565ef23d959b126b0df50e0a3992c52da2.md (0 hunks)
  • docs/code-reviews/PR172/82dab217893b6ee8bb8dcdca2217f9900a06b76f.md (0 hunks)
  • docs/code-reviews/PR172/8a32c6a810ebf632709cec6c928381c9c47fdee9.md (0 hunks)
  • docs/code-reviews/PR172/b22c22398de39c4ab93e1c747b1122d2241eed22.md (0 hunks)
  • docs/code-reviews/PR172/d11ee830d5615e5582114d625a52283760d61767.md (0 hunks)
  • docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md (1 hunks)
💤 Files with no reviewable changes (8)
  • docs/code-reviews/PR172/8a32c6a810ebf632709cec6c928381c9c47fdee9.md
  • docs/code-reviews/PR172/5add14fcdabafff59a99ea484d691140afdb68c3.md
  • docs/code-reviews/PR172/5402cadb5e7a3f71e0bee7a1e05a1f5034d4fc3c.md
  • docs/code-reviews/PR172/203f4e3539b1d8fc73b641e94b0a420f2e592a14.md
  • docs/code-reviews/PR172/82dab217893b6ee8bb8dcdca2217f9900a06b76f.md
  • docs/code-reviews/PR172/d11ee830d5615e5582114d625a52283760d61767.md
  • docs/code-reviews/PR172/7b7b5f565ef23d959b126b0df50e0a3992c52da2.md
  • docs/code-reviews/PR172/b22c22398de39c4ab93e1c747b1122d2241eed22.md
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{c,cc,cpp,cxx,h,hpp,hxx,m,mm}

📄 CodeRabbit inference engine (CLAUDE.md)

NEVER use NOLINT to suppress clang-tidy warnings; ALWAYS fix the underlying issue

Files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_shard_distribution.c
  • core/tests/unit/test_edge_equal_semantics.c
  • core/include/gitmind/util/oid.h
  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_cache_edge_map.c
  • core/src/hooks/augment.c
  • core/tests/unit/test_edge_attributed_cbor.c
  • core/tests/unit/test_cache_query.c
  • core/src/util/oid.c
  • core/src/journal/writer.c
  • core/src/cache/query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_edge_oid_fallback.c
  • core/tests/unit/test_journal_safety.c
{core,apps,tests}/**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

{core,apps,tests}/**/*.{c,h}: Use gm_snprintf, gm_strcpy_safe, and gm_memcpy_span for all string/memory operations; check return codes and treat truncation as an error; zero output buffers on error paths before copying/formatting
C23 only with warnings-as-errors; no VLAs; no shadowing; all functions have explicit prototypes
Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Prefer specific headers in includes; follow include order/regrouping enforced by .clang-format
Build refs via gm_build_ref and reject inputs starting with "refs/" to avoid double-prefixing; follow libgit2 ref-name safety via normalization

Files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_shard_distribution.c
  • core/tests/unit/test_edge_equal_semantics.c
  • core/include/gitmind/util/oid.h
  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_cache_edge_map.c
  • core/src/hooks/augment.c
  • core/tests/unit/test_edge_attributed_cbor.c
  • core/tests/unit/test_cache_query.c
  • core/src/util/oid.c
  • core/src/journal/writer.c
  • core/src/cache/query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_edge_oid_fallback.c
  • core/tests/unit/test_journal_safety.c
{core,apps}/**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

Naming: functions/variables lower_snake_case with gm_ prefix; macros UPPER_SNAKE; typedef’d types end with t; header guards begin with GITMIND

Files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_shard_distribution.c
  • core/tests/unit/test_edge_equal_semantics.c
  • core/include/gitmind/util/oid.h
  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_cache_edge_map.c
  • core/src/hooks/augment.c
  • core/tests/unit/test_edge_attributed_cbor.c
  • core/tests/unit/test_cache_query.c
  • core/src/util/oid.c
  • core/src/journal/writer.c
  • core/src/cache/query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_edge_oid_fallback.c
  • core/tests/unit/test_journal_safety.c
core/src/**/*.c

📄 CodeRabbit inference engine (AGENTS.md)

Do not allocate GM_PATH_MAX*2 buffers; prefer GM_PATH_MAX and allocate dynamically if larger is required

Files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/src/domain/cache/edge_map.c
  • core/src/hooks/augment.c
  • core/src/util/oid.c
  • core/src/journal/writer.c
  • core/src/cache/query.c
**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

Formatting must follow .clang-format (LLVM style, 4 spaces, 80 cols, pointer alignment right); run clang-format via pre-commit

Files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_shard_distribution.c
  • core/tests/unit/test_edge_equal_semantics.c
  • core/include/gitmind/util/oid.h
  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_cache_edge_map.c
  • core/src/hooks/augment.c
  • core/tests/unit/test_edge_attributed_cbor.c
  • core/tests/unit/test_cache_query.c
  • core/src/util/oid.c
  • core/src/journal/writer.c
  • core/src/cache/query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_edge_oid_fallback.c
  • core/tests/unit/test_journal_safety.c
core/src/domain/cache/**/*.c

📄 CodeRabbit inference engine (AGENTS.md)

Cache lives under refs/gitmind/cache/ and is rebuildable; do not merge cache refs

Files:

  • core/src/domain/cache/edge_map.c
core/src/domain/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep domain logic pure (no direct IO/libgit2/global state) and one responsibility per translation unit

Files:

  • core/src/domain/cache/edge_map.c
core/tests/unit/test_*.c

📄 CodeRabbit inference engine (AGENTS.md)

Unit tests live in core/tests/unit/ and must be deterministic and isolated; name files test_.c

Files:

  • core/tests/unit/test_cache_shard_distribution.c
  • core/tests/unit/test_edge_equal_semantics.c
  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_cache_edge_map.c
  • core/tests/unit/test_edge_attributed_cbor.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_edge_oid_fallback.c
  • core/tests/unit/test_journal_safety.c
{include,core/include/gitmind}/**/*.h

📄 CodeRabbit inference engine (AGENTS.md)

{include,core/include/gitmind}/**/*.h: Public headers must be umbrella-safe, compile standalone, use stable header guards, and include C++ linkage guards (extern "C")
Avoid public ABI breaks: when changing public structs, only append new fields at the end; mark old fields deprecated rather than removing/reordering

Files:

  • core/include/gitmind/util/oid.h
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Docs: include front matter first, a single H1 matching the title, a '## Table of Contents' section, and SPDX license comments after front matter; API docs must include api_version
Conform to markdownlint rules configured by .markdownlint.jsonc (e.g., underscore emphasis/strong, blockquote spacing, code fence and heading punctuation)

Files:

  • docs/activity/2025-09.md
  • docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Learnt from: flyingrobots
PR: neuroglyph/git-mind#169
File: docs/templates/code-review-feedback.md:26-33
Timestamp: 2025-09-16T17:10:27.477Z
Learning: The user (flyingrobots) uses Obsidian to view/edit Markdown files and prefers to keep Obsidian-specific syntax like collapsible callout markers (e.g., `[!NOTE]-` for collapsible callouts) even if they're not GitHub-compatible.
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Conventional commits and PR hygiene: type(scope): description, link issues, include test plan, keep clang-tidy at zero for touched files, update docs as needed

Applied to files:

  • AGENTS.md
  • docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist

Applied to files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_shard_distribution.c
  • core/tests/unit/test_edge_equal_semantics.c
  • core/include/gitmind/util/oid.h
  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_cache_edge_map.c
  • core/src/hooks/augment.c
  • core/tests/unit/test_edge_attributed_cbor.c
  • core/tests/unit/test_cache_query.c
  • core/src/util/oid.c
  • core/src/journal/writer.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_edge_oid_fallback.c
  • core/tests/unit/test_journal_safety.c
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind.h : Maintain umbrella API at include/gitmind.h

Applied to files:

  • core/src/edge/edge.c
  • core/src/edge/attributed.c
  • core/include/gitmind/util/oid.h
  • core/tests/unit/test_cache_branch_limits.c
  • core/src/hooks/augment.c
  • core/tests/unit/test_cache_query.c
  • core/src/journal/writer.c
  • core/tests/unit/test_journal_mixed_cbor.c
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to {include,core/include}/**/*.h : Header guards use GITMIND_* naming

Applied to files:

  • core/src/hooks/augment.c
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps}/**/*.{c,h} : Naming: functions/variables lower_snake_case with gm_ prefix; macros UPPER_SNAKE; typedef’d types end with _t; header guards begin with GITMIND_

Applied to files:

  • core/src/hooks/augment.c
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind/**/*.h : Public, namespaced headers live under include/gitmind/

Applied to files:

  • core/src/hooks/augment.c
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {include,core/include/gitmind}/**/*.h : Public headers must be umbrella-safe, compile standalone, use stable header guards, and include C++ linkage guards (extern "C")

Applied to files:

  • core/src/hooks/augment.c
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to core/src/domain/journal/**/*.c : Journal is append-only under refs/gitmind/edges/<branch>; never mutate history entries

Applied to files:

  • core/src/journal/writer.c
🧬 Code graph analysis (9)
core/src/edge/edge.c (1)
core/src/cbor/cbor.c (1)
  • gm_cbor_read_bytes (190-244)
core/src/edge/attributed.c (1)
core/src/cbor/cbor.c (1)
  • gm_cbor_read_bytes (190-244)
core/include/gitmind/util/oid.h (1)
core/src/util/oid.c (6)
  • bool (75-80)
  • bool (82-92)
  • int (36-63)
  • int (65-73)
  • int (94-112)
  • int (114-144)
core/tests/unit/test_cache_query.c (1)
core/src/cache/query.c (2)
  • gm_cache_query_fanout (386-390)
  • gm_cache_result_free (400-406)
core/src/util/oid.c (2)
core/include/gitmind/security/memory.h (1)
  • gm_memset_safe (47-59)
core/include/gitmind/util/memory.h (1)
  • gm_memcpy_span (32-47)
core/src/journal/writer.c (1)
core/include/gitmind/security/memory.h (1)
  • gm_memset_safe (47-59)
core/src/cache/query.c (1)
core/include/gitmind/security/memory.h (1)
  • gm_memset_safe (47-59)
core/tests/unit/test_journal_mixed_cbor.c (2)
core/src/types/ulid.c (1)
  • gm_ulid_generate (118-126)
core/src/edge/edge.c (1)
  • gm_edge_encode_cbor (260-361)
core/tests/unit/test_journal_safety.c (1)
core/src/edge/edge.c (1)
  • gm_edge_equal (112-141)
🔇 Additional comments (40)
core/src/util/oid.c (4)

75-80: LGTM: OID-first equality via byte-compare

Using memcmp over GM_OID_RAWSZ aligns with OID-first semantics; no SHA fallback here.

Based on learnings


82-92: Confirm NULL-semantics for gm_oid_is_zero

Returning true for NULL is convenient but can mask bugs if callers mistakenly pass NULL. Confirm all call sites intend this behavior; otherwise, consider returning false on NULL to force explicit zero-init.

Based on learnings


114-144: LGTM: Strict full-length hex parsing with case-insensitive nibbles

Length check + nibble validation + zeroing on error is solid and side-channel safe enough for our use.


36-63: LGTM: Safe hex encoding with overflow checks and zeroing

Argument validation, required-size computation, and out-buffer zeroing on failure look correct.

core/tests/unit/test_edge_oid_fallback.c (1)

29-36: LGTM: OID-first equality behavior is exercised correctly

Zero OIDs → SHA fallback; non-zero OIDs (different) → edges not equal. Matches policy.

Based on learnings

core/src/domain/cache/edge_map.c (1)

129-132: LGTM: Switch to gm_oid_equal for key match

Equality predicate aligns with OID-first rule and avoids libgit2 dependency here.

Based on learnings

core/src/hooks/augment.c (1)

16-16: Good: migrated to public OID utilities header.

Using gitmind/util/oid.h aligns this hook with the gm_oid_* API surface. Based on learnings

core/tests/unit/test_cache_edge_map.c (3)

11-11: Header update LGTM.

Including gitmind/util/oid.h is correct for gm_oid_* in tests. Based on learnings


15-16: Parsing OIDs via gm_oid_from_hex with GM_OK assert: good.

This makes failures explicit and decouples from libgit2.


39-41: OID-first equality via gm_oid_equal: good.

Aligns test semantics with production comparison rules. Based on learnings

core/tests/unit/test_cache_shard_distribution.c (1)

10-12: Headers LGTM.

Pulling in gitmind/util/oid.h and error definitions matches the new helpers.

core/tests/unit/test_cache_branch_limits.c (2)

18-18: Header update LGTM.

Using gitmind/util/oid.h in this test is correct.


77-79: Good: populate OIDs via gm_oid_from_raw with GM_OK asserts.

This removes libgit2 coupling for OID population.

core/tests/unit/test_edge_cbor_oid.c (3)

10-12: Headers LGTM.

Includes align with gm_oid_* usage and error handling.


31-33: Good: set OIDs via gm_oid_from_raw with explicit length checks.

Clear, deterministic setup for encode/decode.


45-50: OID-first equality usage is correct.

gm_oid_equal checks plus gm_edge_equal uphold OID-wins semantics. Based on learnings

AGENTS.md (1)

452-455: Docs alignment with OID-first + gm helpers looks good

The activity log accurately captures the gm_oid_to_hex migration and remaining sweep items. No changes requested. Run docs check to keep guardrails green.

make docs-verify

core/tests/unit/test_cache_query.c (2)

17-17: Good migration to gm_oid_ in tests*

Adopting gm_oid_from_raw and passing gm_oid_t into queries is aligned with the OID-first policy.

Also applies to: 91-96, 108-109, 114-115


120-129: Remove incorrect double-free warning The dispose callback only frees the port’s internal state and does not free repo, so calling git_repository_free(repo) is correct and does not double-free.

Likely an incorrect or invalid review comment.

core/src/edge/attributed.c (1)

241-259: CBOR → raw bytes → gm_oid_from_raw is correct

Decoding OIDs via gm_cbor_read_bytes then gm_oid_from_raw with GM_OID_RAWSZ is the right flow.

core/src/journal/writer.c (4)

53-55: gm_oid_from_hex for EMPTY_TREE_SHA — good

Parsing the empty tree via gm helper aligns with the migration.


116-121: gm_oid_to_hex with zeroing on failure — nice hardening

Zeroing oid_hex on error follows the “zero outputs on error paths” rule.


126-128: Commit OID param narrowed to gm_oid_t*

Type narrowing keeps internal surfaces consistent with OID-first design.


374-376: Repeat of EMPTY_TREE_SHA parse via gm helper — consistent

Good consistency between writer entry points.

core/src/edge/edge.c (2)

117-131: OID-first equality is implemented correctly

Checks use gm_oid_is_zero + gm_oid_equal with SHA fallback only when OIDs are absent.

Based on learnings.

Also applies to: 129-133


319-346: CBOR OID encoding mirrors policy and pads from SHA when missing

Local fixed-size buffers + padding are correct and deterministic.

Also applies to: 348-357

core/include/gitmind/util/oid.h (2)

40-56: OID equality/zero helpers look correct and align with OID‑first semantics.

Null handling is explicit in both docs and implementation; this matches the project rule to prefer OIDs when present. Looks good. Based on learnings


68-76: gm_oid_from_hex API is well‑specified; LGTM.

Exact-length requirement and failure clearing behavior are documented and consistent with impl.

core/tests/unit/test_edge_attributed_cbor.c (4)

12-13: Correct include additions for gm OID helpers.

Brings in the new public API; good.


28-29: Good: length‑checked OID initialization via gm_oid_from_raw.

Passing sizeof raw* ensures strict GM_OID_RAWSZ validation.


43-44: Good: compare OIDs with gm_oid_equal (OID‑first).

Matches the repo’s equality rule. Based on learnings


110-111: Good: legacy backfill validated via non‑zero OIDs.

Assert ensures decode path populates OIDs from legacy SHAs.

core/tests/unit/test_journal_safety.c (2)

60-64: LGTM: OID‑first equality semantics are exercised correctly.

Using gm_oid_from_raw with explicit sizes and then asserting gm_edge_equal behavior matches the OID‑first rule even when legacy SHAs differ/match. Based on learnings

Also applies to: 76-77


12-13: Include of gm OID utilities is correct and necessary.

No issues.

core/src/cache/query.c (3)

190-201: Good: OID‑first comparison with proper fallbacks

Using gm_oid_is_zero + gm_oid_equal, and falling back to gm_oid_from_hex, matches the OID‑first equality rule. Looks correct and simplifies the old branching. Based on learnings


302-305: Good: zero‑OID fast‑exit for cache tip

Early return when meta.cache_tip_oid is zero avoids unnecessary IO.


429-438: Good: gated tree‑size lookup with OID zero‑check and fallback estimate

This keeps gm_cache_stats robust even when the tip is missing.

core/tests/unit/test_edge_equal_semantics.c (2)

10-11: Headers: correct public OID/error includes for new helpers

Including gitmind/util/oid.h and gitmind/error.h is appropriate for gm_oid_from_raw and GM_OK.


21-26: Good: OID‑first equality scenario validated

Asserting GM_OK from gm_oid_from_raw and verifying equality with differing SHAs enforces the OID‑first rule the project requires. Based on learnings

core/tests/unit/test_journal_mixed_cbor.c (1)

60-61: Good: gm_oid_from_raw with explicit lengths

Correctly populates OIDs from raw bytes with GM_OK assertions.

Also applies to: 68-69

#ifndef GITMIND_UTIL_OID_H
#define GITMIND_UTIL_OID_H

#include <stdbool.h>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify umbrella exposure in include/gitmind.h.

Public headers must be umbrella‑safe and reachable via the umbrella. Please confirm this header is re‑exported.


🏁 Script executed:

#!/bin/bash
# Expect: include/gitmind.h exists and references util/oid.h
fd -a gitmind.h include | xargs -I{} rg -n 'gitmind/util/oid\.h' {}
# Also check for duplicates/different paths:
rg -nP --glob 'include/**' '\butil/oid\.h\b'

Length of output: 0


🏁 Script executed:

#!/usr/bin/env bash
# Locate all gitmind.h files and check for util/oid.h references
find . -type f -name gitmind.h | while read file; do
  echo "---- $file ----"
  grep -Hn "util/oid\.h" "$file" || echo "no reference"
done

Length of output: 42


Include util/oid.h in the umbrella header
Add the following to include/gitmind.h so that core/include/gitmind/util/oid.h is re-exported by the umbrella API:

--- a/include/gitmind.h
+++ b/include/gitmind.h
@@ /* somewhere among other includes */
+#include <gitmind/util/oid.h>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include <stdbool.h>
++ b/include/gitmind.h
@@ /* somewhere among other umbrella-header includes */
#include <gitmind/other_header.h>
#include <gitmind/util/oid.h>
#include <gitmind/yet_another_header.h>
🤖 Prompt for AI Agents
In core/include/gitmind/util/oid.h at line 7, the util/oid header is not being
re-exported by the umbrella API; open include/gitmind.h and add an #include
"gitmind/util/oid.h" (placed with the other util/includes or alphabetical group)
so that core/include/gitmind/util/oid.h is exposed via the umbrella header;
update any include guards or ordering if necessary to preserve compile order.

Comment on lines +280 to +285
if (gm_oid_is_zero(&out.src_oid)) {
(void)gm_oid_from_raw(&out.src_oid, out.src_sha, GM_OID_RAWSZ);
}
if (gm_oid_is_zero(&out.tgt_oid)) {
(void)gm_oid_from_raw(&out.tgt_oid, out.tgt_sha, GM_OID_RAWSZ);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix OID backfill length mismatch (potential OOB read)

You pass GM_OID_RAWSZ while sourcing from out.src_sha/out.tgt_sha (GM_SHA1_SIZE). That can read past the SHA buffer or fail. Zero‑pad into a GM_OID_RAWSZ scratch first.

-    if (gm_oid_is_zero(&out.src_oid)) {
-        (void)gm_oid_from_raw(&out.src_oid, out.src_sha, GM_OID_RAWSZ);
-    }
-    if (gm_oid_is_zero(&out.tgt_oid)) {
-        (void)gm_oid_from_raw(&out.tgt_oid, out.tgt_sha, GM_OID_RAWSZ);
-    }
+    if (gm_oid_is_zero(&out.src_oid)) {
+        uint8_t tmp[GM_OID_RAWSZ];
+        gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
+        gm_memcpy_span(tmp, sizeof tmp, out.src_sha, GM_SHA1_SIZE);
+        (void)gm_oid_from_raw(&out.src_oid, tmp, GM_OID_RAWSZ);
+    }
+    if (gm_oid_is_zero(&out.tgt_oid)) {
+        uint8_t tmp[GM_OID_RAWSZ];
+        gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
+        gm_memcpy_span(tmp, sizeof tmp, out.tgt_sha, GM_SHA1_SIZE);
+        (void)gm_oid_from_raw(&out.tgt_oid, tmp, GM_OID_RAWSZ);
+    }

As per coding guidelines (zero outputs on error paths; use gm_memcpy_span). Based on learnings.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (gm_oid_is_zero(&out.src_oid)) {
(void)gm_oid_from_raw(&out.src_oid, out.src_sha, GM_OID_RAWSZ);
}
if (gm_oid_is_zero(&out.tgt_oid)) {
(void)gm_oid_from_raw(&out.tgt_oid, out.tgt_sha, GM_OID_RAWSZ);
}
if (gm_oid_is_zero(&out.src_oid)) {
uint8_t tmp[GM_OID_RAWSZ];
gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
gm_memcpy_span(tmp, sizeof tmp, out.src_sha, GM_SHA1_SIZE);
(void)gm_oid_from_raw(&out.src_oid, tmp, GM_OID_RAWSZ);
}
if (gm_oid_is_zero(&out.tgt_oid)) {
uint8_t tmp[GM_OID_RAWSZ];
gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
gm_memcpy_span(tmp, sizeof tmp, out.tgt_sha, GM_SHA1_SIZE);
(void)gm_oid_from_raw(&out.tgt_oid, tmp, GM_OID_RAWSZ);
}

Comment thread core/src/edge/edge.c
Comment on lines +492 to 497
if (gm_oid_is_zero(&edge.src_oid)) {
(void)gm_oid_from_raw(&edge.src_oid, edge.src_sha, GM_OID_RAWSZ);
}
if (git_oid_is_zero(&edge.tgt_oid)) {
git_oid_fromraw(&edge.tgt_oid, edge.tgt_sha);
if (gm_oid_is_zero(&edge.tgt_oid)) {
(void)gm_oid_from_raw(&edge.tgt_oid, edge.tgt_sha, GM_OID_RAWSZ);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix OID backfill length mismatch (potential OOB read)

As in attributed.c, passing GM_OID_RAWSZ while sourcing from GM_SHA1_SIZE buffers risks OOB. Zero‑pad into a GM_OID_RAWSZ scratch first.

-    if (gm_oid_is_zero(&edge.src_oid)) {
-        (void)gm_oid_from_raw(&edge.src_oid, edge.src_sha, GM_OID_RAWSZ);
-    }
-    if (gm_oid_is_zero(&edge.tgt_oid)) {
-        (void)gm_oid_from_raw(&edge.tgt_oid, edge.tgt_sha, GM_OID_RAWSZ);
-    }
+    if (gm_oid_is_zero(&edge.src_oid)) {
+        uint8_t tmp[GM_OID_RAWSZ];
+        gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
+        gm_memcpy_span(tmp, sizeof tmp, edge.src_sha, GM_SHA1_SIZE);
+        (void)gm_oid_from_raw(&edge.src_oid, tmp, GM_OID_RAWSZ);
+    }
+    if (gm_oid_is_zero(&edge.tgt_oid)) {
+        uint8_t tmp[GM_OID_RAWSZ];
+        gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
+        gm_memcpy_span(tmp, sizeof tmp, edge.tgt_sha, GM_SHA1_SIZE);
+        (void)gm_oid_from_raw(&edge.tgt_oid, tmp, GM_OID_RAWSZ);
+    }

As per coding guidelines (safe memory ops; zero on error).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (gm_oid_is_zero(&edge.src_oid)) {
(void)gm_oid_from_raw(&edge.src_oid, edge.src_sha, GM_OID_RAWSZ);
}
if (git_oid_is_zero(&edge.tgt_oid)) {
git_oid_fromraw(&edge.tgt_oid, edge.tgt_sha);
if (gm_oid_is_zero(&edge.tgt_oid)) {
(void)gm_oid_from_raw(&edge.tgt_oid, edge.tgt_sha, GM_OID_RAWSZ);
}
if (gm_oid_is_zero(&edge.src_oid)) {
uint8_t tmp[GM_OID_RAWSZ];
gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
gm_memcpy_span(tmp, sizeof tmp, edge.src_sha, GM_SHA1_SIZE);
(void)gm_oid_from_raw(&edge.src_oid, tmp, GM_OID_RAWSZ);
}
if (gm_oid_is_zero(&edge.tgt_oid)) {
uint8_t tmp[GM_OID_RAWSZ];
gm_memset_safe(tmp, sizeof tmp, 0, sizeof tmp);
gm_memcpy_span(tmp, sizeof tmp, edge.tgt_sha, GM_SHA1_SIZE);
(void)gm_oid_from_raw(&edge.tgt_oid, tmp, GM_OID_RAWSZ);
}
🤖 Prompt for AI Agents
In core/src/edge/edge.c around lines 492 to 497, the code calls gm_oid_from_raw
using edge.src_sha/edge.tgt_sha buffers sized GM_SHA1_SIZE but passes
GM_OID_RAWSZ which can read past the source buffer; to fix, allocate a
GM_OID_RAWSZ-byte scratch array, zero it, copy GM_SHA1_SIZE bytes from the SHA
buffer into the scratch, then call gm_oid_from_raw with the scratch and
GM_OID_RAWSZ; ensure the scratch is zeroed before use and that any failure from
gm_oid_from_raw leaves the oid zeroed (follow existing safe-memory/error-zeroing
patterns).

Comment thread core/src/util/oid.c
Comment on lines 4 to 17
#include "gitmind/util/oid.h"

#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "gitmind/error.h"
#include "gitmind/result.h"
#include "gitmind/security/memory.h"
#include "gitmind/types.h"
#include "gitmind/util/memory.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Repo-wide check: ensure no straggler git_oid_cmp/raw memcmp remain

Run a quick scan to confirm all equality moves funnel through gm_oid_equal.


🏁 Script executed:

#!/bin/bash
# Find legacy equality patterns that should be gm_oid_equal
rg -nP --type=c --type=h -C2 '\bgit_oid_cmp\s*\(|\bmemcmp\s*\(\s*[^,]*->id\s*,\s*[^,]*->id\s*,\s*GM_OID_RAWSZ\s*\)'

Length of output: 201


Replace raw memcmp in OID comparison with gm_oid_equal

  • In core/src/util/oid.c:79, replace
    return memcmp(lhs->id, rhs->id, GM_OID_RAWSZ) == 0;
    with
    return gm_oid_equal(lhs, rhs);
🤖 Prompt for AI Agents
In core/src/util/oid.c around lines 4 to 17 and specifically at line ~79,
replace the raw memcmp comparison `memcmp(lhs->id, rhs->id, GM_OID_RAWSZ) == 0`
with the helper `gm_oid_equal(lhs, rhs)`; update the return to `return
gm_oid_equal(lhs, rhs);` so the OID equality uses the centralized function (no
other changes needed if oid.h is already included).

Comment thread core/tests/unit/test_cache_query.c Outdated
Comment on lines +1 to +10
---
title: 7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md
description: Preserved review artifacts and rationale.
audience: [contributors]
domain: [quality]
tags: [review]
status: archive
---

# Code Review Feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Align title/H1, add ToC, and insert SPDX header

To meet docs guidelines: make H1 match the title, add a "## Table of Contents", and place SPDX after front matter.

As per coding guidelines

 --- 
-title: 7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md
+title: Code Review Feedback
 description: Preserved review artifacts and rationale.
 audience: [contributors]
 domain: [quality]
 tags: [review]
 status: archive
 ---
 
-# Code Review Feedback
+<!-- SPDX-License-Identifier: LicenseRef-MIND-UCAL-1.0 -->
+
+# Code Review Feedback
+
+## Table of Contents
+- Overview
+- Commits Reviewed
+- Notes
+- Finishing Touches
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
title: 7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md
description: Preserved review artifacts and rationale.
audience: [contributors]
domain: [quality]
tags: [review]
status: archive
---
# Code Review Feedback
---
title: Code Review Feedback
description: Preserved review artifacts and rationale.
audience: [contributors]
domain: [quality]
tags: [review]
status: archive
---
<!-- SPDX-License-Identifier: LicenseRef-MIND-UCAL-1.0 -->
# Code Review Feedback
## Table of Contents
- Overview
- Commits Reviewed
- Notes
- Finishing Touches
🤖 Prompt for AI Agents
In docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md around
lines 1 to 10, the document needs to follow docs guidelines: make the H1 match
the title, add a "## Table of Contents" section, and insert an SPDX header
immediately after the YAML front matter; update the top-level heading to exactly
match the title line, add a "## Table of Contents" line beneath the H1, and add
a standard SPDX license identifier line (e.g., "SPDX-License-Identifier: MIT")
directly after the closing front-matter delimiter.

Comment thread docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
core/tests/unit/test_cache_branch_limits.c (1)

53-54: Use gm_snprintf and validate bounds (no raw snprintf in tests)

Replace raw snprintf with gm_snprintf and assert no truncation, as required by guidelines.

Apply:

-    snprintf(refname, sizeof refname, "refs/heads/%s", branch);
+    int wn = gm_snprintf(refname, sizeof refname, "refs/heads/%s", branch);
+    assert(wn >= 0 && (size_t)wn < sizeof refname);

Also ensure the header is included:

 #include "gitmind/edge.h"
 #include "gitmind/util/memory.h"
+#include "gitmind/security/string.h"
 #include "gitmind/error.h"

As per coding guidelines.

core/tests/unit/test_edge_cbor_oid.c (1)

25-27: Remove leftover raw strcpy (violates safety guidelines)

These raw strcpy calls precede the safe copies below and should be removed to avoid regressions and to follow project policy.

Apply:

-    strcpy(e.src_path, "src/A.c");
-    strcpy(e.tgt_path, "src/B.c");
-    strcpy(e.ulid, "01ARZ3NDEKTSV4RRFFQ69G5FAV");
core/src/cache/query.c (1)

216-225: Fix hex buffer size for OID → hex conversion (risk: truncation/overflow/false error)

sha_hex is sized with SHA_HEX_SIZE but you encode GM_OID_RAWSZ bytes. If GM_OID_RAWSZ encodes to GM_OID_HEX_CHARS, a smaller buffer triggers GM_ERR_BUFFER_TOO_SMALL or worse. Use GM_OID_HEX_CHARS + 1.

Apply:

-    char sha_hex[SHA_HEX_SIZE];
+    char sha_hex[GM_OID_HEX_CHARS + 1];

This matches get_sha_prefix’s pattern and keeps encoding consistent with OID size.
Based on learnings

🧹 Nitpick comments (9)
core/src/adapters/git/libgit2_repository_port.c (2)

892-896: Validate target OID isn’t zero before proceeding.

Add a fast input guard using gm_oid_is_zero to reject invalid/placeholder targets early. This prevents attempting to create/update refs to a zero OID.

     if (spec == NULL || spec->ref_name == NULL || spec->target_oid == NULL) {
         return gm_err_void(GM_ERROR(GM_ERR_INVALID_ARGUMENT,
                                     "reference update spec missing inputs"));
     }
 
+    if (gm_oid_is_zero(spec->target_oid)) {
+        return gm_err_void(GM_ERROR(GM_ERR_INVALID_ARGUMENT,
+                                    "reference update target OID is zero"));
+    }

Based on learnings.


927-946: Early return on equal OIDs to avoid redundant reflog entries

Bail out immediately when current_target equals spec->target_oid, then run the ancestry check only otherwise—this skips the extra git_reference_set_target call and reflog noise.

-    if (!gm_oid_equal(current_target, spec->target_oid)) {
-        int descendant = git_graph_descendant_of(state->repo, spec->target_oid,
-                                                current_target);
-        if (descendant < 0) {
-            git_reference_free(existing);
-            return gm_err_void(GM_ERROR(GM_ERR_UNKNOWN,
-                                        "failed to check ancestry for %s", spec->ref_name));
-        }
-        if (descendant == 0) {
-            git_reference_free(existing);
-            return gm_err_void(GM_ERROR(GM_ERR_ALREADY_EXISTS,
-                                        "non-fast-forward update rejected for %s",
-                                        spec->ref_name));
-        }
-    }
+    if (gm_oid_equal(current_target, spec->target_oid)) {
+        git_reference_free(existing);
+        return gm_ok_void();
+    }
+    int descendant =
+        git_graph_descendant_of(state->repo, spec->target_oid, current_target);
+    if (descendant < 0) {
+        git_reference_free(existing);
+        return gm_err_void(GM_ERROR(GM_ERR_UNKNOWN,
+                                    "failed to check ancestry for %s", spec->ref_name));
+    }
+    if (descendant == 0) {
+        git_reference_free(existing);
+        return gm_err_void(GM_ERROR(GM_ERR_ALREADY_EXISTS,
+                                    "non-fast-forward update rejected for %s",
+                                    spec->ref_name));
+    }

Apply the same refactor at lines 951–956.

core/tests/unit/test_cache_branch_limits.c (1)

85-86: Check gm_ulid_generate result

Assert the result to keep tests deterministic and aligned with “check return codes”.

-    (void)gm_ulid_generate(edge.ulid);
+    gm_result_ulid_t ur = gm_ulid_generate(edge.ulid);
+    assert(ur.ok);
core/src/domain/cache/edge_map.c (3)

49-50: Avoid narrowing cast in modulo (handle very large bucket_count)

Dropping the uint32_t cast prevents unexpected wrap when bucket_count > UINT32_MAX.

-    return (size_t)(hash_value % (uint32_t)bucket_count);
+    return (size_t)hash_value % bucket_count;

95-99: Null out out_map on error paths

Set *out_map = NULL before returning errors to avoid stale pointers on caller side.

     map->buckets = calloc(bucket_count, sizeof(*map->buckets));
     if (map->buckets == NULL) {
-        free(map);
-        return gm_err_void(GM_ERROR(GM_ERR_OUT_OF_MEMORY, "edge map buckets alloc failed"));
+        free(map);
+        *out_map = NULL;
+        return gm_err_void(GM_ERROR(GM_ERR_OUT_OF_MEMORY, "edge map buckets alloc failed"));
     }

And above:

-    if (bucket_count == 0U) {
-        return gm_err_void(GM_ERROR(GM_ERR_INVALID_ARGUMENT,
-                                    "edge map bucket count must be > 0"));
-    }
+    if (bucket_count == 0U) {
+        *out_map = NULL;
+        return gm_err_void(GM_ERROR(GM_ERR_INVALID_ARGUMENT,
+                                    "edge map bucket count must be > 0"));
+    }

And for map alloc failure:

-    if (map == NULL) {
-        return gm_err_void(GM_ERROR(GM_ERR_OUT_OF_MEMORY, "edge map alloc failed"));
-    }
+    if (map == NULL) {
+        *out_map = NULL;
+        return gm_err_void(GM_ERROR(GM_ERR_OUT_OF_MEMORY, "edge map alloc failed"));
+    }

10-12: Drop unused include

gitmind/util/memory.h isn’t used here. Remove to keep headers minimal.

-#include "gitmind/util/memory.h"
 #include "gitmind/util/oid.h"
core/src/cache/query.c (1)

260-269: Prefer gm_oid_equal over raw memcmp for OID id bytes

For consistency and single‑point semantics, compare OIDs with gm_oid_equal instead of memcmp on ->id. You can pass a gm_oid_t* target (or wrap target_sha into a temporary gm_oid_t) to avoid raw byte compares.

Example:

-    const uint8_t *edge_sha = state->check_source
-        ? (const uint8_t *)edge->src_oid.id
-        : (const uint8_t *)edge->tgt_oid.id;
-    if (memcmp(edge_sha, state->target_sha, GM_OID_RAWSZ) == 0) {
+    const gm_oid_t *edge_oid = state->check_source ? &edge->src_oid : &edge->tgt_oid;
+    if (gm_oid_equal(edge_oid, (const gm_oid_t *)state->target_sha)) {

Or change journal_scan_state_t.target_sha to const gm_oid_t* and adjust callers.
Based on learnings

Also applies to: 333-341, 360-367

docs/code-reviews/PR173/17ddad1aa3747f40ecacc0bd202e7b83edbf1d1d.md (2)

1-11: Align front matter, SPDX, and H1 with docs rules

Title and H1 must match; add SPDX after front matter; include a Table of Contents.

Apply:

----
-title: 17ddad1aa3747f40ecacc0bd202e7b83edbf1d1d.md
+title: Code Review Feedback
 description: Preserved review artifacts and rationale.
 audience: [contributors]
 domain: [quality]
 tags: [review]
 status: archive
 ---
 
-# Code Review Feedback
+<!-- SPDX-License-Identifier: LicenseRef-MIND-UCAL-1.0 -->
+
+# Code Review Feedback
+
+## Table of Contents
+ - Overview
+ - Commits Reviewed
+ - Notes
+ - Finishing Touches

As per coding guidelines


112-115: Remove {response} placeholders and marketing/tips/internal-state blocks

Static artifacts shouldn’t contain unresolved placeholders or third‑party promo/tips and massive internal state blobs. Remove these sections to keep the doc concise and repo‑appropriate.

Suggested deletions:

  • Literal “{response}” lines
  • “tips_start … tips_end”
  • “internal state start … end” (large embedded block)

Also applies to: 179-181, 264-265, 375-377, 678-681

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebd9f75 and eaf10c6.

📒 Files selected for processing (13)
  • core/src/adapters/git/libgit2_repository_port.c (2 hunks)
  • core/src/cache/query.c (4 hunks)
  • core/src/domain/cache/edge_map.c (3 hunks)
  • core/src/hooks/augment.c (4 hunks)
  • core/tests/unit/test_cache_branch_limits.c (2 hunks)
  • core/tests/unit/test_cache_query.c (4 hunks)
  • core/tests/unit/test_edge_cbor_oid.c (3 hunks)
  • core/tests/unit/test_edge_oid_fallback.c (2 hunks)
  • core/tests/unit/test_journal_mixed_cbor.c (2 hunks)
  • core/tests/unit/test_journal_safety.c (2 hunks)
  • docs/activity/2025-09.md (1 hunks)
  • docs/code-reviews/PR173/17ddad1aa3747f40ecacc0bd202e7b83edbf1d1d.md (1 hunks)
  • docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/code-reviews/PR173/7445bcf00c71b6f768e9eb6b1fd99d2b1c60783f.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/src/hooks/augment.c
  • docs/activity/2025-09.md
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{c,cc,cpp,cxx,h,hpp,hxx,m,mm}

📄 CodeRabbit inference engine (CLAUDE.md)

NEVER use NOLINT to suppress clang-tidy warnings; ALWAYS fix the underlying issue

Files:

  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_journal_safety.c
  • core/src/adapters/git/libgit2_repository_port.c
  • core/src/cache/query.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_edge_oid_fallback.c
{core,apps,tests}/**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

{core,apps,tests}/**/*.{c,h}: Use gm_snprintf, gm_strcpy_safe, and gm_memcpy_span for all string/memory operations; check return codes and treat truncation as an error; zero output buffers on error paths before copying/formatting
C23 only with warnings-as-errors; no VLAs; no shadowing; all functions have explicit prototypes
Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Prefer specific headers in includes; follow include order/regrouping enforced by .clang-format
Build refs via gm_build_ref and reject inputs starting with "refs/" to avoid double-prefixing; follow libgit2 ref-name safety via normalization

Files:

  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_journal_safety.c
  • core/src/adapters/git/libgit2_repository_port.c
  • core/src/cache/query.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_edge_oid_fallback.c
{core,apps}/**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

Naming: functions/variables lower_snake_case with gm_ prefix; macros UPPER_SNAKE; typedef’d types end with t; header guards begin with GITMIND

Files:

  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_journal_safety.c
  • core/src/adapters/git/libgit2_repository_port.c
  • core/src/cache/query.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_edge_oid_fallback.c
**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

Formatting must follow .clang-format (LLVM style, 4 spaces, 80 cols, pointer alignment right); run clang-format via pre-commit

Files:

  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_journal_safety.c
  • core/src/adapters/git/libgit2_repository_port.c
  • core/src/cache/query.c
  • core/src/domain/cache/edge_map.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_edge_oid_fallback.c
core/tests/unit/test_*.c

📄 CodeRabbit inference engine (AGENTS.md)

Unit tests live in core/tests/unit/ and must be deterministic and isolated; name files test_.c

Files:

  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_journal_safety.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_edge_oid_fallback.c
core/src/**/*.c

📄 CodeRabbit inference engine (AGENTS.md)

Do not allocate GM_PATH_MAX*2 buffers; prefer GM_PATH_MAX and allocate dynamically if larger is required

Files:

  • core/src/adapters/git/libgit2_repository_port.c
  • core/src/cache/query.c
  • core/src/domain/cache/edge_map.c
core/src/domain/cache/**/*.c

📄 CodeRabbit inference engine (AGENTS.md)

Cache lives under refs/gitmind/cache/ and is rebuildable; do not merge cache refs

Files:

  • core/src/domain/cache/edge_map.c
core/src/domain/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep domain logic pure (no direct IO/libgit2/global state) and one responsibility per translation unit

Files:

  • core/src/domain/cache/edge_map.c
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Docs: include front matter first, a single H1 matching the title, a '## Table of Contents' section, and SPDX license comments after front matter; API docs must include api_version
Conform to markdownlint rules configured by .markdownlint.jsonc (e.g., underscore emphasis/strong, blockquote spacing, code fence and heading punctuation)

Files:

  • docs/code-reviews/PR173/17ddad1aa3747f40ecacc0bd202e7b83edbf1d1d.md
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Learnt from: flyingrobots
PR: neuroglyph/git-mind#169
File: docs/templates/code-review-feedback.md:26-33
Timestamp: 2025-09-16T17:10:27.477Z
Learning: The user (flyingrobots) uses Obsidian to view/edit Markdown files and prefers to keep Obsidian-specific syntax like collapsible callout markers (e.g., `[!NOTE]-` for collapsible callouts) even if they're not GitHub-compatible.
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist

Applied to files:

  • core/tests/unit/test_edge_cbor_oid.c
  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/tests/unit/test_journal_safety.c
  • core/src/adapters/git/libgit2_repository_port.c
  • core/tests/unit/test_cache_branch_limits.c
  • core/tests/unit/test_edge_oid_fallback.c
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Use gm_snprintf, gm_strcpy_safe, and gm_memcpy_span for all string/memory operations; check return codes and treat truncation as an error; zero output buffers on error paths before copying/formatting

Applied to files:

  • core/tests/unit/test_cache_query.c
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to core/src/**/*.c : Do not allocate GM_PATH_MAX*2 buffers; prefer GM_PATH_MAX and allocate dynamically if larger is required

Applied to files:

  • core/tests/unit/test_cache_query.c
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind.h : Maintain umbrella API at include/gitmind.h

Applied to files:

  • core/tests/unit/test_cache_query.c
  • core/tests/unit/test_journal_mixed_cbor.c
  • core/src/adapters/git/libgit2_repository_port.c
  • core/tests/unit/test_cache_branch_limits.c
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind/**/*.h : Public, namespaced headers live under include/gitmind/

Applied to files:

  • core/tests/unit/test_cache_query.c
🧬 Code graph analysis (7)
core/tests/unit/test_edge_cbor_oid.c (1)
core/include/gitmind/util/memory.h (1)
  • gm_strcpy_safe (113-138)
core/tests/unit/test_cache_query.c (2)
core/src/types/ulid.c (1)
  • gm_ulid_generate (118-126)
core/src/cache/query.c (2)
  • gm_cache_query_fanout (391-395)
  • gm_cache_result_free (405-411)
core/tests/unit/test_journal_mixed_cbor.c (2)
core/include/gitmind/util/memory.h (1)
  • gm_strcpy_safe (113-138)
core/src/edge/edge.c (1)
  • gm_edge_encode_cbor (260-361)
core/tests/unit/test_journal_safety.c (1)
core/src/edge/edge.c (1)
  • gm_edge_equal (112-141)
core/src/cache/query.c (1)
core/include/gitmind/security/memory.h (1)
  • gm_memset_safe (47-59)
core/tests/unit/test_cache_branch_limits.c (1)
core/include/gitmind/util/memory.h (1)
  • gm_strcpy_safe (113-138)
core/tests/unit/test_edge_oid_fallback.c (2)
core/include/gitmind/util/memory.h (1)
  • gm_strcpy_safe (113-138)
core/src/edge/edge.c (1)
  • gm_edge_equal (112-141)
🔇 Additional comments (12)
core/src/adapters/git/libgit2_repository_port.c (1)

40-40: LGTM: include added for gm OID utilities is correct.

Header placement looks consistent with local-project includes and supports the new gm_oid_* calls.

core/tests/unit/test_edge_oid_fallback.c (1)

24-27: LGTM: OID-first equality/fallback behavior is correctly exercised

  • Good use of gm_strcpy_safe with return checks and gm_oid_from_raw with GM_OK asserts. The test validates SHA fallback only when OIDs are zero, and switches to OID equality when non-zero, matching project semantics. Based on learnings

Also applies to: 35-38

core/tests/unit/test_cache_branch_limits.c (1)

78-80: Good migration to gm helpers in tests

  • gm_oid_from_raw and gm_strcpy_safe with asserts are correct and follow guidelines.

Also applies to: 83-84

core/src/domain/cache/edge_map.c (3)

85-89: Good input validation for bucket_count

Rejecting bucket_count == 0 prevents modulo-by-zero and aligns with defensive API design.


131-136: Correctly switched to gm_oid_equal for identity checks

This matches the OID-first equality rule and detaches from libgit2 helpers. Based on learnings


11-11: Repo-wide migration check

  • Verified removal of all git_oid_{fromraw,cmp,is_zero} usages across core/apps/tests.
  • Tests under core/tests/unit still call strcpy—replace each with gm_strcpy_safe and handle return codes per string/memory guidelines.
⛔ Skipped due to learnings
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Use gm_snprintf, gm_strcpy_safe, and gm_memcpy_span for all string/memory operations; check return codes and treat truncation as an error; zero output buffers on error paths before copying/formatting
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Build refs via gm_build_ref and reject inputs starting with "refs/" to avoid double-prefixing; follow libgit2 ref-name safety via normalization
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind.h : Maintain umbrella API at include/gitmind.h
core/tests/unit/test_cache_query.c (3)

39-41: Good: gm_snprintf with bounds check

The format/size check is correct and consistent across tests.


93-99: Good: OID construction via gm_oid_from_raw with GM_OK asserts

Edges and query OIDs are populated correctly.

Also applies to: 110-116


17-19: Replace raw strcpy with gm_strcpy_safe and assert results

Two raw strcpy calls remain; switch to gm_strcpy_safe and check return. Also include the correct header used elsewhere in tests.

 #include "gitmind/edge.h"
 #include "gitmind/types.h"
 #include "gitmind/util/oid.h"
 #include "gitmind/security/string.h"
+#include "gitmind/util/memory.h"
@@
-    edges[0].rel_type = GM_REL_IMPLEMENTS; edges[0].confidence = 0x3C00; strcpy(edges[0].src_path, "A"); strcpy(edges[0].tgt_path, "B");
-    (void)gm_ulid_generate(edges[0].ulid);
+    edges[0].rel_type = GM_REL_IMPLEMENTS;
+    edges[0].confidence = 0x3C00;
+    assert(gm_strcpy_safe(edges[0].src_path, sizeof edges[0].src_path, "A") == GM_OK);
+    assert(gm_strcpy_safe(edges[0].tgt_path, sizeof edges[0].tgt_path, "B") == GM_OK);
+    gm_result_ulid_t ulr0 = gm_ulid_generate(edges[0].ulid);
+    assert(ulr0.ok);
@@
-    edges[1].rel_type = GM_REL_IMPLEMENTS; edges[1].confidence = 0x3C00; strcpy(edges[1].src_path, "A"); strcpy(edges[1].tgt_path, "C");
-    (void)gm_ulid_generate(edges[1].ulid);
+    edges[1].rel_type = GM_REL_IMPLEMENTS;
+    edges[1].confidence = 0x3C00;
+    assert(gm_strcpy_safe(edges[1].src_path, sizeof edges[1].src_path, "A") == GM_OK);
+    assert(gm_strcpy_safe(edges[1].tgt_path, sizeof edges[1].tgt_path, "C") == GM_OK);
+    gm_result_ulid_t ulr1 = gm_ulid_generate(edges[1].ulid);
+    assert(ulr1.ok);

As per coding guidelines.

Also applies to: 95-100

core/tests/unit/test_journal_mixed_cbor.c (1)

56-63: Good migration to safe string ops and gm_oid API

Using gm_strcpy_safe and gm_oid_from_raw with explicit GM_OK assertions hardens the tests and aligns with OID‑first semantics. LGTM.

Also applies to: 67-79

core/tests/unit/test_edge_cbor_oid.c (1)

32-37: LGTM: OID creation + equality via gm helpers

gm_oid_from_raw and gm_oid_equal usage is correct and matches OID‑first comparisons.

Also applies to: 50-51

core/tests/unit/test_journal_safety.c (1)

61-79: LGTM: OID‑first equality semantics covered

Nice coverage: equal with same OIDs despite differing legacy SHAs, and negative cases when OIDs diverge.
Based on learnings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
core/include/gitmind/util/oid.h (1)

40-48: New OID helpers are well-scoped and umbrella-safe.

Signatures and NULL-handling are clear; align with OID-first equality policy. Consider clarifying in gm_oid_from_hex docs whether mixed-case hex is accepted (implementation via gm_hex_value likely allows both).

Also applies to: 49-56, 57-66, 68-76

core/tests/unit/test_cache_query.c (1)

17-19: Drop redundant header to avoid dual declarations.

gm_strcpy_safe appears to be provided by gitmind/util/memory.h; including gitmind/security/string.h as well risks duplicate prototypes. Remove it unless it’s the canonical shim.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eaf10c6 and 28cf980.

📒 Files selected for processing (5)
  • core/include/gitmind/util/oid.h (2 hunks)
  • core/src/util/oid.c (2 hunks)
  • core/tests/unit/test_cache_query.c (4 hunks)
  • docs/code-reviews/PR173/e0243058aac14ff3a8c83af2f6d4dcfe97dd2804.md (1 hunks)
  • include/gitmind.h (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/code-reviews/PR173/e0243058aac14ff3a8c83af2f6d4dcfe97dd2804.md
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{c,cc,cpp,cxx,h,hpp,hxx,m,mm}

📄 CodeRabbit inference engine (CLAUDE.md)

NEVER use NOLINT to suppress clang-tidy warnings; ALWAYS fix the underlying issue

Files:

  • core/src/util/oid.c
  • include/gitmind.h
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
{core,apps,tests}/**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

{core,apps,tests}/**/*.{c,h}: Use gm_snprintf, gm_strcpy_safe, and gm_memcpy_span for all string/memory operations; check return codes and treat truncation as an error; zero output buffers on error paths before copying/formatting
C23 only with warnings-as-errors; no VLAs; no shadowing; all functions have explicit prototypes
Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Prefer specific headers in includes; follow include order/regrouping enforced by .clang-format
Build refs via gm_build_ref and reject inputs starting with "refs/" to avoid double-prefixing; follow libgit2 ref-name safety via normalization

Files:

  • core/src/util/oid.c
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
{core,apps}/**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

Naming: functions/variables lower_snake_case with gm_ prefix; macros UPPER_SNAKE; typedef’d types end with t; header guards begin with GITMIND

Files:

  • core/src/util/oid.c
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
core/src/**/*.c

📄 CodeRabbit inference engine (AGENTS.md)

Do not allocate GM_PATH_MAX*2 buffers; prefer GM_PATH_MAX and allocate dynamically if larger is required

Files:

  • core/src/util/oid.c
**/*.{c,h}

📄 CodeRabbit inference engine (AGENTS.md)

Formatting must follow .clang-format (LLVM style, 4 spaces, 80 cols, pointer alignment right); run clang-format via pre-commit

Files:

  • core/src/util/oid.c
  • include/gitmind.h
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
{include,core/include/gitmind}/**/*.h

📄 CodeRabbit inference engine (AGENTS.md)

{include,core/include/gitmind}/**/*.h: Public headers must be umbrella-safe, compile standalone, use stable header guards, and include C++ linkage guards (extern "C")
Avoid public ABI breaks: when changing public structs, only append new fields at the end; mark old fields deprecated rather than removing/reordering

Files:

  • include/gitmind.h
  • core/include/gitmind/util/oid.h
core/tests/unit/test_*.c

📄 CodeRabbit inference engine (AGENTS.md)

Unit tests live in core/tests/unit/ and must be deterministic and isolated; name files test_.c

Files:

  • core/tests/unit/test_cache_query.c
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist
Learnt from: flyingrobots
PR: neuroglyph/git-mind#169
File: docs/templates/code-review-feedback.md:26-33
Timestamp: 2025-09-16T17:10:27.477Z
Learning: The user (flyingrobots) uses Obsidian to view/edit Markdown files and prefers to keep Obsidian-specific syntax like collapsible callout markers (e.g., `[!NOTE]-` for collapsible callouts) even if they're not GitHub-compatible.
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Equality and identity are OID-first: when OIDs are present, compare via git_oid_cmp (typedef gm_oid_t) and do not fall back to SHA if OIDs exist

Applied to files:

  • core/src/util/oid.c
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind.h : Maintain umbrella API at include/gitmind.h

Applied to files:

  • include/gitmind.h
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to include/gitmind/**/*.h : Public, namespaced headers live under include/gitmind/

Applied to files:

  • include/gitmind.h
  • core/tests/unit/test_cache_query.c
  • core/include/gitmind/util/oid.h
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {include,core/include/gitmind}/**/*.h : Public headers must be umbrella-safe, compile standalone, use stable header guards, and include C++ linkage guards (extern "C")

Applied to files:

  • include/gitmind.h
  • core/include/gitmind/util/oid.h
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {include,core/include/gitmind}/**/*.h : Avoid public ABI breaks: when changing public structs, only append new fields at the end; mark old fields deprecated rather than removing/reordering

Applied to files:

  • include/gitmind.h
  • core/include/gitmind/util/oid.h
📚 Learning: 2025-09-13T03:13:54.145Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-13T03:13:54.145Z
Learning: Applies to {include,core/include}/**/*.h : Header guards use GITMIND_* naming

Applied to files:

  • include/gitmind.h
  • core/include/gitmind/util/oid.h
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to {core,apps,tests}/**/*.{c,h} : Use gm_snprintf, gm_strcpy_safe, and gm_memcpy_span for all string/memory operations; check return codes and treat truncation as an error; zero output buffers on error paths before copying/formatting

Applied to files:

  • core/tests/unit/test_cache_query.c
📚 Learning: 2025-09-29T06:07:18.746Z
Learnt from: CR
PR: neuroglyph/git-mind#0
File: AGENTS.md:0-0
Timestamp: 2025-09-29T06:07:18.746Z
Learning: Applies to core/src/domain/journal/**/*.c : Journal is append-only under refs/gitmind/edges/<branch>; never mutate history entries

Applied to files:

  • core/tests/unit/test_cache_query.c
🧬 Code graph analysis (3)
core/src/util/oid.c (2)
core/include/gitmind/security/memory.h (1)
  • gm_memset_safe (47-59)
core/include/gitmind/util/memory.h (1)
  • gm_memcpy_span (32-47)
core/tests/unit/test_cache_query.c (3)
core/include/gitmind/util/memory.h (1)
  • gm_strcpy_safe (113-138)
core/src/types/ulid.c (1)
  • gm_ulid_generate (118-126)
core/src/cache/query.c (2)
  • gm_cache_query_fanout (391-395)
  • gm_cache_result_free (405-411)
core/include/gitmind/util/oid.h (1)
core/src/util/oid.c (6)
  • bool (75-80)
  • bool (82-92)
  • int (36-63)
  • int (65-73)
  • int (94-112)
  • int (114-144)
🔇 Additional comments (11)
include/gitmind.h (1)

31-31: Umbrella exposure of OID utilities added — LGTM.

Public OID helpers are now re-exported via the umbrella header as required.

core/include/gitmind/util/oid.h (1)

7-7: Include <stdbool.h> — LGTM.

Ensures bool in public signatures without relying on transitive includes.

core/tests/unit/test_cache_query.c (3)

39-41: Correct bounds-checked gm_snprintf usage — LGTM.

Asserting no truncation matches guidelines.


91-110: Good migration to gm_oid_from_raw and gm_strcpy_safe.

Zero-init, explicit sizes, and result checks look solid.


120-121: Query OIDs built via gm_oid_from_raw — LGTM.

Consistent with gm_cache_query_* contracts.

Also applies to: 126-126

core/src/util/oid.c (6)

7-7: LGTM! Header includes properly added for new functionality.

The new includes (stdbool.h, string.h, gitmind/util/memory.h) and hex offset constant are correctly added to support the new OID utility functions.

Also applies to: 10-10, 16-16, 21-22


23-34: LGTM! Hex parsing implementation is correct and defensive.

The gm_hex_value helper correctly handles both uppercase and lowercase hex digits with proper bounds checking, returning -1 for invalid characters.


75-80: Past review concern already addressed - raw memcmp usage is acceptable here.

While the past review comment suggested replacing memcmp with gm_oid_equal, this would create a recursive call since we're implementing gm_oid_equal itself. The raw memcmp usage is appropriate and correct for the core equality implementation.


82-92: LGTM! Zero-check implementation follows secure coding practices.

The function correctly handles null input and uses a loop instead of memcmp against a zero buffer, which is both clear and avoids potential timing attacks.


94-112: LGTM! Secure raw OID initialization with proper validation.

The implementation correctly:

  • Validates input parameters including exact length requirement
  • Zero-initializes output on both entry and error paths using gm_memset_safe
  • Uses gm_memcpy_span for bounds-checked copying as per coding guidelines
  • Returns appropriate error codes for different failure modes

114-144: LGTM! Hex-to-OID conversion follows secure patterns.

The implementation is well-structured with:

  • Proper null checking and defensive programming
  • Safe error handling with output zeroing on all error paths
  • Correct hex string length validation (GM_OID_HEX_CHARS)
  • Manual nibble assembly with appropriate bit shifting and masking
  • Consistent error reporting

The manual hex parsing approach provides good control over validation and error handling compared to library functions.

@flyingrobots
flyingrobots merged commit e08d76f into main Sep 29, 2025
5 checks passed
@flyingrobots
flyingrobots deleted the feat/edge-port-followup branch September 29, 2025 12:19
@coderabbitai coderabbitai Bot mentioned this pull request Sep 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant