Repository navigation
P1b — SLM: memory-lifecycle aggregator + MemoryLifecycleTab monitoring tab #12632
Description
Activity
- added 5 commits that reference this issue
on Aug 19, 2026 Part 1 of 2 landed — #14653 merged as
1aa44f734. This issue stays open; the frontend half is not built.Done
The SLM aggregator:
GET /api/memory/lifecycle, admin-gated, calling the node endpoint from #12631 (merged as00720b5d1).Verified in base: the aggregator module, the verify-on TLS default, the SSOT-derived limit ceiling, the gated mount, and 8 aggregator tests.
The property that carried the design is that
degradedcomposes — the node reports its own partial reads, so a proxy surfacing only transport failures would show a node whose decay section is broken as perfectly healthy. Each failure cause stays distinct rather than collapsing into "unreachable": 403 means the key is wrong, 404 means the node predates #12631, a timeout means alive but slow, and an operator acts differently on each.Still open — the frontend half
autobot-slm-frontend/src/composables/useMemoryLifecycleApi.tsautobot-slm-frontend/src/views/monitoring/MemoryLifecycle.vue— reinforcement leaderboard, cold-facts table, and the "what decay would prune" table with a clear dry-run affordance- Router child under
/monitoringand the nav entry - The
monitoring.memory.*key block across every SLM locale
Two corrections from review worth carrying forward
TLS verification defaulted OFF. The module cited
api/voice_proxy.pyas its pattern and inverted it —voice_proxyreadsAUTOBOT_SKIP_TLS_VERIFYand verifies unless told not to; this required opting in, on the channel carrying the internal API key. Now the same variable and polarity, so one switch covers every node proxy.The limit ceiling was a magic number.
le=100inlined in theQuerytripped the #694 hardcoded-value check. Fixed withQueryDefaults.MAX_SEARCH_LIMITrather than theKNOWLEDGE_DEFAULT_LIMITthe linter suggested — both are 100 today, but one is a maximum and the other a default, and a ceiling that tracks a default drifts the moment the default moves.Note on the stack
This was built as a stacked PR on
issue-12631. Worth recording for anyone doing the same here: while stacked it ran 1 CI check, because the workflows filter on base branch. It only got the full suite after #14651 merged and GitHub retargeted it. A stacked PR must never be merged while stacked — its green means nothing.github-actions commented
on Aug 22, 2026 on Aug 22, 2026 – with GitHub ActionsContributorMore actionsHandoff — everything needed to finish this from the issue alone
The backend half is merged and live. What follows is the frontend half, with the details verified against the tree rather than copied from the plan.
Already done (merged, no action)
- Node endpoint
GET /api/memory/lifecycle— P1a — Node: GET /api/memory/lifecycle (reinforcement + dry-run prune preview) #12631 /00720b5d1 - SLM aggregator
GET /api/memory/lifecycle— feat(memory): SLM aggregator for the node lifecycle view (#12632, part 1 of 2) #14653 /1aa44f734, mounted inmain.pywithdependencies=_SM(admin/operator only)
The payload the tab renders
{ "nodes": [ { "node": "<node base url>", "degraded": false, "reinforcement": { "hot": [ ... ], "cold": [ ... ] }, "decay": { "last_run": "...", "config": { ... }, "prune_preview": [ ... ] } } ], "degraded": false }- Each
hot/coldentry:fact_id,quality_score,access_count,last_accessed,effective_score - Each
prune_previewentry:fact_id,reasons: [str]— the reasons carry values, e.g."quality 0.01 below floor 0.10" decay.config:epoch_set,quality_floor,max_age_days,max_per_run,scan_limit- An unreachable node still carries every section key, plus
error— one ofnode_unreachable,node_timeout,node_status_<code>,node_bad_payload,internal_api_key_not_configured. Render the cause; they are distinct on purpose (403 = wrong key, 404 = node predates P1a — Node: GET /api/memory/lifecycle (reinforcement + dry-run prune preview) #12631, timeout = alive but slow). degradedcomposes: it is true if the node reports its own partial read, not only on transport failure.
Query param:
limit, default 20, maxQueryDefaults.MAX_SEARCH_LIMIT(100).To build
autobot-slm-frontend/src/composables/useMemoryLifecycleApi.ts—fetchLifecycle(limit?)autobot-slm-frontend/src/views/monitoring/MemoryLifecycle.vue— reinforcement leaderboard, cold-facts table, and a "what decay would prune" tableautobot-slm-frontend/src/router/index.ts— a/monitoring/memorychild- Nav entry alongside the other monitoring tabs
autobot-slm-frontend/src/locales/en.json— amonitoring.memory.*key block
Correction to the plan on locales. The plan says "SLM locale files (all locales)". Verified: this frontend registers only
en—src/i18n/index.tsimports@/locales/en.jsonand nothing else, andsrc/locales/contains that one file. The 11-locale rule applies toautobot-frontend, not here. One file to touch, not eleven.Mirror an existing tab in
src/views/monitoring/—AlertsMonitor.vuehas a test alongside it (AlertsMonitor.test.ts) worth copying the shape of.The one thing the UI must not get wrong
The prune table is a dry-run preview — nothing is deleted, and that has to be unmistakable in the UI. It is the list an operator reviews before enabling enforcement. A table of facts headed for deletion, without a clear affordance saying nothing has happened yet, invites exactly the misreading this feature exists to prevent.
Also worth surfacing:
decay.config.epoch_set: falsemeans pruning is disabled entirely — the single most consequential thing an operator can be wrong about here, and invisible unless the tab says so.Acceptance
- The tab renders all three sections from one aggregator call
- A degraded node shows which cause, not a generic error
- The prune table states plainly that it deletes nothing
epoch_set: falseis visible as "pruning disabled"
Related
Umbrella #12630. Phase 2 (#12633 node breaker states, #12634 SLM lifecycle aggregate) is unstarted and independent of this. #14655 is a prune-predicate bug found while building P1a, deliberately unfixed — this umbrella's non-goals forbid changing prune behaviour in P1/P2.
- Node endpoint
- addedarea: observabilityWave 1 · cluster S — Observability & silent failuresWave 1 · cluster S — Observability & silent failures
on Sep 1, 2026 Stale-issue sweep (never auto-closed — Dev_new_gui wasn't GitHub's default branch at merge time). Verified against current
origin/main; leaving open.- Aggregator: MET —
autobot-slm-backend/api/memory_lifecycle_proxy.py:69-70GET /lifecycle, registeredmain.py:713. - Frontend
MemoryLifecycleTab: NOT MET — no*MemoryLifecycle*file exists underautobot-slm-frontend/src, no router/nav entry.
The delivering PR (#14653) says so itself: "Does not close #12632... frontend tab, composable, router child, nav entry, locale blocks are not in it." Backend-only so far; the frontend half is undelivered.
- Aggregator: MET —
Plan (execute from here):
docs/superpowers/plans/2026-07-26-system-lifecycle-observability.md— find this task's section.Part of umbrella #12630. Depends on #12631. Design:
docs/superpowers/specs/2026-07-26-system-lifecycle-observability-design.md.Phase 1b — SLM aggregator + monitoring tab.
autobot-slm-backend: thin endpoint calling the nodeGET /api/memory/lifecyclevia the SLM→node client; fleet-aware (single node now, structured to fan out); degrades todegraded: true+ empty sections when node down.autobot-slm-frontend/src/views/monitoring/MemoryLifecycleTab.vueunder/monitoring(router child + nav entry). Reinforcement leaderboard + cold-facts table + "what decay would prune" table with a clear "dry-run — nothing is deleted" affordance. i18n across all SLM locales.Tests: aggregator returns node payload; degraded path when node absent; tab renders sections.