mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-12 16:23:18 -10:00
A plan's task count was bounded by ONE hard-coded number with no way to move it. Twenty was too many for someone on a metered provider and too few for a real sweep, and the only way to discover it was to read plan_tool.go. profiles.planSize now names the ceiling: small 5, medium 20, large 50, unrestricted. NAMED rather than numeric so the config file says what it means and so "no ceiling at all" is expressible without a sentinel integer. TWO DELIBERATE DIVERGENCES FROM THE REPORT, both worth stating. It stays a HARD CAP, not the advisory warning the reference implementation has. Under this posture every plan task is a child inheriting a 320-turn ceiling, so fifty tasks authorise 16,000 child turns from a single tool call. A warning the model emits to itself is not a bound on that. What the report actually wanted — that the number be discoverable and movable — is delivered by the rejection naming the tier and the setting instead of printing a bare integer. And medium is 20, not the reference's 15, because 20 is the number defaultPlanMaxTasks already held. Making a bound configurable and moving it in the same change hides a behaviour change inside a mechanism change; the tier mechanism is the deliverable and the number stays where it was. PROJECT CONFIG MAY ONLY TIGHTEN IT. A cloned repo can ask for a smaller ceiling and can never raise one, because raising it raises a spend ceiling for whoever opens the repo. Same privilege boundary as Sandbox.Network's allow/deny rule and DisableZeromaxing's disable-only rule, and a looser tier is dropped silently the way an ignored network "allow" is: the project scope simply does not hold that privilege, which is not a malformed config. Fail closed throughout. An unrecognised tier resolves to the default and never to "no ceiling" — a typo must not be the thing that removes a bound — and the same is true when the early config resolve in exec fails. The mutation sweep found that rank() returned -1 for an unknown tier with a comment claiming that made it safe. It does the opposite: the tighten-only comparison adopts the SMALLER rank, so -1 would have beaten every real tier. Nothing was reachable through it, because ParsePlanSize rejects the name first — but a defence-in-depth value that only holds because of the guard in front of it is not defence in depth. Verified against the real binary, not just the tests: the same six-task plan is admitted with no setting and refused at 5 with planSize small, and a project config asking for unrestricted against a user config of small stays refused.