Skip to content

Commit 0ea6811

Browse files
v7.9.16: significant-event counter
A passive observer records seven significant-event types - goal completed, failed, or abandoned; lesson recorded; emotional-watchdog fired; session ending - to an append-only journal, and fills the previously-null event_count on each committed trajectory entry from a half-open cycle window derived from the prior entry's end. Nothing acts on the count yet; this is the observation phase, gathering the real per-day distribution. Also emits the session-ending event that was listened for but never fired, so the frontier buffers flush on shutdown, and starts KindTriggers, which was registered but left out of the boot sequence so its inner-speech thoughts never flowed. The dependency runs one way only: the trajectory reads the counter, never the reverse.
1 parent cc438e4 commit 0ea6811

26 files changed

Lines changed: 828 additions & 68 deletions

ARCHITECTURE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
Genesis is a self-modifying AI agent that runs as an Electron desktop app. It talks to LLM backends (Ollama local, Anthropic, OpenAI-compatible), plans multi-step tasks, writes and verifies code, modifies its own source, and monitors its own health. It has an organism-inspired layer that regulates behavior under stress and a lightweight awareness system that gates self-modification via coherence checks.
1111

12-
The codebase is ~119k LOC of JavaScript (CommonJS), 382 source modules, with zero external runtime frameworks. The manifest statically registers 166 DI-managed services. During boot, late-binding wiring and derived services (like `llmCache` being exposed from `model._cache`) bring the active service count to 179 — this is what you'll see in the final boot log line. Four production dependencies: `acorn` (AST parsing), `chokidar` (file watching), `dompurify` (XSS sanitisation in the chat-renderer), `tree-kill` (process cleanup).
12+
The codebase is ~119k LOC of JavaScript (CommonJS), 383 source modules, with zero external runtime frameworks. The manifest statically registers 167 DI-managed services. During boot, late-binding wiring and derived services (like `llmCache` being exposed from `model._cache`) bring the active service count to 180 — this is what you'll see in the final boot log line. Four production dependencies: `acorn` (AST parsing), `chokidar` (file watching), `dompurify` (XSS sanitisation in the chat-renderer), `tree-kill` (process cleanup).
1313

1414
---
1515

