Files
codebase-memory-mcp/tests
Martin Vogelandmoofone 4cbc9e1ca2 fix(artifact): stamp the clean-basis trust check the way the rows were written
The reconcile_basis marker was never written on Windows, so all six
build_trusted_artifact_repo() tests plus artifact_export_marks_clean_basis
failed there (16 passed, 7 failed) while every Linux and macOS leg was green.

Root cause is a stamp-encoding mismatch, not shell quoting. file_hashes rows
are stamped by the semantic manifest via cbm_path_info_utf8(), which on Windows
derives mtime_ns from ftLastWriteTime -- 100-nanosecond FILETIME ticks.
db_hashes_match_disk() re-stat()ed those same files through _wstat64, whose
st_mtime carries WHOLE SECONDS, and compared the two. The values can only agree
when a file's write time lands exactly on a second boundary, so the trust check
rejected the very first row on every export, on Windows and only on Windows.
On POSIX both paths read st_mtim nanoseconds and agree, which is why the split
was clean along platform lines.

The disk side now reads through cbm_path_info_utf8 -- the same function that
wrote the rows -- so there is no encoding left to keep in sync. Its
is_regular/is_symlink guard preserves exactly the symlink refusal
reconcile_stat_no_symlink provided.

reconcile_restamp_rows deliberately keeps art_stat_mtime_ns: a restamped row is
read by the incremental classifier and by check_index_coverage, both of which
stat() and encode whole seconds on Windows. The asymmetry is now pinned with a
comment at both sites so neither is "unified" into breaking the other.

Diagnostics, which is why this took two wrong diagnoses to find:

- Export's four clean-basis preconditions were one short-circuiting && chain
  collapsing to a single bool. They are now evaluated by reconcile_basis_trusted,
  which records the first failing gate (head_unresolved / head_not_hex_oid /
  tree_not_clean / db_hashes_differ_from_disk, the last carrying the offending
  path and BOTH stamps) and logs it as artifact.reconcile_basis_omitted. The
  reason is recorded rather than recomputed on demand: export's own
  ensure_gitattributes leaves an untracked .gitattributes behind, so any later
  evaluation answers tree_not_clean whatever the real cause was.

- build_trusted_artifact_repo() had six `return NULL` exits and reported none of
  them; CI could not tell a failed `git commit` from a missing marker. Every exit
  now names its step and carries the number that decided it -- git exit status,
  pipeline rc, or export's recorded blocker -- surfaced through
  BUILD_TRUSTED_REPO_OR_FAIL at the call site so file:line still points at the
  failing test.

Verified locally on macOS by emulating the Windows encoding: truncating the
disk-side mtime to whole seconds reproduces the CI signature exactly (16 passed,
7 failed, same seven sites), and the new diagnostic names it as
`db_hashes_differ_from_disk path=a.rs reason=mtime_differs stored_mtime_ns=...
disk_mtime_ns=...`. Restored, the artifact/pipeline/incremental/mcp/index_format/
daemon_bootstrap suites are green and make lint-ci passes.

Co-authored-by: moofone <35233167+moofone@users.noreply.github.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-08-29 20:33:15 +02:00
..
2026-06-28 13:05:05 +02:00