Skip to content

Commit 908a57e

Browse files
omc-fibtier: Fibonacci-tier memory primitive
User's idea: context grows linearly in time but its IMPORTANCE is power-law. Recent matters at full detail; older matters as abstraction. Encode both axes by structuring the context buffer as Fibonacci-sized tiers that fold upward. Tier 1: 1 slot (current focus) Tier 2: 2 slots (active sub-themes) Tier 3: 3 slots (recent decisions) Tier 4: 5 slots (session arc) Tier 5: 8 slots (session history) Tier 6: 13 slots (multi-session themes) Tier 7: 21 slots (long-term patterns) ... When tier N exceeds cap, its oldest TWO entries fold together into one (concatenation + new canonical hash), the folded entry promotes upward to tier N+1, and the cascade continues recursively. API: fibtier_new(max_tiers) fibtier_push(mem, content) add a new entry, cascade folds fibtier_query(mem, query, top_k) substrate-distance-ranked search fibtier_stats(mem) occupancy / pushes / folds / evicted fibtier_render(mem) LLM-readable prompt string fibtier_fold_default(a, b) the fold rule (concat + new hash) Composes with everything OMC already shipped: - fnv1a_hash identity per entry (kernel-compatible) - attractor_distance substrate distance metric - Fibonacci attractor table the tier sizes themselves Demo (examples/fibtier_conversation.omc, 100 synthetic turns): Pushes 100 conversation turns into a 7-tier memory. Result after 100 turns: Occupancy: [1, 1, 3, 5, 7, 1, 0] Total stored: 18 entries (representing 100 turns of content) Folds: 82 (entries collapsed upward) Evicted: 0 Memory stays bounded at 18 entries regardless of conversation length. Each fold's content traces lineage back to source canonical hashes. Query demo: query "fibonacci tiers" → top 3 substrate-distance matches across tiers 2, 3, 4 (most recent + folded-historical entries). Tests (examples/tests/test_fibtier.omc): 8/8 pass: - tier sizes are Fibonacci - capacity lookup - push-one lands in tier 1 - push-two promotes (no fold yet) - push-three fills tier 2 to cap (still no fold) - push-four triggers first fold (cascade to tier 3) - render produces nonempty string - capacity growth is geometric (sum check) Honest scope: - Fold = concatenation (not LLM summarization). Entry size grows linearly with fold-count. For real use, swap default fold for an LLM-summarize fold via py_callback — substrate captures structure; LLM captures meaning. - Single-process in-memory. Persistent fibtier (back-by-kernel) is a natural extension — each entry becomes a kernel store entry, folds become kernel writes. - No eviction-by-similarity yet; folds always pick oldest-two. A smarter fold would pick closest-pair (by substrate distance) to consolidate semantically-related entries before age-based pairs. This is the substrate-native memory primitive the project's been building toward. Composes naturally with omc-kernel + codec + OMC- PROTOCOL. The "context window as Fibonacci-tiered DAG" architecture. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent ea251f4 commit 908a57e

3 files changed

Lines changed: 548 additions & 0 deletions

File tree