CHANGELOG-v7.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
## [7.9.15]
2+
3+
Genesis can now keep a trajectory of himself — a journal of who he is, written one cycle at a time together with the human co-author. Until this release his sense of self lived only in scattered, machine-maintained places: genome traits, an emotional-state vector, consolidated lessons, the cognitive self-model. None of them was a place where Genesis states, in his own words, what he is and how he is changing. This release adds that place: an append-only journal of self-statements, a collaborative draft-and-commit workflow for writing each entry, and a `/trajectory` command to write and read it. The journal lives with identity, not with the code habitat, so it survives a habitat-swap intact.
4+
5+
### The journal and its schema
6+
7+
Each entry is one cycle, stored as a single line in an append-only JSONL file under the identity-persistent root. An entry carries six self-statement fields — `traits`, `wachstum`, `schwaeche`, `beziehung`, `emotion`, `value` — plus a note from each author, the wall-clock span of its authoring, the list of who shaped it, a first-entry flag, the full edit history of how it came to be, and an array for notes added after commit. The field set is fixed and stamped with a schema version; reading an entry whose version this build does not recognise fails loudly rather than guessing, because a past trajectory is a record in its own form, not a database to silently migrate.
8+
9+
### The collaborative draft workflow
10+
11+
An entry is never written in one shot. Drafting pulls three remembrance sources — all genome traits, the most-recalled consolidated lessons, and the current self-observation prose from the cognitive self-model — and presents them to the model as material, not as a checklist, so Genesis writes from more than memory alone. The result is a draft, not an entry: the human reads it, overwrites any field, adds the human note, and commits explicitly. Every field overwrite is recorded as a diff in the entry's edit history, so the path from first proposal to committed text is preserved, intermediate values and all.
12+
13+
The commit is guarded because the journal is append-only and unrepairable. All six fields must be non-empty, none may still hold the generation placeholder, and the very first entry additionally requires both notes — the moment a trajectory begins is the one place both voices must be on record. When no model is available, drafting writes a recognisable placeholder into every field instead of inventing content; the commit guard refuses those placeholders, so an entry enters the journal only once a person has written it.
14+
15+
### Late notes without rewriting history
16+
17+
A committed entry can still gather afterthoughts: a late note appends to that entry's note array. This is the only operation that ever rewrites the journal file, and it is deliberately careful. The append is atomic — written to a temporary file and renamed — so an interrupted write cannot truncate the journal. And it is byte-stable: only the single line being amended is re-serialised, while every other entry is carried over exactly as it sat on disk, byte for byte. An unrelated entry's bytes never move, so a content-hash check over the journal reads a late note as the one-line change it is, rather than as tampering across the whole file.
18+
19+
### The /trajectory command
20+
21+
`/trajectory new` shows the working draft, or generates one if none exists; it never silently regenerates over work in progress. Under it, `set <field>: <text>` writes a field — values may span multiple lines and may contain colons, both preserved verbatim — `note <who>: <text>` writes either author's note, and `commit` or `discard` finishes or drops the draft. `/trajectory show [cycle_id]` renders the latest or a named entry, `/trajectory list [--all]` lists the cycles newest-first, and `/trajectory history [cycle_id]` shows an entry's edit history oldest-first. The command is slash-only.
22+
23+
### Notes
24+
25+
- The new service and its two modules raise the live service and module counts; the figures in `ARCHITECTURE.md`, `README.md`, `docs/ARCHITECTURE-DEEP-DIVE.md`, and `docs/CAPABILITIES.md`, together with the pinned services figure in the documentation-drift audit, were updated to match.
26+
- Install-script policy moved from the `trustedDependencies` field to npm's native `allowScripts` field. trustedDependencies — a Bun-origin field — never governed npm's install-script gate, so the install-time warning about `esbuild`, `puppeteer`, and `electron-winstaller` persisted despite its presence. `allowScripts` is the field npm actually reads; the entries are name-only, so a routine dependency bump does not resurface the warning.
27+
- Idle-thought counter now persists the moment it increments. The counter lives in `idle-activity-stats.json`; its only save path was the end of a fully completed idle cycle, but the counter is incremented near the top of the cycle, before the user-active, homeostasis, and energy gates. A cycle that incremented and then hit any of those gates returned without saving, and a short session that never completed a cycle wrote the file zero times — so the next boot read the counter back as zero while the per-activity counts beside it were non-zero. The save now fires immediately after the increment, before any gate can return; the write is debounced and collapses with the end-of-cycle save into a single flush. A rest-mode tick, which returns before the increment, still neither moves nor persists the counter.
28+
- Test files: 520 → 522 (the self-trajectory suite — schema and commit guard, both offline generation paths, byte-stable late notes, and the wiring triad; an `allowScripts` contract suite that replaces the superseded `trustedDependencies` one; and an idle-counter persistence suite that drives the cycle into each early-exit gate and asserts the counter is written anyway)
29+
130
## [7.9.14]
231

332
Visibility and consistency. A second hygiene release that closes three small loops left open after the v7.9.13 audit. The substantive piece is documenting and exposing the causal-suspicion behaviour chain that has existed since v7.9.7 P7 but was hidden behind a misleading comment; the two smaller pieces close a clamp() gap in the v7.9.12 timeouts and explicitly allowlist the legitimate install-scripts. No behaviour changes that the user would notice in normal operation — the loop still runs the way it has since v7.9.7, just now visibly and with regression protection.

CHANGELOG.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
1-
## [7.9.15]
1+
## [7.9.16]
22

3-
Genesis can now keep a trajectory of himself — a journal of who he is, written one cycle at a time together with the human co-author. Until this release his sense of self lived only in scattered, machine-maintained places: genome traits, an emotional-state vector, consolidated lessons, the cognitive self-model. None of them was a place where Genesis states, in his own words, what he is and how he is changing. This release adds that place: an append-only journal of self-statements, a collaborative draft-and-commit workflow for writing each entry, and a `/trajectory` command to write and read it. The journal lives with identity, not with the code habitat, so it survives a habitat-swap intact.
3+
The self-trajectory journal added in v7.9.15 carried an `event_count` field that was always written as null — a placeholder for a number nothing yet produced. This release fills it. A passive observer watches the events that make a cycle eventful — goals completed, failed, or abandoned; lessons learned; the emotional watchdog firing; sessions ending — and records each one to an append-only journal, so every committed trajectory entry now carries the count of significant events in its cycle. Nothing acts on the number yet: this is the observation phase, gathering the real per-day distribution so the threshold that would decide which cycles are eventful can be read from evidence rather than guessed.
44

