fix(import_closure): 破M1b无限退回死循环——globals()运行时注入逃逸阀+责任范围过滤(2026-09-17 pbls实锤)
根因1(逃逸阀缺口): agent用工具脚本生成db.py compat块(globals()[_name]=_val逐符号注入)修import闭包断裂,
运行时实测全通(pbl_blueprint.db/api/blueprint_crud/subobjects/templates import OK,PblError/require_tenant/
get_env全True),但ast静态量不出Subscript下标赋值→门禁恒报20处断裂→QC按'声称修复vs引擎实测断裂直接矛盾'
判造假证据→4轮退回达上限→fault→项目paused。与PEP562 __getattr__同类:静态不可判定即保守放行。
识别三形态: globals()[k]=v(含For/Try嵌套walk_top可达) / globals().update({...}) / _g=globals()别名。
函数体内globals()不算模块级注入(walk_top只走模块级stmts,不误放行)。
根因2(责任范围过宽): 依赖方向拉进来的外部文件(pbl_agent_runtime/api.py因import pbl_blueprint入范围)的
断裂源在pbl_common(半迁移存量欠账114处,别的任务的账)——违背门禁自己声明的'任务未触碰的包存量断裂不拦,
防死锁'原则,M1b实测26处里6处是pbl_common欠账,小任务永远修不完全空间账。
修: problems过滤 source.split('.')[0] in owned_pkgs(只拦涉及仓库自有包的契约断裂)。
原pbl_common事故形状防护不受影响: 重写pbl_common的任务owned_pkgs含pbl_common,断裂全保留。
修后M1b剩余真实断裂仅1处: m1b_common.py:114 from .errors import PblError而errors.py只有
PblBlueprintError——门禁拦它是对的(补一行别名即闭环),FAIL消息可行动。
本地走查6例通过(注入3形态识别/普通模块不误伤/函数内globals不误放行/真实compat块形状)。
This commit is contained in:
parent
2607176cb7
commit
12f8384d49
@ -15,9 +15,18 @@ ImportError,公共内核对外契约瘫痪。设计文档明文「接口变更
|
||||
2. 对每个 .py 收集模块级名字绑定(def/class/赋值/import 别名,含 If/Try
|
||||
分支),对每条 from-import 核验符号在目标模块有定义(含再导出/子模块)。
|
||||
3. 逃逸阀(防误报死锁):目标模块定义 module-level __getattr__(PEP 562
|
||||
动态属性)→ 跳过符号级核验;ast 解析失败跳过(语法归空壳门禁);外部库
|
||||
动态属性)或 module-level `globals()[...] = ...` 运行时符号注入(2026-09-17
|
||||
pbls M1b 死循环根治:agent 用工具脚本生成 compat 注入块修断裂,运行时
|
||||
import 全通但 ast 量不出下标赋值 → 门禁恒报断裂 → QC 判「声称修复 vs
|
||||
实测断裂」矛盾 → 无限退回;与 PEP 562 同类,静态不可判定即保守放行)
|
||||
→ 跳过该模块符号级核验;ast 解析失败跳过(语法归空壳门禁);外部库
|
||||
(顶层名不在包映射)不核验;本核验器自身异常 → 返回 None 放行(记日志)。
|
||||
|
||||
责任范围过滤(2026-09-17 同日修正):依赖方向拉进来的外部文件,只拦
|
||||
「引用涉及包」的断裂;它引用其他包(如半迁移欠账 pbl_common)的存量断裂
|
||||
不是本任务责任,不进门禁清单——否则小任务背上全空间欠账,永远修不完
|
||||
(pbls M1b 实测:26 处里 6 处是 pbl_agent_runtime→pbl_common 存量断裂)。
|
||||
|
||||
门禁范围(check_closure_for_delivery):
|
||||
- 本任务写入 .py 所属的包 = 涉及包;核验对象 = 涉及包内全部文件 + 全空间
|
||||
import 涉及包的文件。改公共包断掉依赖方(事故形状)会在 deliver 当轮被拦,
|
||||
@ -45,11 +54,16 @@ def _add_target(t, names):
|
||||
|
||||
|
||||
def _collect_defs(tree):
|
||||
"""模块级名字绑定集合 + 是否定义 __getattr__ + 星号导入 (module, level) 列表。"""
|
||||
"""模块级名字绑定集合 + 是否定义 __getattr__/globals()注入 + 星号导入列表。"""
|
||||
names = set()
|
||||
dynamic = False
|
||||
stars = []
|
||||
|
||||
def _is_ns_call(node):
|
||||
"""globals()/vars()/locals() 调用形态(运行时符号注入,静态不可判定)。"""
|
||||
return (isinstance(node, ast.Call) and isinstance(node.func, ast.Name)
|
||||
and node.func.id in ("globals", "vars", "locals"))
|
||||
|
||||
def walk_top(stmts):
|
||||
nonlocal dynamic
|
||||
for s in stmts:
|
||||
@ -61,6 +75,19 @@ def _collect_defs(tree):
|
||||
elif isinstance(s, ast.Assign):
|
||||
for t in s.targets:
|
||||
_add_target(t, names)
|
||||
# globals()[name] = val / vars()[...] = ... 运行时注入:
|
||||
# 符号面静态不可判定 → 整模块按动态放行(同 PEP 562 逃逸阀)
|
||||
if (isinstance(t, ast.Subscript) and _is_ns_call(t.value)):
|
||||
dynamic = True
|
||||
if _is_ns_call(s.value):
|
||||
# X = globals() 之后再 X[...] = ...:保守也视为注入形态
|
||||
dynamic = True
|
||||
elif isinstance(s, ast.Expr) and isinstance(s.value, ast.Call):
|
||||
# globals().update({...}) 形态
|
||||
fn = s.value.func
|
||||
if (isinstance(fn, ast.Attribute) and fn.attr == "update"
|
||||
and _is_ns_call(fn.value)):
|
||||
dynamic = True
|
||||
elif isinstance(s, ast.AnnAssign):
|
||||
if s.target is not None:
|
||||
_add_target(s.target, names)
|
||||
@ -342,6 +369,13 @@ def check_closure_for_delivery(space_dir, written_files, max_problems=30):
|
||||
problems = []
|
||||
for f in sorted(targets):
|
||||
problems.extend(ck.check_file(f))
|
||||
# 责任范围过滤(2026-09-17 pbls M1b 死循环修正):只保留「断裂源在
|
||||
# 涉及仓库自有包」的问题——即本任务改动面自己的契约断裂(含依赖方
|
||||
# import 涉及包断裂 = pbl_common 事故形状)。断裂源在其他包(如
|
||||
# pbl_common 半迁移存量欠账)的不是本任务责任:小任务修不完全空间
|
||||
# 欠账,硬拦只会无限退回(实测 26 处里 6 处是别的包的存量账)。
|
||||
problems = [p for p in problems
|
||||
if p.get("source", "").split(".")[0] in owned_pkgs]
|
||||
# 去重
|
||||
seen, uniq = set(), []
|
||||
for p in problems:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user