Skip to content

I0821 — Flattened YAML is cached under .ai/local/cache by content hash

Cache the output of mj_yaml_flatten under .ai/local/cache/flat/<parser sha256>/, keyed by the file's content (held in the entry and compared in full, because hashing the file costs the process a hit is there to save) and the flattener's own version, so a second command on unchanged files does no parsing.

VERIFY wave 1 · p0 · implementation profile · runs alone

Part of M004 — Performance is executable evidence, and the hot path does no canonical work twice.

Implementation is complete and the required evidence is not. It stays here until every token below has a command behind it — completion is gated on evidence, not on a claim.

Objective

Cache the output of mj_yaml_flatten under .ai/local/cache/flat/<parser sha256>/, keyed by the file's content (held in the entry and compared in full, because hashing the file costs the process a hit is there to save) and the flattener's own version, so a second command on unchanged files does no parsing.

Why

doctor flattens 181 files and knowledge nodes 146; across the hook, watch and context the same files are parsed again and again.

Current state

.ai/README.md already reserves local/cache/ for rebuildable caches; nothing uses it.

Desired state

A miss parses and writes atomically; a hit copies; a changed file cannot hit because its bytes are not the ones the entry holds; the cache is bounded by an entry cap in the policy and trimmed oldest first.

Scope

  • lib/common.sh
  • share/allow/policy.txt
  • share/skeleton/policy.yaml
  • .ai/repo/policy.yaml
  • docs/SCHEMAS.md
  • test/cases

Out of scope

  • A cross-process cache of command results

Dependencies

What waits on this

Acceptance criteria

  • Byte-identical output of every read-only command with a cold and a warm cache, proved by case 3090
  • A changed file is re-parsed, proved by mutation
  • The cache never grows past the cap
  • yaml_flatten count is unchanged; a new counter flatten_cache_hit reports hits

Validation

  • bash test/run.sh 3090_a_flatten_is_cached_by_its_content
  • MJ_TIMING=1 bin/majordomus doctor

Evidence required

  • flatten_cache

Evidence

coverstypecommandresultat commit
flatten_cachetestbash test/run.sh 3090_a_flatten_is_cached_by_its_content && MJ_TIMING=1 bin/majordomus doctorok 3090: every parseable tracked YAML file (546 of 551) flattens byte-identically to the parser alone, cold and warm, each warm call a counted hit; a same-length change in the same slot is parsed again; truncated, garbage, forged-source, forged-length, empty and unreadable entries are never served and are rewritten; a failed parse prints and exits 3 as before and is never kept; the directory never exceeds a cap of 3, oldest written removed first; no key or 0 is no cache; a changed parser gets another directory; doctor, context, history, prompt list, skills list and check print the same cold and warm in a fresh repository with yaml_flatten counted equally. Per call on 44 issue files: uncached 171-175 ms (about 4.0 ms each), warm 49-68 ms (about 1.2 ms), cold 400-606 ms once (the write and rename). doctor on this repository: yaml_flatten 571 cold and warm, flatten_cache_hit 16 cold and 337 warm, output identical but for clock-driven lines; wall time 511 s cold and 523 s warm at load average 40-62, which the load dominates. The other 234 calls run in processes that never load the policy and stay uncached.d116266

Risk

Hashing a file costs a subprocess too; the cache pays only when a flatten is materially dearer than a hash, which the counters must show before this lands.

Timeline

started
2026-10-16T09:50:41Z
verified
2026-10-16T09:50:55Z
completed
—

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I0821.yaml. Read it back with majordomus plan show I0821.

Searches the titles and descriptions of every page this site publishes.