Skip to content

feat(slm): Data hygiene page — list, preview and confirm cleanup of orphaned data; host #16927's unreachable-resource repair (#17038) #17040

Description

@mrveiss

Owner rules (2026-09-18), binding on this feature and on any data or credential cleanup

  1. Human-supervised: "any data or credential cleanup should be handled the same way — no agent can do that on its own without supervision." Every deletion, rewrite or rotation of stored data or credentials is previewed to and approved by an interactive human session. Agents, services and API keys may propose a cleanup, never approve or execute one unattended.
  2. An always-available review process: "there needs to be always available review process." A proposed cleanup lands in a durable review queue that a human can always reach, and approve or reject from. It is never approved automatically: no timeout, no default-yes, no expiry into approval. A proposal that nobody reviews stays pending, and stays visible.
  3. A paper trail: "removal process always leaves papertrail." Every proposal, approval, rejection and execution is recorded durably, with who proposed it, who approved or rejected it, when, what exactly was affected (identity, logical location, size and a before-state summary, never secret values), and the execution result. The removal process can never delete or alter its own trail, and the trail outlives the removed data.

Mechanism: consolidate, don't fork. AutoBot already has approval gates: services/approval_gate_service.py, api/approval_gates.py, and the frontend llc/ApprovalsInbox.vue. A cleanup proposal becomes an approval-gate request, and approving it triggers the owning service's removal. The Approvals inbox and the SLM Data hygiene page both show pending cleanup requests. The approval record plus an audit entry are the paper trail. No second approval system.

What

An SLM Data hygiene page, in the admin or maintenance area:

Acceptance criteria

  • The page lists both sections from the real APIs. A frontend test with mocked APIs covers the table and totals.
  • Preview then confirm; nothing deletes without confirmation. A test covers cancelling at preview.
  • A failure reported by the backend is shown per row, not hidden.
  • All strings are i18n'd in 11 locales, and the page is in the admin navigation.
  • Admin only, both in the route guard and on the backend.

Activity

  1. added this to the v0.9.0 milestone on Sep 18, 2026
  2. mrveiss commented on Sep 28, 2026

    @mrveiss
    OwnerAuthor

    Chunking triage — a proposal, not an assignment

    Nothing was relabelled, moved or closed by this pass.

  3. mrveiss commented on Sep 28, 2026

    @mrveiss
    OwnerAuthor

    Closure pass — 4 of 5 criteria met from merged code. Not closed, on one wording. Evidence at origin/main 7adaca8c29; landed via a248a04900.

    AC1 — both sections listed from the real APIs, with a frontend test over the table and totals — MET. autobot-slm-frontend/src/views/settings/admin/DataHygieneView.vue, tested at DataHygieneView.test.ts:138 — "renders the storage and resources tables with their totals from the mocked APIs".

    AC2 — preview then confirm, nothing deletes without confirmation, with a cancel test — MET. :154 "cancelling the preview issues no POST /approval-gates request" — an assertion about the request never being made, which is the right shape: it fails if the component deletes eagerly, and it cannot pass by mocking the outcome.

    AC3 — a backend failure is shown per row, not hidden — MET, on both sections. :171 (a proposed candidate) and :202 (a repaired resource), each asserting the failure lands "against that row only, not swallowed". :225 additionally covers the success confirmation surviving the auto-refresh, which is the regression the obvious implementation of AC3 would introduce.

    AC5 — admin only in the route guard and on the backend — MET. Route: autobot-slm-frontend/src/router/index.ts:305 meta: { title: 'Data Hygiene', parent: 'settings', admin: true }. Backend: the endpoints it calls are require_role admin/superadmin (autobot-backend/api/admin_orphan_storage.py:11), and deletion is not exposed as a bare admin route at all — it goes through the approval chain, which the router's own comment at :300 records: "cleanup via POST /approval-gates, never deletes directly".

    AC4 — half verified, and I am not ticking the other half

    "All strings are i18n'd in 11 locales, and the page is in the admin navigation."

    • Locale coverage: 11 of 11. Every locale file under autobot-slm-frontend/src/locales/ — ar, de, en, es, fa, fr, he, lv, pl, pt, ur — carries the page's keys. No locale is missing.
    • Admin navigation: present, via the route's admin: true meta under the settings parent.
    • "All strings", though, is a claim about absence — that no literal remains in the component — and the only thing that settles it is the repository's own hardcoded-UI-string guard, which I cannot run here (running repo code is reserved to hooks and CI under the current ruling). A green run of that guard over DataHygieneView.vue closes this criterion; my grep over locale files cannot, because a component can be fully keyed in 11 locales and still hold one literal.

    Not closed on that single unverified half. Four criteria verified with tests that assert the right things.

  4. mrveiss commented on Sep 29, 2026

    @mrveiss
    OwnerAuthor

    v0.9-host review — this issue is not waiting on a host. Its remaining criterion is a CI run.

    Part of a review of all ten v0.9-host issues: for each, is host evidence genuinely the only thing missing, or is something else hiding behind "waiting for a deployment"?

    This one is in the wrong place. Its open criterion needs a run, not a deployed host — the distinction matters because the deployment call is an event nobody controls, while a CI run is available today. Parked here, it waits for the wrong thing.

    Detail is in my earlier per-AC audit on this issue. The short form:

    Recommendation: move these three out of v0.9-host. They belong wherever a "needs a run" bucket lives, or back in their topic chunk with the criterion marked needs a CI run. Leaving them here means the deployment call arrives, nobody looks at them because they are not host work, and they stay parked for the next reason.

  5. mrveiss commented on Sep 29, 2026

    @mrveiss
    OwnerAuthor

    Verdict: the last AC is already satisfied by merged code — this was never host-blocked

    The unticked AC is "All strings are i18n'd in 11 locales, and the page is in the admin navigation." Both halves are delivered on main.

    In the admin navigation — autobot-slm-frontend/src/views/SettingsView.vue:62:

    { id: 'data-hygiene', name: t('dataHygiene.tabName'), path: '/settings/admin/data-hygiene', icon: ... }
    

    The comment at :59-61 records why that placement is load-bearing: it is "reachable through this same tab bar so the router's existing admin-route guard covers it automatically" — which is also what backs the already-ticked admin-only AC. Route: autobot-slm-frontend/src/router/index.ts:302-304 (admin/data-hygiene → DataHygieneView.vue). :22-24 notes this tab is the only entry in that array added through i18n; the siblings hardcode their names, a pre-existing gap explicitly scoped out.

    i18n in 11 locales — dataHygiene keys are present and uniform across every shipped locale:

    ar=3 de=3 en=3 es=3 fa=3 fr=3 he=3 lv=3 pl=3 pt=3 ur=3
    

    The guards that hold this, and they do cover the SLM-frontend paths (checked by what each receives, not by its filename):

    Guard Root it receives What it settles
    repo_tests/slm_frontend_i18n_parity_test.py :41 _APP = Path("autobot-slm-frontend"), :42 _LOCALES = _APP/src/locales :49 _EXPECTED_LOCALES is exactly the 11; :129-130 asserts each {locale}.json exists, failing with "the SLM console is back to fewer than 11 locales". Declares REACH at :77.
    repo_tests/slm_frontend_bare_ui_literals_test.py :83 _SRC = Path("autobot-slm-frontend")/"src", :190/:203 rglob("*.vue") Any bare visible string in any .vue under that tree fails, across _VISIBLE_ATTRS (:86). Declares REACH at :215.

    Together they are a real enforcement pair for this page: a string left hardcoded in DataHygieneView.vue trips the literals guard, and a key added to en.json alone trips parity. Both are Python guards under repo_tests/, so the pre-push hook runs them.

    With this, all five ACs are met. I am not ticking or closing — this issue hosts #17038/#16927's repair flow, so whether it closes now is the owner's call, not a measurement. Flagging it as closable on the evidence above.

  6. mrveiss commented on Sep 29, 2026

    @mrveiss
    OwnerAuthor

    All five criteria met — flagged closable, not closed, because the closure is an owner call. This issue hosts #17038/#16927's repair flow, so whether it closes is a scope decision rather than a measurement. Evidence for the last one (AC4, all strings are i18n'd): nav entry autobot-slm-frontend/src/views/SettingsView.vue:62 { id: 'data-hygiene', name: t('dataHygiene.tabName'), … }, route at src/router/index.ts:302-304, and dataHygiene keys uniform across all 11 locales (3 each: ar de en es fa fr he lv pl pt ur).

    The absence claim is settled by two guards, both genuinely rooted in the SLM frontend — checked by what each receives, not by its filename: repo_tests/slm_frontend_i18n_parity_test.py (:41 _APP = Path("autobot-slm-frontend"), :49 the 11 locales, :129-130 asserts each {locale}.json exists, REACH at :77) and repo_tests/slm_frontend_bare_ui_literals_test.py (:83 _SRC = autobot-slm-frontend/src, :190/:203 rglob("*.vue"), REACH at :215). They are a real pair for this page: a hardcoded string trips the literals guard, a key added to en.json alone trips parity. Both under repo_tests/, so the pre-push hook runs them.

    This issue was never host-blocked — moved out of v0.9-host today.

  7. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Closed — the last unticked criterion is delivered, verified at 2a6c281760

    Four of five were already ticked. The fifth — "All strings are i18n'd in 11 locales, and
    the page is in the admin navigation"
    — has both halves:

    i18n: 11 of 11. Every autobot-slm-frontend/src/locales/*.json carries dataHygiene
    keys; counted across the whole locale set, not sampled.

    Navigation: a real entry, not merely a route. I checked these separately because a
    registered route is not a navigation item, and the criterion asks for the second:

    • src/router/index.ts:302-304 — the route admin/data-hygiene →
      settings-admin-data-hygiene → DataHygieneView.vue.
    • src/views/SettingsView.vue:62 — the nav entry itself:
      { id: 'data-hygiene', name: t('dataHygiene.tabName'), path: '/settings/admin/data-hygiene', icon: … }.

    Had only the route existed, the page would be reachable by URL and invisible in the UI —
    which is the half the criterion is actually about, and the half a route grep would have
    scored as satisfied.

    No remainder. The other four cover the page listing both sections from the real APIs
    with a mocked-API frontend test, preview-then-confirm with a cancel test, and per-row
    backend failures shown rather than hidden.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions