Repository navigation
Description
Summary
settings.Set.Clamp validates a requested dial value against the ceiling's enum, not the dial's own enum. For the one dial whose enum is a strict subset of its ceiling — prompt.autonomy ({propose, run}, clamped by autonomy.max's full ladder {off, advise, ask, propose, apply, run}) — a request for a value the dial can never hold passes through untouched, unlowered and unerrored, as long as it is anywhere on the ceiling's ladder and at or below the ceiling. The error for a truly unknown value also lists the ceiling's values, telling the caller that apply/off/ask are acceptable for prompt.autonomy.
Evidence (verified on main ed8e5910)
pkgs/mcpx/internal/settings/clamp.go:36-48 (Set.Clamp): the only rank check is
want, ok := cdecl.Rank(requested) // cdecl = the CEILING's declaration (autonomy.max)
if !ok {
return Clamp{}, fmt.Errorf("%s: %q is not one of %v", path, requested, cdecl.Enum)
}decl.Rank(requested) (the dial's own enum) is never consulted. The declarations (internal/settings/consumer.go:118-119 and :156-157): autonomy.max has Enum: AutonomyLevels (off, advise, ask, propose, apply, run, consumer.go:12); prompt.autonomy has Enum: []string{"propose", "run"}, ClampedBy: "autonomy.max". checkClamp (clamp.go:82-115) deliberately allows this shape — a dial's values must be an ordered subset of the ceiling's — so subset dials are a designed-for case, not a misconfiguration.
Probe on the laptop driving the real internal/settings package with the real registry (default autonomy.max = run; probe + log in the fleet's run records, run twice with identical output):
Clamp(prompt.autonomy, "propose") -> value="propose" lowered=false err=nil (control, valid)
Clamp(prompt.autonomy, "run") -> value="run" lowered=false err=nil (control, valid)
Clamp(prompt.autonomy, "apply") -> value="apply" lowered=false err=nil (BUG: not a prompt.autonomy value)
Clamp(prompt.autonomy, "off") -> value="off" lowered=false err=nil (BUG: same)
Clamp(prompt.autonomy, "advise") -> value="advise" lowered=false err=nil (BUG: same)
Clamp(prompt.autonomy, "ask") -> value="ask" lowered=false err=nil (BUG: same)
Clamp(prompt.autonomy, "plan") -> err=prompt.autonomy: "plan" is not one of [off advise ask propose apply run] (error lists the CEILING's enum)
Clamp(repair.autonomy, "apply") -> value="apply" err=nil (control: repair's enum IS the full ladder)
Clamp(repair.autonomy, "plan") -> err=... "plan" is not one of [off advise ask propose apply run] (correct list here)
Existing coverage misses exactly this: internal/settings/clamp_test.go builds the same subset shape (t.dial = {propose, run} under the full ladder) but only ever clamps run, propose, and plan — a value outside both enums. No ceiling-enum-but-not-dial-enum request (apply/off/advise/ask) is tested.
Reachability today (honest scope)
The two prompt routes are not currently exploitable end-to-end: promptAutonomy (internal/daemon/routes_consumer.go:507-518) pre-validates the request body to propose/run before calling Clamp, and the call-settings header path (callSettings, routes_settings.go:79 / Normalize) and file/env layers validate against the dial's own enum. What is broken is Clamp itself — the function its own doc names as the choke point for this job ("A handler that takes the dial from a request body calls this", clamp.go:23-26). Any present or future handler that relies on Clamp alone (as its contract invites) gets out-of-enum values back labelled as the request's autonomy: e.g. apply satisfies AutonomyAtLeast(level, "propose") (routes_consumer.go:337,:400) yet is neither run nor a handled level, so a recipe/intent resolution would return its source unexecuted under a nonsense autonomy: "apply" label, with no error anywhere.
What must NOT change
Lowering to a ceiling value below the dial's whole range is intentional and pinned by the existing test (clamp_test.go: ceiling off lowers a propose request to off, and routes_consumer.go's belowPropose exists for exactly those levels). The defect is only the unlowered pass-through of a requested value that is not in the dial's enum (and the wrong enum in the error). A fix that rejects lowered-to-ceiling results would break that design.
Acceptance criteria
-
Clamp("prompt.autonomy", x)forxin{apply, off, advise, ask}(in the ceiling's enum, not the dial's) with ceilingrunreturns an error instead of passingxthrough as the value — or, if triage prefers a different ruling, that ruling is pinned by tests and documented onClamp. - The error for an invalid request names the dial's permitted values (
propose, runforprompt.autonomy), not the ceiling's ladder. - Valid requests are unchanged:
propose/runpass at or below the ceiling; a request above the ceiling is lowered to the ceiling value (including a ceiling below the dial's range, e.g. ceilingoffloweringpropose→off, per the existing pinned behaviour). -
repair.autonomy/hooks.autonomy(dial enum == ceiling enum) behave exactly as before. - New tests in
internal/settingscover the ceiling-enum-but-not-dial-enum shapes against a subset dial (theclamp_test.gofixture shape already supports this).
Activity
developing-today commentedon Oct 28, 2026
CODE-659
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
Set.Clampranks a requested dial value only in the ceiling's enum, so ceiling-enum values outsideprompt.autonomy's own enum (apply/off/advise/ask) pass through unlowered and unerrored, and the invalid-value error lists the ceiling's ladder instead of the dial's values.Clamp, add subset-dial regression tests.internal/settingspackage on the laptop, run twice identical); queue packet enqueued this run.dezren39 commentedon Oct 31, 2026
🤖 Agent note · picked up
Set.Clampto validate the requested value against the dial's own enum before ceiling ranking; preserve pinned lowering; add subset-dial regression tests inclamp_test.go.internal/settingstests against clean main per mcpx: internal/settings tests red on clean main — TESTING.md missing from compendium manifest, model.* settings lack effect probes, env doc drift #2846.dezren39 commentedon Oct 31, 2026
🤖 Agent note · done (triage)
b5d334b0b6de(2026-10-31):pkgs/mcpx/internal/settings/clamp.goSet.Clampcomputes the only rank check ascdecl.Rank(requested)wherecdeclis the ceiling's declaration; the error message formatscdecl.Enum; the dial's owndecl.Rankis never consulted. The code path is unchanged from the packet'sed8e5910evidence.internal/settingspackage, run twice identical,probe-2026-10-28-laneA-clamp/out.log):Clamp(prompt.autonomy, apply|off|advise|ask)all return the value withlowered=false, err=nil— none is aprompt.autonomyvalue ({propose, run});planerrors but lists the ceiling's ladder as the permitted values. Controlspropose/runpass;repair.autonomy(enum == ladder) behaves correctly;ceiling=asklowersapply/propose→ask(the pinned below-range lowering the fix must preserve).promptAutonomypre-validation,Normalize) do not change the verdict —Clampremains the documented choke point for request-body dials.internal/settingstests are red on clean main for unrelated reasons filed as mcpx: internal/settings tests red on clean main — TESTING.md missing from compendium manifest, model.* settings lack effect probes, env doc drift #2846 — baseline-compare rather than inheriting or fixing them.packet-1641-fix.json): validate the requested value against the dial's own enum first (error naming the dial's values), then rank in the ceiling for lowering; preserve pinned lowering semantics; regression tests on the existing subset-dial fixture inclamp_test.go.dezren39 commentedon Oct 31, 2026
Fix PR opened: #2883
Branch:
queue/4071-1641-clamp-dial-enum→ PR #2883 (open, not merged — checks below).Change (
pkgs/mcpx/internal/settings/clamp.go, +3):Set.Clampnow validatesrequestedagainst the dial's own enum first (decl.Rank, error names the dial's values), then ranks in the ceiling for the lowering comparison. The ceiling check stays as a defensive backstop.Tests:
go test ./internal/settings/ -run 'TestNewRefusesAClampThatCannotHold|TestACallerCannotRaiseAClampedSetting'(incl. new regression assertions foroff/advise/ask/applyerroring with[propose run]): PASS, run locally in the task worktree.mainbaseline: identical 5 failures before and after (TestEveryDocumentHasAChapter,TestNoUndeclaredEnvRead,TestEverySettingHasAnEffectProbeOrAnExemption,TestTheScriptEnvironmentIsWhatTheCodeSets,TestTheEnvironmentDocIsCurrent) — the pre-existing mcpx: internal/settings tests red on clean main — TESTING.md missing from compendium manifest, model.* settings lack effect probes, env doc drift #2846 reds. Zero clamp failures.CI on #2883:
basic: lintpass,plugin testspass,nix build .#mcpx-docspass — butstress: PR changed testsfails solely on those same 5 pre-existing #2846 tests (verified: the job log contains only those 5 test names, 10x each under race/shuffle/repeat; no clamp failure). Per standing merge criteria (checks green) and the packet's out-of-scope ruling on #2846, not merging — merge when #2846 clears or by explicit override.🤖 Agent note · pr_opened, merge-blocked on pre-existing reds
internal/settingsCI is green again (mcpx: internal/settings tests red on clean main — TESTING.md missing from compendium manifest, model.* settings lack effect probes, env doc drift #2846 fixed) or by override; no further code change needed for mcpx(settings): Clamp validates a dial request against the ceiling's enum, not the dial's — prompt.autonomy accepts apply/off/advise/ask #1641.Merge pull request #2883 from developing-today/queue/4071-1641-clamp-…