mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-05 19:47:03 +09:00
Plan 55 task 7, backend half. A manifest's `permissions` array was declaration-only: the install dialog showed it and nothing ever compared it against what the extension went on to do. The capability gate now records every call through it -- including the refusals, which are the interesting ones -- so `usage_report(slug)` can answer declared-versus-observed per extension. Observations are in-memory and per-process by design: the question is "what has this extension done since the panel started", and persisting it would outlive the evidence and start reading like an audit trail, which this is not. `has()` deliberately does not record; it is a question, not a use, and counting it would fabricate activity for callers that only checked. The larger half of this change is admitting what the panel cannot see. Task 7 was specified as hooks at "the shell/docker/db helper entry points", and those do not exist: the SDK exposes no shell, docker, filesystem or network helper at all, and hands out `db` as raw SQLAlchemy. An extension wanting any of them imports the host module directly, where no in-process gate is involved. The one genuinely gated capability is `agent.command:<action>`, because the SDK is the only way to reach an agent. So observability is data, not prose: OBSERVABLE_PREFIXES marks what the gate truly mediates, and the report marks every other declared permission `observable: false` rather than showing it as "never used". Absence of evidence is not evidence of absence here, and a UI claiming otherwise would be inventing enforcement the panel does not have -- exactly the honesty the plan's D2 decision asks for. GET /plugins/<id>/permissions returns the report, admin-only: it describes what third-party code has been reaching for. The UI surface and the docs follow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>