fix(dashboard): tolerate string decisions, derive active projects, log passive activations#23
Open
juanparisma wants to merge 1 commit into
Conversation
…g passive activations
- collect_decisions: handle strategicDecisions as plain strings (not just
objects). Previously crashed with AttributeError: 'str' has no 'get' when
operator-state stored decisions as strings.
- collect_projects: 'active' count was always 0 because the registry never
sets an 'active' flag. Now derives activity from observation recency
(<=14d) and resolves friendly project names from the registry/observations
instead of showing raw hashes.
- _passive-activator.sh: write fired rule activations to _passive.log
('TS | rule_id | tool') so the dashboard and /passive-status can report
passive-rule telemetry. Previously passive rules fired silently with no
log, so activation counts were always 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Luispitik
requested changes
Jun 10, 2026
Luispitik
left a comment
Owner
There was a problem hiding this comment.
Top-quality PR — I reproduced all three bugs on main before reading your fixes, and they match exactly:
- A single string in
strategicDecisionscrashescollect_decisions()withAttributeErrorand kills the whole dashboard (main()re-raises). - Nothing ever writes an
activeflag (_session-learner.shwrites{id,name,root,remote,created,last_seen}), so the dashboard always showed 0 active projects. Your mtime<=14d derivation + friendly-name resolution check out: the registry id matches the homunculus sha256[:12] hash, and every observation line carriesproject_name. _passive-activator.shwrote no telemetry, socollect_passive_log()always returned empty. YourISO | rule_id | toolformat is parsed correctly by the dashboard, and I verified functionally on Windows Git Bash that the activator still injects and never corrupts the rules JSON.
The patch applies clean on v4.6.1 and the full suite is green with it (I ran all 11 suites: 147/147).
Four asks before merge:
- Guard the log-path derivation so a future rename can't corrupt the rules file — if
replace()doesn't match,logPathIS_passive-rules.jsonand the append would corrupt it:const logPath = process.argv[1].replace(/_passive-rules\.json$/, "_passive.log"); if (logPath !== process.argv[1]) { const ts = new Date().toISOString(); fs.appendFileSync(logPath, topIds.map(id => ts + " | " + id + " | " + tool + "\n").join("")); }
- Empty string instead of
Nonefor the synthetic decision id — the template renders${d.id}directly (lines 408/424), so string-decisions currently show a literalnullin the timeline:decs.append({'id': '', 'date': '', 'decision': d}). - Regression tests in
tests/test-dashboard.sh(repo convention — every fix ships with one): T13 mixed strings+objects instrategicDecisions→ dashboard generates without crash; T14 one recent observations file + one with old mtime (touch -d '30 days ago') →active==1and friendly name resolved from registry/last observation, not the hash; T15 invoke_passive-activator.shwith a sandboxed HOME →_passive.logexists with thets | rule_id | toolshape and_passive-rules.jsonis still valid JSON. - Trim
_passive.login the dream cycle (e.g. keep the last 5000 lines) — none of our logs rotate, and this one grows with every matching tool use.
Nit (optional): in collect_projects(), capture the last line during the same counting loop instead of re-reading the file when the name isn't in the registry.
With those in, this merges. Thanks — the repro quality made the review fast.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three fixes found while auditing a live Sinapsis install.
1.
collect_decisionscrashes on string-form decisions_operator-state.jsoncan storestrategicDecisionsas a list of plain strings. The current code calls.get('date')on each item, raisingAttributeError: 'str' object has no attribute 'get'and aborting the whole dashboard generation. Now tolerates both shapes (objects{id,date,decision}and plain strings).2.
collect_projectsalways reports 0 active projectsactivewas computed as[p for p in projects if p.get('active')], but the registry never sets anactiveflag, so the dashboard always showed 0 projects even with thousands of observations. Now derives 'active' from observation recency (≤14 days) and resolves friendly project names from the registry / last observation instead of showing raw dir hashes.3. Passive rules fire silently — no telemetry
_passive-activator.shinjected matched rules but never wrote a log, socollect_passive_log()always returned empty and the dashboard reported 0 passive activations. Added a one-line-per-fired-rule append to_passive.log(TIMESTAMP | rule_id | tool), matching the formatcollect_passive_log()already parses. Mirrors how the instinct activator logs to_instinct.log.All three verified against a real install (Windows, py 3.12 / node 24): dashboard went from 'Projects: 0' to the real count, and
_passive.lognow populates on tool use.py_compileand a functional smoke test pass for both files.