Skip to content

/reload leaves live Python-extension surface stale/partial on a failed reload (disagrees with vis doctor, which loads the same file with 0 errors) #44

Description

@WZHKAWF

Summary

/reload is documented as reloading Python extensions "in place", but a
reload that reports 1 failed leaves the live session's Python surface
in a stale / partially-updated state instead of either (a) applying the new
module or (b) cleanly keeping the last-good one. The disagreement is observable
because a fresh vis doctor loads the identical file with 0 errors, while
the live session keeps calling the old module and aborting.

Documented contract (docs/python-extensions)

Python extensions … loaded at startup and reloadable in place with /reload
A file that fails to load becomes a warning in vis doctor — it never crashes Vis.

Observed

  1. Edit a project .vis/extensions/<name>.py (add a new tool symbol, fix a load-time bug).
  2. /reload → header reports Python extensions: 0 loaded, 1 failed.
  3. In the same live session, probe the surface:
    • a newly added tool symbol is absent from the sandbox (new module never applied), yet
    • old tool symbols are still bound and, when called, abort with:
      ⚠ error: { "message": "Context execution was cancelled.",
                 "data": {"phase":"host","type":"tool-failure","symbol":"<sym>"} }
      
  4. Run vis doctor on the same on-disk file
    ℹ load: Python extension '<name>' loaded … Summary: 0 errors.

So: doctor load path succeeds, /reload path fails, and after the failed
reload the live surface is neither the new module nor a clean last-good one

it is a stale/partial mix (old symbols present, new symbols missing, calls dead).

Why it matters

  • Violates the "reloadable in place" promise: the only recovery observed is
    restarting Vis; re-issuing /reload in the affected session does not converge.
  • The "1 failed" vs vis doctor "0 errors" discrepancy means the two load paths
    do not share the same loader/validation, so /reload fails on files that are
    actually loadable.
  • A partial apply is worse than a rejected one: callers get an opaque
    phase: host abort (compounded by Extension tool exceptions surface as uncatchable "Context execution was cancelled" instead of the raised message #42) with no way to tell the surface is stale.

Expected

  • /reload and vis doctor use the same loader → a file that loads in doctor
    also reloads in a live session (and vice-versa); the N failed count matches.
  • On a failed reload, the live surface is left in a well-defined state:
    either the previous last-good module is retained wholesale, or the extension's
    symbols are cleared — never a stale mix of old+missing symbols.
  • Surface a clear reason for the 1 failed (which extension, why) the same way
    vis doctor does, instead of only a bare count.

Environment

  • Project-local extension under <project>/.vis/extensions/.
  • Reproduced repeatedly across edit→/reload cycles in one session; vis doctor
    on the same file always reports 0 errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions