Repository navigation
Closed
Labels
domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
Description
在实施 #5932(补 min/max/minLength/maxLength 的执行)时顺带发现,记录下来交 triage。不在 #5932 的完成范围内 —— #5932 的分诊评论按名点死了那四个键,step 是第五个。
事实
packages/spec/src/system/settings-manifest.zod.ts 的 SpecifierSchema 在同一段注释下声明了三个键:
/** `number` / `slider`: numeric bounds and step. */
min: z.number().optional(),
max: z.number().optional(),
step: z.number().optional(),
#5932 落地后,min / max 在写入路径(validatePatch)与 env 路径
(effectiveEnvOverride)都被执行了。同一行注释下的 step 仍然零读取点 ——
packages/services/service-settings/src/ 里没有任何消费者,superRefine 也不校验它
(不像 min/max 至少查了次序、minLength/maxLength 至少查了次序)。
生产侧目前只有一处声明:packages/services/service-settings/src/manifests/ai.manifest.ts:189
的 temperature(min: 0, max: 2, step: 0.1)。
为什么单独一条,而不是 #5932 的续集
因为它先需要一个产品判断,而不是一段实现。step 有两种读法,导向不同的结果:
- 它是值约束 —— 值必须落在
min + k * step的网格上。那么temperature: 0.15
应当在写入时被拒(码表里invalid_value可用),step就应当照 settings 写入路径只执行 required / options / pattern —— 声明的 min / max / minLength / maxLength 一条都不校验(auth.password_min_length 可被写成 1) #5932 同形补执行。
代价:浮点网格判定需要容差策略(0.1的整数倍在二进制浮点下不精确),这本身是个
需要定的规格。 - 它是纯 UI affordance —— 只是 HTML
input[type=number]的step属性,告诉控件
上下箭头一次走多远,从不表达「其他值非法」。那么它今天的行为就是正确的,不该补执行;
该做的是把注释写清楚,免得下一个人按 ADR-0049「declared ≠ enforced」把它当洞来补。
我倾向第二种(HTML 语义就是这样,而且 temperature: 0.15 对 AI 服务显然是合法值),
但这是规格判断不是实现细节,所以按 #5932 分诊的同一条界线上报而不自行决定。
影响面
- 今天没有用户会撞到:唯一的声明点是
ai.temperature,step: 0.1与min: 0 max: 2
并存,而越过网格的值(如0.15)对下游是完全合法的温度。故按观察类记录
(finding,不入pm:queue),严重度请 triage 定。 - 若判定为「纯 UI affordance」,建议把
SpecifierSchema的注释从
"numeric bounds and step" 拆开,并在step上写明它不参与校验 —— 否则 settings 写入路径只执行 required / options / pattern —— 声明的 min / max / minLength / maxLength 一条都不校验(auth.password_min_length 可被写成 1) #5932 的
同族记忆会让下一个 agent 再来补一次。
相关
- settings 写入路径只执行 required / options / pattern —— 声明的 min / max / minLength / maxLength 一条都不校验(auth.password_min_length 可被写成 1) #5932 —— 同族的
min/max/minLength/maxLength执行(本条的发现上下文)。 - service-settings: select 型 specifier 的 options 在保存期完全不校验 —— 声明的枚举不被强制 #5131 ——
options表在写入路径上的执行。 - env 来源的 settings 值绕过 manifest 的 options 表校验 —— #5094 在写入 API 上堵住的洞,在 OS_* 覆盖这一侧原样敞开 #5204 —— env 侧与写入侧对齐。
Metadata
Metadata
Assignees
Labels
domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
Activity
os-project-manager commentedon Aug 8, 2026
Findings sweep (maintainer-authorized one-off, 2026-08-07 — registered on #6015): promoted to the queue, inheriting the #5932 family ruling:
stepsits under the same "numeric bounds and step" comment asmin/max, and the mother ruling's rationale (declared bounds must bind) transfers cleanly — enforce it the same way. Per the inheritance discipline: if the dev's premise check findsstepis genuinely a UI-only hint, report back for a re-ruling instead of forcing it.finding→pm:queue.Generated by Claude Code
os-project-manager commentedon Aug 8, 2026
Claim: PM loop round 1 (services seat)
Session:
session_01USNUyHEr7uaU6MoEWXiteiBranch:
claude/issue-6199-settings-step-enforceWorktree:
objectstack-issue-6199Domain:
domain:servicesFile surface:
packages/services/service-settings/src/**(validatePatch value-window family + env path + tests).packages/specis explicitly out of surface —stepis already declared and the error-code table already has the member; any spec-side need stops the dev withneeds_decision.Serial constraints cleared: same-function predecessor #6201 (Fixes #5932, merged 2026-08-07T10:57Z) is landed; no open PR currently touches service-settings; #5712/#5933 (valueDomain family, same function eventually) are
pm:blocked/unclaimed in other lanes — nothing in flight. Zero in-flight claims in this lane.Container class: S —
mode:subagent, shared container.Generated by Claude Code
os-project-manager commentedon Aug 8, 2026
Review verdict: ACCEPT — PR #6501.
What shipped: the declared
stepgrid is enforced on both settings doors —validatePatch(write) andeffectiveEnvOverride(env), by construction one family (DeclaredBounds/firstRangeViolation), so it cannot become the next one-door constraint. Grid breach emits the existing catalog memberinvalid_valuewithconstraint: { step, min? };packages/specuntouched. Anchor = declaredminelse 0 (themin: 1, step: 2= odd-numbers argument), relative tolerance 1e-9 with the float traps pinned numerically (0.7 and 1.2 on a 0.1 grid), window judged before grid, TOUCH gate inherited, non-positivesteprecords no grid (report-never-refuse posture). Rejection tests assert the full ADR-0112 envelope including the route-level 400. Reverse verification: 12 red / 5 green exactly as predicted. CI converged green — ESLint and TypeScript Type Check job conclusions bothsuccess.The promotion's escape hatch did not fire, and the dev strengthened the ruling:
stephas zero read points in this repo and inobjectui, so the "UI-only hint" reading would have the key expressing presentation for a renderer that does not exist — positive evidence for enforce, not just inheritance.PM dispositions on the report's open questions:
stepgrid on the settings write path and the env path (#6199) #6501 or The data-fieldstep(slider) is the settingsstep's unenforced twin —record-validator.tsreadsmin/maxand neverstep#6514. The Chinese changeset is fine — changesets are repo files that compile into release notes and follow their predecessor's language.ai.manifesttemperaturestep: 0.1— now that the declaration binds, whether it is product-correct is the manifest owner's question; filed as ai.manifest temperature declaresstep: 0.1— now that the grid binds (#6199), decide whether the declaration itself is product-correct #6550 for triage (the dev's recommendation B is recorded there). Not this PR's scope, deliberately.Out-of-scope finding #6514 (data-field
steptwin) verified filed withfindingand no queue label — correct discipline.Proceeding to ready-for-review + merge queue.
Generated by Claude Code
docs(service-settings): re-anchor the dead tracker citations to the c…