mirror of
https://github.com/morluto/rea.git
synced 2026-10-27 18:05:45 +00:00
fix(environment): share write overlap and check clocks on earlier calls
Observation search skips a read begun before the write ended. That comparison now uses the same overlap as the check path. A clock learned on a later call was not checked against earlier calls that kept the field. Serving would stamp those calls too, so the plan stays unserved. A clock learned earlier is still refused when a later call does not advance it. Regression tests cover an overlapping empty update and a published_at clock that one recorded call leaves unchanged. Co-authored-by: morluto <morluto@users.noreply.github.com>
This commit is contained in:
4 files changed
+129
-4
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import type { JsonValue } from "../jsonValue.js";
|
||||
import { overlapsWrite } from "./environmentStateWriteAttribution.js";
|
||||
import {
|
||||
collectionPathOf,
|
||||
isObject,
|
||||
@@ -62,7 +63,7 @@ export const newEntityIn = (
|
||||
export interface ObservationSearch {
|
||||
readonly records: readonly StateRecordFacts[];
|
||||
readonly from: number;
|
||||
/** A timed write's completion; reads begun before it cannot observe its effect. */
|
||||
/** A timed write's completion. A read begun while it still ran may show the prior state. */
|
||||
readonly after?: number;
|
||||
readonly viewOf: (ordinal: number) => StateView | undefined;
|
||||
readonly withBody: <T>(
|
||||
@@ -77,6 +78,7 @@ const succeeded = (record: StateRecordFacts): boolean =>
|
||||
/**
|
||||
* The first later read, before the next write, that shows a written entity: an item read of
|
||||
* `id` when given, else an item read of an unheld id or a collection read listing exactly one.
|
||||
* A read begun while the write still ran may show the earlier state, so it is not chosen.
|
||||
*/
|
||||
export const laterObservation = (
|
||||
search: ObservationSearch,
|
||||
@@ -93,7 +95,9 @@ export const laterObservation = (
|
||||
): Observed | undefined => {
|
||||
for (const record of search.records.slice(search.from + 1)) {
|
||||
if (target.isWrite(record)) return undefined;
|
||||
if (search.after !== undefined && record.start < search.after) continue;
|
||||
// The same overlap the check path ignores: the write was still running when this read began.
|
||||
if (search.after !== undefined && overlapsWrite(search.after, record.start))
|
||||
continue;
|
||||
const view = search.viewOf(record.ordinal);
|
||||
if (
|
||||
!succeeded(record) ||
|
||||
|
||||
Reference in new issue
Block a user