Repository navigation
Conversation
…nflict
demand_engine_request decided sharing from the stored entry's nature alone, so a
FreshEffect request could attach to a PureComputation entry (including one already
holding an available result), and Pure/Idempotent or a changed WorldRead envelope
were treated as one demand.
The request now compares the complete stored and requested natures with
std.materialization_ladder nature_eq before any attachment or re-production. An
unequal pair marks the entry DemandBlocked { BlockedKeyConflict { stored, requested } }
(the arm existed with no producer; it now carries both natures). The conflict is
durable: readiness, seal and settlement carry it rather than re-deriving over it,
later requests leave it standing, and direct dependents read it as a refused
prerequisite instead of waiting with no cause.
Witnesses: Pure/Fresh in both orders, Pure/Idempotent in both orders, WorldRead
envelope both directions, conflict after an Available result (dependent leaves the
ready order), conflict surviving seal/settle/re-request and never admitted; positive
controls that equal natures still attach and share one execution. Against a mutant
keeping the stored-nature decision the six conflict claims fail and the two controls
hold; against a mutant without readiness preservation the durability claim fails.
Out of scope and still open (roadmap native-memory-demand-nature): two same-key
FreshEffect requests leave one runnable entry while counting productions; distinct
executions are not yet demonstrated. The native planner's contracts are all
PureComputation, so no suppressed native effect is claimed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca19fc47be
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| dependents_of: e.dependents_of, | ||
| prerequisites_of: e.prerequisites_of, | ||
| ready: demand_ready_remove(ready: e.ready, id: id), | ||
| in_flight: e.in_flight + demand_in_flight_delta(before: demand_entry_state(entry: existing), after: conflict), |
There was a problem hiding this comment.
Keep conflicted running work in the in-flight count
When the conflicting entry is DemandRunning, this delta decrements in_flight immediately even though its producer is still executing. Its eventual settlement preserves the conflict and computes a zero delta from conflict to conflict, so the seat is never held during the remaining execution and demand_engine_next can admit work beyond the offered capacity. Keep the seat occupied until the running production actually settles.
Useful? React with 👍 / 👎.
| } | ||
| let direct = demand_engine_dependents(e: marked, id: id) | ||
| DemandEngine { | ||
| entries: demand_engine_reevaluate_only(e: marked, ids: direct), |
There was a problem hiding this comment.
Preserve running dependents until their production settles
If a dependent is already DemandRunning when its previously available prerequisite receives a conflicting request, this reevaluation overwrites the dependent with BlockedByRefusedPrerequisite while leaving in_flight unchanged. When that production later settles, its prior state is no longer running, so no decrement occurs and the seat remains counted forever, preventing further admissions at that capacity. Preserve the running lifecycle or otherwise retain enough state to release its seat on completion.
Useful? React with 👍 / 👎.
…ves the report The seat is now carried on the entry and moved only by the producer's own report. A key conflict on a running demand no longer releases its seat early, and a running dependent whose prerequisite is then conflicted keeps its seat until it reports, and keeps its refusal when it does. Readiness no longer re-derives a seat-holding demand to ready. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Roadmap:
native-memory-demand-nature(D15 census #10,gunbc.plans.demand_engine_program).Defect
v2.std.demand_enginedemand_engine_requestdecided what to do with an existing identity fromexisting.naturealone and ignored the requestednature:FreshEffectrequest attached to aPureComputationentry, including one already holdingDemandAvailable;PureComputationandIdempotentEffectboth share, so one key served two different contracts;WorldReadstaleness envelope was ignored.Change
std.materialization_laddernature_eqbefore any attachment or re-production. Checking only the requested nature is not enough: Fresh→Pure would then attach.DemandBlocked { BlockedKeyConflict { stored, requested } }. The arm already existed with no producer; it now carries both natures.demand_readinesspreviously preserved only settled and cycle-blocked states, so a bare blocked state would have been re-derived to ready. Now:BlockedByRefusedPrerequisite. They do not wait with no cause.Running demands (second commit, after review at ca19fc4)
The first commit read the seat off the state, so a verdict that replaced
DemandRunningmoved the seat with it:BlockedByRefusedPrerequisitewithout releasing its seat, and its later report overwrote that refusal with a value.Now:
DemandEntrycarriesseat_held, and only the producer's own report (demand_engine_settle, viademand_entry_settled) moves it.in_flightis the delta of that bit, and its rebuild counts it.demand_state_stands_over_a_report); it still counts as a production.Evidence
v2.test.demand_engine.demand_enginehas ten new claims; all 37 claims in the module PASS (claim_batch, worktree-built binary, local, at 94b26f2).a_key_conflict_survives_seal_settle_and_rerequest_holdsFAILSRunning-state claims, against the engine at ca19fc4 and one mutant:
a_conflict_on_a_running_demand_keeps_its_seat_until_it_reports_holdsa_running_dependent_keeps_its_seat_and_refusal_when_a_prerequisite_conflicts_holdsThe original engine source does not resolve against the new claims (
BlockedKeyConflicthas nostored/requested), which is why the first row keeps the new types.Witnesses lane (local,
claim_executor --required-ci --required-lane witnesses, 94b26f2): parse and resolve clean; all ten new claimsplanned-and-passed; 16 wet refusals, none in this change's closure: the 15 known local host refusals (mtcollins1_kvm_observer_protocol_wet_witness×7,allocation_client_execution_wet_witness×8) andv41_source_patch_converge_witnessred5, which also refuses on #13577's head and whose cause is unresolved. The first lane run caught a//annotation inside a declaration body thatclaim_batchhad accepted; fixed by moving it to module grain.Not in this PR (still open on the roadmap node)
FreshEffect. Two requests leave one runnable entry whileproductionscounts both. With the seat now held on the entry, a second Fresh request while the first runs leaves the entry waiting until that first production reports, and the report then answers both. Neither the old behavior (re-offered while running) nor this one is right; it stays with that task. The existingfresh_effect_is_never_attached_holdschecks counters only. Closing it needs a control that requests twice, admits and settles once, then requires a second distinct execution or an explicit refusal.native_demand_plan_module) are allPureComputation. This fixes a generic engine defect; it does not repair an observed native effect suppression.🤖 Generated with Claude Code