Repository navigation
fix(pr-pipeline): judge floor-file reflective references by position, not count #11048
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Labels
agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.Fully specified and briefed; eligible for autonomous pickup from the frontier.priority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.Triaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.
Description
Problem
#10966's floor-shrink judge counts reflective, dunder, import and frame references in the head against the base. The independent security review of 081662b showed that a PR can trade an existing reference for a new one, so the count does not rise:
- Python: remove an existing
getattr(...)inbabysit_risk.py, then addgetattr(lambda: 0, "__glob" "als__")["FLOOR_" "CLASSES"] = ().floor-ast.pyexits 0, and FLOOR_CLASSES goes from 110 rows to 0 when the module loads. - JS:
[].constructor.constructor("...")()passesJS_DYNAMIC, and so does a prototype patch with no token at all (Array.prototype.some = function () { return false; };).
None is HIGH: the owner's Q5 decision accepts that a logic edit to a lane-armed file merges on the two bound reviews plus the pr-merge/lane-armed attestation. These close defense-in-depth gaps on top of that residual.
Fix
- floor-ast.py: compare a multiset of each reflective or dunder reference's source text, together with its enclosing function, instead of a count per name. Refuse a
getattr/setattr/delattrwhose name argument is not a literal identifier. Refuse string concatenation whose parts join into a dunder name or a floor table name. - lane-armed.mjs
JS_DYNAMIC: addconstructor,prototype,getPrototypeOfandsetPrototypeOf. - Decide on evidence whether a logic judge (for example an independent model pass over floor-file diffs, bound to the head) is worth its cost, compared with the post-merge hub audit.
Acceptance
- Each bypass above has a failing-then-passing test.
- A pure logic edit with no new reflective use still passes.
- An independent security review of the change finds no HIGH/CRITICAL.
Refs: #10966
Metadata
Metadata
Assignees
Labels
agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.Fully specified and briefed; eligible for autonomous pickup from the frontier.priority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.Triaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.
Type
Fields
No fields configured for Bug.
Activity
github-actions commentedon Oct 29, 2026
Proposed work class: work-class: scoped
Basis: automated intake triage; the lanes App applied this class.
Size: Medium
Complexity: Medium
Uncertainty: Knowable
Flags: none
Blocked by: none
Understood: the floor-shrink judge from #10966 counts reflective and dunder references per name, so a PR can swap one reference for another without the count rising. The issue gives Python and JS bypasses. It proposes comparing a multiset of reference source text plus enclosing function in floor-ast.py, refusing non-literal getattr/setattr/delattr names, and extending JS_DYNAMIC in lane-armed.mjs. It also lists acceptance tests.
The third Fix bullet, whether a logic judge is worth its cost, is an evidence-gathering step. The two concrete fixes don't depend on it. No duplicates found among the open issues.
Automated triage, applied by the lanes App.
kyle-sexton commentedon Oct 29, 2026
Closing as moot. The floor-shrink judge this hardens (floor-ast.py, lane-armed.mjs) lived in #10966, which the owner closed unmerged after decision Q15 ("We shouldn't really have any path restrictions at all"). #11058 replaces it with one switch, merge.diff-check.path-holds. Hardening returns as a config edit once open issues and PRs reach 0.
[-]fix(pr-pipeline): judge floor-file reflective references by position, not count[/-][+]fix(pr-pipeline): judge floor-file reflective references by position, not count (hardening deferred)[/+][-]fix(pr-pipeline): judge floor-file reflective references by position, not count (hardening deferred)[/-][+]fix(pr-pipeline): judge floor-file reflective references by position, not count[/+]