Hidden plans #44

Closed
opened 2026-10-06 23:14:28 +02:00 by EduarD3V · 4 comments
Owner

Plans used by agent for machine control have to be hidden from users, just shown the exectuions for example like http://192.168.31.41:5173/plans/machine-control

Plans used by agent for machine control have to be hidden from users, just shown the exectuions for example like http://192.168.31.41:5173/plans/machine-control
gotoi-agent added reference issue/44-hidden-plans 2026-10-07 10:31:43 +02:00
Collaborator

Claimed — branch issue/44-hidden-plans. Doing: hide the shared system plans (machine-control, evidence-gather, agent-test) from the dashboard plans list and rule plan-pickers for non-instance-operators, keep /plans/{id} detail and its executions reachable by not filtering $plans.

Claimed — branch `issue/44-hidden-plans`. Doing: hide the shared system plans (`machine-control`, `evidence-gather`, `agent-test`) from the dashboard plans list and rule plan-pickers for non-instance-operators, keep `/plans/{id}` detail and its executions reachable by not filtering `$plans`.
Collaborator

Issue #44 — Hidden plans

Restated goal

Plans the agent uses for its own machine control — the shared system plans
(machine-control, evidence-gather, agent-test, middleware/src/types.ts
SYSTEM_PLAN_IDS) — must stop appearing to users as plans. The operator still
wants to reach their executions, which is what the example URL
/plans/machine-control shows (Recent executions tab).

"Done" for the operator: a normal org user opening /plans sees only their own
plans and the copy-and-edit templates — no machine-control / evidence-gather /
agent-test rows, and no plan-picker entry that lets a rule be aimed at them —
while /plans/machine-control (and the execution detail pages) still resolve.
An instance operator (user.instanceOperator) still sees everything, because
UC-MW-142 makes the shared plans instance-operator-visible.

Scope

Change (frontend presentation layer only):

  • dashboard/src/routes/plans/+page.svelte — derive the list from $plans
    minus system plans when the viewer is not an instance operator; use the
    filtered list for rows, counts, search, and listSelectionAfterLoad's
    knownIds. Per-row selection and the whole detail pane are unchanged.
  • dashboard/src/lib/types.ts — add the SYSTEM_PLAN_IDS /
    isSystemPlan() mirror of middleware/src/types.ts (constants only; no
    interface change, so check-type-mirror.py is unaffected).
  • dashboard/src/lib/components/RuleFormFields.svelte + its two callers — feed
    the plan picker the same filtered list, so a rule cannot be aimed at
    machine-control (a user has no reason to match an alert to the agent's
    internal control plan). Callers: dashboard/src/routes/plans/rules/+page.svelte,
    dashboard/src/routes/plans/rules/new/+page.svelte.
  • docs/use-cases/frontend/UC-FE-97-hidden-system-plans.md — new UC (highest
    frontend id is 96).
  • dashboard/src/lib/usecases-frontend.test.ts — describe('UC-FE-97 …').

