Two things land together: the plan and contract draft P6 needs before it starts, and the
working notes that until now existed on exactly one machine.
1. P6's plan and contract draft (neither started; not one line of code)
docs/Disaggregated/P6-SPAWN-PLAN.md the package plan
docs/Disaggregated/P6-CONTRACT-DRAFT.md the contract draft (moves to
MG_Remote/CONTRACT-P6.md when c6 lands)
The three findings that mattered, all written into the documents:
a. P6 is SMALLER than its roadmap cell suggests. The transport primitives are already in
the tree and already tested: SocketDoorbell including hangup detection and the two
lost-wakeup fences (Doorbell.cpp:211-360, four cases in FdPassingTest), SCM_RIGHTS fd
passing, ShmSegment::Adopt, and the SurfaceOp / WindowKind schema already defined in
protocol.fbs. inproc uses a real second shm mapping rather than an alias, and
SessionRings.h:22-28 says that was done so today is not the first time it runs. P6 is
assembly plus a control plane plus a process, not "write a socket transport".
b. The evidence for "P6 is only a transport swap" has EXPIRED. It was bought by P5c, whose
audit found 59 direct memory accesses in a tree that already looked clean. P5e changed
the tree again. So the first package, a6, is a read-only audit that writes no code, and
every contract row that depends on it is marked PENDING a6 rather than decided in
advance.
c. P6 does not get a game running on the phone. ANativeWindow* is meaningless in the child,
and protocol.fbs:186-196's own comment says Android transfers the window out of band -
that band is P12. P6 lands pbuffer / surfaceless / offscreen, which is what HeadlessGL,
the split-equivalent lane and trace replay need, and which is exactly what P6's own exit
gate measures. A real window reaching the server is a named refusal. This gets its own
section because "P6 is done" would otherwise read as "the game runs now".
The contract adds rule G: a role may not name a process-local handle. It extends P5c's
rule E (a role may not name the other role's memory) from memory to identity - EGLDisplay /
EGLSurface / EGLContext / ANativeWindow* / fd number / pid / mapped address either cross as
a token this contract defines or they do not cross, and a descriptor crosses only through
SCM_RIGHTS, where the kernel renumbers it.
What P5e left for P6 gets its own section. The latch semantics are already designed
(ARCHITECTURE.md:504) and are copied unchanged. What is new is that after run-ahead the
client no longer waits while the peer process can DIE: the client holds records that were
published and will never be applied, and Android's freezer suspends the child without
closing anything. So slow and dead must be distinguishable WITHOUT a timeout threshold.
That is P6's only new design; everything else is carriage. It shares a predicate with E1's
outstanding re-specification (ID-122), and the two should be designed together.
Two gates carried over from P5e's lessons: G2 requires integration-spawn's test-name set to
match integration-split's name for name, because a differing set means the lane is quietly
running less; and the arm-proof gate requires every entry to record the child pid and
transport=spawn in its OWN private log - ID-124 established that this kind of false green
really happens, and a spawn lane that actually ran monolith would pass every other gate.
S2's shape must be settled before it is written, and the document says why: E1 is the
cautionary case.
2. The working notes move into the repository (docs/Disaggregated/notes/, 415 .md files)
ROADMAP / CURRENT_STAGE_PROGRESS / MEASUREMENTS cite ruling numbers, audit line numbers and
the provenance of gate figures from ~/w7/notes/, a directory that exists on one machine and
is under no version control. A record cited hundreds of times that lives only locally is not
a record, so it moves in whole, with its directory structure intact.
Only .md moves. Scripts, run logs, census and gate result JSON, patches, APKs and nm dumps
stay where they are: they are evidence DATA rather than documents - large, regenerated per
run, and mostly carrying absolute paths and device serials that mean something only on the
machine that produced them. The mapping and this split are written in
docs/Disaggregated/notes/README.md.
Two exceptions are recorded there too: P6's BRIEF has been promoted to a first-class
document and keeps no copy under notes/, so the two cannot drift apart; and recovered/ holds
material salvaged from failed workflow runs, which may duplicate the like-named phase
directories and is kept because a few of those were the only complete version at the time.
CI's citation lint takes docs/Disaggregated/*.md only (non-recursive), and notes/ is
deliberately outside it: those notes' file:line citations were written against their own
code heads, and resolving them against today's HEAD would fail wholesale - which is not an
error, it is their correct state as a historical record. To check one, use the revision it
declares (--rev).
3. Inconsistencies fixed in passing
- README.md's status line still said P5e was in progress while the stage table already said
closed.
- CURRENT_STAGE_PROGRESS's next-step item 1 still listed the exit gate as pending, though
(a) and (b) were run in the previous commit; rewritten to closed plus the one item that
actually remains (E1).
- ROADMAP's P6 row still had the pre-phase plan in three of its cells; it now carries the
package order, the scope boundary and the two new gates.
Checked with check_doc_citations.py: 125 citations across docs/Disaggregated/*.md, 0 problems.
27 KiB
P2 package B — p2/tracker — result, rework round 5
Tree ~/w7/p2-tracker, branch p2/tracker, branched from the contract commit 9c6a8a25
(the p2/contract tag). Not pushed. Supersedes tracker-v4.md; everything that file says
still holds except its §2.3 cross-product numbers and its §7.4 "remaining limits", both
replaced by §2 and §6 below.
Round-5 scope: tracker-review-v4.md's two majors, implemented as the FIXED DESIGN the task
handed down (two-level tokens on both sides, alias tracking with taint, field-resolved
readers, the four-way match rule, --check counting only field-resolved answers, and the
listed self-test controls). One commit sits on top of 9ff6061c. The review's nine minors
are not closed this round except where the fix happened to close one (§4).
1. Commits
Rounds 1–4 (9c6a8a25..9ff6061c, unchanged): f52dd262, 9c9df515, 8d000f7e,
a0c44c4f, e54e7399, e49f0ea7, b3daa404, 7993d711, 57b85f73, 80b861b8,
d5d4e757, dc452c02, 4e8f7179, 06f9adfd, 9ff6061c.
Round 5 (9ff6061c..HEAD, new):
| sha | subject | closes |
|---|---|---|
dddb60b0 |
[Fix] (Pipe, DirtySurface): resolve both sides of the dirty-surface derivation to member+field, follow reference and pointer aliases, and turn every write the analysis cannot place into an UNDECIDED answer instead of a verdict |
MAJOR 1, MAJOR 2 |
Round-5 diffstat: 2 files, +990 / −271.
MobileGL/MG_Pipe/DirtySurface.def | 60 +-
scripts/gen_pipe_dirty_surface.py | 1201 +++++++++++++++++++++++++++++--------
Both are B's rows in C.5. Whole package: 26 files, git diff --summary p2/contract..HEAD
shows 0 mode change lines; every subject matches ^\[Type\] (Scope): ; git log --format=%B p2/contract..HEAD contains no Co-Authored-By (grep count 0). git status --porcelain empty after the commit. Nothing compiles: neither file is included by any
translation unit (the only mention of DirtySurface.def outside itself is still the comment
at MG_Impl/Pipe/PipeFill.cpp:926), and all three build directories print ninja: no work to do. — so every binary measured in §3 is the one round 4's review measured.
2. The two majors — one root cause, one fix
2.1 What was wrong (confirmed, both parts)
The two halves of the derivation did not resolve to the same thing. The writer side
recorded m_x.f = v as MEM:m_x + FIELD:f, but a write bound to a reference
(for (auto& blendState : m_parameters.BlendStates) { blendState.ColorEquation = color; })
as FIELD:ColorEquation with no MEM: at all — so seven RenderState.cpp setters read
as writing nothing, and the gate printed a false UNDER-FIRING about them (MAJOR 1). The
reader side resolved render.PatchVertices through the walk local render to the whole of
MEM:m_parameters, so once round 4 taught the writer side to see m_parameters, every setter
that wrote any byte of it "supported" NEW_PATCH_STATE: 5 legal carriers became 35, and
X(SetClearColor, NEW_RENDER_STATE|NEW_PATCH_STATE) was green (MAJOR 2). Reproduced at
9ff6061c with the reviewer's own shapes (§2.4's "old" column is that script, loaded as a
module).
2.2 What landed (dddb60b0) — the fixed design, item by item
- Two-level tokens on both sides. Every write and every read is
MEM:<member>plusFIELD:<member>.<leaf>, where<leaf>is the first field below the member (a deeper path collapses to it — that is the granularity the shutter reads at) or*for a whole-member write or read (m_x = y;,memcpy(&m_x, …),m_x.reset(),return m_x;). - Alias tracking.
extract_writes()parses each body's declarations: a local with a&/*mark, or whose initialiser takes an address, is an alias;auto& r = m_x.y,for (auto& e : m_x.arr),T* p = &m_x.y, a pointer rebound byp = &m_x.g(every binding counts —RenderState::SetHint'sHint* slot = nullptr; … slot = &m_parameters.X; *slot = mode;is that shape), and an alias of an alias all resolve to the root member and the path they were bound to; a write through them recordsMEM:m_xFIELD:m_x.y. A value local written through->or*is a pointer or an iterator and is resolved the same way. A root the analysis cannot place — a reference/pointer parameter, a local bound to a call result or a ternary, a name the body never declares (a member without them_prefix such asImageUnitBinding::Access, a global), an assignment operator no pattern attributes, a##left after expansion — taints the function: aTAINT:<site>token that rides the call-graph fixed point, so a mutator that reaches a tainted body is UNDECIDED for every bit, never a verdict. Nothing is trusted by name except the standard library'ssize()/begin()/find()family: a non-read-only method call on an unplaceable root taints too (its callee's writes are still inherited by name, but the object they land in is unattributed, and forpush_back/resetthat is the whole write). - The reader resolves to the same token, through one-line getters.
render.PatchVerticesisCTXFIELD:GetRenderStateParameters.PatchVerticesinshutter_readers(), whichshutter_movers()resolves —GetRenderStateParameters→m_renderState.GetAllParameters()→return m_parameters;=FIELD:m_parameters.*— and narrows toFIELD:m_parameters.PatchVertices. A bare use of a walk local still expands whole. The walk's shutters now resolve to:(all 18 resolved; the pack/unpack ternary still yields both halves, as declared).NEW_PATCH_STATE m_parameters{PatchDefaultInnerLevel,PatchDefaultOuterLevel,PatchVertices} NEW_PIXEL_PACK m_pixelStorePackParameters{*}, m_pixelStoreUnpackParameters{*} NEW_SAMPLER_VIEWS m_anyTextureContentGeneration{*}, m_textureBindGeneration{*} NEW_SO_TARGETS m_anyBufferChangeGeneration{*}, m_transformFeedbackGeneration{*} NEW_VERTEX_ATTRIB_DEFAULTS m_anyVertexAttribDefaultGeneration{*} - Match rule (
match_writes()): a writer supports a bit iff there is a member in common AND, both sides field-resolved for it, the field sets intersect (*on either side is every field); a member in common with no field information on one side is COARSE; UNDER-FIRING only when every member the shutter reads is unwritten or written in disjoint fields with both sides resolved. --checkcounts only SUPPORTED pairs as derived, prints the COARSE and UNDECIDED tallies, and fails on an UNDECIDED pair unlessDirtySurface.def's newMGP_DIRTY_SURFACE_UNDECIDED_LIST(X)marks it — and fails on a mark whose pair the derivation now decides, so a mark cannot outlive its reason. The list is empty.- Self-test: 10 → 21 negative controls, all against synthetic dictionaries or synthetic bodies through the real extractor (§2.5).
2.3 The gate's own output at HEAD
$ python3 scripts/gen_pipe_dirty_surface.py --check # rc 0, 3.0 s (was 1.5 s)
dirty-surface: 73 mutators, all mapped, no stale rows; 45 render-state answers derived from RenderState.cpp and matching
dirty-surface: 8 other (mutator, bit) answers derived from their shutter in Tracker.h - supported at field level, under-firing only; 0 COARSE (a member in common, no field information, not counted); 0 UNDECIDED (listed in MGP_DIRTY_SURFACE_UNDECIDED_LIST, not counted); 24 rows carry a prose answer (kExplicitDestroy, kImmediate, kNoBackendRead, kPulledEveryVerb, kReverseChannel, kUnpublishedDestroy) that no derivation checks
dirty-surface: the under-firing half read 1262 function bodies across 82 files under MobileGL/MG_State/GLState + MobileGL/MG_Impl/Pipe, macros expanded first, both sides resolved to MEM:<member> + FIELD:<member>.<leaf>; 157 of those bodies carry a write it could not attribute and taint whatever reaches them, 10 of the 73 mutators reach one; 347 members are written outside those roots and any absence claim over one is undecided; a mutating call on a member-rooted lvalue and a call resolved by name both only WIDEN what a mutator is credited with, and a FIELD token is not scoped to a type
$ python3 scripts/gen_pipe_dirty_surface.py --self-test # rc 0
dirty-surface self-test: 21 negative controls, all tripped; positive controls OK (SetPixelStoreParam's sixteen token-pasted writes are read at field level, and the seven reference-alias setters of RenderState.cpp resolve to m_parameters' fields)
Final tallies, honestly: derived (supported at field level) 8 of 8 non-render
(mutator, bit) answers in the file; COARSE 0; UNDECIDED 0. The eight are
BumpTextureBindGeneration←NEW_SAMPLER_VIEWS, the three SetCurrentVertexAttribute*← NEW_VERTEX_ATTRIB_DEFAULTS, the three patch rows ←NEW_PATCH_STATE, and
SetPixelStoreParam←NEW_PIXEL_PACK (the kPulledPartialShutter bit). The number is the
same 8 round 4 reported, but three of those were vacuous then (any byte of m_parameters)
and none is now: SetPatchVertices supports the bit through FIELD:m_parameters.PatchVertices
and SetClearColor cannot. The count did not go down; what changed is that the gate can
now refuse the other 30.
The ten mutators that reach a tainted body are MarkBufferObjectForDeletion,
MarkFramebufferObjectForDeletion, MarkProgramForDeletion, MarkRenderbufferObjectForDeletion,
MarkSamplerObjectForDeletion, MarkShaderForDeletion, MarkTextureObjectForDeletion,
MarkTransformFeedbackObjectForDeletion, RecordError, SetNamedTransformFeedbackBinding —
every one a prose row, so no answer in the file depends on them. The taint they reach is
real, not a parser artefact, and it is the by-name call resolution that spreads it: each
calls something named Bind(, and one body of that name (ImageUnitBinding::Bind,
TextureState.h:27-34) writes Level, Layer, Access, Format — members without the
m_ prefix, which the analysis cannot tell from globals.
2.4 The verdicts flipping, old script vs new, over the whole cross product
~/w7/p2r5-logs/flips.out (the script at 9ff6061c loaded as a module against the same
tree; 73 rows × 16 non-render bits):
old tallies: {'REJ': 1104, 'ACC': 64}
new tallies: {'UNDECIDED': 160, 'UNDER-FIRING': 996, 'SUPPORTED': 12}
flips (old -> new): {('REJ', 'UNDECIDED'): 138, ('ACC', 'UNDECIDED'): 22, ('ACC', 'UNDER-FIRING'): 30}
-- REJ -> SUPPORTED (must be empty or explained): (empty)
-- legal carriers per bit (old ACC count -> new SUPPORTED count):
NEW_PATCH_STATE 33 -> 3 ['SetPatchDefaultInnerLevel', 'SetPatchDefaultOuterLevel', 'SetPatchVertices']
NEW_PIXEL_PACK 1 -> 1 ['SetPixelStoreParam']
NEW_VERTEX_ATTRIB_DEFAULTS 3 -> 3 ['SetCurrentVertexAttributeFloat', 'SetCurrentVertexAttributeInt', 'SetCurrentVertexAttributeUint']
NEW_SAMPLER_VIEWS 3 -> 1 ['BumpTextureBindGeneration']
NEW_SO_TARGETS 2 -> 1 ['BeginTransformFeedback']
NEW_INDEX_BUFFER / NEW_VERTEX_BUFFERS / NEW_VERTEX_ELEMENTS 7 -> 1 each ['MarkVertexArrayForDeletion']
NEW_FRAMEBUFFER 1 -> 0
(the other 7 bits: 0 -> 0)
The 30 ACC → UNDER-FIRING are exactly the NEW_PATCH_STATE collapse the review measured
(its 35 was over 936 function names; 33 here is over the 73 mapped mutators). The 22
ACC → UNDECIDED and 138 REJ → UNDECIDED are the ten tainted mutators over the other bits.
Zero rejections became acceptances. The review's three named rows:
$ (derive_bit_answers on the tip, one synthetic row each)
UNDER-FIRING SetClearColor <- NEW_PATCH_STATE it writes nothing NEW_PATCH_STATE's shutter reads (shutter: m_parameters{PatchDefaultInnerLevel,PatchDefaultOuterLevel,PatchVertices}; it writes: m_parameters{ClearColor}, m_renderState{*}, m_version{*})
UNDER-FIRING SetScissorBox <- NEW_PATCH_STATE … it writes: m_parameters{ScissorBoxWrittenMask,ScissorBoxes}, …
UNDER-FIRING SetViewportIndexed <- NEW_PATCH_STATE … it writes: m_parameters{Viewports}, …
UNDER-FIRING SetBlendEquation <- NEW_PATCH_STATE … it writes: m_parameters{BlendStates}, …
UNDER-FIRING SetCurrentVertexAttributeInt <- NEW_PIXEL_PACK (control 7, still red)
UNDECIDED SetNamedTransformFeedbackBinding <- NEW_SO_TARGETS the write analysis is not complete for this mutator: Bind() writes 'Access', which it never declares …
SUPPORTED SetPixelStoreParam <- NEW_PIXEL_PACK
The seven setters of MAJOR 1, resolved through the alias (~/w7/p2r5-logs/seven.out; the
m_parameters/m_pixelStore* tokens only, taint count is the whole reachable set):
SetBlendFunc taint=0 m_parameters{BlendStates}
SetBlendFuncIndexed taint=0 m_parameters{BlendStates}
SetBlendEquation taint=0 m_parameters{BlendStates}
SetBlendEquationIndexed taint=0 m_parameters{BlendStates}
SetStencilFunc taint=0 m_parameters{StencilStates}
SetStencilMask taint=0 m_parameters{StencilStates}
SetStencilOp taint=0 m_parameters{StencilStates}
SetClearColor taint=0 m_parameters{ClearColor}
SetScissorBox taint=0 m_parameters{ScissorBoxWrittenMask,ScissorBoxes}
SetViewportIndexed taint=0 m_parameters{Viewports}
SetPatchVertices taint=0 m_parameters{PatchVertices}
SetPixelStoreParam taint=0 m_pixelStorePackParameters{Alignment,ImageHeight,LSBFirst,RowLength,SkipImages,SkipPixels,SkipRows,SwapBytes}, m_pixelStoreUnpackParameters{…same eight…}
and the three sites the review called "luck, not a property", on their own bodies:
VertexArrayState.cpp:CreateVertexArrayObject auto& vao = m_vertexArrays[ -> FIELD:m_vertexArrays.*, MEM:m_vertexArrays | taint=0
VertexArrayState.cpp:VertexArrayState m_vertexArrays.push_back -> FIELD:m_vertexArrays.*, MEM:m_vertexArrays | taint=0
VertexArrayState.cpp:CreateVertexArrayObject m_vertexArrays.resize -> (same)
ProgramState.cpp:UseProgram m_currentProgram.reset() -> FIELD:m_currentProgram.*, MEM:m_currentProgram | taint=0
2.5 --self-test, 21 controls
| # | control | what it asserts | kind |
|---|---|---|---|
| 1–5 | unchanged (withheld mutator, stale row, bad answer, under-firing render bit, dropped publisher) | real def | |
| 6 | SetNamedTransformFeedbackBinding ← NEW_SO_TARGETS |
--check goes red on it (UNDER-FIRING or unmarked UNDECIDED) and the verdict is never SUPPORTED — the mutator reaches Bind() by name, so the honest red is UNDECIDED |
real tree |
| 6b | BumpTextureBindGeneration ← NEW_GLOBAL_CONSTANTS |
UNDER-FIRING outright — the object-class family can still go red as a verdict | real tree |
| 7 | SetCurrentVertexAttributeInt ← NEW_PIXEL_PACK |
UNDER-FIRING | real tree |
| 8 | kPulledPartialShutter naming no bit |
BAD | real def |
| 9a | a mutator given a canned TAINT: token |
UNDECIDED, never a verdict | synthetic |
| 9b | the same, row unmarked | --check fails with UNDECIDED answer …, no UNDER-FIRING line |
synthetic |
| 9c | the same, row marked in the undecided list | no problem, still no verdict | synthetic |
| 10 | shutter member written outside the roots | UNDECIDED with that reason | synthetic |
| 11 | body writing m_parameters.ClearColor vs a patch-field shutter |
UNDER-FIRING (design 6a) | synthetic body |
| 12 | for (auto& blendState : m_parameters.BlendStates) and StencilFaceState& state = m_parameters.StencilStates[…] |
MEM:m_parameters+FIELD:m_parameters.BlendStates/.StencilStates, no taint, SUPPORTED against their shutter, UNDER-FIRING against the patch shutter (6b) |
synthetic body |
| 13 | auto& state = LookUpSomewhere(face); state.WriteMask = mask; and a write through a RenderStateParameters& parameter |
both tainted, both UNDECIDED (6c) | synthetic body |
| 14 | m_parameters = fresh; |
FIELD:m_parameters.*, supports the patch, blend and LineWidth shutters (6d) |
synthetic body |
| 15 | SetPixelStoreParam |
tokens contain FIELD:m_pixelStore{Pack,Unpack}Parameters.<leaf> (or the mutator is tainted), never paramNameTail, never UNDER-FIRING (6e) |
real tree |
| 16 | X(SetClearColor, NEW_RENDER_STATE|NEW_PATCH_STATE) |
UNDER-FIRING answer NEW_PATCH_STATE for SetClearColor — the row that was green at 9ff6061c |
real tree |
| 17 | a shutter of MEM:m_parameters alone (no fields) vs a field writer |
COARSE: counted as 0 derived, 1 coarse, no problem | synthetic |
| 18 | an undecided mark on a pair the derivation decides | STALE undecided mark |
real tree |
| + | positive: SetPixelStoreParam ← NEW_PIXEL_PACK SUPPORTED, no undecided line; the seven alias setters each carry MEM:m_parameters and their field with no taint |
real tree |
3. Verification — every command and its actual output
All at dddb60b0 in ~/w7/p2-tracker. cmake --build {build-linux,build-push,build-verify} -j 12 → ninja: no work to do. ×3.
3.1 The package's own verification block (brief §C.1, with ID-4's errata)
| command | output |
|---|---|
python3 scripts/gen_pipe_dirty_surface.py --check |
rc 0 — §2.3 verbatim |
python3 scripts/gen_pipe_dirty_surface.py --self-test |
rc 0 — 21 negative controls, all tripped; positive controls OK … |
python3 scripts/gen_pipe_dirty_surface.py --summary |
rc 0, 81 lines, byte-identical to 9ff6061c's (diff empty) — E's CI step keeps working |
python3 scripts/gen_pipe.py --check / --self-test |
rc 0 — inventory 477 rows: 299 -> call, 5 client-resolved, 6 reverse-channel, 167 structural handle, 0 UNMAPPED, generated files are up to date; 7 negative-control trip(s), positive control OK |
symbol_report.py --before ~/w7/p2-before-libMobileGL.so --after build-linux/libMobileGL.so --threshold 0 |
rc 0 — 27799 -> 27799 defined symbols: 0 added, 0 removed, 4 resized, 0 renamed; .text 10792579 -> 10792739 (+160, +0.001%); both files 19100448 bytes; the four resized are ID-3's set (RenderState::RenderState() +148, SetCapability +77, IsCapabilityEnabled +29, _GLOBAL__sub_I_DirectGLES.cpp −9) |
ctest --test-dir build-{linux,push,verify} -L unit --no-tests=error -j 8 |
rc 0 ×3 — 100% tests passed, 0 tests failed out of 1529 ×3 |
ctest --test-dir build-push -L integration-gpu --no-tests=error -j 4 |
rc=0 100% tests passed, 0 tests failed out of 878 |
MOBILEGL_PIPE_PUSH=0 ctest --test-dir build-push -L integration-gpu --no-tests=error -j 4 (the all-pull arm) |
rc=0 100% tests passed, 0 tests failed out of 878 |
ctest --test-dir build-linux -L integration-gpu --no-tests=error -j 4 |
rc=0 100% tests passed, 0 tests failed out of 878 |
ctest --test-dir build-verify -L integration-verify --no-tests=error -j 4 |
rc=0 100% tests passed, 0 tests failed out of 818 |
python3 ~/w7/retrace_gate.py --tree ~/w7/p2-tracker --lib build-push/libMobileGL.so --out ~/w7/retrace-out/v5-push -j 4 (G3) |
STILL RUNNING / NOT YET RUN when this file was written - the orchestrator called for the result while ~/w7/p2r5-lanes.sh was in flight; the outcome lands in ~/w7/p2r5-logs/lanes.out (binary unchanged since round 4, where it was 79/79) |
MOBILEGL_PIPE_VERIFY=1 python3 ~/w7/retrace_gate.py … --lib build-verify/libMobileGL.so --out ~/w7/retrace-out/v5-verify -j 4 + Fatal{ / PipeVerifyDiffer / PipeResidualDiverged / UnmigratedPipeInput / not-MGPipe: verify armed greps over <out>/<case>/<backend>/output/mobilegl.log (G4) |
STILL RUNNING / NOT YET RUN when this file was written - the orchestrator called for the result while ~/w7/p2r5-lanes.sh was in flight; the outcome lands in ~/w7/p2r5-logs/lanes.out (binary unchanged since round 4, where it was 79/79, Fatal{ 0, not-armed 0) |
3.2 Section-A gates this tree can reach on its own
| gate | command | output |
|---|---|---|
| G1 | above | 0/0/4/0, the admitted four |
| G2 | ID-4's ctest-name extraction on build-linux and build-push |
2407 and 2407, diff empty |
| G5 | for r in refs/tags/p2/contract HEAD; do git show $r:MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | awk '/^ namespace RenderStateImpl \{/,/^ \} \/\/ namespace RenderStateImpl/' | sha256sum; done |
d8fd1c48716056c536752fde09db3a9e5aa8494b70404798bfc15d11220efe27 on both sides and equal to ~/w7/p2-before-syncrenderstate.sha |
| G9 | §2.3 | green, and the three patch rows are now supported for the field they write |
| G13 | gen_pipe.py --check/--self-test (above); check_include_closure.py → 4 probes, 0 skipped, 0 problem(s); grep -rc 'pGLContext' MobileGL/MG_Backend | grep -v ':0$' → empty |
green |
| G14 | LC_ALL=C comm -23 <LC_ALL=C-sorted baseline> <build-linux names> |
0 of 2363 baseline names removed; 44 added |
Not reachable from this tree: G6/G7 (package A), G8/G12 (package E), G11 (device). Not claimed.
3.3 Discipline
git status --porcelain empty; git diff --summary refs/tags/p2/contract..HEAD | grep -c 'mode change' → 0; git log --format=%B refs/tags/p2/contract..HEAD | grep -ci co-authored
→ 0; 16 commits, every subject [Type] (Scope): …, bodies - bullets. Not pushed.
4. The review's nine minors
writers_outside()shares the write analysis's blind spots — still true and now said in its docstring and in the.defheader ("a shutter member written outside … is undecided in the absence direction", "textual and file-wide"). It was not switched to the new extractor: an outside body's writes through a reference are its own object's, and treating every unplaceable outside write as a possible frontend writer would make every shutter undecided. Open, declared.macro_table()collects#defines only under the two roots — open, unchanged.expand_macros(…, rounds=4)gives up silently — open, unchanged.- the decline path never fires on the real tree — now it does, one level down: 157
bodies are tainted and 10 mutators reach one,
--checkprints both counts, and the 22 + 138 pairs of §2.4 are real UNDECIDED verdicts on the real tree (none of them a bit answer in the file). Controls 9a–c, 13 and 18 exercise the plumbing synthetically. - "8 other bit answers" is pairs, not rows — the line now says
(mutator, bit) answers, and none of the eight is vacuous (§2.3). - the three §A command defects — unchanged; ID-4 records the corrected forms and §3
uses them (the brief's
<out>/*/mobilegl.logglob still matches nothing; the real path is<out>/<case>/<backend>/output/mobilegl.log). - round 3's minors 3, 4, 5, 8 (raw-address context identity,
LiveContext()inMGPipeNoteAggregate, the three emission globals,MGPipeCsoCacheslot reclamation) — open, untouched, as before. - no lane started skipping — nothing compiled this round either; the two deliberate skip pairs are unchanged (G2's 2407 = 2407).
- the outstanding list — restated in §6.
5. Deviations from the brief (new in round 5; 1–17 from tracker-v2/3/4.md stand)
DirtySurface.defcarries a second X-list,MGP_DIRTY_SURFACE_UNDECIDED_LIST(X). D16 shows one list. The fixed design's item (5) needs the file to mark which rows are derived; marking the exceptions (known-undecided pairs, with the reason) keeps the default the strong claim, and--checkrefuses a stale mark so the list cannot hide a row. It is empty today.load_mapping()splits the file at that#define; a consumer of the first list sees no change.function_signatures()no longer yieldsif/for/while/switch/catch/elseblocks as functions.FUNCTION_REmatchedfor (...) {as a function namedfor; as a "body" it had no enclosing declarations (every write in it tainted) and every function with a loop "called" it. This also changesfunction_bodies()for the scanner half, but--summaryis byte-identical, so the report is unaffected.- A non-read-only method call is a whole write of its object. The design says "a
mutating member call on
m_x"; the script cannot tell mutating from not, so on a member-rooted lvalue every call except the standard library'ssize()/begin()/find()family is credited (widening), and on an unplaceable root it taints. No name prefix (Get*,Is*) is trusted: I measured both policies and they taint the same ten mutators, so the version with fewer assumptions shipped. - FIELD tokens are two-level. The design writes the alias case as
FIELD:m_x.y[.leaf]; the token shipped isFIELD:<member>.<first field>, with deeper paths collapsed, because the shutter side reads at exactly that depth (render.<Field>) and a third level would make a writer ofm_x.y.zand a reader ofm_x.ymiss each other by string. Prefix matching would have been the alternative; not invented. - A tainted mutator is UNDECIDED for every bit, even where a visible direct write would support one. Design (2) says "never a verdict" and that is what shipped. A support-first ordering (SUPPORTED is monotone under unknown extra writes) would be sound and changes nothing today — none of the eight supported rows is tainted — but it is the integrator's call, not mine.
- Const aliases. A write or call through a
const-qualified alias with.and aconstraw pointer are taken as impossible (the language forbids them);->/*through aconstreference is not, because aconst SharedPtr<T>&reaches a mutable pointee.mutablemembers written through a const path escape this; declared. --checkcosts 3.0 s, up from 1.5 s (the declaration parse per body).
6. Unfinished, and the hand-off
- By-name call resolution is what spreads taint.
SetNamedTransformFeedbackBindingis undecided because some body namedBindwritesAccess. Scoping a call to its receiver's type would recover the ten prose-row mutators and let control 6 be an UNDER-FIRING verdict again; no bit answer in the file needs it today, so it is recorded, not done. - Members without the
m_prefix cannot be placed (ImageUnitBinding::Access,ProgramLinkTask::artifacts); they taint their bodies. A class-context pass (know which struct a body belongs to) would place them. Same status as 1. writers_outside()is still the regex scan (review minor 1); the.defsays so.- Unchanged from rounds 2–4: package A's
MGPipeApplySetVertexAttribDefaultshand-off (the applier-repairMGLOG_W_ONCEstill lands once per push/verify process), the 26 derived render-state mirrors still pulled until A'sc1,kPulledEveryVerbstill an unchecked absence claim, G9 not a CI gate until E landspipe-gates, theMEASUREMENTS.mditems the integrator owns (four resized symbols;T1 − T2; the flake family; §3.4 oftracker-v4.md's residual firing rate),FormatWindowLine, the six unwiredSetHashSuppressorslots,MGPipeWidenedCounterat exactly 65536,s_hashForTest, the three header-only files'list(APPEND)line, no device work.
Logs kept under ~/w7: p2r5-logs/{lanes.out,flips.out,seven.out} and the verify retrace
corpus ~/w7/retrace-out/v5-verify/; every other intermediate file of this round was
deleted.