No update or delete for plans and rules; every fix orphans an object #87
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Labels: api, tools, priority/high
"Fix the plan" is impossible with the current toolset. create_plan exists; nothing else does. The only fix path is create-a-new-id and abandon the old one.
In this session the operator had to delete plan 0c52ac87-8ab6-42cb-a072-b02bc116e6f0 and rule 3749b312 by hand, outside the agent. I have no tool for either.
Consequences:
Acceptance criteria
issue/87-plan-rule-update-deleteto issue/87-plan-rule-updateIssue #87 — Plan/rule update+delete; PATCH semantics; orphan prevention
Branch:
issue/87-plan-rule-update(fromorigin/agent-develop@d6bb5c3).Worktree:
/home/eduardez/workspace/gotoi-wt/issue-87.Scope
Already met on the base (
d6bb5c3) — no work redoneThe issue was written against an older base. On
d6bb5c3the tools and routesalready exist. Verified by reading the code:
plan_updatePATCH semanticsplan_updatetool sends subset;applyPlanPatchmerges only present keysmiddleware/src/control-agent.ts:990-1039,middleware/src/plans.ts:161-217plan_deleteplan_deletetool +DELETE /plans/:idmiddleware/src/control-agent.ts:1042-1063,middleware/src/routes/plans.ts:627-636plan_archivePATCH {status:'deprecated', replacementId}→deprecatePlanmiddleware/src/routes/plans.ts:549-556,middleware/src/plans.ts:219-228rule_update(planId/enabled/conditions/hostnames/groupIds)PATCH /rules/:id;rulePatchSchemacoversplanId,enabled,conditions,hostnames,groupIdsmiddleware/src/control-agent.ts:1098-1161,middleware/src/routes/rules.ts:59-91,middleware/src/rules.ts:41-52rule_deleteDELETE /rules/:idmiddleware/src/control-agent.ts:1163-1182,middleware/src/routes/rules.ts:93-101DELETE /plans/:idnor theplan_deletetool consultsstores.rules; no409, no reference checkstores\.rulesinplans.ts/routes/plans.tsreturns nothingThe only gap is criterion 5. A plan delete proceeds even while a match rule
(or a rule
chainstep) still points at it, orphaning the binding exactly asthe issue's consequences describe.
Files to CHANGE
middleware/src/plans.ts— addreferencingRules(planId, rules)helper (pure, returns rule ids whoseplanIdor anychain[].planIdequalsplanId).middleware/src/routes/plans.ts—DELETE /plans/:id: consultreferencingRules; on a hit return 409 Conflict with{ error, code: 'plan_referenced', ruleIds }; do not auto-disable. Update headerLast:.middleware/src/control-agent.ts—plan_deletetool: same refusal beforestores.plans.delete; throw an explicit message naming the rule ids. Update headerLast:.middleware/tests/uc-mw-171-plan-delete-rule-refusal.test.ts— new red-first test file.docs/use-cases/middleware/UC-MW-171-plan-delete-rule-refusal.md— new UC.docs/use-cases/README.md— bumpversion:; add UC-MW-171 to the index.docs/use-cases/middleware/UC-MW-35-delete.md— add the 409 extension + version bump (this is where plan-delete behaviour lives).Files NOT to touch
middleware/src/rules.ts(schemas already cover AC3) — only read.middleware/src/routes/rules.ts(rule patch/delete already correct) — only read.middleware/src/types.tsanddashboard/src/lib/types.ts— no wire-type change: the refusal adds no field toPlan/Rule(the 409 body is a response shape, not a stored type). Mirror stays byte-identical →check-type-mirror.pyunaffected.plans/(product content) — forbidden.dashboard/**beyond the mirror check (no UI asked for).UC-OP-02,UC-MW-19— left red.New UC ids to create
UC-MW-171— "Deleting a referenced plan is refused" (next free afterUC-MW-170;UC-MW-168absent,UC-MW-169/UC-MW-170taken; grep confirmsUC-MW-171unused).Tasks
middleware/tests/uc-mw-171-plan-delete-rule-refusal.test.ts:ref-plan+ rule bound to it →DELETE /plans/ref-planmust be 409(currently 204 → RED).
chainstep also blocks.Verify RED in isolation, then commit
test: repro plan/rule update+delete gaps (red) Refs #87.referencingRuleshelper + refusal in route and tool (see above).uc-mw-cluster2-plans.test.ts+uc-mw-100-rules.test.ts;commit
feat(plans/rules): plan_update + plan_delete + rule_update + rule_delete, refuse plan delete with rule Refs #87.docs:commit allowed).meta/issue-87.report.md.Refusal contract (the one new behaviour)
DELETE /plans/:idand theplan_deletetool both callreferencingRules.{ error: 'plan is referenced by N rule(s)', code: 'plan_referenced', ruleIds: [...] }.deleted <id>).Gates
Pre-existing reds
UC-OP-02,UC-MW-19stay red — expected.DONE — branch
issue/87-plan-rule-update(worktree branch; task text said…-update-delete, which does not exist as a ref).AC audit: AC1–AC4 already satisfied by the PR #94 / #85 merge (plan_update/plan_delete/rule_update/rule_delete tools + PATCH/DELETE routes) — cited file:line in the plan comment. AC5 (referential guard) was the only gap and is implemented:
middleware/src/plans.tsreferencingRules(planId, rules)— planId or any chain[].planId.DELETE /plans/:id→ 409 {code:'plan_referenced', ruleIds} before any store mutation.plan_deletetool → same message naming the rule ids, before stores.plans.delete.No auto-disable (avoids silent data loss). New UC-MW-171; UC-MW-35 gains the 409 extension.
Commits (local, not pushed):
bf62634test: repro plan/rule update+delete gaps (red) Refs #87bde005efeat(plans/rules): refuse plan delete while a match rule references it Refs #879c0519edocs(uc): UC-MW-171 refuses plan delete while a rule references it Refs #87c3b1fb8test(uc-mw-171): plan_delete control tool refuses a referenced plan Refs #87Gates:
docs/use-cases/_check.py → exit 0
scripts/check-ai-headers.py → exit 0 (577 ok)
scripts/check-type-mirror.py → exit 0
cd middleware && bun test → exit 0 (610 pass, 0 fail)
cd agent && go test ./... → exit 1, PRE-EXISTING env failure (/etc/gotoi/agent.json permission denied; identical set in meta/issue-86.gate-agent2.log; my diff touches zero agent/ files)
rg 'Showing lines' → only .md docs that quote the rule; zero source hits.
NOTE: earlier plan comment posted from the worktree copy of forgejo.py; this done comment from the skill copy.
KILLED-LIVE-AUTHORITY on 2026-10-08 20:40 CEST by operator override (operator wants to drain the queue end-to-end; paused gotoi-issue-runner / gotoi-guard / gotoi-integrator / gotoi-run-capture crons for the duration).
Snapshot at kill time:
c3b1fb8(4 commits ahead of agent-develop, 0 behind):c3b1fb8test(uc-mw-171): plan_delete control tool refuses a referenced plan Refs #879c0519edocs(uc): UC-MW-171 refuses plan delete while a rule references it Refs #87bde005efeat(plans/rules): refuse plan delete while a match rule references it Refs #87bf62634test: repro plan/rule update+delete gaps (red) Refs #87c3b1fb8.The orchestrator is now going to verify gates on the head, open the PR to agent-develop, and post the DONE comment — same path as the stranded-branch recovery from earlier today. Refs #87
DONE — PR #96 opened: #96
Branch issue/87-plan-rule-update @
c3b1fb8(4 commits ahead of agent-develop, 0 behind):bf62634test: repro plan/rule update+delete gaps (red) Refs #87bde005efeat(plans/rules): refuse plan delete while a match rule references it Refs #879c0519edocs(uc): UC-MW-171 refuses plan delete while a rule references it Refs #87c3b1fb8test(uc-mw-171): plan_delete control tool refuses a referenced plan Refs #87Note on the issue's 5 acceptance criteria:
Gates re-verified on head:
This was an operator-kicked queue-drain (operator paused gotoi-issue-runner/guard/integrator/run-capture for the duration). Refs #87
issue/87-plan-rule-updateto issue/87-plan-rule-updateREVIEW: CLEAN — findings: AC1-4 cites verified live (plan_update patchFrom/applyPlanPatch partial merge; rule_update/rule_delete tool+route; deprecate covers archive) exercised green via uc-mw-cluster2-plans + uc-mw-100-rules (25 pass); AC5 verified both halves — referencingRules covers planId AND chain[].planId, DELETE /plans/:id returns 409 {code:'plan_referenced',ruleIds} before stores.plans.delete, plan_delete tool throws naming rule ids before delete (only two plans.delete call sites in src, both guarded); plan fidelity — all 7 in-scope files touched, UC-MW-100/123 touched only for bidirectional related (checker-required); repo law — _check.py / check-ai-headers.py / check-type-mirror.py all exit 0, 'Showing lines' hits only in docs quoting the rule; test integrity — nothing deleted/skipped/weakened, new tests assert ruleIds named and plan survives (4 pass); report honesty — checker claims re-run true, diff touches zero agent/ files consistent with env go-test claim, 9 files +244/-16 matches, README has no version line as claimed (full-suite 610-pass NOT re-run per instructions); UNFIXED: none