Описание
The state-protocol profile, and with it the TB-MVP-01 typed EF workflow, protects the local C# capabilities and aliases of one tracked entity instance. It explicitly does not protect the persisted row from the following.
-
Concurrent writers. TB-MVP-01 registered concurrency as option A, out of scope: there is no concurrency token. Two requests that both load a Submitted order can both pass WithSubmitted and both save Approved. Two different transitions racing (approve vs. something else) are not claimed correct.
-
Writes that bypass the entity's C# surface:
ExecuteUpdate/ExecuteDelete;
Entry(order).Property("Status").CurrentValue = …;
- raw SQL;
- another process;
- reflection.
These are stated limits, and they are pinned as fixtures that are accepted:
frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenByBulkUpdate.cs.txt;
frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenThroughChangeTracker.cs.txt;
samples/OrderBackend/corpus/limits/K2_execute_update.cs.txt.
Proposal, as two separable slices:
- (a) Concurrency in the Typed Builder slice (product). Add a normal EF optimistic-concurrency token to the generated protocol, either
[ConcurrencyCheck] on the state or a row version, and map DbUpdateConcurrencyException to a registered HTTP contract (e.g. 409 concurrent_transition). Acceptance needs a two-context conflict case: the second save loses and the row holds the first transition only. This was option B of TB-MVP-P24.
- (b) Bypass detection (analysis). Decide whether the profile should flag
ExecuteUpdate/SetProperty on protocol-owned state, string-keyed metadata writes of protocol-owned properties, and similar. If not, keep them as documented limits. Today they are accepted on purpose; turning them into refusals changes the profile's claim and needs a ruling.
Мотивация / сценарий
frontend/roslyn/README.md, "What is claimed": "It does not protect the persisted row from other ways of changing it… Those belong to concurrency tokens, constraints and transactions."
samples/OrderBackend/README.md opens with "Not claimed: concurrency".
docs/notes/tb-mvp-01-preregistration.md: concurrency option A.
A real backend runs requests concurrently, so (a) is the obvious next production gap of the typed workflow.
Альтернативы
- Pessimistic locking or serializable transactions per transition. Provider-specific and heavier; optimistic tokens are the normal EF answer.
- Do nothing and keep the explicit non-claim. That is honest, but it blocks "production-ready".
Область
tooling (scripts / CLI / CI)
Refs: #391 (TB-MVP-01), docs/notes/tb-mvp-01-report.md section "What the slice does not claim".
Описание
The state-protocol profile, and with it the TB-MVP-01 typed EF workflow, protects the local C# capabilities and aliases of one tracked entity instance. It explicitly does not protect the persisted row from the following.
Concurrent writers. TB-MVP-01 registered concurrency as option A, out of scope: there is no concurrency token. Two requests that both load a
Submittedorder can both passWithSubmittedand both saveApproved. Two different transitions racing (approve vs. something else) are not claimed correct.Writes that bypass the entity's C# surface:
ExecuteUpdate/ExecuteDelete;Entry(order).Property("Status").CurrentValue = …;These are stated limits, and they are pinned as fixtures that are accepted:
frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenByBulkUpdate.cs.txt;frontend/roslyn/protocol-samples/efcore/known-gaps/StateWrittenThroughChangeTracker.cs.txt;samples/OrderBackend/corpus/limits/K2_execute_update.cs.txt.Proposal, as two separable slices:
[ConcurrencyCheck]on the state or a row version, and mapDbUpdateConcurrencyExceptionto a registered HTTP contract (e.g.409 concurrent_transition). Acceptance needs a two-context conflict case: the second save loses and the row holds the first transition only. This was option B of TB-MVP-P24.ExecuteUpdate/SetPropertyon protocol-owned state, string-keyed metadata writes of protocol-owned properties, and similar. If not, keep them as documented limits. Today they are accepted on purpose; turning them into refusals changes the profile's claim and needs a ruling.Мотивация / сценарий
frontend/roslyn/README.md, "What is claimed": "It does not protect the persisted row from other ways of changing it… Those belong to concurrency tokens, constraints and transactions."samples/OrderBackend/README.mdopens with "Not claimed: concurrency".docs/notes/tb-mvp-01-preregistration.md: concurrency option A.A real backend runs requests concurrently, so (a) is the obvious next production gap of the typed workflow.
Альтернативы
Область
tooling (scripts / CLI / CI)
Refs: #391 (TB-MVP-01),
docs/notes/tb-mvp-01-report.mdsection "What the slice does not claim".