Skip to content

Commit ae42235

Browse files
committed
docs(agent-memory): add 9.5 option (d), trim review-history prose
Round-37 review. The substantive finding: 9.5's options (a) fits / (b) raise the budget / (c) drop the hook all treat spawn cost as a constant to tolerate -- while last round's measurement showed spawn cost is the ONLY cost that matters (scan 2-3ms, interpreter ~20ms). None of the three attacks the measured bottleneck. That follows directly from a number this doc already carried, and I should have drawn it rather than waiting for a reviewer to. Added (d): a warm resident process holding the store in memory, with the hook reduced to a socket round-trip. Named as a real option because it is the only one that removes the dominant term, explicitly NOT as the recommendation -- its costs land on this design's own properties. A "never blocks, exit 0" hook gains a liveness dependency and must keep the cold path anyway, so complexity is added to rather than swapped for what (a)-(c) need; lifecycle and stale-socket handling are a second heuristic alongside 5.4's; a resident process holding memory contents in RAM is a different security surface; and stdlib-scripts-that-exit is this repo's shape. Sequenced behind the busy-machine measurement: if 100ms holds under load, a daemon buys latency nobody needed. Also trimmed the three passages the review named as archive-not-spec. One of them ("the sentence went stale twice (53 -> 57 -> 67)") was itself stale at 69, which is the argument for cutting it rather than updating it. Verified: 69 checks, 0 failures; derive_counters.py --check unchanged (363/89/663). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
1 parent 75dd6d1 commit ae42235

2 files changed

Lines changed: 45 additions & 24 deletions

File tree

engineering/agent-memory/DESIGN.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,36 @@ Needed before implementation starts:
929929
carry the system. Option (c) is a real, acceptable outcome — a recall hook
930930
that misses its budget on every prompt is worse than no recall hook.
931931

932+
**(d) Attack the measured cost instead of budgeting around it — a warm
933+
resident process.** (a)–(c) all treat spawn cost as a constant to tolerate,
934+
which the measurement above says is the *only* cost that matters: the scan is
935+
2–3 ms, the interpreter is the other ~20 ms, and it is paid again on **every
936+
prompt for the life of every session** — a fixed tax, not a one-off. A small
937+
daemon holding the atom store in memory, with `user_prompt_submit.py` reduced
938+
to a socket write and a read, removes the dominant term rather than fitting
939+
inside it.
940+
941+
Named as a real option because it is the only one that does, **not** as the
942+
recommendation — it is the most expensive by a wide margin, and its costs
943+
land squarely on this design's stated properties:
944+
945+
- A hook that "never blocks, exit 0 on failure" (§5.2) becomes a hook with a
946+
liveness dependency. It must still fail open when the socket is missing,
947+
stale, or wedged — which means keeping the cold path anyway, so the
948+
complexity is *added to*, not swapped for, what (a)–(c) need.
949+
- Lifecycle: who starts it, what restarts it after a crash or reboot, how a
950+
stale socket is distinguished from a live one, and how it terminates when
951+
no session is using it. §5.4 already carries a stale-lock heuristic; this
952+
would need a second one for a different resource.
953+
- It is a long-lived local process holding memory contents in RAM, which is a
954+
different security surface from a script that reads a file and exits.
955+
- This repo's convention is stdlib-only scripts that run and exit; a resident
956+
service is a genuinely new shape here, not a variation on an existing one.
957+
958+
**Sequencing:** (d) is only worth its cost if the busy-machine measurement
959+
turns (a) into (b) or (c). Measure first — the same instruction this decision
960+
opened with. If 100 ms holds under load, a daemon buys latency nobody needed.
961+
932962
**If (c) wins, `hooks/hooks.json` must shrink too** — the `UserPromptSubmit`
933963
entry is already written there as a contract, so deleting the hook from this
934964
doc alone would leave the contract file asserting a hook the design no longer
@@ -1029,11 +1059,8 @@ claims that must match measured reality · lifecycle coherence across a
10291059
multi-tier id group).
10301060

10311061
That count is **itself checked** — family 6's last assertion compares it against
1032-
the number of checks the run actually executed. It is written that way because
1033-
the sentence above went stale twice (53 → 57 → 67) while this section argued
1034-
against exactly that, and a review then quoted the stale figure back. A number
1035-
in prose describing a program's behaviour is drift waiting to happen unless the
1036-
program owns it.
1062+
the number of checks the run actually executed. A number in prose describing a
1063+
program's behaviour is drift waiting to happen unless the program owns it.
10371064

10381065
**To run it** (it is `.txt`, so it cannot be executed in place, and it resolves
10391066
its own paths by walking up from `__file__` — a `python3 <(cat …)` or `-c

engineering/agent-memory/assets/validate_examples.py.txt

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -332,20 +332,14 @@ def main():
332332

333333
# -- family 6: claims in prose that must match measurable reality --------
334334
# The 1 size claim is a POINT-IN-TIME measurement, so this family checks
335-
# what the doc controls, not what it does not. An earlier version compared
336-
# the cited figure against the LIVE byte count of the repo-root CLAUDE.md
337-
# -- a file this repo appends a release note to on nearly every point
338-
# release. That check would have started failing on the next unrelated PR,
339-
# for a reason with nothing to do with this folder, and 10.1's own thesis
340-
# says a checker must own its ground truth rather than borrow a moving
341-
# one. Snapshotting the byte count as a constant here is not the fix
342-
# either: it just moves the same number to a second place that can drift
343-
# from the first, with nothing able to say which one is wrong.
344-
#
345-
# What IS durable, and what the original defect actually was (1 once read
346-
# "~40 KB", eyeballed, off by more than 2x): the claim must name its
347-
# method and carry a real byte figure, and its two units must agree with
348-
# each other. Both are properties of the sentence itself.
335+
# what the doc controls, not what it does not. Do NOT compare the cited
336+
# figure against the live byte count of repo-root CLAUDE.md: that file gets
337+
# a release note on nearly every point release, so the check would go red on
338+
# unrelated PRs. Snapshotting it as a constant here is no better -- the same
339+
# number in a second place, with nothing able to say which drifted. What is
340+
# durable, and what the original defect was ("~40 KB", eyeballed, off by
341+
# >2x): the claim must name its method, carry a real byte figure, and have
342+
# its two units agree. All properties of the sentence itself.
349343
m = re.search(r"\*\*(\d+) KB\*\*[^.]*?`wc -c`[^.]*?([\d,]{4,})\s+bytes", design)
350344
check(m is not None,
351345
"the CLAUDE.md size claim names `wc -c` and cites a byte figure")
@@ -358,11 +352,11 @@ def main():
358352
"promotion row names sessions, not observations, as the gate")
359353

360354
# 4.1.1's merge step must account for EVERY schema-required field, not the
361-
# interesting ones. That step has now shipped three separate omissions --
362-
# `source`, then `promoted_from_projects`, then confidence/redacted/kind --
363-
# each caught by a human reading the list against the schema. Each fix was
364-
# an instance; this is the class. An implementation written literally
365-
# against a step that skips a required field emits a schema-invalid atom.
355+
# interesting ones -- repeated omissions there (`source`,
356+
# `promoted_from_projects`, confidence/redacted/kind) were each caught by a
357+
# human reading the list against the schema. This is the class, not another
358+
# instance: an implementation written literally against a step that skips a
359+
# required field emits a schema-invalid atom.
366360
merge = design[design.index("#### 4.1.1"):design.index("#### 4.1.2")]
367361
merge_flat = norm_prose(merge)
368362
# norm_prose strips `_` (a markdown italic marker), so field names must be

0 commit comments

Comments
 (0)