also looking at this
feat: continue unresolved runtime update maintenance
#59
21 files
+1097
-40
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -182,8 +182,10 @@ cuts do not cover every write/sync boundary or actual physical power loss. | ||
| 182 | 182 | The metadata format is bounded to 256 attempts, 10,000 metadata advances and a 128 MiB |
| 183 | 183 | state database. Each attempt allows 64 inputs, 32 MiB of metadata and 512 KiB per |
| 184 | 184 | file. Exhaustion fails closed; history is not automatically deleted or compacted. |
| 185 | Capacity migration, the full storage-fault campaign, authenticated repair/key | |
| 186 | revocation, durable slot coordination and session-bound health remain in #42. | |
| 185 | Capacity migration, the full storage-fault campaign and authenticated repair/key | |
| 186 | revocation remain in #42. [Owned host slots](#owned-host-slots-and-observed-health) | |
| 187 | below add durable host roles and observed boot/session health. Physical board | |
| 188 | selection, boot health and recovery still require their separate qualification. | |
| 187 | 189 | |
| 188 | 190 | ## Protected signed-image preparation |
| 189 | 191 | |
| @@ -168,8 +168,9 @@ export async function qualifyHostFullVolume(directory: string) { | ||
| 168 | 168 | assert.ok(rejection.errorCodes.includes('ENOSPC') && rejection.errorCodes.includes('SQLITE_FULL')) |
| 169 | 169 | assert.ok(Array.isArray(rejection.phases) && rejection.phases.includes('slot-selected')) |
| 170 | 170 | assert.ok(!rejection.phases.includes('slot-image-written') && !rejection.phases.includes('runtime-started') && !rejection.phases.includes('runtime-input-committed')) |
| 171 | assert.equal(checkedVolume(volume).freeBytes, 0) | |
| 172 | await writeFile(join(directory, 'full-volume.json'), JSON.stringify(checkedVolume(volume), null, 2)) | |
| 171 | const fullVolume = checkedVolume(volume) | |
| 172 | assert.equal(fullVolume.freeBytes, 0) | |
| 173 | await writeFile(join(directory, 'full-filesystem.json'), JSON.stringify(fullVolume, null, 2)) | |
| 173 | 174 | await archiveVolume(volume, join(directory, 'full-volume')) |
| 174 | 175 | await unlink(join(volume, 'filler.bin')) |
| 175 | 176 | const failed = await inspectRuntimeFirmwareSlots(reference) |
| @@ -207,7 +208,7 @@ export async function qualifyHostFullVolume(directory: string) { | ||
| 207 | 208 | assert.notEqual(fresh.knownGood!.health!.sessionId, good.knownGood!.health!.sessionId) |
| 208 | 209 | assert.deepEqual(await readFile(partialPath), partial); assert.deepEqual(await readFile(previousImage), image) |
| 209 | 210 | assert.deepEqual(await readFile(join(reference.directory, 'host-slots', fresh.knownGood!.id, 'image.bin')), image) |
| 210 | const result = { evidence: 'host-actual-enospc-v1', filesystemType: 'tmpfs', filesystemBytes: mounted.capacityBytes, freeBytesAfterFailure: 0, sourceRevision, authorizedImageBytes: image.length, authorizedImageSha256: signed.imageHash, partialImageBytes: partial.length, partialImageSha256: digest(partial), errorCodes: rejection.errorCodes, interruptedPhase: failed.trial!.phase, interruptedAttempt: failed.store.attempt!.phase, acceptedRootVersion: version('root'), acceptedTargetsVersion: version('targets'), releaseFloor: fresh.store.releaseFloor, abandonedPhase: abandoned.trial!.phase, previousSlotId: good.knownGood!.id, failedSlotId: failed.trial!.id, confirmedSlotId: fresh.knownGood!.id, previousBootId: good.knownGood!.health!.bootId, freshBootId: fresh.knownGood!.health!.bootId, physicalDeploymentAllowed: fresh.physicalDeploymentAllowed } | |
| 211 | const result = { evidence: 'host-actual-enospc-v1', filesystemType: 'tmpfs', filesystemBytes: mounted.capacityBytes, freeBytesAfterFailure: fullVolume.freeBytes, sourceRevision, authorizedImageBytes: image.length, authorizedImageSha256: signed.imageHash, partialImageBytes: partial.length, partialImageSha256: digest(partial), errorCodes: rejection.errorCodes, interruptedPhase: failed.trial!.phase, interruptedAttempt: failed.store.attempt!.phase, acceptedRootVersion: version('root'), acceptedTargetsVersion: version('targets'), releaseFloor: fresh.store.releaseFloor, abandonedPhase: abandoned.trial!.phase, previousSlotId: good.knownGood!.id, failedSlotId: failed.trial!.id, confirmedSlotId: fresh.knownGood!.id, previousBootId: good.knownGood!.health!.bootId, freshBootId: fresh.knownGood!.health!.bootId, physicalDeploymentAllowed: fresh.physicalDeploymentAllowed } | |
| 211 | 212 | await writeFile(join(directory, 'qualification.json'), JSON.stringify(result, null, 2)) |
| 212 | 213 | return result |
| 213 | 214 | } |