8000 feat(control): enforce affine single-shot handler resumption · Issue #208 · Mnehmos/mnehmos.nls.lang · GitHub
[go: up one dir, main page]

Skip to content

feat(control): enforce affine single-shot handler resumption #208

Open

Description

@Mnehmos

Problem

Retrying a requested operation and replaying the rest of its caller are different actions. A payment handler may make two permitted gateway attempts yet must deliver only one successful answer to the workflow that sends the receipt.

#207 introduces direct-return handlers. This follow-up adds a small, explicit resumption contract to the typed control IR. It does not claim exactly-once external payment execution; replay/idempotency obligations remain in #201, and resource-token consumption remains in #200.

Minimum deliverable

Support a synchronous affine, single-shot request continuation: it may be resumed at most once. The first slice uses an explicit resuming-arm mode, with terminal Resume(value) or a declared typed failure that exits the handled region. These names are proposed IR constructs, not existing .nl syntax.

Keep direct-return arms from #207 semantically distinct. Do not infer their behavior from whether a sibling arm contains the word resume. Defer successful zero-resume answer replacement, work after resume returns, multi-shot continuations, first-class continuation values, and cross-fiber resumption until their control and cleanup contracts have separate implementations.

Implementation hints

  • Give each dynamic operation request its own continuation token and region identity. It moves from pending to resumed or failed/closed. This is per request, not one token per operation declaration or whole program.
  • Resume(value) checks the operation's result type. The surrounding handled region retains its own answer type; those types need not match. A handler failure follows feat(errors): add checked failure sets and a portable typed exception contract #198's checked failure contract and produces no successful operation result.
  • Extend bug(control): check branch outputs, binding mutation, and loop-carried values before emission #196's control analysis with token use counts: sum along sequential paths and take the maximum across mutually exclusive alternatives. Conservatively reject a loop or recursive/indirect path that can reuse the same token. Two resume sites on exclusive branches are legal.
  • Initially keep the token lexical and non-first-class: reject copying, storage in records, returning it, passing it to unknown callbacks, or crossing task/fiber boundaries. Track aliases if any safe forwarding form is later allowed.
  • Specify that the same lexical handlers remain installed for the resumed remainder. Preserve ordered effects, typed failure propagation, and cleanup when the region exits.
  • Lower through an explicit continuation/state-machine or equivalent structured protocol shared by backend contracts. Do not require Python/TypeScript to capture arbitrary native stacks. Gate unsupported forms before output under feat(backends): consume checked IR and enforce executable Python/TypeScript semantic conformance #202.
  • Reta 8000 in a runtime consumed-token guard at foreign/runtime boundaries. A duplicate completion must not execute the downstream continuation twice, even if an adapter violates its declared contract.
  • An operation's replayability, its continuation's consumption, and its resource's typestate are separate facts. None substitutes for the other two.

Acceptance criteria

  • Sequential double resume, possible loop reuse, an escaped token, and a wrong resume value type are rejected with diagnostics pointing to the relevant operation and control paths.
  • Exclusive success branches may each contain one resume; ordinary successive operation requests receive distinct tokens.
  • A fake gateway fixture records two allowed internal attempts, one resume, and one receipt in that order. The second attempt uses the same key/payload under feat(control): add checked Retry and Timeout policies with explicit idempotency obligations #201's policy when retry integration lands.
  • A terminal declared decline performs zero resumes and sends zero receipts; its typed failure leaves the region and runs the supported cleanup exactly once.
  • A runtime duplicate-completion probe cannot send a second receipt; cross-thread/asynchronous support remains unavailable until explicitly implemented.
  • Nested handlers and region answer types preserve the same values, failure payloads, and ordered traces on each supporting backend.
  • Documentation states the at-most-once downstream guarantee and explicitly separates it from external deduplication, cancellation, and exactly-once execution.

Ordering

Depends on #207, #196, #197, and #198. Use #202's conformance/capability mechanisms. #201 can implement ordinary bounded retry independently; handler-based retry integration follows this issue. No general concurrency runtime or complete ownership system is required.

Osprey references and limits

Pinned to 8792de9f6d159922141f9d191e4bc5d256fbb971:

The reference tests were inspected, not executed during this audit. Osprey's single-shot design is an implementation reference, not evidence of externally exactly-once I/O.

Activity

  1. added
    enhancementNew feature or request
    coreCore language semantics and design
    specificationLanguage specification documents
    on Sep 10, 2026
  2. Mnehmos commented on Sep 12, 2026

    @Mnehmos
    OwnerAuthor

    Staging note (planning pass, 2026-09-13)

    Depends on #207 by the issue's own ordering ("Use #207's operation handler boundary and #208's consumed-token checks when implementing handler-based retry"). Additional prerequisites, checked against master:

    No code exists for handler resumption (no Resume/Perform nodes; IROperation has no handler slot). Keeping open with this note; the natural sequence is #207 slice 1 (syntax + IR + checker + capability refusal) → #207 runtime → #208 specification and checker.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreCore language semantics and designenhancementNew feature or requestpriority-mediumShould be addressedspecificationLanguage specification documents

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull r 32B2 equests

      Issue actions

      0