feat(validation): state_machine.initialStates enforces the FSM entry point on INSERT (#3165)#3188
Merged
Conversation
…point on INSERT (#3165) A `state_machine` rule's `transitions` only governs UPDATE — on INSERT it was a no-op, and a `select` field permits ANY declared option as the initial value, so a record could be born mid-flow (created already `approved`), skipping the whole state machine. This was the gap #3043's mitigation idea assumed didn't exist (declared ≠ enforced, ADR-0049). `state_machine` rules gain an optional `initialStates: string[]` — the states a record may be CREATED in. When set, an insert whose (defaulted) state-field value is outside the list is rejected server-side with code `invalid_initial_state`. Omit it to keep the legacy behavior (no initial-state check on insert). A missing / empty value is left to required-validation; `transitions` (UPDATE) is unaffected. Enforced at the `evaluateValidationRules(..., 'insert')` seam the engine already runs after field defaults (engine.ts:2294). - spec: `StateMachineValidationSchema.initialStates` (additive, optional). - objectql: `checkStateMachine` insert branch + `invalid_initial_state` code. - docs: data-modeling/validation.mdx + regenerated reference. - tests: rule-validator unit (allowed/rejected/absent/update-unaffected/legacy no-op) + engine integration (real insert: 'approved' rejected & nothing written; 'draft' and defaulted 'draft' accepted). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P5fRY4ctobCeFpBba1oGrz
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 18, 2026 07:10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
关闭 #3165(在 #3043 探索中发现)。
state_machine规则的transitions只约束 UPDATE;在 INSERT 上它是 no-op,而select字段允许任意声明选项作为初始值——所以一条记录可以「一出生就在流程中间」(创建即approved),完全跳过状态机。这正是 #3043 备选缓解思路所依赖、但当时并不存在的能力(declared ≠ enforced,ADR-0049)。改动
state_machine规则新增可选initialStates: string[]——记录允许被创建于的状态集合。声明后,insert 时状态字段(经默认值解析后)的值若不在集合内,服务端拒绝(code: 'invalid_initial_state')。不声明则维持旧行为(insert 不做初始态检查);字段缺失/空值交由 required-validation;transitions(UPDATE)不受影响。强制点就在引擎 insert 已有的evaluateValidationRules(..., 'insert')(engine.ts:2294,在字段默认值之后)。StateMachineValidationSchema.initialStates(additive,optional)。checkStateMachine的 insert 分支 +invalid_initial_statecode。data-modeling/validation.mdx+ 重新生成的 reference。测试
rule-validator.test.ts):初始态放行 / 违规拒绝(invalid_initial_state)/ 空值 no-op / 不影响 UPDATE transition / 未声明 initialStates 的旧行为仍放行。plugin.integration.test.ts):真实 insert ——approval_status: 'approved'被拒且不落库;'draft'与默认值补全的'draft'均通过。@objectstack/objectql943 passed;@objectstack/specvalidation 测试通过;check:docsin sync。关联
state_machine校验规则在 INSERT 上是 no-op —— 无法强制记录的初始状态(declared ≠ enforced) #3165(本 issue) · 安全/设计:静态 readonly 的 INSERT 豁免让审批/状态字段可在创建时被直接播种(比 #3003 少一步) #3043 / PR fix(metadata-protocol): strip staticreadonlyon INSERT at the data-write ingress (#3043) #3162(探索来源) · ADR-0020(state_machine) · ADR-0049(enforce-or-remove)🤖 Generated with Claude Code
Generated by Claude Code