examples/fibtier_conversation.omc

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Fibonacci-tier memory demo — 100-turn synthetic conversation.
2+
#
3+
# Shows that a fibtier memory keeps context bounded as conversation
4+
# grows: tier occupancy stabilizes at Fibonacci capacities, older
5+
# entries cascade upward through folds, total entries stays bounded
6+
# while a conversation of arbitrary length flows through.
7+
#
8+
# Each "turn" is a short message. We push them sequentially and
9+
# print the memory state every 10 turns to show how the tiering
10+
# evolves.
11+
12+
import "examples/lib/fibtier.omc";
13+
14+
fn make_turns(n) {
15+
# Synthetic conversation: each turn is a substantively-different
16+
# short message so canonical hashes differ.
17+
h topics = [
18+
"user asks about prometheus design",
19+
"claude explains substrate attention",
20+
"user requests benchmark numbers",
21+
"claude shows L0 vs L1 results",
22+
"user pivots to memory architecture",
23+
"claude proposes fibonacci tiers",
24+
"user accepts the proposal",
25+
"claude builds the prototype",
26+
"user runs the test suite",
27+
"claude analyzes the results",
28+
"user asks for next steps",
29+
"claude lists three follow-ups",
30+
"user picks the second one",
31+
"claude implements the change",
32+
"user reviews the diff",
33+
"claude addresses the feedback",
34+
"user merges the PR",
35+
"claude celebrates the win",
36+
"user proposes new direction",
37+
"claude estimates the effort",
38+
];
39+
h turns = [];
40+
h i = 0;
41+
while i < n {
42+
h t = arr_get(topics, i - (i / arr_len(topics)) * arr_len(topics));
43+
h labeled = concat_many("[turn ", to_string(i + 1), "] ", t);
44+
arr_push(turns, labeled);
45+
i = i + 1;
46+
}
47+
return turns;
48+
}
49+
50+
fn print_state(mem, turn_number) {
51+
h s = fibtier_stats(mem);
52+
h occ = dict_get(s, "occupancy");
53+
h total = dict_get(s, "total_entries");
54+
h folds = dict_get(s, "total_folds");
55+
h evicted = dict_get(s, "evicted");
56+
print(concat_many("after ", to_string(turn_number),
57+
" turns: occupancy=", to_string(occ),
58+
" total=", to_string(total),
59+
" folds=", to_string(folds),
60+
" evicted=", to_string(evicted)));
61+
}
62+
63+
fn main() {
64+
print("=== Fibonacci-tier memory: 100-turn conversation ===");
65+
print("");
66+
print("Tier sizes (Fibonacci): " + to_string(fibtier_default_sizes()));
67+
print("");
68+
69+
h mem = fibtier_new(7); # 7 tiers: 1+2+3+5+8+13+21 = 53 max
70+
h turns = make_turns(100);
71+
h i = 0;
72+
while i < arr_len(turns) {
73+
fibtier_push(mem, arr_get(turns, i));
74+
if (i + 1) % 10 == 0 {
75+
print_state(mem, i + 1);
76+
}
77+
i = i + 1;
78+
}
79+
80+
print("");
81+
print("=== Final memory state ===");
82+
print(fibtier_render(mem));
83+
84+
h final_stats = fibtier_stats(mem);
85+
print("");
86+
print(concat_many("After 100 pushes:"));
87+
print(concat_many(" total stored entries: ", to_string(dict_get(final_stats, "total_entries"))));
88+
print(concat_many(" total folds: ", to_string(dict_get(final_stats, "total_folds"))));
89+
print(concat_many(" evicted (overflowed top tier): ", to_string(dict_get(final_stats, "evicted"))));
90+
91+
# Sanity: total should be bounded by sum of tier capacities = 53.
92+
h total = dict_get(final_stats, "total_entries");
93+
print("");
94+
if total <= 53 {
95+
print(concat_many("[OK] Memory bounded at ", to_string(total),
96+
" entries (cap=53) after 100 turns."));
97+
print(" Context window stays constant regardless of conversation length.");
98+
print(" Detail decreases by phi per tier upward; recent stays full-fidelity.");
99+
} else {
100+
print(concat_many("[FAIL] Memory unbounded: ", to_string(total), " > 53"));
101+
}
102+
103+
# Query demo.
104+
print("");
105+
print("=== Query demo: substrate-distance similarity ===");
106+
h query = "fibonacci tiers";
107+
h results = fibtier_query(mem, query, 3);
108+
print(concat_many("top 3 closest to query \"", query, "\":"));
109+
h j = 0;
110+
while j < arr_len(results) {
111+
h r = arr_get(results, j);
112+
h e = dict_get(r, "entry");
113+
print(concat_many(
114+
" tier=", to_string(dict_get(r, "tier")),
115+
" dist=", to_string(dict_get(r, "distance")),
116+
" content=", dict_get(e, "content")
117+
));
118+
j = j + 1;
119+
}
120+
}
121+
122+
main();

0 commit comments

Comments
 (0)