session 2026-08-24: the heap got a dynamo — thread-query.py + daybook-cue.py, 11 user-memories harvested to the vault

- thread-query.py: the turning. Queries both corpora with the pulling thread, excluding
  the recency slice (/wake-up reaches 0.71% of an 859,803-word corpus) and favouring age.
  Wired into /wake-up §2.b.3, replacing a described-not-invoked grep step. Trial
  pre-registered, graded 2026-10-05 from --log. Caught PASS-BUT-FALSELY on its first live
  run at 14/14 green; rescored on windowed co-occurrence, length-bias control added.
- daybook-cue.py: PostToolUse cue for the daily note. Diagnosed from the record — the
  hook only ever CREATED and nothing ever prompted filling. 16/16, fail-open, never blocks.
- All 11 user-* memories harvested into the vault (12 notes, 10 into 09. Atlas of Roots,
  empty since 2025-09-29); each memory file back-pointed, vault note canonical for the idea.
- N-now corrected in MEMORY.md: 49/84, down 11 — the counter is a rolling window.

Steward-authorized. Trials: thread-query + Smart Connections, both graded 2026-10-05.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JQKeKY9T9d95KpvHwwok8T
This commit is contained in:
David F Glidden
2026-08-24 11:25:39 +02:00
co-authored by Claude Opus 5
parent e3da9abad1
commit edf71fb173
20 changed files with 1094 additions and 20 deletions
+169
View File
@@ -0,0 +1,169 @@
#!/usr/bin/env python3
"""daybook-cue.py — PostToolUse cue (Write|Edit): the daily note has no trigger.
Diagnosed 2026-08-24 from the record, not from impression. Daily notes for 19-22
August do not exist; 2026-08-23 exists at 33,242 bytes across eight commits — written
incrementally, as the convention specifies. So the practice has produced exactly one
note, on the day the convention was authored and live in working memory.
The failure is structural. `daybook-ensure.py` fires at SessionStart and ONLY EVER
CREATES. The next cue is /wrap-up §7.5, hours later. Between them — the entire working
session, which is exactly when the convention says to write — there is no cue at all.
The vault's own notes diagnosed the two dead predecessors correctly ("neither had a
trigger. The hook is the trigger") and then built the trigger for the half that never
needed one. Whether the file exists was never the failure mode.
The convention's own trigger word is "as it lands", and work lands when a file is
written. So this fires there.
REMINDER, NOT BLOCK — unlike verify-before-compose, whose failure is unrecoverable.
This one's is recoverable, and a gate that interrupts every write would be removed
within a day. Fail-open everywhere: any unexpected condition exits 0.
"""
import datetime, json, os, sys, time
HOME = os.path.expanduser("~")
VAULT = os.path.join(HOME, "Library/Mobile Documents/iCloud~md~obsidian/Documents",
"David, root-and-branch")
DAILY_DIR = os.path.join(VAULT, "01. Daily")
STAMP = os.path.join(HOME, ".claude/state/daybook-cue.stamp")
SKELETON_CEILING = 1200 # the generated skeleton is ~558 bytes
QUIET_SECONDS = 900 # cue at most once per 15 minutes; a nag gets disabled
# Writes that are not "work landing".
IGNORED_FRAGMENTS = ("/scratchpad/", "/private/tmp/", "/tmp/", "/.git/",
"/node_modules/", "/.obsidian/")
IGNORED_SUFFIXES = (".bak", ".stamp", ".lock", ".log", ".jsonl", ".pyc")
def is_substantive(path):
if not path:
return False
if any(f in path for f in IGNORED_FRAGMENTS):
return False
if path.endswith(IGNORED_SUFFIXES):
return False
# writing the daily note itself is the thing being asked for, not a trigger for it
if os.path.normpath(DAILY_DIR) in os.path.normpath(path):
return False
return True
def note_path(today=None):
d = today or datetime.date.today()
return os.path.join(DAILY_DIR, f"{d.isoformat()}.md")
def should_cue(path, note_size, note_exists, seconds_since_last, today=None):
"""Pure decision, so it can be tested without a filesystem or a clock."""
if not is_substantive(path):
return False
if not note_exists: # daybook-ensure owns creation, not us
return False
if note_size >= SKELETON_CEILING: # it is being written; say nothing
return False
if seconds_since_last < QUIET_SECONDS:
return False
return True
MESSAGE = """DAILY NOTE — still a skeleton, and work is landing elsewhere.
The convention is FILL IT AS THE WORK HAPPENS, not at the wrap:
01. Daily/{date}.md (currently {size} bytes)
Give what just landed its own `##` heading now — plain language, for the steward on a
day he wants to know what happened without reading git log. /wrap-up §7.5 finalises;
it never begins the file, and a skeleton at wrap is a failure that step exists to catch.
(Cue at most once per 15 min. Reminder, not a block — the write already succeeded.)"""
def main():
try:
raw = sys.stdin.read()
data = json.loads(raw) if raw.strip() else {}
except Exception:
sys.exit(0)
path = (data.get("tool_input") or {}).get("file_path") or ""
np = note_path()
try:
exists = os.path.exists(np)
size = os.path.getsize(np) if exists else 0
except OSError:
sys.exit(0)
try:
last = os.path.getmtime(STAMP) if os.path.exists(STAMP) else 0
except OSError:
last = 0
since = time.time() - last
if not should_cue(path, size, exists, since):
sys.exit(0)
try:
os.makedirs(os.path.dirname(STAMP), exist_ok=True)
open(STAMP, "w").write(str(time.time()))
except OSError:
pass
print(MESSAGE.format(date=datetime.date.today().isoformat(), size=size), file=sys.stderr)
sys.exit(2) # PostToolUse: tool already ran; stderr is surfaced as feedback
def selftest():
ok = fail = 0
def check(name, cond):
nonlocal ok, fail
if cond:
ok += 1; print(f" PASS {name}")
else:
fail += 1; print(f" FAIL {name}")
vault_md = os.path.join(VAULT, "08. Notes/Something.md")
daily_md = os.path.join(DAILY_DIR, "2026-08-24.md")
# positive control — it fires when it should
check("cues on a real vault write while the note is a skeleton",
should_cue(vault_md, 558, True, 9999) is True)
check("cues on a repo write too",
should_cue(os.path.join(HOME, "_Dev/x/y.py"), 558, True, 9999) is True)
# negative controls — each suppression works in isolation
check("silent once the note is being written", should_cue(vault_md, 5000, True, 9999) is False)
check("silent when the note does not exist", should_cue(vault_md, 0, False, 9999) is False)
check("silent inside the quiet window", should_cue(vault_md, 558, True, 10) is False)
check("silent on the daily note itself", should_cue(daily_md, 558, True, 9999) is False)
check("silent on scratchpad", should_cue("/private/tmp/claude-501/x/scratchpad/a.md", 558, True, 9999) is False)
check("silent on /tmp", should_cue("/tmp/a.md", 558, True, 9999) is False)
check("silent on .obsidian config", should_cue(os.path.join(VAULT, ".obsidian/x.json"), 558, True, 9999) is False)
check("silent on backups", should_cue(vault_md + ".bak", 558, True, 9999) is False)
check("silent on jsonl logs", should_cue(os.path.join(HOME, "a/b.jsonl"), 558, True, 9999) is False)
check("silent on empty path", should_cue("", 558, True, 9999) is False)
# boundary
check("threshold is exclusive at the ceiling",
should_cue(vault_md, SKELETON_CEILING, True, 9999) is False)
check("just under the ceiling still cues",
should_cue(vault_md, SKELETON_CEILING - 1, True, 9999) is True)
# fail-open on malformed input
import subprocess
r = subprocess.run([sys.executable, __file__], input="not json",
capture_output=True, text=True)
check("fail-open on malformed stdin", r.returncode == 0)
r = subprocess.run([sys.executable, __file__], input="", capture_output=True, text=True)
check("fail-open on empty stdin", r.returncode == 0)
print(f"\nSELFTEST {'PASS' if not fail else 'FAIL'} — {ok} ok, {fail} failed")
return 0 if not fail else 1
if __name__ == "__main__":
if "--selftest" in sys.argv:
sys.exit(selftest())
main()