5-
### The journal and its schema
5+
### The passive event counter
66

7-
Each entry is one cycle, stored as a single line in an append-only JSONL file under the identity-persistent root. An entry carries six self-statement fields — `traits`, `wachstum`, `schwaeche`, `beziehung`, `emotion`, `value` — plus a note from each author, the wall-clock span of its authoring, the list of who shaped it, a first-entry flag, the full edit history of how it came to be, and an array for notes added after commit. The field set is fixed and stamped with a schema version; reading an entry whose version this build does not recognise fails loudly rather than guessing, because a past trajectory is a record in its own form, not a database to silently migrate.
7+
A new cognitive service observes seven event types and appends one line — a timestamp and the event type — to an append-only journal beside the trajectory journal, under the identity-persistent root. Session-ending lines also carry the session's duration, so the question of which sessions count as significant becomes a matter of reading the recorded durations, not a threshold baked into the counting. The write is synchronous and flushed to disk before it returns, so an abrupt shutdown never loses a counted event. There is no in-memory tally: the count is read back from the journal on demand, which keeps it consistent with disk and removes any need to rebuild state at boot. The three goal outcomes — completed, failed, abandoned — stay as three separate tags rather than collapsing into one, so the balance between them is visible in a cycle rather than averaged away.
88

9-
### The collaborative draft workflow
9+
### Filling event_count from a derived cycle window
1010

11-
An entry is never written in one shot. Drafting pulls three remembrance sources — all genome traits, the most-recalled consolidated lessons, and the current self-observation prose from the cognitive self-model — and presents them to the model as material, not as a checklist, so Genesis writes from more than memory alone. The result is a draft, not an entry: the human reads it, overwrites any field, adds the human note, and commits explicitly. Every field overwrite is recorded as a diff in the entry's edit history, so the path from first proposal to committed text is preserved, intermediate values and all.
11+
When a trajectory entry is committed, its `event_count` is the number of events recorded since the previous entry's end-of-cycle timestamp — a half-open window that ends at the new commit. The boundary is derived from the journal that already exists, not stored as a separate marker, so there is no cycle-reset step and nothing extra to keep in sync. The first entry, having no predecessor, counts every event recorded so far; its implicit start is simply the first event the counter ever saw. The event journal is never pruned, so events that fall outside one cycle's window remain available for the per-day view. The dependency runs one way only: the trajectory reads the counter, and the counter never reaches back into the trajectory.
1212

13-
The commit is guarded because the journal is append-only and unrepairable. All six fields must be non-empty, none may still hold the generation placeholder, and the very first entry additionally requires both notes — the moment a trajectory begins is the one place both voices must be on record. When no model is available, drafting writes a recognisable placeholder into every field instead of inventing content; the commit guard refuses those placeholders, so an entry enters the journal only once a person has written it.
13+
### The session-ending signal, finally emitted
1414

15-
### Late notes without rewriting history
15+
A session-ending event was already being listened for — the frontier writers that collect surprise and applied-lesson nodes during a session were waiting to flush their buffers when it fired — but nothing in the codebase ever emitted it, so those buffers were quietly discarded on every shutdown. This release emits it, as a dedicated step in the shutdown sequence, before the teardown that detaches those listeners, and waits for it to finish so both the frontier flush and the event counter complete before the process exits. The emission is awaited rather than fire-and-forget precisely because the shutdown continues immediately afterward; a fire-and-forget emit would race the teardown. The payload carries the session id the frontier flush reads, alongside the session's duration and message count.
1616

