← Về thư mục
📄 / / profiles / r-and-d / raw_evidence / OpenAI4S / openai4s / execution / README.md

Scientific cell execution policies

中文说明

This is the shared execution layer. Once an outer-loop action or an explicit notebook request has become a scientific Python/R cell, the policies that apply to it live here. None of them know which provider produced the cell or which UI asked for it.

Where this fits

The package sits between the outer-loop/Web adapters above and the persistent managers in ../kernel/ below. It parses no model replies, performs no Host RPC, and runs no code itself. What it does own: one scientific writer at a time per session, an exact owner/ticket/lease identity for every request, a projection of the namespace a cell depends on, the normalized request/result values both adapters share, and timeout supervision.

The FIFO coordinator covers Agent, user REPL, lifecycle, and recovery writers. Cancellation targets the exact ticket, and the adapter still has to deliver the interrupt through the matching kernel generation and lease. That is what keeps a stale cancellation from interrupting a newer owner.

Files

File Responsibility
__init__.py Re-exports the coordinator's tickets and errors, the cell request/result and capture values, and the watchdog policy together with its cancellation outcomes.
coordinator.py Per-session FIFO admission and the whole observable life of a ticket: queue position, the cancellation signal that only its exact holder sees, snapshots for UI and persistence, and the shutdown/recovery transitions. It admits and releases writers; it never executes code and never delivers a process signal, which the caller does through the kernel lease bound to the admitted ticket. The pending queue is capped per session and refused at submit, before anything is registered, so the caller learns now rather than holding a ticket that was never going to run. This is the one admission path every executing writer goes through, and capping the workers, the kernel frames and the job buffers while leaving its deque unbounded relocates the growth into accumulated tickets instead of stopping it. The cap counts what is waiting, not what is running, and is per session — one busy session must not refuse another's work.
dependencies.py Uses Python's ast and a deliberately small R lexer to record what each cell reads, writes, and deletes, and projects stale cells from those edges. The visibility and replay_policy defaults come from here too. A construct that can change the namespace without naming it is flagged uncertain rather than guessed at: this is a conservative projection, not a security boundary.
models.py The three dataclasses passed across the boundary: CellRequest, CaptureResult, and CellExecutionResult. No provider or UI types in any of them. CaptureResult records the files a cell read alongside those it wrote, and CellExecutionResult.executed says whether a kernel actually ran the cell — a safety-gate refusal or an unavailable runtime synthesizes a result byte-identical to a real failure, and the agent loop's evidence ledger must not count a refused cell as finalize-time evidence.
watchdog.py The protocol-neutral timeout ladder for one frozen kernel lease: wait, interrupt the exact owner, kill if the interrupt does not land, then restart or abandon according to policy. A pending permission decision freezes the timeout budget, and a cancellation still cuts through it. The ladder's outcome is reported, not assumed: an interrupt whose delivery verdict says it reached nobody skips the grace wait, and the terminal exception distinguishes a kernel that was really reset from one that could not be reset from this daemon (KernelNotReset… — a remote worker cannot be respawned here, so cluster work may still be running) and from a reset whose replacement failed to initialize (KernelResetUnavailable…), each in a timeout and a cancellation spelling — reporting a reset that did not happen makes the user stop looking for the work.
attempts.py The terminal state of a durable Cell execution attempt, shared by the CLI LocalActionExecutor and the Web CellExecutionService so the two writers cannot drift. A returned result is interrupted, failed or completed; a Host-side exception is cancelled for a watchdog cancellation, timed_out for a watchdog TimeoutError, and the caller's own fallback otherwise. It never reads error text: a worker's error is the whole user traceback, and a frame passing timeout=timeout, a NameError about a variable called timeout or a urllib connection error all used to be recorded as timeouts — and then shown in the Action Timeline as interrupted rather than failed.
process_group.py Stop a spawned process group and confirm it stopped: TERM, grace, KILL, then probe the group rather than the leader. Shared with the kernel-side host.bash executor, which passed timeout= to subprocess.run with shell=True and so killed the shell while the work it started carried on. Two implementations would have disagreed about exactly that case.
budget.py The four numbers a bounded channel reports: seen, retained, dropped, truncated. Seven buffers in the tree drop input to stay inside a budget and four spellings of the accounting existed, two of them empty — a bound that is enforced and unreported does not produce missing information, it produces a confident wrong answer. A function, not a dataclass, so it cannot become one more declared shape nothing fills in; here rather than in kernel/ for the same reason process_group.py states, since sdk/bash.py imports it from inside the worker.

Concurrency and recovery contract