Skip to content

bpo-29403: Fix mock's broken autospec behavior on method-bound builtin functions#3

Merged
berkerpeksag merged 3 commits intopython:masterfrom
habnabit:fix-mock-builtin-methods-for-cython
Jul 20, 2017
Merged

bpo-29403: Fix mock's broken autospec behavior on method-bound builtin functions#3
berkerpeksag merged 3 commits intopython:masterfrom
habnabit:fix-mock-builtin-methods-for-cython

Conversation

@habnabit
Copy link
Copy Markdown
Contributor

http://bugs.python.org/issue29403

Cython will, in the right circumstances, offer a MethodType instance
where im_func is a builtin function. Any instance of MethodType is
automatically assumed to be a python-defined function (more
specifically, a function that has an inspectable signature), but
_set_signature was still conservative in its assumptions. As a result
_set_signature would return early with None instead of a mock since the
im_func had no inspectable signature. This causes problems deeper inside
mock, as _set_signature is assumed to always return a mock, and
nothing checked its return value.

In similar corner cases, autospec will simply not check the spec of the
function, so _set_signature is amended to now return early with the
original, not-wrapped mock object.

@the-knights-who-say-ni
Copy link
Copy Markdown

Hello, and thanks for your contribution!

I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA).

Unfortunately we couldn't find an account corresponding to your GitHub username on bugs.python.org (b.p.o) to verify you have signed the CLA. This is necessary for legal reasons before we can look at your contribution. Please follow these steps to help rectify the issue:

  1. If you don't have an account on b.p.o, please create one
  2. Make sure your GitHub username is listed in "Your Details" at b.p.o
  3. If you have not already done so, please sign the PSF contributor agreement
  4. If you just signed the CLA, please wait at least a day and then check "Your Details" on bugs.python.org to see if your account has been marked as having signed the CLA (the delay is due to a person having to manually check your signed CLA)
  5. Reply here saying you have completed the above steps

Thanks again to your contribution and we look forward to looking at it!

@habnabit
Copy link
Copy Markdown
Contributor Author

I signed the CLA when I opened the bug on bpo last week, but my account doesn't say received still: http://bugs.python.org/user25445

@ShalbafZadeh
Copy link
Copy Markdown

@habnabit
have you added you github username to your bpo account?
i can't see it
https://bugs.python.org/user6636

@habnabit
Copy link
Copy Markdown
Contributor Author

@ShalbafZadeh that was an old account; I made a new one last week from a newer openid provider. http://bugs.python.org/user25445 is the new one, which I'm logged into now.

@ShalbafZadeh
Copy link
Copy Markdown

@habnabit seems odd

@habnabit habnabit force-pushed the fix-mock-builtin-methods-for-cython branch from c8bc9c9 to 9148028 Compare February 11, 2017 01:47
@habnabit
Copy link
Copy Markdown
Contributor Author

Rebased and pushed, including a test fix. The third-party mock used six, and the stdlib does not include six.

@habnabit habnabit force-pushed the fix-mock-builtin-methods-for-cython branch 2 times, most recently from e12a088 to 97bb733 Compare February 11, 2017 06:25
@habnabit
Copy link
Copy Markdown
Contributor Author

Rebased again!

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 11, 2017

Codecov Report

Merging #3 into master will increase coverage by <.01%.

@@            Coverage Diff             @@
##           master       #3      +/-   ##
==========================================
+ Coverage   82.37%   82.37%   +<.01%     
==========================================
  Files        1427     1427              
  Lines      350948   350959      +11     
==========================================
+ Hits       289088   289104      +16     
+ Misses      61860    61855       -5

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e7ffb99...97bb733. Read the comment docs.

Copy link
Copy Markdown
Member

@berkerpeksag berkerpeksag left a comment

Choose a reason for hiding this comment

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

I haven't had a time to dive into the whole life cycle of _set_signature() yet, but from a quick glance it looks good to me.

@berkerpeksag
Copy link
Copy Markdown
Member

Please add an entry to Misc/NEWS. It should be in the "Library" section.

@habnabit habnabit force-pushed the fix-mock-builtin-methods-for-cython branch from 97bb733 to c5b3653 Compare February 23, 2017 22:40
@habnabit
Copy link
Copy Markdown
Contributor Author

Okay, rebased and added a NEWS entry.

@Yhg1s
Copy link
Copy Markdown
Member

Yhg1s commented May 22, 2017

This change looks good to me: returning None does not make sense in the one place where _set_signature is called, and I don't think there's a better solution here. If the code wants to try harder and figure out what signature to use, that would be a change to _get_signature, not _set_signature, and this change would still make sense.

@voidspace, do you want to take a look, or can we merge?

@buhtz
Copy link
Copy Markdown

buhtz commented Jul 19, 2017

Can we merge this?

habnabit and others added 2 commits July 20, 2017 02:33
Cython will, in the right circumstances, offer a MethodType instance
where im_func is a builtin function. Any instance of MethodType is
automatically assumed to be a python-defined function (more
specifically, a function that has an inspectable signature), but
_set_signature was still conservative in its assumptions. As a result
_set_signature would return early with None instead of a mock since the
im_func had no inspectable signature. This causes problems deeper inside
mock, as _set_signature is assumed to _always_ return a mock, and
nothing checked its return value.

In similar corner cases, autospec will simply not check the spec of the
function, so _set_signature is amended to now return early with the
original, not-wrapped mock object.
@berkerpeksag berkerpeksag force-pushed the fix-mock-builtin-methods-for-cython branch from 75ad0f4 to 989e99a Compare July 19, 2017 23:35
@berkerpeksag berkerpeksag merged commit 856cbcc into python:master Jul 20, 2017
ericvsmith pushed a commit to ericvsmith/cpython that referenced this pull request Feb 24, 2026
Initial version of !p with f-strings.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 19, 2026
PyMem_RawRealloc of forward_vals array leaves new entries
uninitialized. phx_bs_init checks initialized field (garbage) and
tries to free garbage bits pointer. Fix: memset new entry to zero
before phx_bs_init.

Same bug class as bug python#3 (PhxPhiSupport memset). Found via ASAN:
phx_bv_destroy called from phx_bs_init with garbage bits pointer.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Push 44 W3 Step 5 (final): self-test script that validates the W3 R4
oracle's diagnostic capability via 3 falsifiers + synthetic injection.

Per theologian 2026-04-22 02:30:08Z W3 spec falsifier:
  "inject a synthetic refcount bug into the C path — scripts/
  rc_diff_oracle.sh produces non-empty output. If diff is empty under
  injection, oracle is non-functional and W3 has not delivered the
  diagnostic capability it promised."

Script structure:
  --check mode: pre-conditions only (3 nm-based assertions)
  default: pre-conditions + Phase A (clean diff = empty) + Phase B
           (injected diff = non-empty) + post-restore verification

FALSIFIERS validated:
  python#1 — production python has 0 rc_oracle symbols (RC_ORACLE undefined,
       dispatcher block ABSENT from compiled binary). VERIFIED via
       --check mode at HEAD a99db92: 'PASS: production python has 0
       rc_oracle symbols'.
  python#2 — libphoenix_rc_oracle.a exports rc_oracle_run T-symbol. VERIFIED:
       'PASS: scratch lib exports rc_oracle_run (C entry point)'.
  python#3 — python_rc_cpp has rc_oracle_run T-symbol. PENDING — operator must
       run out-of-band link via the recipe in scripts/build_oracle.sh
       tail (per supervisor 02:51:14Z option (c)).

INJECTION mechanism:
  Phase B comments out the FIRST 'phx_rc_emit_incref' call site in
  Python/jit/hir/refcount_pass_c.c via sed. Rebuilds C path. Runs
  rc_diff_oracle.sh and asserts non-empty diff. Restores via backup +
  rebuild. Final verification: post-restore diff is empty.

  Injection target chosen for stability: phx_rc_emit_incref is a
  high-frequency call across all refcount_insertion paths; commenting
  one removes one Incref → guaranteed runtime divergence under
  Py_REF_DEBUG (under-count → leak) AND under PYDEBUG (use-after-free).

  Injection is reversible: cp $INJECT_TARGET.oracle_backup back +
  rebuild. trap EXIT ensures restore even on script error.

Per supervisor 02:51:14Z option (c): out-of-band link of python_rc_cpp
is operator-driven (not embedded in this script), since W3 is a
one-shot oracle resurrection; no permanent Makefile.pre.in touch.

Pre-commit verification:
  bash -n: SYNTAX OK
  scripts/rc_oracle_self_test.sh --check: pre-conditions python#1, python#2 PASS;
  python#3 expected to FAIL until operator runs the link recipe.

Push 44 W3 batch is now 2 commits (per supervisor 02:51:14Z amended):
  a99db92 — W3 Steps 1-4 bundled (scratch lib + dispatcher + adapter)
  THIS COMMIT — Step 5 self-test
ABBA cap 15 → 17. MANDATORY ABBA + auto-compile re-experiment after
push 44 lands per pre-authorization.

Process lesson applied (per supervisor 02:51:14Z): explicit
'git add scripts/rc_oracle_self_test.sh' (single file) + 'git diff
--cached --stat' verification BEFORE commit, to avoid the over-broad
staging that produced a99db92's bundled scope.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Convert HIRBuilder::emitLoadMethodOrAttrSuper from C++ multi-block
deopt+dispatch to a thin delegation stub. New C function
hir_builder_emit_load_method_or_attr_super_c builds the deopt path
(snapshot+deopt) and fast path (CondBranchCheckType + RefineType +
LoadAttrSuper or LoadMethodSuper+GetSecondOutput).

C++ stub computes nothing — passes oparg + bc_offset.value() through
to C. The C body computes name_idx/load_method/no_args from oparg
(3.11+ packing per theologian audit python#3 — load_method param overwrite),
following the project's 3.12-only convention dropping the pre-3.11
oparg-tuple branch.

Theologian invariant audit (2026-04-22 11:58:52Z) drives the
implementation:

  python#1 phx_frame_state_copy runs BEFORE the 3 pops so deopt-path frame
     preserves PRE-POP stack for interpreter resumption
  python#4 pop order: receiver (TOS), type, global_super
  python#5 push order varies by load_method (1 value vs 2)
  python#8 deopt-path emits go into deopt_tc.block
  python#9 CondBranchCheckType branches; tc.block <- fast_path; emit
     RefineType in-place

Both exit paths phx_frame_state_destroy the deopt_tc to avoid leaking
the heap-allocated stack/locals arrays.

testkeeper pre-commit verify (2026-04-22 12:15:46Z): JIT_BUILD_EXIT=0,
full BUILD_EXIT=0, 7/7 phoenix-jit tests PASS at HEAD+uncommitted.
W26 gate-hardening not triggered (no recent fail).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Per pythia python#76 [chat 16:45Z] + supervisor revision [chat 16:45Z python#3]:
filed-not-owned workstreams accrue weed-debt ('a field marked for
fallow grows weeds named next year'). W27 was filed at bf8982b
without ownership, falsification test, or revisit-trigger.

Added §1 frontmatter:
  - Owner: theologian (design), generalist (implementation)
  - Schedule: entry-trigger = Tier 5 ZERO C++ complete + no active
    push-class blocker; exit by start of cinderx Tier 6 cleanup
  - Falsification test reference: §8

Added §8 falsification test sketch:
  Lib/test/test_phoenix_w27_module_unload_uaf.py
  - SKIPPED until W27 work begins
  - Reproducer: register cache entry → del sys.modules → gc.collect →
    fire builtins event → expect SEGV pre-W27 / clean post-W27
  - Acceptance: reproduces SEGV pre-W27 + passes post-W27, OR W27
    scope re-opens if reproducer is harder to trigger than predicted
  - Discipline: 'falsification-first' — test lands before fix code

Added §7 cross-references:
  - Push 58 ARM64-pydebug coredump finding from testkeeper [chat
    16:45Z]: 8b7b935 baseline ALSO produces shutdown coredump
    on the same falsifier workload (just non-deterministic vs push
    59's deterministic SEGV) — independent confirmation that this
    is pre-existing latent (pythia python#75 b1 outcome) not push-59-port-
    shape-specific
  - W27 ownership update authority chain

This commit IS supervisor's pythia python#76 python#3 corrective action — turning
'filed' into 'owned, scheduled, testable'. Pattern reusable: same
audit will be applied to W23 (verifier hardening), W25 (typed bridges),
W26 (build-state hardening) per supervisor [chat 16:45Z python#3] deferral.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Sibling of emitInlineExceptionMatch (~95% shared per theologian PTE
pre-audit chat 2026-04-22 16:53Z). Shared-helper design (option a) —
D-1774910012 PA invariant lives in EXACTLY ONE C body across both
callers, eliminating invariant-drift surface.

  Python/jit/hir/builder.cpp:
    emitCallExceptionHandler C++ body (160 lines) → C++ stub (~75 lines):
      D1 pre-amble: setSuppressExceptionDeopt(true) + pop result
      Build OpcodeArrayEntry_CXX vector (same shape as inline-match)
      Call new C body via hir_builder_emit_call_exception_handler_c
    Net: -167 (replaces inline body with stub call)

  Python/jit/hir/builder_emit_c.c:
    NEW static helper emit_except_match_body_c (~140 lines):
      P2: exc_tc setup + depth-trim
      P2 inv 8-13: exc_type_reg + JITRT_MatchAndClearException CallStatic + CondBranch
      P3: match_tc setup + (PA D-1774910012) Py_None push + dispatch loop (10 cases + default→deopt)
      P4: deopt_tc setup (origin = tc.frame per PB.b) + optional left/right re-push + Snapshot + Deopt
      PE: phx_frame_state_destroy on EXACTLY 3 TCs (exc_tc, match_tc, deopt_tc)
    REFACTORED hir_builder_emit_inline_exception_match_c (~30 lines):
      P1 (getitem CallStatic) + ok_block alloc + CondBranch + helper-call + P5 RefineType
      Passes left/right as deopt_repush args (BINARY_SUBSCR offset expects them).
    NEW hir_builder_emit_call_exception_handler_c (~30 lines):
      ok_block alloc + CondBranch on result + helper-call + D3 P5 RefineType + push result
      Passes NULL/NULL deopt_repush args (call-result already popped on C++ side).
    Net: +85 (helper extraction + new C function)

PTE-trial invariant inventory verification per theologian [chat L1899]:
  29 invariants total = 26 SHARED (in helper, single-source) + 3 UNIQUE (D1/D2/D3).
  PA D-1774910012: helper guarantees Py_None push + POP_EXCEPT pop, no callsite
    can violate. Mutation-test sensitivity preserved (same code path as push 59).
  PB pitfalls: helper enforces deopt_origin = tc (not exc_tc).
  PE: helper destroys all 3 TCs unconditionally before return.

ZERO new bridges per theologian [chat L1899] gate verdict:
  Reuses hir_c_create_call_static_reg, hir_c_create_load_const,
    hir_c_create_cond_branch_cpp, hir_c_create_branch_cpp,
    hir_c_create_snapshot, hir_c_create_deopt, hir_c_create_refine_type_reg,
    hir_c_create_return, hir_builder_emit_swap_c/load_fast_c/store_fast_c/binary_op_c.

Bundled W25 metadata update per supervisor [chat L1894] decision (a):
  docs/w25-typed-bridges.md §7 PARKED — Owner+Schedule+Falsification+Closure
  criteria fields added per pythia python#76 python#3 fallow-workstream discipline. Theologian-
  authored, gen-staged + bundled into this commit (gate-cycle efficiency).

testkeeper x86_64 compile-only PASS verified pre-commit at binary timestamp
1776877216 (chat L1900). Awaiting ARM64 pydebug --clean + 8-test gate +
push 58 baseline regression check before push.

Authorization chain:
  - theologian PTE pre-audit + STRONG (a) lean: chat L1899
  - emitCallExceptionHandler queue unblocked: supervisor chat L1894 (b1 outcome)
  - W25 metadata bundle option (a): supervisor chat L1894
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
…/144 = 71.5%)

PartialConversion per theologian PTE pre-audit (chat 2026-04-22 17:15Z) +
supervisor concurrence (chat 17:18Z) + Alex 'NO SESSION BOUNDARIES — keep
working until ZERO C++' anchor [memory 2026-04-21]. Bridge-count gate
satisfied: 1 new top-level bridge (within gate), 0 sub-bridges.

SCOPE: only the await-tail dispatch (lines 2963-2993 in pre-conversion
source) is converted to C. The opcode-switch + INVOKE_FUNCTION/NATIVE/
METHOD/METHOD_VECTORCALL dispatch stay C++ until Tier 6 INVOKE_*
re-architecture (deferred per gate-count gate per [chat L1922]:
FullConversion would require 4+ new bridges, violating ≤1 limit).

  Python/jit/hir/builder.cpp:
    emitAnyCall await-tail block (lines 2963-2993, ~30 lines C++) →
    1) C++ stub: 3x ++bc_it + 3x JIT_CHECK on opcode sequence (PA + A4) +
       checkAsyncWithError(get_awaitable_bc) → (error_aenter, error_aexit) +
       extract load_const_oparg from LOAD_CONST bc + call C body
    2) checkAsyncWithError forward decl added (defined static at builder.cpp
       :~4856, post-call-site refactor required forward visibility)
    3) New extern decl: hir_builder_emit_awaited_call_tail_c

  Python/jit/hir/builder_emit_c.c:
    NEW hir_builder_emit_awaited_call_tail_c (~50 lines):
      A5 alloc out + 2 blocks (await_block + post_await_block)
      A5 dispatch_eager_coro_result (chains to push 55 C function)
      A6 tc->block = await_block
      A7 get_awaitable using pre-computed error flags (chains to push 56)
      A8 load_const using pre-computed oparg + caller-passed code
      A9 yield_from_method (chains to push 53)
      A10 phx_tc_emit branch to post_await_block
      A11 tc->block = post_await_block

PTE-trial invariant inventory verification per theologian [chat L1928]:
  12 invariants A1-A12 + 4 pitfalls PA-PD.
  PA: JIT_CHECK fires C++-side BEFORE C call ✓
  PB: iterator state stays C++-side; only ints + pointers cross boundary ✓
  PC: tc->block reassignment in C body (A6 + A11) ✓
  PD: code passed as PyCodeObject* (not void*) — preserves emitGetAwaitable
      port's PA invariant ✓

PTE TRIAL ROUND 2 FEEDBACK: A4 IF/THEN structure made
'JIT_CHECK MUST fire BEFORE C call' visually unambiguous. PD pitfall
on code_ typing caught at design time. Two empirical wins
(round 1: PD.a/PD.b distinction, round 2: A4 + PD).

Bridge spec (8 args, ratified by theologian [chat L1931]):
  void hir_builder_emit_awaited_call_tail_c(
      PhxTranslationContext* tc, void* func, void* builder,
      PyCodeObject* code, int code_flags,
      int get_awaitable_error_aenter, int get_awaitable_error_aexit,
      int load_const_oparg);

testkeeper x86_64 compile-only PASS verified pre-commit at binary
timestamp 1776878644 (chat 17:24Z). Iter 1 needed forward decl for
checkAsyncWithError; v2 cleaned.

Tier 5 milestone: 103/144 = 71.5% with PartialConversion-asterisk on
emitAnyCall (await-tail in C, opcode-switch + INVOKE_* still C++).

Pre-push 61 gate ahead (per pythia python#77 python#3 + supervisor [chat L1939]):
  testkeeper authors call-shape falsifier extension exercising
  emitCallExceptionHandler D1-D3 invariants (theologian spec [chat L1942]:
  3 tests covering function-call-in-try + closure-LOAD_DEREF +
  unmatched-exception-deopt). Lands as separate commit before
  Tier 5 close push.

Authorization chain:
  - theologian PTE pre-audit + design lean (a, but generalist chose b): chat L1928
  - bridge spec ratification: chat L1931
  - supervisor concurrence on (B) PartialConversion: chat L1930
  - testkeeper x86_64 compile PASS: chat L1944
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Per pythia python#77 python#3 [chat L1937] gap + supervisor [chat L1939] authorization +
theologian [chat L1942] spec: extend test_phoenix_jit_inline_except_closure.py
with TestJitCallExceptionHandler class covering 3 tests that exercise the
emitCallExceptionHandler unique invariants (D1-D3) NOT covered by the
existing inline-except (BINARY_SUBSCR_DICT) tests.

GAP CONTEXT: push 60 (9630005) landed emitCallExceptionHandler with
shared-helper design — D1-D3 unique invariants ride only the shared
P2+P3+P4 helper through the closure-LOAD_DEREF inline-except falsifier.
Call-shape (function-call-in-try) was empirically untested at push 60.
This falsifier closes that coverage gap retroactively.

  Lib/test/test_phoenix_jit_inline_except_closure.py:
    +135 lines, new class TestJitCallExceptionHandler with 3 tests:
    - C1 test_call_in_try_simple_except: function-call-in-try, ValueError
      matched + return from except. Exercises D1 (setSuppressExceptionDeopt
      + pop result pre-call) + D3 (RefineType + result push on OK path).
    - C2 test_call_in_try_with_closure_load_deref: function-call-in-try,
      LOAD_DEREF on closure variable in except body. Exercises D1-D3 +
      PA (D-1774910012 prev_exc Py_None placeholder under
      emitCallExceptionHandler entry).
    - C3 test_call_in_try_deopt_path: function-call-in-try, unmatched
      exception (TypeError vs except ValueError). Exercises D2 (DeoptTC
      zero re-push, no left/right context — call-handler doesn't have
      left/right unlike inline-match).

EXISTING TESTS PRESERVED unchanged:
  TestJitInlineExceptClosure (3 tests) — D-1774910012 PA invariant
    via inline-except path, retained as the original falsifier.

EMPIRICAL VALIDATION RESULT (testkeeper [chat L1946]):
  Run on push 60 binary 9630005 (ARM64 pydebug):
    6/6 PASS, OK, 0.177s, EXIT=0, NO core dump.
  All D1-D3 invariants empirically validated; PA preserved across both
  call-handler and inline-match entry paths.

PYTHIA python#77 python#3 SUBSTANCE CLOSED:
  D1-D3 unique invariants now empirically exercised, not only ride-along
  through shared helper. Falsifier-pre-port discipline restored for
  emitCallExceptionHandler (regression test exists post-port; ideal would
  have been pre-port but supervisor [chat L1939] accepted post-port
  retroactive validation as remediation).

Bundled with push 61 (b28b512 emitAnyCall PartialConversion, Tier 5
close) per testkeeper [chat L1946] (a) sequencing — single gate cycle,
single push, no separate gate ceremony for .py-only change.

Authorization chain:
  - pythia python#77 python#3: chat L1937 (gap surfaced)
  - supervisor authorization: chat L1939
  - theologian spec: chat L1942
  - testkeeper draft + push-60-binary validation: chat L1946
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Per pythia python#79 python#3 [chat L2032] + supervisor [chat L2034] assignment:
the brace-counted scan methodology that produced 100/123 = 81.3%
Tier 5 close ratio existed only in chat history (D-1776880902). Anyone
re-grepping in two weeks reproduces the same /144-class lapse.

This script anchors the methodology in repo:
  - Brace-balanced extraction of HIRBuilder::emit* method definitions
    (multi-line signatures + any return type + balanced { } body)
  - Categorization: stub (≤8 body lines + has hir_builder_emit_*_c call) /
    partial (>8 body lines + has C call) / pure C++ (no C call)
  - Output: counts + exhaustive pure-C++ + partial method lists

Reference values verified at HEAD a642405 (post-Tier-5-close, push 62):
  TOTAL: 123
  STUBS: 93
  PARTIAL: 7
  PURE C++: 23
  RATIO: 100/123 = 81.3%

Closes pythia python#79 python#3 'methodology not committed to repo' substance.
Anyone running scripts/count_emit_methods.sh reproduces the canonical
baseline without needing chat-search or external memory.

Origin lessons embedded in script header:
  - /144 propagated 2026-04-21 (commit 7783df7) → 2026-04-22 Tier 5 close
  - Real denominator at HEAD a642405 was 123 (pythia python#78 python#1 catch)
  - Methodology lives in repo, not chat

Authorization chain:
  - pythia python#79 python#3 surfaced gap: chat L2032
  - supervisor python#3 assignment: chat L2034
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Per W25 spec §3 Step B + theologian L2189 4-class taxonomy. B-1 batch
(~10 lint-pattern externs across 3 small TUs) per spec §3 sequencing
(B-0 cfg.cpp d0e8031 validated Class C2 pattern; B-1 scales to
Class A + Class C2 mix).

PER-TU CLASS CLASSIFICATION + CLEANUP:

  ssaify_c.c (1 lint extern):
    hir_func_alloc_register → Class A (hir_c_api.h:52)
    Fix: add #include hir_c_api.h, delete local extern.
    Kept non-lint externs (hir_reflow_types, hir_phi_elimination_run)
    as out-of-W25-scope; tracked separately.

  licm_c.c (3 lint externs):
    hir_func_cfg_ptr → Class C2 (hir_instr_c.h:232 static inline,
      already included via hir_instr_c.h)
    hir_instr_unlink → Class A (hir_c_api.h)
    hir_c_insert_before → Class A (hir_c_api.h:726)
    Fix: add #include hir_c_api.h, delete 3 lint externs.
    Kept hir_reg_instr (non-lint) as out-of-scope.

  resolve_kwargs_c.c (5 lint externs):
    hir_func_cfg_ptr → Class C2 (already accessible)
    hir_instr_replace_with → Class A
    hir_c_create_vectorcall_reg → Class A
    hir_c_create_call_method_reg → Class A
    hir_c_copy_frame_state → Class A
    Fix: add #include hir_c_api.h, delete 5 lint externs + duplicate
    typedef HirFunction (already in hir_c_api.h).
    Kept hir_register_type (non-lint) as out-of-scope.

DIFF: +7/-13 across 3 files (lint extern reduction without API expansion).

DEFERRED to B-2: hir_basic_block_c.c (Class C1 — hir_bb_destroy not
in any header). Needs API-expansion decision before deletion.

PER GATEITEM python#3 HARDENING (post L2174 lapse):
  testkeeper to verify post-commit, working tree clean. Both HEAD-match
  AND tree-clean must hold for valid PASS report.

Authorization chain:
  - W25 spec §3 + 4-class taxonomy: theologian L2017 + L2189
  - B-1 sequencing per supervisor [chat L2179]
  - QUERY-BEFORE-PIVOT discipline applied to scope decisions
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 22, 2026
Per theologian L2430 INVOKE_* Phase 2 spec.

Changes:
  - Python/jit/hir/builder_emit_c.c: new C body
    hir_builder_emit_invoke_function_c (~115 lines). Mirrors C++
    emitInvokeFunction with three paths (A/B/C):
    - Path A: container_is_immutable + is_function + is_statically_typed
      → direct InvokeStaticFunction emit (no VectorCall fallback)
    - Path B: container_is_immutable + is_builtin → tryEmitDirectMethodCall
      fast path
    - Path C: VectorCall fallback (or patchable LoadFunctionIndirect path)

    PY_VERSION_HEX >= 0x030C0000 conditional for __static__.rand
    special-case folded into hir_builder_is_static_rand_and_try_emit_c
    bridge (version-guarded inside the bridge, no #if in C body).

  - Python/jit/hir/builder.cpp: HIRBuilder::emitInvokeFunction becomes
    a 7-line delegation stub. Adds 4 NEW C bridges (function-target
    variants of python#2 bridges, since invokeFunctionTarget != invokeMethodTarget):
    - hir_builder_invoke_function_target_c: 8-field InvokeTarget query
      (container_is_immutable, is_function, is_statically_typed, is_builtin,
      callable, func, indirect_ptr, return_type)
    - hir_builder_try_emit_direct_method_call_for_function_c: path B fast path
    - hir_builder_setup_static_args_for_function_c: arg_regs via VLA
    - hir_builder_is_static_rand_and_try_emit_c: PY_VERSION_HEX folded

  - Python/jit/hir/builder.h: extern "C" forward decls + 4 new friend
    declarations granting bridges access to private members.

C body uses C99 VLA (void *arg_regs[nargs]). CallFlags::Static = 1<<2
hardcoded as 4u (matches hir.h:881-886). Direct C calls to
hir_c_create_invoke_static_function_reg + hir_c_create_load_function_indirect_reg
+ hir_c_create_load_const + hir_c_create_vectorcall_reg (all already exist
in hir_c_api.h, no new factories needed). hir_type_from_object handles
Type::fromObject conversion in C.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
Sole-path validation pending — INVOKE_FUNCTION only emitted in __static__
modules, standard test suite does not exercise.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
PRIMITIVE_BINARY_OP (Static Python) opcode handler. Per W27a Step A scope.

C body: hir_builder_emit_primitive_binary_op_c (~75 lines incl static
helpers inlined). Inlines get_primitive_bin_op_kind (PRIM_OP_* → HIR_BOP_*
mapping) + is_double_binop (DBL variant detection) directly into a single
switch statement.

PHX_PRIM_OP_* values hard-coded to mirror cinderx/StaticPython/classloader.h:
70-90 — same pattern as builder_emit_c.c:2862 avoidance of classloader.h
in C TU (header pulls in extensive C++-cinderx surface). Static Python ABI
is stable; values unchanged across releases.

C primitives used: hir_c_create_int_binary_op + hir_c_create_double_binary_op
+ hir_builder_temps_alloc_stack (all existing).

C++ HIRBuilder::emitPrimitiveBinaryOp → 3-line delegation stub.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
Sole-path validation: PRIMITIVE_BINARY_OP only in __static__ modules
(emitInvokeNative precedent caveat acknowledged).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
PRIMITIVE_COMPARE_OP (Static Python) opcode handler. Per W27a Step A scope.

C body: hir_builder_emit_primitive_compare_c (~50 lines). Inlines the
PRIM_OP_* → HIR_PCMP_* mapping switch directly. Reuses PHX_PRIM_OP_*
defines from python#3 (emitPrimitiveBinaryOp).

C primitives used: hir_c_create_primitive_compare + hir_builder_temps_alloc_stack
(both existing).

C++ HIRBuilder::emitPrimitiveCompare → 3-line delegation stub.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
BUILD_CHECKED_LIST (Static Python) opcode handler. Per W27b Step A scope.

C body: hir_builder_emit_build_checked_list_c (~25 lines). Pops descr +
list_size from const_arg tuple, queries preloader type+py_type via
existing bridges, emits make_checked_list_reg, fills operands right-to-left
from stack.

Includes added: cinderx/StaticPython/checked_list.h (Ci_CheckedList_TypeCheck).
Header verified C-safe: Ci_CHECKED_LIST_H guard (unique), no Py_OPCODE_H
collision (theologian L2515 caveat satisfied).

C primitives used: hir_builder_preloader_type + hir_builder_preloader_py_type
+ hir_c_create_make_checked_list_reg + hir_c_set_operand
+ hir_builder_temps_alloc_stack (all existing).

C++ HIRBuilder::emitBuildCheckedList → 3-line delegation stub.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
Helper for emitSetupWith + emitBeforeWith. Per W27c Step A scope.

C body: hir_builder_emit_setup_with_common_c (~45 lines). Pops manager,
allocates enter+exit, emits load_attr_special_reg for both, pushes exit,
allocates enter_result, emits vectorcall_reg with CallFlags::None=0u,
sets enter as operand 0, sets frame state, emits.

PY_VERSION_HEX conditional (_Py_Identifier vs PyObject*) folded into C++
stub: ids are passed as opaque void* downward. is_async drives error
message text selection.

NEW BRIDGE: hir_builder_emit_setup_with_common_c — out-param returns
enter_result via void**.

C primitives used: hir_c_create_load_attr_special_reg + hir_c_create_vectorcall_reg
+ hir_c_set_operand + hir_deopt_set_frame_state + hir_builder_temps_alloc_stack
(all existing).

C++ HIRBuilder::emitSetupWithCommon → 6-line bridge stub returning
Register* via cast of out-param.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
This is the chain-dep root for W27c python#2 (SetupWith) + python#3 (BeforeWith).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
BEFORE_WITH/BEFORE_ASYNC_WITH (3.12+) + pre-3.12 BEFORE_ASYNC_WITH opcode
handler. Per W27c Step A scope.

C body: hir_builder_emit_before_with_c (~17 lines). Calls SetupWithCommon
helper (W27c python#1) → push enter_result. Simpler than SetupWith — no
SetupFinally call.

PY_VERSION_HEX + opcode-branch conditional folded into C++ stub:
  - pre-3.12: __aenter__/__aexit__, is_async=1
  - 3.12+ BEFORE_ASYNC_WITH: __aenter__/__aexit__, is_async=1
  - 3.12+ BEFORE_WITH: __enter__/__exit__, is_async=0

ZERO new bridges (uses W27c python#1 helper).

C++ HIRBuilder::emitBeforeWith → ~25-line stub (PY_VERSION_HEX + opcode
branch + delegation).

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
MATCH_CLASS (mainline) opcode handler. Per W27d Step A scope.

C body: hir_builder_emit_match_class_c (~70 lines). Pops names/type/subject.
Loads nargs as TCUInt64 const. Emits MatchClass → attrs_tuple. Refines to
TOptTupleExact = TTupleExact|TNullptr (constructed via hir_type_union per
theologian L2544 fallback — HIR_TYPE_OPTTUPLEEXACT not defined). Cond-branch:
true_block refines to TTupleExact + (pre-3.12) loads Py_True; false_block
emits CheckErrOccurred + (pre-3.12 Py_False+assign-subject; 3.12+ Py_None
+assign-none). Converges at done.

ZERO new bridges.

C primitives: hir_c_create_load_const + hir_c_create_match_class_reg2 +
hir_c_create_refine_type_reg + hir_c_create_cond_branch +
hir_c_create_check_err_occurred_reg + hir_c_create_assign_reg +
hir_c_create_branch_cpp + hir_type_from_cuint + hir_type_union +
hir_type_from_object + hir_func_alloc_register + hir_cfg_alloc_block
+ hir_builder_temps_alloc_stack (all existing).

C++ HIRBuilder::emitMatchClass → 4-line delegation stub.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
Sole-path: MATCH_CLASS is mainline-tested per theologian L2544
coverage observation.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
…ERO C++

SEQUENCE_GET (Static Python) opcode handler. FINAL emit-method conversion
in W27 burndown. Per W27d Step A scope.

C body: hir_builder_emit_sequence_get_c (~85 lines). Same shape as
emitSequenceSet (W27c python#5) + SEQ_SUBSCR_UNCHECKED bit gating + emitLoadArrayItem
(vs StoreArrayItem):
  - oparg & SEQ_SUBSCR_UNCHECKED set → skip CheckSequenceBounds, raw idx
  - else CheckSequenceBounds + adjusted_idx
  - Per (oparg & ~UNCHECKED): SEQ_LIST/INEXACT/CHECKED_LIST → load_field
    'ob_item' at PyListObject offset + TCPtr; SEQ_ARRAY_INT64 → load_const
    offset + load_field_address
  - LoadArrayItem with element_type_from_seq_type(oparg)

PHX_SEQ_SUBSCR_UNCHECKED = (1<<3) = 8 hard-coded inline.
PHX_SEQ_* base values reused from W27c python#5 (PHX_SEQ_LIST/TUPLE/LIST_INEXACT/
CHECKED_LIST/ARRAY_INT64).

ZERO new bridges.

C primitives: hir_c_create_load_field_reg + hir_c_create_guard_is_reg +
hir_c_create_refine_type_reg + hir_c_create_check_seq_bounds_reg +
hir_c_create_load_field_address_reg + hir_c_create_load_array_item_reg +
hir_c_create_load_const + hir_type_from_cint +
hir_builder_temps_alloc_stack (all existing).

C++ HIRBuilder::emitSequenceGet → 4-line delegation stub.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
Sole-path: SEQUENCE_GET is __static__-only per accepted-residual L2531.

🎯 W27d CLOSURE — ZERO C++ ACHIEVED for emit-methods:
  W27d python#1: emitCopyFreeVars
  W27d python#2: emitGetYieldFromIter
  W27d python#3: emitMatchClass
  W27d python#4: emitMatchMappingSequence
  W27d python#5: emitSequenceGet (THIS)

Pure-C++ count: 5 → 0 / 123 (100% per scripts/count_emit_methods.sh).
Total W27 burndown: 20 → 0 across 4 batches (W27a/b/c/d).
W27e residual paragraph (theologian L2533) attached to closure announcement
to Alex (10 __static__-only methods accepted-residual per Phoenix-doesn't-
expose-Static-Python framing).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
Per supervisor L2565 + theologian L2569 ACK. Reduces C++ stub from
~13 lines to 8 lines (qualifies as STUB).

Strategy: change bridge convention from caller-allocates-out to
callee-allocates-out. C body of bridge now allocates 'out' internally
via hir_builder_temps_alloc_stack. Both call sites (C++ stub at
builder.cpp + C-body call from emit_any_call_c) updated to drop
the explicit out alloc.

Bridge sig change: void *out param removed (was 4th arg). Falsification
discipline: change is mechanically validated by build (callers updated
in same commit) — no signature drift surface beyond the tightening.

Verification: cmake --build target jit/phoenix_jit clean (BUILD_EXIT=0).
Pure-C++ count unchanged (still 0); PARTIAL count drops 9→8.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
Per supervisor [chat L2626] + L2742 + librarian L2737 (close pythia python#87
python#3 ephemera-gap durably).

Captures empirical W26 push 84 incident (95c9f9b1553c14 fix):
- Both cinder_opcode_ids.h + Include/opcode.h use Py_OPCODE_H guard
- Include order silently shadows whichever loads second
- W26 case: BINARY_OP_ADD_INT undefined → attr_probe HIR regression
  caught by W21 golden trip-wire

Three resolution options enumerated:
- (A) rename cinder_opcode_ids.h guard to CINDERX_OPCODE_IDS_H —
  recommended, eliminates collision class
- (B) static_assert in cinder_opcode.h to detect collision at compile
  — hardens detection without fixing
- (C) header-comment only — current state, NOT recommended (chat-
  ephemera proven insufficient)

Related W29 candidate noted: PHX_PRIM_OP_* / PHX_PRIM_UOP_* hard-coded
in builder_emit_c.c lines 3727-3746 with no static_assert binding to
classloader.h authoritative #defines (per pythia python#89 python#3 re-issue).

DEFERRED per supervisor — schedule post-Batch-2 burndown, before any
upstream sync touching Include/opcode.h or classloader.h.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
…r.cpp

Per supervisor 21:27:42Z + theologian 21:28:13Z methodology cross-check:
4 caller-search patterns (word-boundary + fn-pointer + Lib/test
substring + broad), 1 caller (FORMAT_SIMPLE bytecode dispatch at
builder.cpp:2457), argument-forwarding equivalence verified.

Caller-rewrite: FORMAT_SIMPLE case now invokes
hir_builder_emit_format_simple_c(&tc, current_func_, this) directly
instead of going through the C++ method wrapper. Extern "C" decl
hoisted to file-scope (builder.cpp:56) so the dispatch loop has
visibility before the method's original location.

Numstat (verified pre-commit per shepard 20:41:46Z + supervisor
20:16:25Z discipline):
  builder.cpp   +4/-8   (NET -4; 3-line wrapper deleted + 4-line
                          comment block deleted + 1-line extern decl
                          hoisted to file scope + 4-line comment hoist
                          NET -4 — see split below)
  builder.h     +0/-1   (NET -1; method declaration removed)

Bundle: -5L net, ZERO new bridges (existing C function + existing
extern decl, just relocated).

Pattern validated for Phase 1 batch-of-N scaling per supervisor
21:26:49Z 'Phase 1 python#3 will be batch-of-5+ aggressive across simple
1-caller methods'.

Verified at HEAD post-fix:
  test_phoenix_jit_comparisons + controlflow + autocompile +
    partial_conversions: 369/369 PASS (no regression).
  W44 DO-NOT-USE caller gate: PASS (2 markers, 0 violations).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
Per supervisor 21:39:13Z + theologian 21:39:06Z methodology cross-check
PASS for batch-of-5: emitBuildCheckedList + emitBuildCheckedMap +
emitSequenceGet + emitSequenceSet + emitGetYieldFromIter.

All 5 had 1 caller in builder.cpp dispatch + 0 fn-pointer + 0 Lib/test
substring (caller-search per supervisor 21:13:23Z scope: full repo + .py
+ Lib/test). All 5 were pure delegation stubs (no logic before C call).

Pattern (validated by Phase 1 python#2 emitFormatSimple precedent):
  1. Hoist extern "C" decl to file scope (builder.cpp:54-62)
  2. Rewrite caller in dispatch switch to call C function directly
  3. Delete C++ method wrapper + decl

emitBeforeWith DROPPED from batch (25-line PY_VERSION_HEX-conditional
logic violates 0-bridge constraint per theologian 21:39:06Z; defer to
single-method batch later).

emitGetYieldFromIter caller-rewrite preserves required casts per
theologian warning 21:39:06Z: static_cast<int>(co_flags) +
static_cast<void*>(&PyCoro_Type).

Numstat (verified pre-commit per shepard 20:41:46Z + supervisor
20:16:25Z discipline):
  builder.cpp   +14/-53   (NET -39; 5 wrapper bodies deleted + 5
                            extern decls migrated to file-scope
                            comment block)
  builder.h     +0/-13    (NET -13; 5 method declarations removed)

Bundle: -52L net, ZERO new bridges (all 5 C functions + extern decls
already existed; just relocated externs to file-scope).

Verified at HEAD post-fix:
  test_phoenix_jit_comparisons + controlflow + autocompile +
    partial_conversions: 369/369 PASS (no regression).
  W44 DO-NOT-USE caller gate: PASS (2 markers, 0 violations).

Phase 1 burndown advances: builder.cpp 4900→4859 (-41 lines beyond
Phase 1 python#2 baseline). Pattern repeats cleanly for next batch on the
remaining 1-caller / pure-delegation methods.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
…oadSpecial/MatchClass/MatchMappingSequence/Send)

Per supervisor 21:45:14Z + theologian 21:45:17Z methodology cross-check
PASS for batch-of-5: emitCopyFreeVars + emitLoadSpecial + emitMatchClass
+ emitMatchMappingSequence + emitSend.

Methods deleted (all bytecode-dispatch overloads, NOT the inline
helpers in HIRBuilder class body that share the same name with
Register*-based signatures — overload distinction verified by
theologian on disk: helper at builder.cpp:710/807/859 vs dispatch at
:4642/4679/4728).

emitSetupWith DROPPED from batch (25-line PY_VERSION_HEX-conditional
enter_id/exit_id logic = Cat-B per emitBeforeWith precedent in python#3).

6 caller-rewrites (multi-caller methods: emitCopyFreeVars × 2 at
1065+1878, emitMatchMappingSequence × 2 at 2408+2412; single-caller
methods: emitLoadSpecial+emitMatchClass+emitSend × 1 each).

Numstat (verified pre-commit per shepard 20:41:46Z + supervisor
20:16:25Z discipline):
  builder.cpp   +18/-60   (NET -42; 5 wrapper bodies + 5 inline extern
                            decls deleted, +18 from caller-rewrite
                            expansions and 5 file-scope extern decls
                            for the new C dispatch targets)
  builder.h     +0/-12    (NET -12; 5 method declarations removed)

Bundle: -54L net, ZERO new bridges (5 existing C functions reused via
file-scope extern hoists; matches Phase 1 python#3 -52L precedent).

Verified at HEAD post-fix:
  test_phoenix_jit_comparisons + controlflow + autocompile +
    partial_conversions: 369/369 PASS (no regression).
  W44 DO-NOT-USE caller gate: PASS.

Phase 1 cumulative burndown: -35 (python#1+python#1.5) + -5 (python#2) + -52 (python#3) +
-54 (python#4) = -146L total. builder.cpp 4859→4817.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 23, 2026
Per supervisor 21:54:07Z + theologian 21:53:58Z methodology cross-check
PASS for batch-of-6: emitPrimitiveLoadConst + emitPrimitiveBox +
emitPrimitiveUnbox + emitPrimitiveBinaryOp + emitPrimitiveCompare +
emitPrimitiveUnaryOp.

All 6 had 1 caller each in builder.cpp dispatch (lines 2005/2009/2013/
2017/2021/2025) + Lib/test/ scope EMPIRICALLY VERIFIED clean per
theologian 21:53:58Z (grep -E 'emitPrimitive(LoadConst|Box|Unbox|
BinaryOp|Compare|UnaryOp)' Lib/test/test_phoenix_*.py = 0 references).

Methods deleted (all bytecode-dispatch overloads). Inline helpers in
HIRBuilder class body with Register*-based signatures (lines 944, 733,
456, 978) STAY — distinct overloads. tc.emitPrimitiveBox /
tc.emitPrimitiveUnbox at lines 3875/3884 are TranslationContext class
methods (different class) — NOT affected.

6 caller-rewrites (lines 2005, 2009, 2013, 2017, 2021, 2025) at
bytecode dispatch.

Numstat (verified pre-commit per shepard 20:41:46Z + supervisor
20:16:25Z discipline + supervisor 21:54:07Z 'commit-message count = 6
caller-rewrites avoid python#4 annotation typo'):
  builder.cpp   +14/-62   (NET -48; 6 wrapper bodies + 6 inline extern
                            decls deleted, +14 from caller-rewrite
                            expansions and 6 file-scope extern decl
                            hoists)
  builder.h     +0/-18    (NET -18; 6 method declarations removed,
                            3 lines per declaration)

Bundle: -66L net, ZERO new bridges (6 existing C functions reused via
file-scope extern hoists).

Verified at HEAD post-fix:
  test_phoenix_jit_comparisons + controlflow + autocompile +
    partial_conversions: 369/369 PASS (no regression).
  W44 DO-NOT-USE caller gate: PASS (2 markers, 0 violations).

Phase 1 cumulative burndown: -35 (python#1+python#1.5) + -5 (python#2) + -52 (python#3) +
-54 (python#4) + -66 (python#5) = -212L total. builder.cpp 4817→4769.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 24, 2026
…nix.sh

Adds Step 1g per spec §2.7.3 python#3, invoking
scripts/w45_section_3_5_derivation_drift.sh --strict after Step 1e
(W44 DO-NOT-USE caller gate). Step 1f reserved for future W45 §1-§2
bridge-sig falsifier integration.

Pattern mirrors Step 1e (W44): capture output, exit code, GATE_PASS
flag, FAILURES annotation. ~15L diff.

Authorization: supervisor 00:22:51Z post-push priority (1) per spec
§2.7.3 python#3 integration step; ~10L estimate (actual 15L for output
capture + failure annotation parity with Step 1e).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 24, 2026
Theologian 01:53:41Z draft per shepard 01:53:07Z + pythia python#104 (3) +
supervisor 01:53:55Z GO. Adds proactive complement to existing gate python#3
(HEAD==binary AND tree-clean during build, REACTIVE detection at
build-symptom).

4-step discipline for multi-file (≥2) edit sequences:
1. Pre-edit baseline snapshot
2. Mid-edit integrity check (HALT on unexpected change)
3. Pre-commit verification (HALT if staged diff diverges)
4. HALT response (clean-HEAD restore + observed-but-not-attributed
   report; do NOT auto-resume)

Rationale: 5+ prior incidents caused gate failures + false BUILD PASS +
ARM64 build BLOCK (D-1775810621, D-1775669703, D-1776414469,
D-1776434533, D-1776887480/D-1776890644 per librarian 01:46:19Z).

Triggered by 01:23Z external file-state revert during Tier 8 pilot
Phase A execution (generalist 01:24:43Z observed-but-not-attributed
HALT + clean-HEAD restore demonstrated the prescribed response).

Doc-only +14L. No §3.5 BUILD MODE per touched-files rule (no
builder*.{cpp,h,c} touched).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 24, 2026
…xtension

Per supervisor 02:35:05Z (PIR redirect to theologian) + 02:37:20Z
(GO atomic commit + Tier 8 Phase A resume directive). Theologian
02:36:49Z PIR delivery + 4-section CLAUDE.md amendment.

PIR scope (docs/2026-04-24-pre-edit-revert-pir.md, 132L NEW):
  (1) Automated-detection feasibility — 3 options analyzed:
      (a) inotify file-watcher daemon: feasible but multi-session
          NBS-suite extension; DEFERRED to W48
      (b) pre-commit git hook: REJECTED (duplicates gate python#3)
      (c) agent-side mtime-checkpoint discipline: ADOPTED (~5L per
          agent edit-loop; in-session feasible)
  (2) Per-incident root-cause attribution for 5 priors + this incident:
      D-1775810621 / D-1775669703 / D-1776414469 — SYMPTOM-only
      D-1776434533 — DIRECTIVE-only (Alex 'always full commit checkouts')
      D-1776887480/D-1776890644 — GATE-hardening (gate python#3 added)
      2026-04-24T01:23Z — SYMPTOM-only (observed-but-not-attributed)
      TOTAL: 6 incidents, 0 root-cause attributions
  (3) Class CONFIRMED 'undiagnosed-recurring' (already labeled in
      CLAUDE.md amendment e8a83df per pythia python#105)

CLAUDE.md mtime-checkpoint extension (+1L net, rule 1 enhancement):
  Pre-edit baseline now also captures per-touched-file mtime via
  `stat -c %Y %n`; verify before each subsequent write within edit
  sequence. mtime mismatch = external revert; HALT. Mechanizes
  detection vs requiring agent to notice mid-edit.

Bundle scope: doc-only (PIR file + CLAUDE.md edit), no §3.5 BUILD MODE
per touched-files rule. Atomic per supervisor 02:37:20Z.

Phase 3 closure-amendment (docs/tier7-phase3-closure-summary.md)
remains STAGED on disk per theologian 02:36:49Z + supervisor 02:37:20Z
('RETRACT only on successful Phase A resume push'). NOT committed
this commit.

Tier 8 Phase A resume armed post-push 29 per supervisor 02:37:20Z
GO (R-retry) — PIR + mtime-checkpoint discipline mechanizes
recurrence detection; don't infinitely block on Alex when discipline
armed.
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 24, 2026
…amendment

Per supervisor 02:48:39Z atomic doc-only bundle. Closes the
6→7 escalation triggered by Tier 8 pilot Phase A (R-retry) recurring
revert at incident python#7.

W48 spec (docs/w48-nbs-inotify-file-watcher-spec.md, +194L NEW):
  Theologian 02:48:25Z spec per W42/W44/W45 spec pattern. Elevates
  PIR §2.1 option (a) inotify file-watcher from DEFERRED to ACTIVE
  workstream. Mechanism: pyinotify daemon as NBS-suite sidecar; narrow
  watch per agent edit-set; event correlation with agent Write tool
  calls; forensic snapshot for root-cause attribution (closes
  pythia python#105 (3) zero-attribution gap).
  4-escalation history honest framing: Alex directive D-1776434533 →
  gate python#3 D-1776887480 → 4-step discipline 03a0dcb → mtime-checkpoint
  48339e2 → W48. Each progressively detective, none preventive.
  Cost ~3-5 sessions multi-session NBS-suite extension.
  Acceptance: 7 items including CLAUDE.md rule 5 addition + Tier 8
  pilot retry under W48.

PIR amendment (docs/2026-04-24-pre-edit-revert-pir.md, +21/-2):
  - Incident table: appended incident python#7 (2026-04-24T02:45Z, same
    pattern as python#6, mtime-checkpoint detected but did not prevent)
  - Conclusion: 7 incidents (was 6), 0 root cause attributions
  - NEW 'Incident python#7 ESCALATION' subsection: documents (R-retry)
    reasoning empirically INVALIDATED + pythia python#105 'fever has name'
    validated twice
  - NEW 'W48 ESCALATION' subsection: cross-links W48 spec landing +
    Tier 8 pilot Phase A retry GATED on W48 landing

Doc-only bundle, no §3.5 BUILD MODE per touched-files rule. Closes
the post-incident-python#7 reactive cycle: closure-amendment shipped at
push 30 (f6328cd), W48 + PIR ship at push 31.

Authorization: theologian 02:48:25Z (W48 spec) + supervisor 02:48:39Z
(atomic bundle GO).
SonicField added a commit to SonicField/cpython that referenced this pull request Apr 24, 2026
ROOT CAUSE FIX for the 8-incident undiagnosed-recurring file-state
revert class (D-1776998268 + 7 priors).

Per supervisor 04:14:27Z post-incident-python#8 ROOT CAUSE IDENTIFICATION:
the §3.5 falsifier's restore_files() trap was the "external reverter"
across all 8 incidents. It ran `git checkout HEAD --` on TOUCHED_FILES
on script exit; if those files had unstaged modifications BEFORE the
script ran (e.g., agent's in-flight Tier 8 Phase A content), the trap
blew them away.

Empirical validation (this session 04:13:36Z):
- Test python#6 + python#7 (trivial content, single-mechanism): no revert
- Tests python#5/python#7 idle: no revert
- cmake build alone: no revert
- §3.5 invocation on staged Phase A: REVERT (PhxExceptionTable
  count 13 → 0; mtime bumped 1777002918 → 1777003987; builder_state_c.h
  no longer M in git status)

8 prior incidents now retroactively attributed to §3.5 trap firing
during build/gate cycles concurrent with agent Tier 8 attempts.
NO external actor (no VS Code, no Alex, no formatter, no cron).
W48 inotify daemon NOT NEEDED. (Iso-A) host relocation NOT NEEDED.
Class size CLOSED — class type changed from "undiagnosed-recurring"
to "self-inflicted via §3.5 trap, RESOLVED".

Fix mechanism: snapshot per-file content to /tmp on first
snapshot_file_if_new() call (per fixture mutation start). restore_files()
copies from snapshot (not HEAD), preserving pre-script unstaged state.
Snapshots cleaned + FILE_SNAPSHOTS array unset post-restore.

Re-validation (this session post-fix):
- §3.5 BUILD MODE 4/4 PASS
- post-restore build [OK]
- Phase A content (PhxExceptionTable count 13) SURVIVED §3.5 invocation
- ALL 6 Tier 8 staged files still M

Doc-only (script-only) push, no §3.5 BUILD MODE per touched-files rule
(this IS the §3.5 script being amended; meta-circular but doc-only
gate appropriate).

Authorization: supervisor 04:14:27Z FIX directive post-ROOT-CAUSE
identification (generalist 04:13:58Z catch).

Pythia python#105 'fever has name infection still spreads' was structurally
correct re self-inflicted infrastructure — but the infection wasn't
external-class undiagnosable; it was OUR OWN script's exit trap
trampling unstaged work. 5 detection layers (Alex directive D-1776434533,
gate python#3 D-1776887480, 4-step Pre-Edit WT Integrity D-1776995670,
mtime-checkpoint D-1776998268, W48 spec D-1776999077) added to detect
ourselves. Audit own scripts BEFORE external-actor hypotheses (per
new feedback memory entry).
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.

10 participants