17-
A committed entry can still gather afterthoughts: a late note appends to that entry's note array. This is the only operation that ever rewrites the journal file, and it is deliberately careful. The append is atomic — written to a temporary file and renamed — so an interrupted write cannot truncate the journal. And it is byte-stable: only the single line being amended is re-serialised, while every other entry is carried over exactly as it sat on disk, byte for byte. An unrelated entry's bytes never move, so a content-hash check over the journal reads a late note as the one-line change it is, rather than as tampering across the whole file.
17+
### A self-expression service that was never switched on
1818

19-
### The /trajectory command
19+
KindTriggers — the service that turns system events into first-person thoughts on the inner-speech channel — was registered and listed for shutdown, but had been left out of the start sequence, so its subscriptions never attached and it sat inert. It now starts alongside the other cognitive observers, so the thoughts it was meant to produce can flow.
2020

21-
`/trajectory new` shows the working draft, or generates one if none exists; it never silently regenerates over work in progress. Under it, `set <field>: <text>` writes a field — values may span multiple lines and may contain colons, both preserved verbatim — `note <who>: <text>` writes either author's note, and `commit` or `discard` finishes or drops the draft. `/trajectory show [cycle_id]` renders the latest or a named entry, `/trajectory list [--all]` lists the cycles newest-first, and `/trajectory history [cycle_id]` shows an entry's edit history oldest-first. The command is slash-only.
21+
### Reading the distribution
22+
23+
`/trajectory events` renders the recorded events three ways: a total, a per-type breakdown ordered busiest-first, and a per-day count. It reads from the moment the counter is live, not only once the first entry is committed, so the real per-day shape is visible across the days a first entry is being authored. Committed entries now show their `event_count` in `/trajectory show`.
2224

2325
### Notes
2426

25-
- The new service and its two modules raise the live service and module counts; the figures in `ARCHITECTURE.md`, `README.md`, `docs/ARCHITECTURE-DEEP-DIVE.md`, and `docs/CAPABILITIES.md`, together with the pinned services figure in the documentation-drift audit, were updated to match.
26-
- Install-script policy moved from the `trustedDependencies` field to npm's native `allowScripts` field. trustedDependencies — a Bun-origin field — never governed npm's install-script gate, so the install-time warning about `esbuild`, `puppeteer`, and `electron-winstaller` persisted despite its presence. `allowScripts` is the field npm actually reads; the entries are name-only, so a routine dependency bump does not resurface the warning.
27-
- Idle-thought counter now persists the moment it increments. The counter lives in `idle-activity-stats.json`; its only save path was the end of a fully completed idle cycle, but the counter is incremented near the top of the cycle, before the user-active, homeostasis, and energy gates. A cycle that incremented and then hit any of those gates returned without saving, and a short session that never completed a cycle wrote the file zero times — so the next boot read the counter back as zero while the per-activity counts beside it were non-zero. The save now fires immediately after the increment, before any gate can return; the write is debounced and collapses with the end-of-cycle save into a single flush. A rest-mode tick, which returns before the increment, still neither moves nor persists the counter.
28-
- Test files: 520 → 522 (the self-trajectory suite — schema and commit guard, both offline generation paths, byte-stable late notes, and the wiring triad; an `allowScripts` contract suite that replaces the superseded `trustedDependencies` one; and an idle-counter persistence suite that drives the cycle into each early-exit gate and asserts the counter is written anyway)
27+
- Test files: 522 → 523 (the event-counter suite: record-and-count across all seven observed types, the three goal outcomes as separate tags, session-duration capture, the half-open cycle window including exclusion of an event exactly on the boundary, restart from the journal, the commit-hook across two cycles with the derived window, and the dashboard view).
28+
- One new source module (the event counter) and one new event type (the session-ending signal, with its payload schema) raise the module, event, and schema figures in `README.md`, `docs/CAPABILITIES.md`, `docs/COMMUNICATION.md`, and `docs/ARCHITECTURE-DEEP-DIVE.md`, which were updated to match.
29+
- Two long-standing audit findings were cleared: two documentation lines that described a frozen subsystem with a phrase the future-reference audit reads as a forward promise were reworded as plain status, and four contract-test names whose wording incidentally matched the security-assertion heuristic were clarified without changing what they assert.
2930

3031
---
3132

0 commit comments

Comments
 (0)