Will not touch:

  • middleware/** — GET /plans keeps returning system plans. UC-MW-142 and
    middleware/src/access.ts canRead() make shared plans readable by everyone
    and are covered by existing tests (uc-mw-142-ownership.test.ts,
    uc-mw-tenancy-isolation.test.ts assert a member can read
    /plans/machine-control and /plans/evidence-gather). A middleware filter
    would break those contracts and hide the plans from the instance operator too.
  • dashboard/src/lib/api-cache.ts — $plans stays complete. The detail route
    /plans/[id] and /plans/executions/[id] look the plan up in $plans; a
    cache-level filter would break exactly the URL in the issue.
  • dashboard/src/routes/plans/[id]/+page.svelte and the executions pages — the
    executions surface the operator asked for already exists (Recent executions
    tab + /plans/executions/{id}) and needs no change.
  • plans/ (product content), any DB schema, any middleware type shape, any
    dependency.

UC decision

New UC: UC-FE-97 — "System plans stay out of the plan list"
(docs/use-cases/frontend/UC-FE-97-hidden-system-plans.md, copied from
_TEMPLATE.md).

  • Implementation: dashboard/src/routes/plans/+page.svelte (real page, not
    middleware/src/app.ts), plus dashboard/src/lib/types.ts isSystemPlan.
  • Tests: dashboard/src/lib/usecases-frontend.test.ts (file text will mention
    UC-FE-97).
  • related: UC-FE-39 (plan row opens detail), UC-MW-142 (shared-plan
    readability) — both get the back-link added, which is required by
    _check.py's bidirectional rule, so those two files are edited too
    (front-matter related: and the Related heading only; UC-FE-39 and
    UC-MW-142 Stories are unaffected by this change).

Existing UCs affected in behaviour, not rewritten: UC-FE-39 (list contents),
UC-FE-41 (detail page — explicitly unchanged), UC-MW-142 (readability stays).
UC-FE-97 will state the list-level rule; UC-FE-39 keeps owning the layout.

Ordered tasks

# Task Verify with
1 Write plan; post Claim + Plan comments on #44. python3 $FJ comment 44 --file …/issue-44.plan.md exits 0
2 Add SYSTEM_PLAN_IDS / isSystemPlan to dashboard/src/lib/types.ts. cd dashboard && bun run check
3 Filter the list in dashboard/src/routes/plans/+page.svelte (rows, counts, knownIds); update the Last header field. cd dashboard && bun run check
4 Filter the rule plan pickers in RuleFormFields.svelte + 2 callers; update Last. cd dashboard && bun run check
5 Add UC-FE-97 UC file; add back-links in UC-FE-39 and UC-MW-142. python3 docs/use-cases/_check.py
6 Add describe('UC-FE-97 …') to dashboard/src/lib/usecases-frontend.test.ts. cd dashboard && bun run test
7 Commit; run the touched gates + the one-shot middleware suite. see Gates

Commit after each of tasks 2–6 (dashboard: …, docs: …, Refs #44).

Open questions (assumption taken)

  1. Where to hide — middleware or dashboard? Assumption: dashboard only.
    Rationale: the issue says "hidden from users", not "removed"; UC-MW-142
    deliberately makes shared plans readable by everyone, and the middleware has
    no concept of "hidden". Rejected alternative: filter in
    middleware/src/routes/plans.ts GET /plans — that contradicts
    uc-mw-142-ownership.test.ts / uc-mw-tenancy-isolation.test.ts and
    uc-mw-165-template-library.test.ts, and would also hide them from the
    instance operator, who is the one who needs them.
  2. Hide from instance operators too? Assumption: no. The operator owns
    the instance and needs machine-control to tune it; UC-MW-142 grants them
    the read. Instance-operator is page.data.user.instanceOperator.
  3. Is the detail URL meant to stay? Assumption: yes, unchanged. The
    issue links it as the place where executions show. Making the dashboard filter
    $plans at the cache layer would break it; that is why the filter lives in
    the page derivation.
  4. Should the templates (disk-cleanup etc.) also be hidden? Assumption:
    no. They are the documented copy-and-edit library (UC-MW-165,
    docs/templates.md) and are meant to be seen.
  5. Rules pickers in or out? Assumption: in (same filter). A user binding
    an alert to agent-test is not a supported workflow; hiding the option is the
    minimal consistent rule. Rejected: validate/refuse server-side — that is a
    middleware behaviour change with its own UC and is not what the issue asks.
  6. Does hiding need middleware enforcement? Assumption: no. Anyone who
    can read a system plan already could before this change
    (UC-MW-142); this is a presentation change, not an access-control change.

Risk

  • bun run check (svelte-check) red if the +page.svelte edit is malformed —
    fallback: revert the page edit, keep the types.ts helper + UC, report
    PARTIAL.
  • usecases-frontend.test.ts UC-FE-39 block asserts the page source contains
    listSelectionAfterLoad, Search plans..., maxChars={28}, Open plan,
    api.plans.health, EMPTY_COPY.plans, Recent executions, Open incidents
    and not DataTable. The edit must keep all of those strings.
  • UC-MW-19 plan survives a second buildApp on the same db is a known
    pre-existing red in the middleware suite; not chased.
  • Adding related: links is the one edit that can trip _check.py (bidirectional
    rule); fix forward, do not weaken the checker.
  • Boring fallback if anything fights for >2 attempts: ship the +page.svelte
    filter alone (tasks 2/3/5/6), drop the picker filter, report it.
# Issue #44 — Hidden plans ## Restated goal Plans the agent uses for its own machine control — the shared **system plans** (`machine-control`, `evidence-gather`, `agent-test`, `middleware/src/types.ts` `SYSTEM_PLAN_IDS`) — must stop appearing to users as plans. The operator still wants to reach their *executions*, which is what the example URL `/plans/machine-control` shows (Recent executions tab). "Done" for the operator: a normal org user opening `/plans` sees only their own plans and the copy-and-edit templates — no `machine-control` / `evidence-gather` / `agent-test` rows, and no plan-picker entry that lets a rule be aimed at them — while `/plans/machine-control` (and the execution detail pages) still resolve. An instance operator (`user.instanceOperator`) still sees everything, because `UC-MW-142` makes the shared plans instance-operator-visible. ## Scope **Change (frontend presentation layer only):** - `dashboard/src/routes/plans/+page.svelte` — derive the list from `$plans` minus system plans when the viewer is not an instance operator; use the filtered list for rows, counts, search, and `listSelectionAfterLoad`'s `knownIds`. Per-row selection and the whole detail pane are unchanged. - `dashboard/src/lib/types.ts` — add the `SYSTEM_PLAN_IDS` / `isSystemPlan()` mirror of `middleware/src/types.ts` (constants only; no interface change, so `check-type-mirror.py` is unaffected). - `dashboard/src/lib/components/RuleFormFields.svelte` + its two callers — feed the plan picker the same filtered list, so a rule cannot be aimed at `machine-control` (a user has no reason to match an alert to the agent's internal control plan). Callers: `dashboard/src/routes/plans/rules/+page.svelte`, `dashboard/src/routes/plans/rules/new/+page.svelte`. - `docs/use-cases/frontend/UC-FE-97-hidden-system-plans.md` — new UC (highest frontend id is 96). - `dashboard/src/lib/usecases-frontend.test.ts` — `describe('UC-FE-97 …')`. **Will not touch:** - `middleware/**` — `GET /plans` keeps returning system plans. `UC-MW-142` and `middleware/src/access.ts` `canRead()` make shared plans readable by everyone and are covered by existing tests (`uc-mw-142-ownership.test.ts`, `uc-mw-tenancy-isolation.test.ts` assert a member can read `/plans/machine-control` and `/plans/evidence-gather`). A middleware filter would break those contracts and hide the plans from the instance operator too. - `dashboard/src/lib/api-cache.ts` — `$plans` stays complete. The detail route `/plans/[id]` and `/plans/executions/[id]` look the plan up in `$plans`; a cache-level filter would break exactly the URL in the issue. - `dashboard/src/routes/plans/[id]/+page.svelte` and the executions pages — the executions surface the operator asked for already exists (Recent executions tab + `/plans/executions/{id}`) and needs no change. - `plans/` (product content), any DB schema, any middleware type shape, any dependency. ## UC decision **New UC: `UC-FE-97` — "System plans stay out of the plan list"** (`docs/use-cases/frontend/UC-FE-97-hidden-system-plans.md`, copied from `_TEMPLATE.md`). - `Implementation:` `dashboard/src/routes/plans/+page.svelte` (real page, not `middleware/src/app.ts`), plus `dashboard/src/lib/types.ts isSystemPlan`. - `Tests:` `dashboard/src/lib/usecases-frontend.test.ts` (file text will mention `UC-FE-97`). - `related:` `UC-FE-39` (plan row opens detail), `UC-MW-142` (shared-plan readability) — both get the back-link added, which is required by `_check.py`'s bidirectional rule, so those two files are edited too (front-matter `related:` and the Related heading only; `UC-FE-39` and `UC-MW-142` Stories are unaffected by this change). Existing UCs affected in behaviour, not rewritten: `UC-FE-39` (list contents), `UC-FE-41` (detail page — explicitly unchanged), `UC-MW-142` (readability stays). `UC-FE-97` will state the list-level rule; `UC-FE-39` keeps owning the layout. ## Ordered tasks | # | Task | Verify with | |---|---|---| | 1 | Write plan; post Claim + Plan comments on #44. | `python3 $FJ comment 44 --file …/issue-44.plan.md` exits 0 | | 2 | Add `SYSTEM_PLAN_IDS` / `isSystemPlan` to `dashboard/src/lib/types.ts`. | `cd dashboard && bun run check` | | 3 | Filter the list in `dashboard/src/routes/plans/+page.svelte` (rows, counts, `knownIds`); update the `Last` header field. | `cd dashboard && bun run check` | | 4 | Filter the rule plan pickers in `RuleFormFields.svelte` + 2 callers; update `Last`. | `cd dashboard && bun run check` | | 5 | Add `UC-FE-97` UC file; add back-links in `UC-FE-39` and `UC-MW-142`. | `python3 docs/use-cases/_check.py` | | 6 | Add `describe('UC-FE-97 …')` to `dashboard/src/lib/usecases-frontend.test.ts`. | `cd dashboard && bun run test` | | 7 | Commit; run the touched gates + the one-shot middleware suite. | see Gates | Commit after each of tasks 2–6 (`dashboard: …`, `docs: …`, `Refs #44`). ## Open questions (assumption taken) 1. **Where to hide — middleware or dashboard?** Assumption: **dashboard only.** Rationale: the issue says "hidden from users", not "removed"; `UC-MW-142` deliberately makes shared plans readable by everyone, and the middleware has no concept of "hidden". Rejected alternative: filter in `middleware/src/routes/plans.ts` `GET /plans` — that contradicts `uc-mw-142-ownership.test.ts` / `uc-mw-tenancy-isolation.test.ts` and `uc-mw-165-template-library.test.ts`, and would also hide them from the instance operator, who is the one who needs them. 2. **Hide from instance operators too?** Assumption: **no.** The operator owns the instance and needs `machine-control` to tune it; `UC-MW-142` grants them the read. Instance-operator is `page.data.user.instanceOperator`. 3. **Is the detail URL meant to stay?** Assumption: **yes, unchanged.** The issue links it as the place where executions show. Making the dashboard filter `$plans` at the cache layer would break it; that is why the filter lives in the page derivation. 4. **Should the templates (`disk-cleanup` etc.) also be hidden?** Assumption: **no.** They are the documented copy-and-edit library (`UC-MW-165`, `docs/templates.md`) and are meant to be seen. 5. **Rules pickers in or out?** Assumption: **in** (same filter). A user binding an alert to `agent-test` is not a supported workflow; hiding the option is the minimal consistent rule. Rejected: validate/refuse server-side — that is a middleware behaviour change with its own UC and is not what the issue asks. 6. **Does hiding need middleware enforcement?** Assumption: **no.** Anyone who can read a system plan already could before this change (`UC-MW-142`); this is a presentation change, not an access-control change. ## Risk - `bun run check` (svelte-check) red if the `+page.svelte` edit is malformed — fallback: revert the page edit, keep the `types.ts` helper + UC, report `PARTIAL`. - `usecases-frontend.test.ts` `UC-FE-39` block asserts the page source contains `listSelectionAfterLoad`, `Search plans...`, `maxChars={28}`, `Open plan`, `api.plans.health`, `EMPTY_COPY.plans`, `Recent executions`, `Open incidents` and not `DataTable`. The edit must keep all of those strings. - `UC-MW-19 plan survives a second buildApp on the same db` is a known pre-existing red in the middleware suite; not chased. - Adding `related:` links is the one edit that can trip `_check.py` (bidirectional rule); fix forward, do not weaken the checker. - Boring fallback if anything fights for >2 attempts: ship the `+page.svelte` filter alone (tasks 2/3/5/6), drop the picker filter, report it.
Collaborator

REVIEW: FIXED 2 — findings: stray <<<<<<< HEAD conflict marker committed in dashboard/src/lib/usecases-frontend.test.ts:1487 broke the suite parse (fixed 5442e17); hidden-plans code comments still cited UC-FE-97 after the renumber to UC-FE-98 (fixed 865a38b); RuleFormFields.svelte listed in plan Scope but filter applied at both callers instead — equivalent, only two render sites (accepted); dashboard/src/lib/plans.ts touched though not in plan Scope — browsablePlans helper (accepted); UNFIXED: issue-44.report.md never written by implementer (session ended early, no claims to verify)

REVIEW: FIXED 2 — findings: stray `<<<<<<< HEAD` conflict marker committed in dashboard/src/lib/usecases-frontend.test.ts:1487 broke the suite parse (fixed 5442e17); hidden-plans code comments still cited UC-FE-97 after the renumber to UC-FE-98 (fixed 865a38b); RuleFormFields.svelte listed in plan Scope but filter applied at both callers instead — equivalent, only two render sites (accepted); dashboard/src/lib/plans.ts touched though not in plan Scope — browsablePlans helper (accepted); UNFIXED: issue-44.report.md never written by implementer (session ended early, no claims to verify)
Collaborator

DONE — branch issue/44-hidden-plans, 7 commits, PR #56 opened against agent-develop (the run never merges): #56

System plans (machine-control, evidence-gather, agent-test) are hidden from the /plans list and rule plan-pickers for non-instance-operators via a browsablePlans() helper; /plans/machine-control detail and its executions stay reachable (plan list filter only, $plans cache untouched). Instance operators still see everything (UC-MW-142).

Recovery note: the prior run died after pushing but before opening the PR; this run finished the step. PR #55 (plan download) merged into agent-develop in between and took UC-FE-97, so the branch was rebased (force-with-lease) and the UC renumbered to UC-FE-98; the renumber had clobbered UC-FE-97 plan-download links in UC-FE-41, restored in 09719d3.

Independent review (9router/reviewer, fresh session): REVIEW: FIXED 2 — stray conflict marker in usecases-frontend.test.ts (5442e17), stale UC-FE-97 citations retitled to UC-FE-98 (865a38b); report file absence noted (implementer session ended early).

Gates on final head: UC catalog 0 (frontend 95), ai-headers 0 (571), type-mirror 0, dashboard bun run test 246 pass / 16 files, bun run check 0 errors (7 pre-existing warnings), hidden test UC-OP-02 pass, rg 'Showing lines' clean outside rule text. Middleware and agent untouched.

Refs #44

DONE — branch issue/44-hidden-plans, 7 commits, PR #56 opened against agent-develop (the run never merges): https://git.eduard3v.com/EduarD3V/gotoi/pulls/56 System plans (machine-control, evidence-gather, agent-test) are hidden from the /plans list and rule plan-pickers for non-instance-operators via a browsablePlans() helper; /plans/machine-control detail and its executions stay reachable (plan list filter only, $plans cache untouched). Instance operators still see everything (UC-MW-142). Recovery note: the prior run died after pushing but before opening the PR; this run finished the step. PR #55 (plan download) merged into agent-develop in between and took UC-FE-97, so the branch was rebased (force-with-lease) and the UC renumbered to UC-FE-98; the renumber had clobbered UC-FE-97 plan-download links in UC-FE-41, restored in 09719d3. Independent review (9router/reviewer, fresh session): REVIEW: FIXED 2 — stray conflict marker in usecases-frontend.test.ts (5442e17), stale UC-FE-97 citations retitled to UC-FE-98 (865a38b); report file absence noted (implementer session ended early). Gates on final head: UC catalog 0 (frontend 95), ai-headers 0 (571), type-mirror 0, dashboard bun run test 246 pass / 16 files, bun run check 0 errors (7 pre-existing warnings), hidden test UC-OP-02 pass, rg 'Showing lines' clean outside rule text. Middleware and agent untouched. Refs #44
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
EduarD3V/gotoi#44
No description provided.