Skip to content

fix(runtime): queue completion events in entry order - #456

Open
devin-ai-integration[bot] wants to merge 1 commit into
developfrom
fix/completion-pool-order
Open

devin-ai-integration[bot] wants to merge 1 commit into
developfrom
fix/completion-pool-order

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

What and why

When the entries of two orthogonal regions each generate a completion event, PSSM's pool holds them in generation order — the order the entries happened, which the entry draw decides (§8.5.9: a new completion event goes behind those already in the pool). The runtime queued them once the move had settled, leaf by leaf in region declaration order (scheduleTransitionEvents), whatever the draw was: under declared the two coincide, under reverse, seed:<n>, check and explore the pool's order and the draw disagreed. This is the "pool's order follows the entry draw" item of docs/internals/design/region-order-scheduling.md, now implemented.

  • enterStateInto(state, branches, last) is told when it enters the last state of an entry path (a region's initial or restored state, a fork branch's or a transition's target, the state a shared path ends at). Where that state completes at once (completesAtEntry: a completion transition out of it and nothing below to enter) it calls scheduleCompletionTransitions before returning, so event IDs follow the draw. scheduleTransitionEvents / scheduleFromLeaf now schedule the time triggers of the settled configuration and its ancestors only — a time trigger still counts from the state's entry, and nothing is double-scheduled.
  • Front consequence: entryHead(state, leaf) makes an entry unit that queues a completion non-silent even when the state performs nothing, since its place in the pool is observable; ordinary silent entries keep riding with the neighboring performing unit. The speculative entry-ahead path (state_route.go) stays silent — it never ends an entry path.
  • Completions deferred by a running do behavior (settleDoActions) and composite bodies completing through completeIfDone keep their timing. regionComplete now checks that the completion vertex a region rests at is its own, not a nested composite's done, which the entry-time rule exposed (state_region_completes_at_own_done).

Specification basis

PSSM 1.0 (ptc/18-11-06) §8.5.9, ordered completion-event pool; SysML v2 §7.18.1 / PSSM §8.5.5 for the concurrent entry. docs/project/spec-compliance.md: the entry-order row's wording and coverage are extended; no status moves. precise-semantics-alignment.md SM10 now agrees under every policy; finding 11 keeps its initial-transition, suite-defect and do-step parts.

How it was verified

New fixtures under internal/exec/runtime/testdata/conformance/, each with .expected.json, .check.expected.json and trace goldens (default, declared, seed-1):

  • state_completion_pool_entry_order — two silently entered completing states in orthogonal regions; completion effects log "l r " under declared, "r l " under seed:1; check reaches exactly both.
  • state_completion_pool_history_order (shallow) and state_completion_pool_deep_history_order (deep) — the same through a history restore.
  • state_completion_pool_fork_order — through a fork's branches.
  • state_region_completes_at_own_done — a nested composite's done completes its own region only.

robustness_completion_order_test.go (TestRuntimeRobustnessCompletionOrder): a witness naming a completing state the front does not hold is refused before any completion is queued; both replayed draws dispatch in the draw's order with nothing left over; a witness ordering the pool after the draw is left over; a wide completing front beyond the run budget ends with the budget error.

Goldens that moved (all reviewed; declared queues what it queued, no default outcome moved)

Fixture Movement Why
state_concurrent_do, state_concurrent_inline_do_bodies, state_anonymous_do_atomic .check.expected.json / .expected.json gain 415263 451263 415623 451623; seed-1 trace reorders Each region's start state completes at entry; the region drawn first now enters its work first, so the mirror of the four existing seq values is reached. Comment wording in the .sysml updated to match
state_do_step_among_completions three outcomes → six (did r m, r did m, r m did) m1's and r1's completions dispatch in the entry draw's order; the do step still falls before, between or after
state_call_trigger_regions two outcomes added (Muted before Dimmed) the two start states' completions follow the entry draw
state_composite_region_deeper_first, state_composite_region_depth_order seed-1 outcomes' stateVisits reorder the draw entered rstart first, so rstart -> r1 now dispatches before lstart -> deep; the old order was the divergence this fixes
state_firing_units_interleaved all three traces gain choice on accept Go: next l2(entry), r1(exit) (unordered; took l2(entry) first) l2 has a completion transition, so its entry is a drawn alternative now; order taken is unchanged

PSSM referee — observed vs predicted

No bucket moved: 51 pass / 13 fail / 38 not-expressible / 1 differs-by-design. Every movement is the one the design note's enumeration predicted:

Test Predicted Observed
History 001-C gains its second first-half trace, still fails reached 1 → 2 (S1(entry)::S2.2(entry)::S1.1(exit)::…), fail on the suite's restore-step defect
History 002-B gains one, reaches two the suite does not register reached 1 → 4: two admitted plus the two §8.5.9 orders the suite omits; fail; runs 32 → 48
Transition 017 reachable set grows; needs this plus the do-step site reached 3 → 6 of 8; the two missing fire the parent's completion before its region's (suite defect); runs 12 → 18
Entering 011 reached 1 → 2; the four missing need UML's initial-transition effect as an entry unit (finding 11's open part)
Transition 019, Fork 002 reached sets unchanged; runs 24 → 80 and 12 → 20 (completing entries now drawn)
Event 016 B must stay inside the explore budget 1152 runs, unchanged, under the 4096 budget

Referee output is byte-identical for -jobs 1, -jobs 8 and a repeated -jobs 8 (sha256 9bf3e0b5…a537f). docs/project/omg-issues.md unchanged: its History entry already states the two §8.5.9 orders now reached.

Gates

go build ./... && go vet ./... && gofmt -l .                        ok (gofmt empty)
go test ./...                                                        ok
go test -C tools ./... && go vet -C tools ./...                      ok
OPENSYSML_REQUIRE_PSSM_SUITE=1 go test -C tools ./referee/pssm/...   ok
go run -C tools ./cmd/pssm-referee -check                            ok (counts reproduce)
OPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 go test -count=1 ./tests/corpus   ok (no ratchet movement)
make lint && make docs-check                                         ok
python3 scripts/changelog.py check && python3 scripts/check-doc-ids.py   ok
go run -C tools ./cmd/doc-counts -check                              already current

Checklist

  • make test and make lint pass locally
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (compliance rows need nothing: the census is counted at docs build)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

A state's completion event is queued as its entry unit is performed, so
the pool holds two regions' completions in the order the entry draw
entered their sources (PSSM 8.5.9) rather than in region declaration
order once the move settled. An entry that performs nothing but
generates a completion is drawn as an alternative of the entry front,
its place in the pool being observable; other silent entries keep
riding. Time triggers are still scheduled once the move settles, and a
completion held back by a running do behavior or a nested composite's
regions keeps its timing.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 19, 2026 23:10

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant