v1.75.0 ·
A sync that changed nothing reported 229 updates
The problem
aidlc knowledge sync, run twice with nothing changed in between, reports most of the graph
as updated. Reproduced on this repository on 2026-10-09: the second run reported
updated: 229 of 264 entities. The true answer is 0.
The cause is entitiesEqual in packages/cli/src/knowledge/sync.ts. It compares
JSON.stringify(prior) === JSON.stringify(entity), where prior came back out of SQLite and
entity was just parsed from YAML. The two differ in ways that are not content:
rowToEntityinpackages/cli/src/knowledge/index/sqlite-index.tsalways buildsmetadata: {}, while a YAML document with nometadatakey parses with none.rowToEntitybuilds its keys in a fixed order; a parsed document keeps the file's order.JSON.stringifyis order-sensitive.- The index stores only the entity fields. A key in the YAML outside that shape is never stored, so it can never compare equal.
Measured over the real corpus (264 entities) before writing these criteria: all 229 false
updated come from the missing metadata key. No entity today differs by key order or by an
extra key. Those two are the same defect class and are covered so the fix does not depend on
how today's files happen to be written.
How it could be solved
The obvious fix was in the wrong place. The stored copy of each fact always carries an empty extra-details field, while a fact written by hand usually has none, and that one difference made almost every comparison fail. Making the stored copy leave the field out would have hidden it, but it would have moved the mismatch to every fact that does write an empty field, and changed what every other reader of the store receives. So the store was left alone, and the comparison learned that a missing field and an empty one are the same thing, which is all the store can ever tell anyway.
The risk the other way was a comparison so forgiving that it stops seeing real damage from a merge. Two choices guard against that. The comparison names each field it checks in a structure the compiler holds against the shape of a fact, so a field added later fails the build until someone decides whether it counts. And there is one test per field, each changing that field alone and expecting exactly one update, seen to fail when the field is dropped from the check.
One line had to be drawn by hand: the order of a fact's tags still counts as a change. Reordering a list is an edit someone made to the file, and treating it as nothing would make the check more lenient than the file itself. The order of keys inside the extra details does not count, because that is only how the file happened to be written.
How AIDLC solves it
knowledge-sync-overcounts-updated
aidlc knowledge sync now counts an entity as updated only when its content changed. Run twice
with nothing changed in between, it reports zero added, zero updated and zero removed; before this
it reported 229 of this repository's 264 entities as updated on every run. The comparison now
checks each field the index stores, treats a missing metadata the same as an empty one, and
ignores key order and keys the index never keeps. The order of tags still counts. A field added to
the entity type later fails to compile until the comparison lists it.
Patch, not minor: no command, flag, output field or file format changes. Only the value of
updated becomes correct.
Changes
packages/cli/src/knowledge/sync.ts—entitiesEqualandINDEXED_FIELDS.packages/cli/test/knowledge-sync-counts.test.ts— new, 19 cases..aidlc/knowledge/decisions/knowledge-sync-field-compare.yaml— the decision.packages/website/content/blog/overrides/knowledge-sync-overcounts-updated-post.jsonand-options.md— this release's post.
knowledge-block-vanishes-silently
When a knowledge source file breaks, aidlc update and aidlc init now say so. A merge that leaves
conflict markers in modules.yaml, or a hand edit that makes a document unreadable, prints
knowledge graph: modules.yaml: skipped corrupt document (…) on every run until the file is fixed,
not only on the run that happened to rebuild the index. When nothing is left to render, a second
line says the # Codebase Knowledge block was left out of the instruction files and why. The block
still goes, as it should: keeping rows built from a file that no longer says them would be serving
stale facts.
A document holding a value the index cannot store — a description: that is a map, a missing
author, a null name — no longer throws out of aidlc update, aidlc init and aidlc gate with
a SQLite parameter number. That one document is left out, the warning names its file, its id and
the field, and everything else in the graph is still indexed. An index file that cannot be opened at
all leaves the block out with a warning carrying the error, and the command finishes.
Each warning prints once, however many platforms the project has: the render now runs once per command instead of once per platform. A project with no knowledge graph, or with a healthy one, sees exactly the output it saw before.
The work is three commits on feat/20261009-knowledge-block-vanishes-silently — 22dde444 (the
fix), 6102dee1 (the docs page and the knowledge-graph decision) and 61aa1a7c (what the review
changed) — after 45081758, which holds the requirements and design.