Skip to content

fix(kb-store): putEvent reads, re-sorts, and rewrites events.json in full on every event #204

Description

@drewstone

Version checked: agent-knowledge 15.0.2 (tag v15.0.2, 1b1408e), the Discovery Lab's installed pin. src/kb-store.ts and src/durable-fs.ts are byte-identical on origin/main (a7fb5fc, 15.0.3).

What the code does

  • src/kb-store.ts:307-316FileSystemKbStore.putEvent takes the mutation lock, calls this.readEvents() (the whole events.json, parsed and schema-checked, :407-410), filters out any entry with the same id, appends the new one, re-sorts every event by createdAt, and writes the whole array back with writeJsonDurableWithinRoot (src/durable-fs.ts:70-78: JSON.stringify(value, null, 2) followed by a durable full-file write).
  • src/kb-store.ts:318-325listEvents reads and filters the whole file as well, and applies limit only as a tail slice after the full parse.
  • The file is .agent-knowledge/events.json (KB_EVENTS_PATH, src/kb-store.ts:41).

Recording one event therefore costs O(n) in the events already recorded, in bytes read and in bytes written, and every write goes through the durable path. The in-memory store's putEvent (src/kb-store.ts:170-172) is a plain push, so the two backends already disagree about the cost model.

Measured

The findings file (Discovery #159, row 8b) reads this from source. No event count was measured, and while filing, a read-only check found no events.json under the Lab's kb/.agent-knowledge/ yet, so the growth curve is a projection from the code, not an observation. The same store holds 4,728 pages (index.json 21.7 MB) and grows 50-100 pages per day (#132); row Y7 of the findings projects the event stream of a months-long run to grow linearly and be rewritten in full on every append.

Correct behavior

Append-only events: one durable append per putEvent (JSON Lines, or a segmented log with periodic compaction), with the id-dedup guarantee kept by an id index or enforced on read rather than by rewriting the file. listEvents with a limit should read from the tail instead of parsing the whole history. Ordering by createdAt can be applied on read, or the store can refuse an out-of-order createdAt at intake; neither needs a full rewrite.

Findings: https://github.com/tangle-network/discovery/blob/4cbc5406707cdf753e3b950ad0e38cb67914da95/docs/research/159-long-horizon-ceilings.md (row 8b and "Upstream gaps"). Filed for Discovery map tangle-network/discovery#136 through tangle-network/discovery#167.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions