oxedyne/daimond/dev/verify_parcelbudget.mjs
9.9 KiB, 1 run
created by r2519314175:565, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | // verify_parcelbudget.mjs — the sync parcel's ceiling is set by the door it has to |
| 2 | // go through, and the sections spent against it add up to no more than it. |
| 3 | // |
| 4 | // WHY THIS FILE EXISTS. `SYNC_PARCEL_MAX` was 10 MiB, and the comment above it |
| 5 | // derived that from the GATEWAY's 16 MiB body cap. Steel terminates TLS in front of |
| 6 | // the gateway on jarrah and caps a body at 8 MiB, so the client could compose a |
| 7 | // parcel the front door refuses — and the comment, being a piece of reasoning from |
| 8 | // the wrong authority, would have talked the next reader into putting the number |
| 9 | // back. A value nobody can derive is a value somebody will restore. |
| 10 | // |
| 11 | // Three things are asked, and each is asked of the source rather than of a copy: |
| 12 | // |
| 13 | // 1. THE ARITHMETIC. What travels is base64 of the sealed parcel inside a JSON |
| 14 | // envelope, so the body is 4 bytes for every 3 of parcel plus the AES-GCM IV |
| 15 | // and tag. `SYNC_PARCEL_MAX` inflated that way must fit under Steel's door. |
| 16 | // 2. THE SPLIT. `collectSync` hands the Diamonds |
| 17 | // `min(SYNC_DIAMONDS_MAX, SYNC_PARCEL_MAX - files)`. A Diamonds cap at or above |
| 18 | // the parcel can never be the smaller of those two, so it never binds and reads |
| 19 | // as a guarantee it does not make. |
| 20 | // 3. THE AUTHORITY. The comment on the constant must name Steel. This is the one |
| 21 | // check here that is about prose, and it is the one that stops the regression |
| 22 | // this file was written for. |
| 23 | // 4. AND WHAT DID NOT FIT IS NAMED. Not arithmetic at all, and it is here because |
| 24 | // it is what the arithmetic was being held hostage to: while a file dropped for |
| 25 | // budget was named to nobody, lowering the files budget would have made the sums |
| 26 | // add up by making the failure silent. The names come first; the number after. |
| 27 | // |
| 28 | // How each goes red: |
| 29 | // |
| 30 | // * put `SYNC_PARCEL_MAX` back to `10 * 1024 * 1024` → check 1 goes red and |
| 31 | // check 2 goes red with it (10 MiB of parcel is 13.4 MiB of body, and the |
| 32 | // Diamonds' 3 MiB is then only a fifth of a parcel it was never measured |
| 33 | // against); |
| 34 | // * raise `SYNC_DIAMONDS_MAX` to `5 * 1024 * 1024` → check 2 alone goes red; |
| 35 | // * delete the word Steel from the comment → check 3 alone goes red. |
| 36 | // |
| 37 | // node dev/verify_parcelbudget.mjs |
| 38 | // |
| 39 | // No browser, no gateway, no mock LLM: this reads source and does arithmetic. |
| 40 | import fs from 'node:fs'; |
| 41 | import path from 'node:path'; |
| 42 | import { fileURLToPath } from 'node:url'; |
| 43 | |
| 44 | const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); |
| 45 | const APP = fs.readFileSync(path.join(ROOT, 'www', 'js', 'daimond.js'), 'utf8'); |
| 46 | |
| 47 | // Steel's `http_max_body_bytes`, whose default is 8 MiB in fe2o3_steel/src/srv/cfg.rs |
| 48 | // and which the deployed config does not set. Restated here because fe2o3 is a |
| 49 | // separate repository that may not be beside this one — and checked against it below |
| 50 | // wherever it is, so the restatement cannot quietly go stale. |
| 51 | const STEEL_BODY_MAX = 8 * 1024 * 1024; |
| 52 | // `{"base_version":N,"device":"…","blob":"…","w":"…"}` around the sealed blob, plus |
| 53 | // room for a long device label. Deliberately generous: it is subtracted from the |
| 54 | // door, so over-stating it can only make the ceiling safer. |
| 55 | const ENVELOPE = 512; |
| 56 | // AES-GCM: a 12-byte IV in front of the ciphertext and a 16-byte tag behind it, |
| 57 | // both inside what gets base64'd. See `wrap` in www/js/identity.js. |
| 58 | const SEAL = 12 + 16; |
| 59 | |
| 60 | let bad = 0; |
| 61 | const check = (what, ok, saw) => { |
| 62 | console.log((ok ? 'ok ' : 'FAIL ') + what + (saw === undefined ? '' : ' [' + saw + ']')); |
| 63 | if (!ok) bad++; |
| 64 | }; |
| 65 | |
| 66 | /// A `var NAME = a * b * c;` constant, read out of the app source. |
| 67 | const constOf = (name) => { |
| 68 | const m = new RegExp('var\\s+' + name + '\\s*=\\s*([0-9*\\s]+);').exec(APP); |
| 69 | if (!m) throw new Error('verify_parcelbudget: ' + name + ' not found in www/js/daimond.js'); |
| 70 | return m[1].split('*').reduce((a, b) => a * Number(b.trim()), 1); |
| 71 | }; |
| 72 | |
| 73 | const PARCEL = constOf('SYNC_PARCEL_MAX'); |
| 74 | const DIAMONDS = constOf('SYNC_DIAMONDS_MAX'); |
| 75 | const FILES = constOf('SYNC_FILES_TOTAL_MAX'); |
| 76 | |
| 77 | // ── 1. The arithmetic ──────────────────────────────────────────────── |
| 78 | const body = Math.ceil((PARCEL + SEAL) / 3) * 4 + ENVELOPE; |
| 79 | check('a parcel at the ceiling, sealed and base64\'d, fits under Steel\'s 8 MiB door', |
| 80 | body <= STEEL_BODY_MAX, body + ' bytes of body from ' + PARCEL + ' of parcel'); |
| 81 | |
| 82 | // The largest parcel that fits, so the message says what the ceiling could be rather |
| 83 | // than only that it is not exceeded. |
| 84 | const most = Math.floor((STEEL_BODY_MAX - ENVELOPE) / 4) * 3 - SEAL; |
| 85 | check('the ceiling leaves margin under the arithmetic maximum, for the sections it ' |
| 86 | + 'does not bound and for UTF-8', |
| 87 | PARCEL < most, PARCEL + ' against a maximum of ' + most); |
| 88 | |
| 89 | // ── 2. The split ───────────────────────────────────────────────────── |
| 90 | check('the Diamonds\' cap can actually bind — it is below the parcel it is spent in', |
| 91 | DIAMONDS < PARCEL, DIAMONDS + ' of ' + PARCEL); |
| 92 | |
| 93 | // ── 2b. And what the parcel could not carry is NAMED ───────────────── |
| 94 | // |
| 95 | // THE ASYMMETRY WAS THE DEFECT, not the arithmetic. A Diamond left out of a parcel |
| 96 | // has always been named to the user by `noteDiamondsLeft`; a file skipped for budget |
| 97 | // went into a COUNT, made the census incomplete, and was named to nobody -- so a |
| 98 | // workspace with a few megabytes of inline text quietly stopped travelling between a |
| 99 | // person's devices and the app said nothing at all. Files are spent FIRST and are not |
| 100 | // clamped against the parcel, which makes the unnamed case the commoner of the two. |
| 101 | // |
| 102 | // This was a standing `note` here until 2026-08-28 rather than a check, and it said |
| 103 | // why: lowering `SYNC_FILES_TOTAL_MAX` would have fixed the arithmetic by trading a |
| 104 | // failure that names what was dropped for one that names nothing. The visibility had |
| 105 | // to come first. It has, so this is a check. |
| 106 | // |
| 107 | // ASKED OF THE SOURCE, like everything else here -- no browser, no parcel, no |
| 108 | // workspace. What it cannot see is the toast on the screen; what it can see is that |
| 109 | // every branch which drops a file for budget records its NAME, that `collectSync` |
| 110 | // hands those names to a teller, and that the teller says them out loud. |
| 111 | const collectFiles = APP.slice(APP.indexOf('async function collectFiles()'), |
| 112 | APP.indexOf('async function writeSyncFile')); |
| 113 | const drops = [...collectFiles.matchAll(/>\s*(SYNC_CHUNK_TOTAL_MAX|SYNC_FILES_TOTAL_MAX)\)\s*\{([^}]*)\}/g)]; |
| 114 | check('the budget branches that drop a file were found in collectFiles', |
| 115 | drops.length >= 3, drops.length + ' branch(es)'); |
| 116 | const silent = drops.filter((m) => !/out\.left\.push/.test(m[2])); |
| 117 | check('EVERY FILE THE PARCEL CANNOT CARRY IS RECORDED BY NAME, not merely counted', |
| 118 | silent.length === 0, |
| 119 | silent.map((m) => m[0].replace(/\s+/g, ' ')).join(' | ')); |
| 120 | check('and the names are handed to a teller when the parcel is packed', |
| 121 | /noteFilesLeft\(fileCol\.left\)/.test(APP)); |
| 122 | const teller = APP.slice(APP.indexOf('function noteFilesLeft'), |
| 123 | APP.indexOf('function noteFilesLeft') + 700); |
| 124 | check('which SAYS them, in the same shape a Diamond that did not fit is said in', |
| 125 | /toast\(tn\('sync\.files_left'/.test(teller) && /slice\(0, 3\)/.test(teller)); |
| 126 | // In all eight, because `tOr` and `tn` fall back to English and a missing |
| 127 | // translation looks exactly like a finished one. |
| 128 | const gaps = ['en', 'es', 'de', 'fr', 'pt-BR', 'zh-Hans', 'ja', 'ko'].filter((code) => { |
| 129 | const src = fs.readFileSync(path.join(ROOT, 'www', 'i18n', code + '.js'), 'utf8'); |
| 130 | return !/'sync\.files_left\.one':/.test(src) || !/'sync\.files_left\.other':/.test(src); |
| 131 | }); |
| 132 | check('and the sentence is in all eight catalogues, both plural arms', gaps.length === 0, |
| 133 | gaps.join(', ')); |
| 134 | |
| 135 | // Still over-subscribed, and now it is a DECISION rather than a blocker: the |
| 136 | // condition the old note set -- that a file's skip be as visible as a Diamond's -- |
| 137 | // is met by the checks above, so the files budget can come down without trading a |
| 138 | // named failure for a silent one. Left as a note because what it should come down TO |
| 139 | // is the owner's to say: it is a judgement about how much of a parcel a workspace |
| 140 | // should be able to take from the Diamonds, not an arithmetic fact. |
| 141 | if (FILES + DIAMONDS > PARCEL) { |
| 142 | console.log('note the two section budgets are over-subscribed: files ' + FILES |
| 143 | + ' + Diamonds ' + DIAMONDS + ' = ' + (FILES + DIAMONDS) + ' against a parcel of ' |
| 144 | + PARCEL + '. Files are spent first and are not clamped against the parcel, so a ' |
| 145 | + 'workspace that fills them leaves the Diamonds nothing. The skip is now named to ' |
| 146 | + 'the user, so the files budget may come down: ' + (PARCEL - DIAMONDS) |
| 147 | + ' bytes would leave the Diamonds their whole share.'); |
| 148 | } |
| 149 | |
| 150 | // ── 3. The authority ───────────────────────────────────────────────── |
| 151 | const at = APP.indexOf('var SYNC_PARCEL_MAX'); |
| 152 | const why = APP.slice(Math.max(0, at - 3000), at); |
| 153 | check('the comment on the parcel ceiling names Steel, the door actually in force', |
| 154 | /Steel/.test(why)); |
| 155 | check('and names `http_max_body_bytes`, so the reader can go and read the default', |
| 156 | /http_max_body_bytes/.test(why)); |
| 157 | |
| 158 | // ── 4. And the restated 8 MiB is the one fe2o3 ships, wherever fe2o3 is ── |
| 159 | const cfg = path.join(process.env.HOME || '', 'usr', 'code', 'rust', 'fe2o3', |
| 160 | 'fe2o3_steel', 'src', 'srv', 'cfg.rs'); |
| 161 | if (fs.existsSync(cfg)) { |
| 162 | const m = /http_max_body_bytes:\s+([0-9*\s]+),/.exec(fs.readFileSync(cfg, 'utf8')); |
| 163 | const shipped = m ? m[1].split('*').reduce((a, b) => a * Number(b.trim()), 1) : 0; |
| 164 | check('the 8 MiB restated here is the default fe2o3_steel ships', |
| 165 | shipped === STEEL_BODY_MAX, shipped + ' in ' + cfg); |
| 166 | } else { |
| 167 | console.log('note fe2o3 is not beside this repository, so the restated 8 MiB was ' |
| 168 | + 'not checked against fe2o3_steel/src/srv/cfg.rs.'); |
| 169 | } |
| 170 | |
| 171 | console.log(bad ? '\n' + bad + ' FAILED' : '\nall checks passed'); |
| 172 | process.exit(bad ? 1 : 0); |