|
| 1 | +# Compiler attempt lifetime and output recovery |
| 2 | + |
| 3 | +Status: source implementation and focused acceptance in progress. This record |
| 4 | +supplements the release candidate's compiler scheduling corrections. Native |
| 5 | +source-group API checks do not qualify core or the released dependency group. |
| 6 | + |
| 7 | +## Problem and responsibility |
| 8 | + |
| 9 | +A compiler driver may start a descendant that continues writing after the |
| 10 | +supervisor and directly bound driver have ended. Releasing a kernel permit |
| 11 | +when its holder dies therefore does not prove that its compiler unit is quiet. |
| 12 | +A separate failure occurs after early BMI publication: Ninja has recorded the |
| 13 | +BMI edge while the object/status never completes, so a later build can enter |
| 14 | +an orphan await instead of recompiling. |
| 15 | + |
| 16 | +Core owns the attempt journal, concurrency reservation and recovery of its |
| 17 | +outputs. OS owns declared units, sealed admission and observation through an |
| 18 | +original native reference. OpenKal and the native backends own the kernel |
| 19 | +identity and completion semantics. Plugins do not manage process units. The |
| 20 | +core implementation uses those generic capabilities and does not inspect |
| 21 | +native process identifiers, process groups or platform job handles. |
| 22 | + |
| 23 | +## Runtime protocol |
| 24 | + |
| 25 | +One build drive owns a generation and an actor barrier. Generation identity is |
| 26 | +runtime state; it changes neither build identity nor Ninja command hashes. |
| 27 | +Phase one, ordinary wrappers, supervisors and await helpers acquire actor |
| 28 | +leases before their final owner check. Recovery waits for every actor, including |
| 29 | +phase-one BMI settling and status writers, rather than only compiler permits. |
| 30 | + |
| 31 | +Each attempt publishes a checksummed prepared record before modifying outputs. |
| 32 | +It resolves parent directories in the original execution context and records |
| 33 | +absolute BMI, object, dependency and status identities. A leaf symlink is not |
| 34 | +resolved into an unrelated output target. A previous BMI is copied into a |
| 35 | +protected baseline; its content identity is certified after the copy completes. |
| 36 | +Separate immutable stage records avoid competing writers replacing one record. |
| 37 | + |
| 38 | +A helper acquires a kernel slot, declares its execution unit, publishes that |
| 39 | +unit and its logical slot reservation, and registers with the live owner. The |
| 40 | +owner retains the original native observation reference before acknowledging |
| 41 | +registration over existing directory-local blocking IPC. Only then may the |
| 42 | +helper publish admission and start the compiler. Record, registration or ACK |
| 43 | +failure does not start an unregistered compiler. |
| 44 | + |
| 45 | +An unlocked kernel slot whose reservation remains occupied or unknown is not |
| 46 | +available. A hard-killed supervisor therefore cannot admit a replacement while |
| 47 | +its compiler descendant continues writing. The live owner's listener also |
| 48 | +notices controller loss, so an orphan descendant holding Ninja's output pipe |
| 49 | +does not leave the build waiting indefinitely for EOF. |
| 50 | + |
| 51 | +After the direct compiler exits, retirement seals admission and establishes |
| 52 | +that no external writer remains. On systems that permit leaving a unit, the |
| 53 | +helper uses the build owner's full program identity as a continuation; the |
| 54 | +short-lived BMI publisher is insufficient. A dead, reused or inaccessible |
| 55 | +continuation, including a different native session, yields unknown. Retirement |
| 56 | +does not grant termination or admission authority over the continuation unit. |
| 57 | +The helper publishes its quiet-unit certificate before atomic status and |
| 58 | +releases its logical reservation only after this barrier. |
| 59 | + |
| 60 | +## Recovery and boundaries |
| 61 | + |
| 62 | +Recovery follows the actor barrier and requires either a verified retirement |
| 63 | +certificate, positive native emptiness, or proof that admission never occurred. |
| 64 | +A successful status also needs matching output identities. An incomplete early |
| 65 | +BMI publication is removed to force a new BMI edge; its verified prior baseline |
| 66 | +is retained with a certificate for that retry's equivalence/failure handling. |
| 67 | +A successful cached object carries a quiet completion proof so a later missing |
| 68 | +object can invalidate the BMI without inferring unit death from leader absence. |
| 69 | + |
| 70 | +Malformed records, invalid stage order, write refusal, occupied units and |
| 71 | +unknown observation retain reservations and evidence. Recovery is repeatable |
| 72 | +between file operations. If every original native reference holder is forcibly |
| 73 | +lost before retirement can be certified, Windows may no longer identify the |
| 74 | +original job. That case remains a bounded refusal and is not automatic recovery. |
| 75 | +A C observation job has an observe/close caller precondition; the OS observer |
| 76 | +class hides every native control path. |
| 77 | + |
| 78 | +## Validation layers |
| 79 | + |
| 80 | +The OpenKal actual-source API workflow |
| 81 | +[42110324914](https://github.com/mcpplibs/openkal/actions/runs/42110324914) |
| 82 | +and OS actual-source lifecycle workflow |
| 83 | +[42110397318](https://github.com/mcpplibs/os/actions/runs/42110397318) |
| 84 | +passed on Linux, macOS and Windows. They cover declared-unit registration, |
| 85 | +blocking ACK failure/timeout, driver descendants, sealed retirement, retained |
| 86 | +observation, an expired publisher, forged continuation birth and observer |
| 87 | +control rejection. Linux additionally kills the continuation at native migration |
| 88 | +entry and immediately after successful migration; both report unknown. |
| 89 | + |
| 90 | +Each OS native run recorded two batches of eight paired startup samples. The |
| 91 | +median paired ACK increments were 0.175 ms on Linux, 0.409 ms on macOS and |
| 92 | +2.508 ms on Windows. Listener start/wake/close medians were 0.177, 0.289 and |
| 93 | +0.721 ms respectively. All samples, including negative deltas and tail values, |
| 94 | +are retained in the run artifacts. These measurements describe the source |
| 95 | +consumer, rather than a complete build or core no-op benchmark. |
| 96 | + |
| 97 | +Core acceptance includes checksummed records, baseline staging/corruption, |
| 98 | +atomic status gaps, late failures, missing cached objects, repeated recovery, |
| 99 | +write refusal and changed directory symlinks. The actual helper matrix also |
| 100 | +covers supervisor-only hard loss with a still-writing descendant, a free kernel |
| 101 | +slot with a retained logical reservation, owner cancellation and immediate |
| 102 | +restart, phase-one state writers, and normal/quiet cached replay. Syscall-boundary |
| 103 | +fault controls belong to the test driver and add no product fault hooks. |
| 104 | + |
| 105 | +Final acceptance still requires the completed core fault matrix, actual GCC |
| 106 | +mixed-cap/replay controls, updated user/spec documentation, the coherent public |
| 107 | +OpenKal/backend/runtime/platform/OS version group and full core CI. Core receives |
| 108 | +an independent ecosystem review after those checks and before merge/release. |
| 109 | + |
| 110 | +## 2026-11-06 cached object admission closeout |
| 111 | + |
| 112 | +A completed generation already leaves a quiet completion certificate beside |
| 113 | +each module's object slot. A later missing object originally made cached await |
| 114 | +remove its BMI and fail, requiring a second invocation. The corrected boundary |
| 115 | +reuses those existing certificates under the configuration's object tree after |
| 116 | +old owners, actors and units are quiet and before any new Ninja reader starts. |
| 117 | +Only a certificate's own declared object is checked. A missing object invokes |
| 118 | +the existing certified-baseline invalidation; Ninja then rebuilds in its normal |
| 119 | +graph on that same invocation. There is no additional success index, source |
| 120 | +dirty model, dry run or alternate compiler entry. |
| 121 | + |
| 122 | +Certificate names are bound to their slot/object paths. Absolute BMI scope, |
| 123 | +field values, checksums, regular certificate files and unchanged BMI parents |
| 124 | +are checked before invalidation. Symlinked state does not authorize recovery. |
| 125 | +The checksum detects accidental corruption; it is not authentication against |
| 126 | +a user who can already replace the build tool and its outputs. |
| 127 | + |
| 128 | +The transaction suite passes 19 cases. The actual fresh engine recovers one |
| 129 | +and two deleted completed module objects in a single build and preserves the |
| 130 | +following no-op. Actual CLI controls reject a corrupt certificate before Ninja |
| 131 | +starts and reject a directory symlink without changing an unrelated artifact. |
| 132 | +The implementation's 30 warm admission samples have medians of 0.057 ms for |
| 133 | +two real certificates, 2.200 ms for the core object tree's 1908 entries without |
| 134 | +these new certificates, and 1.089 ms for 200 format-correct synthetic records |
| 135 | +with real object existence checks. The latter is a scale fixture, not evidence |
| 136 | +that those synthetic records came from real retirements. |
| 137 | + |
| 138 | +A separate paired protocol control preserves the actual GCC argument multiset, |
| 139 | +cap two and Ninja twelve. Eight no-op pairs have a median paired difference of |
| 140 | +-0.041 ms. Five small cold-build pairs have a median new/old ratio of 1.101 and |
| 141 | +a median paired increase of 250 ms. The comparison includes the complete old |
| 142 | +protocol/OS and the current source group, and its controlled compiler driver |
| 143 | +sleeps 150 ms after real compilation. It does not isolate IPC, establish an |
| 144 | +absence of build overhead, or extrapolate to large module workloads. |
| 145 | + |
| 146 | +## 2026-11-06 process-visible publication scope |
| 147 | + |
| 148 | +The recovery contract covers owner, supervisor and driver process loss while |
| 149 | +the filesystem continues operating. It requires complete atomic visibility, |
| 150 | +checked write/close outcomes and rejection of damaged records. It does not |
| 151 | +promise persistence across power loss or a filesystem/storage service failure. |
| 152 | +The OS library's existing durable `write_atomic` operation remains unchanged. |
| 153 | + |
| 154 | +The runtime publisher creates an exclusive same-directory temporary, writes |
| 155 | +and flushes the user-space stream, checks its explicit close, then uses the |
| 156 | +existing generic replacing rename. Failed write/close/rename does not publish |
| 157 | +the final name or acknowledge admission. It removes only the temporary it |
| 158 | +created. This composition preserves process-loss visibility without flushing |
| 159 | +each short-lived runtime record to storage. |
| 160 | + |
| 161 | +A controlled libc close returns EIO after closing the actual temporary; the |
| 162 | +publisher rejects the replacement, preserves the previous record and removes |
| 163 | +its temporary. The transaction suite passes 20 functional cases plus one |
| 164 | +subprocess-driver skip. The same candidate passes the actual lifecycle and |
| 165 | +syscall-boundary fault controls, including occupied descendants, reservation |
| 166 | +retention and restart. |
| 167 | + |
| 168 | +A frozen current-protocol durable binary/driver is the comparison baseline. |
| 169 | +Five paired small cold builds preserve source, actual GCC argument multiset, |
| 170 | +cap two and Ninja twelve; the candidate/durable median ratio is 0.900, with a |
| 171 | +median paired reduction of 232 ms. Eight no-op pairs have a median paired |
| 172 | +reduction of 1.639 ms. These samples use blocking child waits, a timeout guard |
| 173 | +and alternating order. The earlier timeout-based sampler rounded short waits |
| 174 | +and its small no-op delta was within that measurement's noise. |
| 175 | + |
| 176 | +A corresponding syscall control records 200 fsync calls and 554 ms of summed |
| 177 | +call wall-time for the durable protocol, and zero fsync calls for the candidate. |
| 178 | +The sampled process wall-times are 2.868 and 2.668 seconds. Summed syscall |
| 179 | +wall-time includes concurrent threads and is not the build wall-time. These |
| 180 | +small-workload results support this publication choice; they are not an |
| 181 | +extrapolation to large module builds or a general benchmark of IPC. |
| 182 | + |
| 183 | +The capacity counter also distinguishes a forcibly ended driver from live |
| 184 | +activity. It records each original pid/birth pair, preserves entries whose |
| 185 | +finally handler did not execute, and counts only the original live processes. |
| 186 | +A deterministic cancellation control kills a real wrapper, retains that |
| 187 | +history, then starts a command returning seven without inflating peak one. |
| 188 | +The prior false failure and its dead-process/empty-reservation evidence remain |
| 189 | +part of the experiment record. |
0 commit comments