Skip to content

Chained exceptions bypass traceback filtering entirely; per-segment filtering was deferred by #197 #203

Description

@CameronBrooks11

Deferred by #197 (the fix for #188). Filed so the deferral has a home rather
than evaporating when #188 closes.

What #197 does, and where it stops

#197 drops partspec's own frames from a traceback when a contract raises,
keeping the user's. It deliberately bails to the unfiltered traceback for
chained exceptions — raise X from Y, and the implicit __context__ chain a
bare raise inside an except block produces.

The reasoning is sound and should be preserved if this is ever picked up:
per-segment filtering means walking the chain and re-emitting CPython's
connector prose (The above exception was the direct cause of the following exception: / During handling of the above exception, another exception occurred:) and the +-+---- 1 ---- group tree by hand. Get a
connector wrong and the output asserts a causal relation that did not happen.
A noisy true trace beats a tidy false one, in a tool whose thesis is that
silence must never read as success.

How big is the affected class?

Smaller than it first appears. Measured across all 21 shipped contract files
(examples/*/*.py, evals/cases*/*/spec.py,
evals/baseline-20260806/*/spec.py):

  • try:/except occurrences: 1 — and it is the word "except" inside a
    docstring
  • raise occurrences: 0

ContractError appears in no example or skill; it occurs only in
docs/SPEC-contract.md, twice, both describing what partspec raises. An AST
sweep of src/partspec/ found zero except: handlers that re-raise
without from, so partspec never manufactures an implicit chain itself.

So try/except → raise ContractError(...) is an idiomatic pattern in
principle but not one this repo's own corpus exhibits. That is an argument for
leaving it deferred, not for closing it — the corpus is our code, and the
users #188 was filed by are not us.

If picked up

Filter each segment of the chain independently while reproducing CPython's
connectors exactly, rather than hand-rolling them. traceback.TracebackException
walks the chain structurally and may make this tractable without string
surgery. Any implementation needs tests for: explicit from, implicit
__context__, from None (__suppress_context__), and a chain whose
segments are themselves ExceptionGroups.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions