From a92767d53f62303c9607db6747d7a997ce07b1cf Mon Sep 17 00:00:00 2001 From: Marat Zimnurov Date: Sun, 4 Oct 2026 16:35:57 +0000 Subject: [PATCH 1/5] refactor(guards): two shell guards are checked by proved plans scripts/guards/proved-share-vs-tree.sh (139 lines) and scripts/guards/guards-without-forgery-probe.sh (275 lines of shell with an embedded python program) are gone. The same two checks now stand as proved-share-vs-tree.fscript (13 obligations, all proved by the kernel) and guards-without-forgery-probe.fscript (11 obligations, all proved). The census (docs/shell-to-flang-census.md) held the first one back with "the place where it is called is a hook that runs before the binary is built". That argument is dead, and the run says so: since task 1219 the hook IS a plan - .githooks/pre-push is two lines of "exec bootstrap/flang io .githooks/pre-push.fscript" - so the binary must already exist by the time the hook calls anything, and binary.yml calls ./bootstrap/flang twelve steps earlier. The second one was held back by "a YAML parser (pyyaml)". That argument was killed by a neighbour, not by words: who-calls-the-guards.fscript already takes run: keys apart by indentation, and this plan imports that module instead of writing a second parser. Only the grouping of lines into bodies is new - "exit 1" has to stand in the SAME body as the condition - plus one fix the neighbour does not need: a trailing ";" is stripped off a word before it is read as a path, the way the python did it. Without it two called probes (licenses:check, emit-promises:check) went missing. Old and new were run on one tree and answered the same, sign for sign: proved share the whole report, 14 numbers (960 files with obligations, 1128 ledger rows, 15761 postconditions, 10841 proved), and all three ledger forgeries gave the same words and code 1 in both forgery probe census, --list and --check (79 guards, 36 called probes, 13 built and uncalled, 43 in debt; 43 names listed), and both ledger forgeries gave the same words and code 1 Each plan carries a Forgery plan of its own, and each forgery works in memory: no file of the tree is touched, so a killed run leaves nothing to roll back. The old shell probe edited the ledger on disk and copied it back. Both forgeries were run against a gutted copy of their own guard ("Troubles of" returning an empty list on any input): the gutted copy answers code 0 and names every side it failed to show. Both plans take their rows in the proved share (13|13|0|0|0 and 11|11|0|0|0), and the four paths of the removed shells that live on in closed task records are entered in the link ledger as history. --- .flangrc | 7 + .githooks/pre-push.fscript | 4 +- .github/workflows/binary.yml | 74 +- .github/workflows/ci.yml | 31 +- .github/workflows/install-path.yml | 4 +- .github/workflows/release.yml | 2 +- .../guards-without-forgery-probe.fscript | 1237 ++++++++++++++++ .../guards/guards-without-forgery-probe.sh | 275 ---- scripts/guards/proved-share-vs-tree.fscript | 1267 +++++++++++++++++ scripts/guards/proved-share-vs-tree.sh | 139 -- .../ledgers/link-guard-known-not-a-path.tsv | 4 + scripts/ledgers/proved-share-ledger.txt | 2 + 12 files changed, 2579 insertions(+), 467 deletions(-) create mode 100644 scripts/guards/guards-without-forgery-probe.fscript delete mode 100755 scripts/guards/guards-without-forgery-probe.sh create mode 100644 scripts/guards/proved-share-vs-tree.fscript delete mode 100755 scripts/guards/proved-share-vs-tree.sh diff --git a/.flangrc b/.flangrc index c09a34f97..1bfeb59e8 100644 --- a/.flangrc +++ b/.flangrc @@ -91,6 +91,13 @@ script.proofs:summary = bootstrap/flang run-script seed:freshness --what proofs: script.word:check = bootstrap/flang run-script seed:freshness --what word:check >&2 && bootstrap/flang io flang/scripts/word-guard.fscript --plan 'Сторож слов' --max-steps 2000000000 --на-веру script.word:forgery = bootstrap/flang run-script seed:freshness --what word:forgery >&2 && bootstrap/flang io flang/scripts/word-guard.fscript --plan 'Подлог слов' --max-steps 2000000000 --на-веру script.guard-calls:check = bootstrap/flang io scripts/guards/who-calls-the-guards.fscript --plan Check +script.proved-share-tree:check = bootstrap/flang io scripts/guards/proved-share-vs-tree.fscript --plan Check +script.proved-share-tree:numbers = bootstrap/flang io scripts/guards/proved-share-vs-tree.fscript --plan Numbers +script.proved-share-tree:forgery = bootstrap/flang io scripts/guards/proved-share-vs-tree.fscript --plan Forgery +script.forgery-probe:check = bootstrap/flang io scripts/guards/guards-without-forgery-probe.fscript --plan Check +script.forgery-probe:census = bootstrap/flang io scripts/guards/guards-without-forgery-probe.fscript --plan Census +script.forgery-probe:list = bootstrap/flang io scripts/guards/guards-without-forgery-probe.fscript --plan List +script.forgery-probe:forgery = bootstrap/flang io scripts/guards/guards-without-forgery-probe.fscript --plan Forgery script.uncalled-checks:check = bootstrap/flang io scripts/guards/checks-nobody-calls.fscript --plan Проверка --max-steps 4000000000 script.closed-length:check = bootstrap/flang io flang/scripts/closed-length-guard.fscript --max-steps 4000000000 script.emptiness:check = bootstrap/flang run-script seed:freshness --what emptiness:check >&2 && bootstrap/flang io flang/scripts/emptiness-guard.fscript --plan 'Пустоты в доказанном нет' --timeout 900000 --max-steps 2000000000 diff --git a/.githooks/pre-push.fscript b/.githooks/pre-push.fscript index d3fb066e7..94ddba505 100644 --- a/.githooks/pre-push.fscript +++ b/.githooks/pre-push.fscript @@ -22,8 +22,8 @@ запись «Check» с «name» равным "seed-refresh" и «command» равным "bootstrap/flang io scripts/seed/seed-refresh.fscript --plan Check", запись «Check» с «name» равным "version-derivations-guard" и «command» равным "bootstrap/flang io scripts/guards/version-derivations-guard.fscript --plan Проверка", запись «Check» с «name» равным "who-calls-the-guards" и «command» равным "bootstrap/flang io scripts/guards/who-calls-the-guards.fscript --plan Check", - запись «Check» с «name» равным "guards-without-forgery-probe" и «command» равным "sh scripts/guards/guards-without-forgery-probe.sh --check", - запись «Check» с «name» равным "proved-share-vs-tree" и «command» равным "sh scripts/guards/proved-share-vs-tree.sh", + запись «Check» с «name» равным "forgery-probe" и «command» равным "bootstrap/flang run-script forgery-probe:check", + запись «Check» с «name» равным "share-tree" и «command» равным "bootstrap/flang run-script proved-share-tree:check", запись «Check» с «name» равным "stdlib-proof-guard" и «command» равным "bootstrap/flang io scripts/guards/stdlib-proof-guard.fscript --plan Brackets", запись «Check» с «name» равным "cyrillic-file-names-guard" и «command» равным "bootstrap/flang io scripts/guards/cyrillic-file-names-guard.fscript --plan Проверка", запись «Check» с «name» равным "translit-file-names-guard" и «command» равным "bootstrap/flang io scripts/guards/translit-file-names-guard.fscript --plan Проверка", diff --git a/.github/workflows/binary.yml b/.github/workflows/binary.yml index 2fcb7efe9..6b7561b41 100644 --- a/.github/workflows/binary.yml +++ b/.github/workflows/binary.yml @@ -394,9 +394,9 @@ jobs: # # Счётчиков долга в дереве было три — раздел «Вне языка» в docs/ROADMAP.md, # docs/javascript-inventory.md и числа сайта, — и все три считали ОДИН - # язык: JavaScript. Оболочка (49 файлов, 9344 строк), HTML, CSS, пробы на - # СНЯТО 2026-10-04 файлов *.sh = 49 (перенос flang/translation/run.sh на план flang/translation/run.fscript снял один файл оболочки; до него 50, снято 2026-10-04) (задачи 0049 и 5821: сняты flang/scripts/word-occupancy.mjs, scripts/seed/seed-freshness.sh и scripts/guards/version-derivations-guard.sh — у каждого двойник на flang доказан прогоном; до них 52, снято 2026-10-04) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 101, снято 2026-09-17) - # СНЯТО 2026-10-04 строк-в *.sh = 9344 (перенос flang/translation/run.sh на план flang/translation/run.fscript снял 214 строк оболочки; до него 9558, снято 2026-10-04) (задачи 0049 и 5821: сняты flang/scripts/word-occupancy.mjs, scripts/seed/seed-freshness.sh и scripts/guards/version-derivations-guard.sh — у каждого двойник на flang доказан прогоном; до них 9756, снято 2026-10-04) (задачи 1426 и 8567: поиск коммита отпечатка по содержимому прибавил 135 строк в scripts/bootstrap-reprint.sh, а отменённая хронология предела шагов убрала 141; до них 9762, снято 2026-09-17) (задача 1400: девять проб на подлог и две честные под правила Н6 и О9 прибавили 42 строки в flang/proof/checker/tests/run.sh) (задача 1416: четырнадцать объявлений ярлыков заведены в скриптах и зов «Сбора» — в хуке; до них 23372, снято 2026-09-17) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 23980, снято 2026-09-22) (ADR-0046: довод в шапках двух сторожей имён — сперва почему flang/proof не судится, потом почему вошёл в область — прибавил 9 строк; до него 23971, снято 2026-09-17) + # язык: JavaScript. Оболочка (47 файлов, 8930 строк), HTML, CSS, пробы на + # СНЯТО 2026-10-04 файлов *.sh = 47 (перенос scripts/guards/proved-share-vs-tree.sh и guards-without-forgery-probe.sh на планы снял два файла оболочки; до них 49, снято 2026-10-04) (перенос flang/translation/run.sh на план flang/translation/run.fscript снял один файл оболочки; до него 50, снято 2026-10-04) (задачи 0049 и 5821: сняты flang/scripts/word-occupancy.mjs, scripts/seed/seed-freshness.sh и scripts/guards/version-derivations-guard.sh — у каждого двойник на flang доказан прогоном; до них 52, снято 2026-10-04) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 101, снято 2026-09-17) + # СНЯТО 2026-10-04 строк-в *.sh = 8930 (перенос scripts/guards/proved-share-vs-tree.sh и guards-without-forgery-probe.sh на планы снял 414 строк оболочки; до них 9344, снято 2026-10-04) (перенос flang/translation/run.sh на план flang/translation/run.fscript снял 214 строк оболочки; до него 9558, снято 2026-10-04) (задачи 0049 и 5821: сняты flang/scripts/word-occupancy.mjs, scripts/seed/seed-freshness.sh и scripts/guards/version-derivations-guard.sh — у каждого двойник на flang доказан прогоном; до них 9756, снято 2026-10-04) (задачи 1426 и 8567: поиск коммита отпечатка по содержимому прибавил 135 строк в scripts/bootstrap-reprint.sh, а отменённая хронология предела шагов убрала 141; до них 9762, снято 2026-09-17) (задача 1400: девять проб на подлог и две честные под правила Н6 и О9 прибавили 42 строки в flang/proof/checker/tests/run.sh) (задача 1416: четырнадцать объявлений ярлыков заведены в скриптах и зов «Сбора» — в хуке; до них 23372, снято 2026-09-17) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 23980, снято 2026-09-22) (ADR-0046: довод в шапках двух сторожей имён — сперва почему flang/proof не судится, потом почему вошёл в область — прибавил 9 строк; до него 23971, снято 2026-09-17) # C, Python, awk и Erlang не считались нигде и ни в одной проверке. Долг, # которого никто не считает, не убывает: его не видно ни в отчёте, ни в # ленте, и растёт он молча. @@ -407,9 +407,9 @@ jobs: # оболочке или на Python останавливает работу в тот же день. # # Замер на этом дереве: 17,7 с и 471 МБ, двоичному хватает `git` и `wc`. - # Предел шагов поднят с умолчания (10 млн): опись обходит 192 файлов и + # Предел шагов поднят с умолчания (10 млн): опись обходит 190 файлов и # семнадцать языков, и в умолчание не укладывается. - # СНЯТО 2026-10-04 файлов *.sh,*.c,*.h,*.py,*.html,*.css,*.awk,*.erl,*.js,*.mjs,*.java,*.cs,*.ex,*.exs,*.go,*.rs,*.lua,*.vim,*.rb,*.cpp,*.cc,*.hpp,*.hh,ярлык,packaging/asdf/bin/download,packaging/asdf/bin/install,packaging/asdf/bin/list-all,.githooks/pre-push = 192 (перенос flang/translation/run.sh на план flang/translation/run.fscript снял один файл вне flang; до него 193, снято 2026-10-04) (задачи 0049 и 5821: сняты flang/scripts/word-occupancy.mjs, scripts/seed/seed-freshness.sh и scripts/guards/version-derivations-guard.sh — у каждого двойник на flang доказан прогоном; до них 196, снято 2026-10-04) (две честные пары сличителя перевода: отбор по признаку и объявленная мера; до них 194, снято 2026-09-17) (задача 5821: семь проверок scripts/** стали планами; до них 251, снято 2026-09-27) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 256, снято 2026-09-17) + # СНЯТО 2026-10-04 файлов *.sh,*.c,*.h,*.py,*.html,*.css,*.awk,*.erl,*.js,*.mjs,*.java,*.cs,*.ex,*.exs,*.go,*.rs,*.lua,*.vim,*.rb,*.cpp,*.cc,*.hpp,*.hh,ярлык,packaging/asdf/bin/download,packaging/asdf/bin/install,packaging/asdf/bin/list-all,.githooks/pre-push = 190 (перенос scripts/guards/proved-share-vs-tree.sh и guards-without-forgery-probe.sh на планы снял два файла вне flang; до них 192, снято 2026-10-04) (перенос flang/translation/run.sh на план flang/translation/run.fscript снял один файл вне flang; до него 193, снято 2026-10-04) (задачи 0049 и 5821: сняты flang/scripts/word-occupancy.mjs, scripts/seed/seed-freshness.sh и scripts/guards/version-derivations-guard.sh — у каждого двойник на flang доказан прогоном; до них 196, снято 2026-10-04) (две честные пары сличителя перевода: отбор по признаку и объявленная мера; до них 194, снято 2026-09-17) (задача 5821: семь проверок scripts/** стали планами; до них 251, снято 2026-09-27) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 256, снято 2026-09-17) # # СКОЛЬКО ИЗ ЭТИХ ПЯТИДЕСЯТИ МИЛЛИОНОВ УХОДИТ, замер 29 августа 2026. # Меряно перебором самого предела: при 10 500 000 опись умирает @@ -504,52 +504,38 @@ jobs: # ── ОПИСЬ ДОКАЗАННОГО СВЕРЯЕТСЯ С ДЕРЕВОМ НА КАЖДОМ ПУШЕ ──────────────── # - # `scripts/guards/proved-share-vs-tree.sh` сверяет знаменатель + # `scripts/guards/proved-share-vs-tree.fscript` сверяет знаменатель # `scripts/ledgers/proved-share-ledger.txt` со счётом по исходнику: у # каждого .flang с обязательствами есть строка, у каждой строки — файл, и # «написано» сходится со счётом. До 15 сентября 2026 его звал только хук # перед пушем, CI — никто: запрос слияния с новым файлом доказательств # проходил зелёным, а хук краснел у следующего, кто пушил поверх main. - # Двоичный сверке не нужен — ей хватает git, grep, md5sum и awk; 12 с на - # машине разработки. FLANG_TMP задан потому, что умолчание /srv/tmp на - # раннере не создать. + # 4 октября 2026 сверка перенесена с оболочки на план: двоичный к этому + # шагу уже собран (шаги выше зовут ./bootstrap/flang), а прежний довод + # «её зовёт хук до сборки двоичного» устарел с задачи 1219 — хук сам стал + # планом. Считает по-прежнему git, grep и md5sum, 11 с на машине + # разработки; FLANG_TMP больше не нужен — времянок план не заводит. - name: Check proved share - env: - FLANG_TMP: ${{ runner.temp }} - run: sh scripts/guards/proved-share-vs-tree.sh - # Три порчи — по одной на каждую беду, которую сверка обязана назвать: - # «написано» первой строки +1, первая строка вынута, строка о файле, - # которого нет. Каждая сличается cmp (подлог собрался), требует кода не 0 - # и своих слов в выводе; опись возвращается и сличается в конце. + run: ./bootstrap/flang run-script proved-share-tree:check + # Четыре стороны порчи — нулевая (опись как есть, бед быть не должно) и по + # одной на каждую беду, которую сверка обязана назвать: «написано» первой + # мерной строки +1, строка о первом файле дерева вынута, вписана строка о + # файле, которого нет. Порча идёт В ПАМЯТИ: файл описи не трогается, и + # откатывать нечего даже если прогон убьют на середине. + # КОДЫ ПЕРЕВЁРНУТЫ, как у пары про опись дерева выше: код 1 — подлог + # пойман на всех четырёх сторонах; код 0 — сверка промолчала хотя бы на + # одной, ЛИБО порча не собралась. Оба случая обязаны красить шаг. + # Прогнано на выпотрошенной копии сверки («Troubles of», возвращающая + # пустой список на любом входе): она даёт этому шагу код 0. + # Зовётся ФАЙЛОМ, а не командой `proved-share-tree:forgery`: прибор проб + # порчи (scripts/guards/guards-without-forgery-probe.fscript) относит + # пробу к сторожу по файлу, а не по имени парной команды. - name: Probe proved share - env: - FLANG_TMP: ${{ runner.temp }} run: | - opis=scripts/ledgers/proved-share-ledger.txt - cp "$opis" "$RUNNER_TEMP/opis" - porcha() { - slova=$1; shift - awk "$@" "$RUNNER_TEMP/opis" > "$opis" - if cmp -s "$opis" "$RUNNER_TEMP/opis"; then - echo "ПОДЛОГ НЕ СОБРАЛСЯ: опись не изменилась (порча «$slova»)" >&2 - exit 1 - fi - if sh scripts/guards/proved-share-vs-tree.sh > "$RUNNER_TEMP/sverka.out" 2>&1; then - cp "$RUNNER_TEMP/opis" "$opis" - echo "СВЕРКА ПРОМОЛЧАЛА на порче «$slova»" >&2 - exit 1 - fi - cp "$RUNNER_TEMP/opis" "$opis" - if ! grep -F "$slova" "$RUNNER_TEMP/sverka.out"; then - echo "ПОКРАСНЕЛО НЕ ПО ПОРЧЕ «$slova»:" >&2 - tail -5 "$RUNNER_TEMP/sverka.out" >&2 - exit 1 - fi - } - porcha '«НАПИСАНО» НЕ СХОДИТСЯ' -F'|' -v OFS='|' '!s && !/^\/\// && NF == 7 && $2 ~ /^[0-9]+$/ { $2 = $2 + 1; s = 1 } { print }' - porcha 'НЕТ СТРОКИ' -F'|' '!s && !/^\/\// && NF == 7 { s = 1; next } { print }' - porcha 'ЛИШНЯЯ СТРОКА' '{ print } END { print "00000000000000000000000000000000|1|×|×|×|0|docs/there-is-no-such-file.flang" }' - cmp "$opis" "$RUNNER_TEMP/opis" + if ./bootstrap/flang io scripts/guards/proved-share-vs-tree.fscript --plan Forgery; then + echo "сверка промолчала на порченой описи — проверять ею нечего" >&2 + exit 1 + fi - name: Check records follow their sources run: ./bootstrap/flang io scripts/guards/record-follows-its-source.fscript --plan Проверка @@ -1021,7 +1007,7 @@ jobs: make -C bootstrap -j"$(nproc)" CFLAGS="$FLANG_CFLAGS" fi # ПРОБА ИДЁТ ПЕРВОЙ И СТОИТ ОДНУ ПЕЧАТЬ ИЗ ТРЁХ. Сторож, которого нельзя - # покрасить, неотличим от выключенного (scripts/guards/guards-without-forgery-probe.sh: + # покрасить, неотличим от выключенного (scripts/guards/guards-without-forgery-probe.fscript: # за одни сутки 5 сентября 2026 эта порода поймана четырежды, и ни разу # прибором). Проба подкладывает сверщику изменённый байт и пропавший # файл и требует красноты, а от дословной копии — молчания. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a717984d..6dcc406e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,8 +212,8 @@ jobs: # 31 августа 2026 в дереве нашлось 31 место в 14 файлах, где записанное рукой # число разошлось с тем, что лежит рядом: `docs/tree-inventory.md` считала # `seed-parses-sources-guard.sh` в 83 строки при 195, оболочку — в 66 файлов - # при 71 тогдашних — сегодня их 49; - # СНЯТО 2026-10-04 файлов *.sh = 49 (перенос flang/translation/run.sh на план flang/translation/run.fscript снял один файл оболочки; до него 50, снято 2026-10-04) (задача 5821: scripts/guards/version-derivations-guard.sh снят — сверка производных версии стала планом scripts/guards/version-derivations-guard.fscript, приговор доказан ядром (13 из 13), хук зовёт план; до него 51, снято 2026-10-04) (задача 0049: scripts/seed/seed-freshness.sh снят — проверка давно живёт планом scripts/seed/seed-freshness.fscript, а переходник ещё и терял довод (exec без "$@"); до него 52, снято 2026-10-04) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 101, снято 2026-09-21) `flang/cat/SPEC.md` обещала восемнадцать поручений при 22; + # при 71 тогдашних — сегодня их 47; + # СНЯТО 2026-10-04 файлов *.sh = 47 (перенос scripts/guards/proved-share-vs-tree.sh и guards-without-forgery-probe.sh на планы снял два файла оболочки; до них 49, снято 2026-10-04) (перенос flang/translation/run.sh на план flang/translation/run.fscript снял один файл оболочки; до него 50, снято 2026-10-04) (задача 5821: scripts/guards/version-derivations-guard.sh снят — сверка производных версии стала планом scripts/guards/version-derivations-guard.fscript, приговор доказан ядром (13 из 13), хук зовёт план; до него 51, снято 2026-10-04) (задача 0049: scripts/seed/seed-freshness.sh снят — проверка давно живёт планом scripts/seed/seed-freshness.fscript, а переходник ещё и терял довод (exec без "$@"); до него 52, снято 2026-10-04) (задача 5821: семь скриптов scripts/** переехали с оболочки на flang; до них 101, снято 2026-09-21) `flang/cat/SPEC.md` обещала восемнадцать поручений при 22; # `flang/PLAN.md` — пять вариантов «Поручение» при 22. Каждое из этих чисел # было ВЕРНО В ДЕНЬ ЗАПИСИ и солгало назавтра, и сторожа не было ни на одном. # @@ -305,7 +305,7 @@ jobs: # ПРОБ ДВЕ, И ВТОРАЯ ВАЖНЕЕ ПЕРВОЙ. Первая подкладывает путь в памяти плана # (`--plan Подлог`). Вторая кладёт НАСТОЯЩУЮ ВРЕМЯНКУ НА ДИСК и требует кода 1: # в чистой выписке CI сторож зелен всегда, а сторож, зелёный всегда, неотличим - # от выключенного (scripts/guards/guards-without-forgery-probe.sh, та же порода). + # от выключенного (scripts/guards/guards-without-forgery-probe.fscript, та же порода). vremyanki: name: stray-temporaries runs-on: ubuntu-latest @@ -1450,6 +1450,29 @@ jobs: - name: Check uncalled guards run: bootstrap/flang run-script guard-calls:check + # ПРИБОР, КОТОРЫЙ СТЕРЕЖЁТ НАЛИЧИЕ ПРОБ ПОРЧИ, ОБЯЗАН НЕСТИ ПРОБУ ТЕМ + # БОЛЕЕ. Сосед выше отвечает на вопрос «кого CI зовёт»; этот — на второй, + # без которого первый мало стоит: «а показано ли, что позванный вообще + # способен покраснеть». 4 октября 2026 он перенесён с оболочки + # (scripts/guards/guards-without-forgery-probe.sh, 275 строк с python и + # pyyaml) на план: разбор ключей run: ввезён у соседа + # scripts/guards/who-calls-the-guards.fscript, и разборщик YAML больше не + # нужен. До переноса его звал только хук перед пушем, CI — никто. + # + # КОДЫ ПЕРЕВЁРНУТЫ, а не как у соседа выше: план «Forgery» здесь портит + # перепись и ведомость В ПАМЯТИ и отвечает кодом 1, когда подлог пойман на + # всех пяти сторонах; код 0 значит «сверка промолчала хотя бы на одной» + # либо «порча не собралась». Прогнано на выпотрошенной копии («Troubles + # of», возвращающая пустой список на любом входе): она даёт шагу код 0. + - name: Probe guards without forgery probe + run: | + if bootstrap/flang io scripts/guards/guards-without-forgery-probe.fscript --plan Forgery; then + echo "сверка промолчала на порченой переписи — проверять ею нечего" >&2 + exit 1 + fi + - name: Check guards without forgery probe + run: bootstrap/flang run-script forgery-probe:check + # ── Ещё двое, прогнанные и снабжённые подлогом задачей 6612 ──────────── # # Оба числились ЗВАНЫМИ у переписи зова, и оба званы не были: прибор @@ -1547,7 +1570,7 @@ jobs: ln -sf "$put" "$podstavnoy/$programma" done # Вызов стоит В УСЛОВИИ `if`, и это не вкусовщина: перепись проб - # (scripts/guards/guards-without-forgery-probe.sh) засчитывает пробу только такой + # (scripts/guards/guards-without-forgery-probe.fscript) засчитывает пробу только такой # форме. Записанный как `otvet=$(…) && { … }`, тот же шаг работает, # но прибор его не видит, и сторож числится беспробным. if otvet=$(PATH="$podstavnoy" bootstrap/flang run-script install-path:check 2>&1); then diff --git a/.github/workflows/install-path.yml b/.github/workflows/install-path.yml index a9875ffcb..7a68a384a 100644 --- a/.github/workflows/install-path.yml +++ b/.github/workflows/install-path.yml @@ -223,7 +223,7 @@ jobs: # копии и ОБЯЗАН ответить провалом «подлог пойман». Ответил кодом 0 — # значит сравнение выпотрошено, и зелёный шаг выше ничего не значит. # Зовётся файлом, а не командой `asdf-plugin:forgery`: прибор проб порчи - # (scripts/guards/guards-without-forgery-probe.sh) относит пробу к сторожу по файлу. + # (scripts/guards/guards-without-forgery-probe.fscript) относит пробу к сторожу по файлу. - name: Probe asdf plugin run: | set -u @@ -247,7 +247,7 @@ jobs: # покраснел на подложенном. Подлог внутренний — план «Подлог» того же # файла вычёркивает проводник из прочитанного состава архива и ОБЯЗАН # ответить провалом «подлог пойман». Зовётся файлом, а не командой: - # прибор проб порчи (scripts/guards/guards-without-forgery-probe.sh) относит пробу к + # прибор проб порчи (scripts/guards/guards-without-forgery-probe.fscript) относит пробу к # сторожу по файлу. - name: Probe delivery contents run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ae3fc8597..a69009517 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -246,7 +246,7 @@ jobs: # ПОКАЗАНО ПРОГОНОМ, ЧТО СТОРОЖ ВЫШЕ УМЕЕТ КРАСНЕТЬ. # # Сторож, у которого не показано, что он краснеет, — это сторож, которому - # верят зря: ровно этот род долга считает `scripts/guards/guards-without-forgery-probe.sh`. + # верят зря: ровно этот род долга считает `scripts/guards/guards-without-forgery-probe.fscript`. # Проба подставляет версию, заметки о которой в json заведомо нет, и # требует от плана ОТКАЗА. Прошёл план — красный здесь, а не молчание. # diff --git a/scripts/guards/guards-without-forgery-probe.fscript b/scripts/guards/guards-without-forgery-probe.fscript new file mode 100644 index 000000000..a06ac84ce --- /dev/null +++ b/scripts/guards/guards-without-forgery-probe.fscript @@ -0,0 +1,1237 @@ +модуль «Guards without forgery probe» + использует «Who calls the guards» из "who-calls-the-guards.fscript" + +примечание "У КАКИХ СТОРОЖЕЙ НЕТ ПРОБЫ ПОРЧИ — поимённо, прибором, а не рукой." +примечание " bootstrap/flang run-script forgery-probe:check сверка с ведомостью, код 1" +примечание " bootstrap/flang run-script forgery-probe:census перепись целиком, код 0" +примечание " bootstrap/flang run-script forgery-probe:list только имена беспробных" +примечание " bootstrap/flang run-script forgery-probe:forgery пять сторон порчи, код 1" + +примечание "ЗАЧЕМ. СТОРОЖ, КОТОРОГО НЕЛЬЗЯ ПОКРАСИТЬ, НЕОТЛИЧИМ ОТ ВЫКЛЮЧЕННОГО. За одни" +примечание "сутки 5 сентября 2026 эта порода поймана четыре раза, и ни разу прибором —" +примечание "всякий раз случайно: target-words:check проверял пустоту (задача 3223); шесть" +примечание "проверок чекера не отрабатывали ни разу (8690); проба под правило 9999 лежала в" +примечание "дереве, а run.sh её не звал (9999); две пробы порчи не собрались, и заметно это" +примечание "было только по тому, что числа не сдвинулись (7855, 9751). Общее у всех" +примечание "четырёх — беспроверочная вера в то, что проверка работает." + +примечание "Прибор scripts/guards/who-calls-the-guards.fscript отвечает на вопрос «кого CI" +примечание "зовёт»; этот отвечает на второй, без которого первый мало стоит: «а показано" +примечание "ли, что позванный вообще способен покраснеть»." + +примечание "ЧТО СЧИТАЕТСЯ ПРОБОЙ ПОРЧИ. Проба — это то, что ЛОМАЕТ проверяемое и требует," +примечание "чтобы сторож на этом покраснел. В дереве проба бывает ПОСТРОЕНА и отдельно —" +примечание "ПОЗВАНА, и путать эти два состояния нельзя: построенная, но никем не званная" +примечание "проба не срабатывает никогда, ровно как сторож без зовущего." +примечание " ПРОБА ПОСТРОЕНА — рядом с ярлыком X:check в .flangrc есть парный X:forgery" +примечание " или X:corrupt. Такая команда портит вход изнутри сторожа: она не зависит от" +примечание " номеров строк и портит ровно то, что сторож смотрит. Лучший вид пробы." +примечание " ПРОБА ПОЗВАНА — в теле run: какого-нибудь workflow стоит вызов сторожа В" +примечание " УСЛОВИИ if, и в том же теле есть exit 1. Признак один и тот же и от вида" +примечание " порчи не зависит: шаг падает ровно тогда, когда сторож промолчал." +примечание "Прибор считает оба и печатает раздельно. В долг («без пробы») попадает тот, у" +примечание "кого НЕТ НИ ОДНОГО из двух." + +примечание "ЧЕГО ЭТОТ ПРИБОР НЕ ГОВОРИТ. Он НЕ говорит, что проба хороша. Проба бывает" +примечание "холостой: правка не собралась либо испорчено не то, что сторож смотрит. Такую" +примечание "пробу прибор считает существующей, потому что отличить её от рабочей он не" +примечание "может — для этого надо прогнать сторожа с порчей и без. Это делает сама проба" +примечание "в CI; здесь считается только ЕЁ НАЛИЧИЕ." + +примечание "ВЕДОМОСТЬ, А НЕ ЗАПРЕТ. Беспробных сторожей больше половины; правило" +примечание "«беспробных быть не должно» красило бы CI всегда, а вечно красный сторож — это" +примечание "выключенный сторож. Поэтому план «Check» сверяет с ведомостью" +примечание "scripts/ledgers/guards-without-forgery-probe.json В ОБЕ СТОРОНЫ:" +примечание " · беспробный, которого в ведомости НЕТ, — красно: появился новый долг;" +примечание " · запись, у которой проба УЖЕ есть, — тоже красно: долг закрыт, запись стала" +примечание " неправдой, и убрать её обязан тот, кто долг закрыл." + +примечание "ЧЕМ ЭТОТ ФАЙЛ ОТЛИЧАЕТСЯ ОТ ПРЕЖНЕГО НА ОБОЛОЧКЕ. До 4 октября 2026 то же" +примечание "считал scripts/guards/guards-without-forgery-probe.sh, 275 строк оболочки с" +примечание "встроенной программой на python. Перепись дерева" +примечание "(docs/shell-to-flang-census.md) держала его доводом «разборщик YAML (pyyaml)»." +примечание "Довод снят не словами, а соседом: who-calls-the-guards.fscript берёт ключи" +примечание "run: разбором отступов, и его разбор здесь ВВЕЗЁН, а не переписан заново." +примечание "Нового в этом файле — только группировка строк в ТЕЛА: прежний сосед отдавал" +примечание "плоский список строк, а здесь нужно, чтобы exit 1 стоял в ТОМ ЖЕ теле, что и" +примечание "условие. Числа прогона обоих приборов на этом дереве 4 октября 2026 сошлись:" +примечание "77 сторожей, 34 пробы позваны, 13 построены и не позваны, 43 в долгу." + +примечание "ЧЕГО ЗДЕСЬ НЕТ. Расхождение кода возврата названо: у плана нет кода 3 за" +примечание "«нет модуля yaml» — разборщик свой; «ведомости нет» отвечает кодом 3, как и у" +примечание "оболочки, а «кривой ключ» у плана невозможен — режим задаётся именем плана." + +объект «Sweep» + «floor»: число + «running»: признак + «lines»: список строки + «bodies»: список строки + +объект «Spot» + «file»: строка + «names»: строка + «scripts»: строка + +объект «Post» + «name»: строка + «file»: строка + «built»: строка + +объект «Side» + «name»: строка + «says»: строка + «stands»: список «Post» + «entries»: список «Entry» + +тип «Stage» + вариант «Listing flows» содержит mode: строка + вариант «Reading a flow» содержит mode: строка, pending: список строки, spots: список «Spot» + вариант «Reading the debt» содержит mode: строка, spots: список «Spot» + вариант «Reading settings» содержит mode: строка, spots: список «Spot», entries: список «Entry» + +примечание "── ТЕЛА КЛЮЧЕЙ run: ГРУППАМИ, А НЕ ПЛОСКИМ СПИСКОМ ────────────────────────" + +примечание "Проба — конструкция из нескольких строк: порча, условие, откат. Резать её на" +примечание "строки значит потерять связь между вызовом и exit 1. Ввезённый сосед" +примечание "«Commands of» отдаёт плоский список со всех ключей run: разом; здесь тот же" +примечание "обход копит строки ТЕЛА и закрывает тело, когда блок кончился." + +тотальная функция «Sweep made» + принимает floor: число, running: признак, lines: список строки, bodies: список строки + возвращает «Sweep» + запись «Sweep» с «floor» равным floor и «running» равным running и «lines» равным lines и «bodies» равным bodies + +тотальная функция «Flushed» + принимает lines: список строки, bodies: список строки + возвращает список строки + пример «The lines of a body become one body» + дано lines равно ["a", "b"] + дано bodies равно пустой список + ожидается ["a\nb"] + пример «An empty body closes nothing» + дано lines равно пустой список + дано bodies равно ["c"] + ожидается ["c"] + если (длина lines) равен 0 + то bodies + иначе добавить (соединить lines по "\n") к bodies + +тотальная функция «Is noted» + принимает line: строка + возвращает признак + пример «A comment of YAML names no key» + дано line равно " # run: sh one.sh" + ожидается да + пример «A key is not a comment» + дано line равно " run: |" + ожидается нет + («Entry body» от line) начинается с "#" + +тотальная функция «Opens body» + принимает line: строка + возвращает признак + пример «A run key with a bar opens a body of commands» + дано line равно " - run: |" + ожидается да + пример «A run key with a plain value opens no body» + дано line равно " - run: make" + ожидается нет + пример «A run key inside a comment opens nothing» + дано line равно " # run: |" + ожидается нет + пусть value равно («Run value» от («Entry body» от line)) + пусть block равно ((value начинается с "|") или (value начинается с ">")) + (не («Is noted» от line)) и притом block + +тотальная функция «Opens any» + принимает line: строка + возвращает признак + пример «A block of another key is opened to be skipped» + дано line равно " script: |" + ожидается да + пример «A plain value opens nothing» + дано line равно " - run: make" + ожидается нет + пусть other равно ((не («Is noted» от line)) и притом («Opens a block» от («Entry body» от line))) + («Opens body» от line) или other + +тотальная функция «Key floor» + принимает line: строка + возвращает число + пример «The floor of a block stands one sign right of its key» + дано line равно " - run: |" + ожидается 9 + пример «A plain value leaves no floor» + дано line равно " - run: make" + ожидается 0 + если («Opens any» от line) + то («Entry indent» от line) плюс 1 + иначе 0 + +тотальная функция «Plain value» + принимает line: строка + возвращает строка + пример «A run key with a plain value is one body» + дано line равно " - run: make" + ожидается "make" + пример «A run key with a bar is not a plain value» + дано line равно " - run: |" + ожидается "" + пример «A comment is not a value» + дано line равно " # run: make" + ожидается "" + пусть value равно («Run value» от («Entry body» от line)) + пусть plain равно ((не («Is noted» от line)) и притом (не («Opens any» от line))) + если plain то value иначе "" + +тотальная функция «Inside sweep» + принимает sweep: «Sweep», line: строка + возвращает «Sweep» + пусть kept равно (добавить line к (sweep.«lines»)) + если sweep.«running» + то «Sweep made» от (sweep.«floor») и да и kept и (sweep.«bodies») + иначе sweep + +тотальная функция «Key sweep» + принимает sweep: «Sweep», line: строка + возвращает «Sweep» + пусть closed равно («Flushed» от (sweep.«lines») и (sweep.«bodies»)) + пусть value равно («Plain value» от line) + пусть bodies равно (если value равен "" то closed иначе (добавить value к closed)) + «Sweep made» от («Key floor» от line) и («Opens body» от line) и (пустой список) и bodies + +тотальная функция «Names a key» + принимает line: строка + возвращает признак + пример «A line with a key is looked at closely» + дано line равно " - run: make" + ожидается да + пример «A filter of paths names no key» + дано line равно " - 'scripts/one.sh'" + ожидается нет + ((line содержит "run:") или (line содержит "|")) или (line содержит ">") + +тотальная функция «Outside sweep» + принимает sweep: «Sweep», line: строка + возвращает «Sweep» + пусть closed равно («Flushed» от (sweep.«lines») и (sweep.«bodies»)) + если («Names a key» от line) + то «Key sweep» от sweep и line + иначе «Sweep made» от 0 и нет и (пустой список) и closed + +тотальная функция «Sweep step» + принимает sweep: «Sweep», line: строка + возвращает «Sweep» + если «Belongs to block» от (sweep.«floor») и line + то «Inside sweep» от sweep и line + иначе «Outside sweep» от sweep и line + +тотальная функция «Bodies of» + принимает text: строка + возвращает список строки + пример «Every run key gives a body of its own, and comments stay inside it» + дано text равно "steps:\n - run: |\n # п\n if sh a.sh; then exit 1; fi\n - run: make\n" + ожидается [" # п\n if sh a.sh; then exit 1; fi", "make"] + пусть start равно («Sweep made» от 0 и нет и (пустой список) и (пустой список)) + пусть swept равно (свёртка (разделить text по "\n") начиная с start как sweep и line → «Sweep step» от sweep и line) + «Flushed» от (swept.«lines») и (swept.«bodies») + +примечание "── ПРИЗНАК ПРОБЫ: ВЫЗОВ В УСЛОВИИ if, И В ТОМ ЖЕ ТЕЛЕ exit 1 ──────────────" + +тотальная функция «Is if line» + принимает line: строка + возвращает признак + пример «A call in a condition is a probe» + дано line равно " if sh one.sh --подлог; then exit 1; fi" + ожидается да + пример «A bare call is a working run, not a probe» + дано line равно " sh one.sh --check" + ожидается нет + пример «A comment of the shell is not a condition» + дано line равно " # if sh one.sh; then exit 1; fi" + ожидается нет + пусть bare равно («Without leading blanks» от line) + (bare начинается с "if ") или (bare начинается с "elif ") + +тотальная функция «Demands red» + принимает body: строка + возвращает признак + пример «A body that falls demands red» + дано body равно "if sh one.sh; then exit 1; fi" + ожидается да + пример «A body that never falls demands nothing» + дано body равно "sh one.sh --check" + ожидается нет + body содержит "exit 1" + +тотальная функция «Spot made» + принимает file: строка, names: список строки, scripts: список строки + возвращает «Spot» + пример «A spot keeps the file and both ways of calling» + дано file равно "ci" + дано names равно ["a:check"] + дано scripts равно ["b.sh"] + ожидается (запись «Spot» с «file» равным "ci" и «names» равным "\na:check\n" и «scripts» равным "\nb.sh\n") + запись «Spot» с «file» равным file и «names» равным («Marked» от names) и «scripts» равным («Marked» от scripts) + +тотальная функция «Parting marks» + возвращает список строки + обеспечивает «знаков оболочки восемь» (длина результат) равен 8 + ["\"", "'", "`", "(", ")", ";", "&", "|"] + +тотальная функция «Cleaned» + принимает line: строка + возвращает строка + пример «The signs that bind a call to the shell are taken off» + дано line равно "if sh one.sh; then exit 1; fi" + ожидается "if sh one.sh then exit 1 fi" + пример «A call in brackets stands on its own» + дано line равно "if (sh one.sh); then" + ожидается "if sh one.sh then" + свёртка («Parting marks») начиная с line как text и sign → соединить (разделить text по sign) по " " + +тотальная функция «Spot of body» + принимает file: строка, body: строка + возвращает «Spot» + пример «The calls of the conditions of a body are gathered» + дано file равно "ci" + дано body равно "if bootstrap/flang run-script a:check; then exit 1; fi\nsh b.sh" + ожидается (запись «Spot» с «file» равным "ci" и «names» равным "\na:check\n" и «scripts» равным "\n\n") + пусть kept равно (отфильтровать (разделить body по "\n") где line → («Is if line» от line)) + пусть lines равно (отобразить kept как line → («Cleaned» от line)) + пусть names равно (свёртка lines начиная с (пустой список) как found и line → «Names in» от found и line) + пусть scripts равно (свёртка lines начиная с (пустой список) как found и line → «Scripts in» от found и line) + «Spot made» от file и names и scripts + +тотальная функция «Spots of» + принимает file: строка, text: строка + возвращает список «Spot» + пусть bodies равно (отфильтровать («Bodies of» от text) где body → («Demands red» от body)) + отобразить bodies как body → («Spot of body» от file и body) + +примечание "── ПАРНАЯ КОМАНДА: X:forgery ЛИБО X:corrupt РЯДОМ С X:check ───────────────" + +тотальная функция «Front pieces» + принимает pieces: список строки + возвращает список строки + обеспечивает «список не длиннее прежнего» (длина результат) не больше (длина pieces) + пример «The last piece is dropped» + дано pieces равно ["word", "occupancy", "check"] + ожидается ["word", "occupancy"] + пример «Of one piece nothing is left» + дано pieces равно ["check"] + ожидается пустой список + разбор pieces + случай пусто + то пустой список + случай голова и хвост + то если (длина хвост) равен 0 + то пустой список + иначе приписать голова к («Front pieces» от хвост) + +тотальная функция «Prefix of» + принимает name: строка + возвращает строка + пример «The prefix is the name without its last share» + дано name равно "codes:check" + ожидается "codes" + пример «A joined name keeps its middle shares» + дано name равно "word:occupancy:check" + ожидается "word:occupancy" + соединить («Front pieces» от (разделить name по ":")) по ":" + +тотальная функция «Pair name» + принимает name: строка, tail: строка + возвращает строка + пример «The pair of a guard stands at its prefix» + дано name равно "codes:check" + дано tail равно "forgery" + ожидается "codes:forgery" + соединить [(«Prefix of» от name), ":", tail] по "" + +тотальная функция «Or corrupt» + принимает name: строка, marks: строка + возвращает строка + пример «A corrupt command counts as a built probe» + дано name равно "codes:check" + дано marks равно "\ncodes:corrupt\n" + ожидается "codes:corrupt" + пример «Without a pair nothing is built» + дано name равно "codes:check" + дано marks равно "\nother:forgery\n" + ожидается "" + пусть corrupt равно («Pair name» от name и "corrupt") + если («Is marked» от marks и corrupt) то corrupt иначе "" + +тотальная функция «Built pair» + принимает name: строка, marks: строка + возвращает строка + пример «A forgery command is the first pair looked for» + дано name равно "codes:check" + дано marks равно "\ncodes:forgery\n\ncodes:corrupt\n" + ожидается "codes:forgery" + пример «Without a forgery the corrupt command is taken» + дано name равно "codes:check" + дано marks равно "\ncodes:corrupt\n" + ожидается "codes:corrupt" + пусть forgery равно («Pair name» от name и "forgery") + если («Is marked» от marks и forgery) + то forgery + иначе «Or corrupt» от name и marks + +примечание "── ПОЛОЖЕНИЕ СТОРОЖА: ГДЕ СТОИТ ЕГО ПРОБА И ПОСТРОЕНА ЛИ ПАРНАЯ КОМАНДА ───" + +тотальная функция «Post made» + принимает name: строка, file: строка, built: строка + возвращает «Post» + запись «Post» с «name» равным name и «file» равным file и «built» равным built + +тотальная функция «No spot» + возвращает «Spot» + пример «A guard nobody probes stands at no spot» + ожидается (запись «Spot» с «file» равным "" и «names» равным "" и «scripts» равным "") + запись «Spot» с «file» равным "" и «names» равным "" и «scripts» равным "" + +тотальная функция «Calls it» + принимает command: «Command», spot: «Spot» + возвращает признак + пример «A probe calls the guard by its name» + дано command равно (запись «Command» с «name» равным "a:check" и «line» равным "sh one.sh") + дано spot равно (запись «Spot» с «file» равным "ci" и «names» равным "\na:check\n" и «scripts» равным "") + ожидается да + пример «A probe calls the guard by its file» + дано command равно (запись «Command» с «name» равным "a:check" и «line» равным "sh one.sh") + дано spot равно (запись «Spot» с «file» равным "ci" и «names» равным "" и «scripts» равным "\none.sh\n") + ожидается да + пример «A spot that calls neither does not call the guard» + дано command равно (запись «Command» с «name» равным "a:check" и «line» равным "sh one.sh") + дано spot равно (запись «Spot» с «file» равным "ci" и «names» равным "" и «scripts» равным "\ntwo.sh\n") + ожидается нет + пусть named равно («Is marked» от (spot.«names») и (command.«name»)) + named или («Is called by file» от (command.«line») и (spot.«scripts»)) + +тотальная функция «Spot found» + принимает command: «Command», spots: список «Spot» + возвращает «Spot» + пусть found равно (отфильтровать spots где spot → («Calls it» от command и spot)) + разбор found + случай пусто + то «No spot» + случай голова и хвост + то голова + +тотальная функция «Post of» + принимает command: «Command», spots: список «Spot», marks: строка + возвращает «Post» + пусть spot равно («Spot found» от command и spots) + пусть built равно («Built pair» от (command.«name») и marks) + «Post made» от (command.«name») и (spot.«file») и built + +тотальная функция «Post named» + принимает name: строка, stands: список «Post» + возвращает «Post» + пример «The stand of the name is taken» + дано name равно "a:check" + дано stands равно [(запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "")] + ожидается (запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "") + пример «A name outside the stands stands nowhere» + дано name равно "b:check" + дано stands равно пустой список + ожидается (запись «Post» с «name» равным "b:check" и «file» равным "" и «built» равным "") + разбор (отфильтровать stands где stand → (stand.«name») равен name) + случай пусто + то «Post made» от name и "" и "" + случай голова и хвост + то голова + +тотальная функция «Sorted stands» + принимает stands: список «Post» + возвращает список «Post» + пусть names равно («Sorted» от (отобразить stands как stand → stand.«name»)) + отобразить names как name → («Post named» от name и stands) + +тотальная функция «Posts of» + принимает commands: список «Command», spots: список «Spot» + возвращает список «Post» + пусть marks равно («Marked» от (отобразить commands как command → command.«name»)) + пусть guards равно (отфильтровать commands где command → («Is guard» от (command.«name»))) + «Sorted stands» от (отобразить guards как command → («Post of» от command и spots и marks)) + +тотальная функция «Is probed» + принимает stand: «Post» + возвращает признак + пример «A guard whose probe stands somewhere is probed» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "") + ожидается да + пример «A guard without a called probe is not probed» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "p") + ожидается нет + не ((stand.«file») равен "") + +тотальная функция «Probed» + принимает stands: список «Post» + возвращает список «Post» + отфильтровать stands где stand → («Is probed» от stand) + +тотальная функция «In debt» + принимает stands: список «Post» + возвращает список «Post» + отфильтровать stands где stand → не («Is probed» от stand) + +тотальная функция «Built only» + принимает stands: список «Post» + возвращает список «Post» + отфильтровать («In debt» от stands) где stand → не ((stand.«built») равен "") + +примечание "── ПЕРЕПИСЬ ──────────────────────────────────────────────────────────────────" + +тотальная функция «Padded out» + принимает text: строка, width: число + возвращает строка + пример «A short name is padded to the column» + дано text равно "a:check" + дано width равно 10 + ожидается "a:check " + пример «A long name is left as it is» + дано text равно "a:very:long:check" + дано width равно 10 + ожидается "a:very:long:check" + если (длина text) меньше width + то соединить [text, («Padding» от (width минус (длина text)))] по "" + иначе text + +тотальная функция «Cut to» + принимает text: строка, width: число + возвращает строка + пример «A short reason is told whole» + дано text равно "дорог" + дано width равно 10 + ожидается "дорог" + пример «A long reason is cut» + дано text равно "дорог, и очень" + дано width равно 5 + ожидается "дорог" + если (длина text) больше width + то подстрока text с 1 по width + иначе text + +тотальная функция «Probe source» + принимает stand: «Post» + возвращает строка + пример «A built pair names itself as the source of the forgery» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "a:forgery") + ожидается "a:forgery" + пример «Without a pair the forgery stands in the step itself» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "") + ожидается "порча внешняя, в самом шаге" + если (stand.«built») равен "" + то "порча внешняя, в самом шаге" + иначе stand.«built» + +тотальная функция «Called line» + принимает stand: «Post» + возвращает строка + пример «A called probe is told with its file and its source» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci.yml" и «built» равным "") + ожидается " a:check ci.yml порча внешняя, в самом шаге" + пусть name равно («Padded out» от (stand.«name») и 30) + пусть file равно («Padded out» от (stand.«file») и 12) + соединить [" ", name, " ", file, " ", («Probe source» от stand)] по "" + +тотальная функция «Built line» + принимает stand: «Post» + возвращает строка + пример «A built but uncalled probe names its command» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "a:forgery") + ожидается " a:check команда a:forgery" + соединить [" ", («Padded out» от (stand.«name») и 30), " команда ", (stand.«built»)] по "" + +тотальная функция «Reason told» + принимает name: строка, entries: список «Entry» + возвращает строка + пример «The reason is read from the ledger» + дано name равно "a:check" + дано entries равно [(запись «Entry» с «guard» равным "a:check" и «reason» равным "дорог")] + ожидается "дорог" + пример «A guard outside the ledger has no reason» + дано name равно "a:check" + дано entries равно пустой список + ожидается "причина в ведомости не названа" + разбор (отфильтровать entries где entry → (entry.«guard») равен name) + случай пусто + то "причина в ведомости не названа" + случай голова и хвост + то голова.«reason» + +тотальная функция «Debt reason» + принимает stand: «Post», entries: список «Entry» + возвращает строка + пример «A built pair that nobody calls is the reason itself» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "a:forgery") + дано entries равно пустой список + ожидается "проба ПОСТРОЕНА командой a:forgery, но её не зовут" + пусть own равно (соединить ["проба ПОСТРОЕНА командой ", (stand.«built»), ", но её не зовут"] по "") + если (stand.«built») равен "" + то «Reason told» от (stand.«name») и entries + иначе own + +тотальная функция «Debt line» + принимает stand: «Post», entries: список «Entry» + возвращает строка + пример «A debt is told with its reason, cut to the column» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "") + дано entries равно [(запись «Entry» с «guard» равным "a:check" и «reason» равным "дорог")] + ожидается " a:check дорог" + пусть reason равно («Cut to» от («Debt reason» от stand и entries) и 80) + соединить [" ", («Padded out» от (stand.«name») и 30), " ", reason] по "" + +тотальная функция «Head lines» + принимает stands: список «Post» + возвращает список строки + пусть probed равно (к строке (длина («Probed» от stands))) + пусть built равно (к строке (длина («Built only» от stands))) + пусть debt равно (к строке (длина («In debt» от stands))) + ["ПЕРЕПИСЬ ПРОБ ПОРЧИ: у кого показано, что он краснеет", "", + (соединить [" сторожей в дереве ", (к строке (длина stands))] по ""), + (соединить [" ПРОБА ПОЗВАНА (CI требует красноты) ", probed] по ""), + (соединить [" проба построена, но НЕ позвана ", built] по ""), + (соединить [" ПРОБА НЕ ПОКАЗАНА (долг) ", debt] по "")] + +тотальная функция «Called lines» + принимает stands: список «Post» + возвращает список строки + пусть told равно (отобразить («Probed» от stands) как stand → («Called line» от stand)) + «Joined» от ["", "ПРОБА ПОЗВАНА, и где стоит:", ""] и told + +тотальная функция «Built lines» + принимает stands: список «Post» + возвращает список строки + пусть told равно (отобразить («Built only» от stands) как stand → («Built line» от stand)) + пусть head равно ["", "ПРОБА ПОСТРОЕНА, НО НИКТО ЕЁ НЕ ЗОВЁТ — она не срабатывает никогда:", ""] + если (длина told) равен 0 то (пустой список) иначе («Joined» от head и told) + +тотальная функция «Debt lines» + принимает stands: список «Post», entries: список «Entry» + возвращает список строки + пусть told равно (отобразить («In debt» от stands) как stand → («Debt line» от stand и entries)) + «Joined» от ["", "ДОЛГ — проба не показана, поимённо:", ""] и told + +тотальная функция «Tail lines» + возвращает список строки + обеспечивает «хвост зовёт тот же прибор» (длина результат) равен 3 + ["", "Сверка с ведомостью — тем же прибором:", + " bootstrap/flang io scripts/guards/guards-without-forgery-probe.fscript --plan Check"] + +тотальная функция «Census» + принимает stands: список «Post», entries: список «Entry» + возвращает строка + пусть head равно («Joined» от («Head lines» от stands) и («Called lines» от stands)) + пусть middle равно («Joined» от head и («Built lines» от stands)) + пусть body равно («Joined» от middle и («Debt lines» от stands и entries)) + соединить («Joined» от body и («Tail lines»)) по "\n" + +примечание "── СВЕРКА С ВЕДОМОСТЬЮ В ОБЕ СТОРОНЫ ──────────────────────────────────────" + +тотальная функция «Debt ledger» + возвращает строка + обеспечивает «ведомость лежит у ведомостей» результат содержит "scripts/ledgers/" + "scripts/ledgers/guards-without-forgery-probe.json" + +тотальная функция «New head» + принимает name: строка + возвращает строка + пример «The head of the word names the guard» + дано name равно "a:check" + ожидается "НОВЫЙ БЕЗ ПРОБЫ: «a:check» заведён, но ни один шаг CI не требует, чтобы он" + соединить ["НОВЫЙ БЕЗ ПРОБЫ: «", name, "» заведён, но ни один шаг CI не требует, чтобы он"] по "" + +тотальная функция «New tail» + возвращает строка + обеспечивает «назван и путь ведомости, и выход из долга» результат содержит "Либо построить пробу" + соединить [" покраснел на порче, и в ", («Debt ledger»), " его нет.\n Либо построить пробу,", + " либо записать в ведомость с причиной: сторож без пробы неотличим от выключенного."] по "" + +тотальная функция «New word» + принимает name: строка + возвращает строка + соединить [(«New head» от name), («New tail»)] по "" + +тотальная функция «Where probed» + принимает stand: «Post» + возвращает строка + пример «A probe that stands somewhere is named by its file» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci.yml" и «built» равным "") + ожидается "проба стоит в ci.yml" + пример «A command no longer kept is named so» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "") + ожидается "команда уже не заведена" + если («Is probed» от stand) + то соединить ["проба стоит в ", (stand.«file»)] по "" + иначе "команда уже не заведена" + +тотальная функция «Closed head» + принимает stand: «Post» + возвращает строка + пример «A closed debt is named with the place of its probe» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci.yml" и «built» равным "") + ожидается "ЗАПИСЬ СТАЛА НЕПРАВДОЙ: «a:check» числится беспробным, а проба стоит в ci.yml." + пусть place равно («Where probed» от stand) + соединить ["ЗАПИСЬ СТАЛА НЕПРАВДОЙ: «", (stand.«name»), "» числится беспробным, а ", place, "."] по "" + +тотальная функция «Closed tail» + возвращает строка + обеспечивает «назван тот, кто обязан убрать запись» результат содержит "обязан тот, кто закрыл" + соединить ["\n Долг закрыт — убрать запись из ", («Debt ledger»), " обязан тот, кто закрыл."] по "" + +тотальная функция «Closed word» + принимает stand: «Post» + возвращает строка + соединить [(«Closed head» от stand), («Closed tail»)] по "" + +тотальная функция «Troubles of» + принимает stands: список «Post», entries: список «Entry» + возвращает список строки + пример «A ledger that names every debt has no troubles» + дано stands равно [(запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "")] + дано entries равно [(запись «Entry» с «guard» равным "a:check" и «reason» равным "дорог")] + ожидается пустой список + пусть written равно (отобразить entries как entry → entry.«guard») + пусть debt равно (отобразить («In debt» от stands) как stand → stand.«name») + пусть fresh равно («Sorted» от (отфильтровать debt где name → не («Holds» от written и name))) + пусть closed равно («Sorted» от (отфильтровать written где name → не («Holds» от debt и name))) + пусть front равно (отобразить fresh как name → («New word» от name)) + «Joined» от front и (отобразить closed как name → («Closed word» от («Post named» от name и stands))) + +тотальная функция «Agreed word» + принимает stands: список «Post» + возвращает строка + пример «The debt that the ledger knows whole is told by its count» + дано stands равно [(запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "")] + ожидается "сторожа без пробы порчи: 1, все названы в ведомости — сходится" + пусть debt равно (к строке (длина («In debt» от stands))) + соединить ["сторожа без пробы порчи: ", debt, ", все названы в ведомости — сходится"] по "" + +тотальная функция «Judgement» + принимает stands: список «Post», troubles: список строки + возвращает «Продолжение» + пример «A ledger that knows every debt ends the work» + дано stands равно [(запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "")] + дано troubles равно пустой список + ожидается вариант «Конец работы» с значение равным "сторожа без пробы порчи: 1, все названы в ведомости — сходится" + если (длина troubles) равен 0 + то вариант «Конец работы» с значение равным («Agreed word» от stands) + иначе вариант «Провал» с код равным "FLANG_FORGERY_PROBE_DEBT" и сообщение равным (соединить troubles по "\n") + +примечание "── ПОРЧА В ПАМЯТИ: ПЯТЬ СТОРОН ────────────────────────────────────────────" + +примечание "ПРИБОР, КОТОРЫЙ СТЕРЕЖЁТ НАЛИЧИЕ ПРОБ, ОБЯЗАН НЕСТИ ПРОБУ ТЕМ БОЛЕЕ. Порча" +примечание "идёт над уже прочитанными ведомостью и переписью: ни один файл дерева не" +примечание "трогается, временный каталог не заводится, откатывать нечего даже если прогон" +примечание "убьют на середине." + +примечание "Пять сторон покрывают оба конца сверки и сам признак пробы:" +примечание " нулевая — перепись как она есть, бед быть не должно;" +примечание " первая — из ведомости вынута первая запись: долг вырос, его не назвали;" +примечание " вторая — в ведомость вписан сторож, у которого проба ЕСТЬ: запись — неправда;" +примечание " третья — заведён сторож, которого никто не зовёт и в ведомости его нет;" +примечание " четвёртая — у первого позванного сторожа проба ОТНЯТА: он обязан стать долгом." + +примечание "КОДЫ ПЕРЕВЁРНУТЫ: код 1 — подлог пойман на всех пяти сторонах; код 0 — сверка" +примечание "промолчала хотя бы на одной либо порча не собралась. Оба случая красят шаг." + +тотальная функция «Side made» + принимает name: строка, says: строка, stands: список «Post», entries: список «Entry» + возвращает «Side» + запись «Side» с «name» равным name и «says» равным says и «stands» равным stands и «entries» равным entries + +тотальная функция «First entry» + принимает entries: список «Entry» + возвращает строка + пример «The first record of the ledger is named» + дано entries равно [(запись «Entry» с «guard» равным "a:check" и «reason» равным "дорог")] + ожидается "a:check" + пример «Of an empty ledger nothing is named» + дано entries равно пустой список + ожидается "" + разбор entries + случай пусто + то "" + случай голова и хвост + то голова.«guard» + +тотальная функция «Without entry» + принимает entries: список «Entry», name: строка + возвращает список «Entry» + обеспечивает «записей не стало больше» (длина результат) не больше (длина entries) + пример «The named record leaves the ledger» + дано entries равно [(запись «Entry» с «guard» равным "a:check" и «reason» равным "дорог")] + дано name равно "a:check" + ожидается пустой список + отфильтровать entries где entry → не ((entry.«guard») равен name) + +тотальная функция «Extra entry» + принимает entries: список «Entry», name: строка + возвращает список «Entry» + обеспечивает «записей стало на одну больше» (длина результат) равен ((длина entries) плюс 1) + пример «A record about a probed guard joins the ledger» + дано entries равно пустой список + дано name равно "a:check" + ожидается [(запись «Entry» с «guard» равным "a:check" и «reason» равным "подлог: этого стерегут пробой")] + добавить (запись «Entry» с «guard» равным name и «reason» равным "подлог: этого стерегут пробой") к entries + +тотальная функция «First probed» + принимает stands: список «Post» + возвращает строка + пример «The first guard with a called probe is named» + дано stands равно [(запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "")] + ожидается "a:check" + пример «Without a probed guard nothing is named» + дано stands равно пустой список + ожидается "" + разбор («Probed» от stands) + случай пусто + то "" + случай голова и хвост + то голова.«name» + +тотальная функция «Unprobed one» + принимает stand: «Post», name: строка + возвращает «Post» + пример «The named guard loses its probe» + дано stand равно (запись «Post» с «name» равным "a:check" и «file» равным "ci" и «built» равным "") + дано name равно "a:check" + ожидается (запись «Post» с «name» равным "a:check" и «file» равным "" и «built» равным "") + если (stand.«name») равен name + то «Post made» от (stand.«name») и "" и (stand.«built») + иначе stand + +тотальная функция «Unprobed» + принимает stands: список «Post», name: строка + возвращает список «Post» + обеспечивает «сторожей столько же» (длина результат) равен (длина stands) + отобразить stands как stand → («Unprobed one» от stand и name) + +тотальная функция «Extra guard» + принимает stands: список «Post» + возвращает список «Post» + обеспечивает «сторожей стало на одного больше» (длина результат) равен ((длина stands) плюс 1) + пример «A guard nobody calls and nobody probes joins the census» + дано stands равно пустой список + ожидается [(запись «Post» с «name» равным "forged:check" и «file» равным "" и «built» равным "")] + добавить («Post made» от "forged:check" и "" и "") к stands + +тотальная функция «Side text» + принимает stands: список «Post», entries: список «Entry» + возвращает строка + пусть told равно (отобразить stands как stand → соединить [(stand.«name»), "|", (stand.«file»)] по "") + пусть kept равно (отобразить entries как entry → entry.«guard») + соединить [(соединить told по "\n"), "\n--\n", (соединить kept по "\n")] по "" + +тотальная функция «Title zero» + возвращает строка + "сторона нулевая: перепись как она есть, бед быть не должно" + +тотальная функция «Title one» + возвращает строка + "сторона первая: первая запись вынута из ведомости" + +тотальная функция «Title two» + возвращает строка + "сторона вторая: в ведомость вписан сторож, у которого проба есть" + +тотальная функция «Title three» + возвращает строка + "сторона третья: заведён сторож без зова и без пробы, в ведомости его нет" + +тотальная функция «Title four» + возвращает строка + "сторона четвёртая: у первого позванного сторожа проба отнята" + +тотальная функция «Sides of» + принимает stands: список «Post», entries: список «Entry» + возвращает список «Side» + пусть dropped равно («Without entry» от entries и («First entry» от entries)) + пусть added равно («Extra entry» от entries и («First probed» от stands)) + пусть taken равно («Unprobed» от stands и («First probed» от stands)) + пусть zero равно («Side made» от («Title zero») и "" и stands и entries) + пусть one равно («Side made» от («Title one») и "НОВЫЙ БЕЗ ПРОБЫ" и stands и dropped) + пусть two равно («Side made» от («Title two») и "ЗАПИСЬ СТАЛА НЕПРАВДОЙ" и stands и added) + пусть three равно («Side made» от («Title three») и "НОВЫЙ БЕЗ ПРОБЫ" и («Extra guard» от stands) и entries) + пусть four равно («Side made» от («Title four») и "НОВЫЙ БЕЗ ПРОБЫ" и taken и entries) + [zero, one, two, three, four] + +тотальная функция «Says it» + принимает found: список строки, says: строка + возвращает признак + пример «The words of the side stand among the troubles» + дано found равно ["НОВЫЙ БЕЗ ПРОБЫ: «a:check» заведён"] + дано says равно "НОВЫЙ БЕЗ ПРОБЫ" + ожидается да + пример «No trouble says it» + дано found равно пустой список + дано says равно "НОВЫЙ БЕЗ ПРОБЫ" + ожидается нет + (длина (отфильтровать found где trouble → trouble содержит says)) больше 0 + +тотальная функция «Side answered» + принимает says: строка, found: список строки + возвращает признак + пример «The clean side wants no trouble at all» + дано says равно "" + дано found равно пустой список + ожидается да + пример «A forged side wants its own words» + дано says равно "НОВЫЙ БЕЗ ПРОБЫ" + дано found равно ["НОВЫЙ БЕЗ ПРОБЫ: «a:check» заведён"] + ожидается да + пример «A forged side that raised nothing has not answered» + дано says равно "НОВЫЙ БЕЗ ПРОБЫ" + дано found равно пустой список + ожидается нет + если says равен "" + то (длина found) равен 0 + иначе «Says it» от found и says + +тотальная функция «Side shown» + принимает name: строка, says: строка, found: список строки + возвращает строка + пример «A shown side names its words and how many troubles it raised» + дано name равно "одна" + дано says равно "НОВЫЙ БЕЗ ПРОБЫ" + дано found равно ["НОВЫЙ БЕЗ ПРОБЫ: «a:check»"] + ожидается "── одна ──\nбед 1, сказано «НОВЫЙ БЕЗ ПРОБЫ»" + соединить ["── ", name, " ──\nбед ", (к строке (длина found)), ", сказано «", says, "»"] по "" + +тотальная функция «Side fault» + принимает name: строка, says: строка, found: список строки + возвращает строка + пример «A side that stayed silent is named» + дано name равно "одна" + дано says равно "НОВЫЙ БЕЗ ПРОБЫ" + дано found равно пустой список + ожидается "ПОДЛОГ НЕ ПОЙМАН — одна: ждали слова «НОВЫЙ БЕЗ ПРОБЫ», а бед найдено 0" + соединить ["ПОДЛОГ НЕ ПОЙМАН — ", name, ": ждали слова «", says, "», а бед найдено ", + (к строке (длина found))] по "" + +тотальная функция «Not assembled» + принимает name: строка + возвращает строка + пример «A forgery that changed nothing is named» + дано name равно "одна" + ожидается "ПОДЛОГ НЕ СОБРАЛСЯ — одна: перепись не изменилась, проверять ею нечего" + соединить ["ПОДЛОГ НЕ СОБРАЛСЯ — ", name, ": перепись не изменилась, проверять ею нечего"] по "" + +тотальная функция «Side judged» + принимает side: «Side», found: список строки + возвращает строка + если («Side answered» от (side.«says») и found) + то «Side shown» от (side.«name») и (side.«says») и found + иначе «Side fault» от (side.«name») и (side.«says») и found + +тотальная функция «Side assembled» + принимает side: «Side», base: строка + возвращает признак + пусть own равно («Side text» от (side.«stands») и (side.«entries»)) + если (side.«says») равен "" то да иначе (не (own равен base)) + +тотальная функция «Side words» + принимает side: «Side», base: строка + возвращает строка + пусть found равно («Troubles of» от (side.«stands») и (side.«entries»)) + если не («Side assembled» от side и base) + то «Not assembled» от (side.«name») + иначе «Side judged» от side и found + +тотальная функция «Forgery words» + принимает stands: список «Post», entries: список «Entry» + возвращает список строки + пусть base равно («Side text» от stands и entries) + отобразить («Sides of» от stands и entries) как side → («Side words» от side и base) + +тотальная функция «Is fault» + принимает word: строка + возвращает признак + пример «A side that was not shown is a fault» + дано word равно "ПОДЛОГ НЕ ПОЙМАН — одна" + ожидается да + пример «A forgery that did not assemble is a fault» + дано word равно "ПОДЛОГ НЕ СОБРАЛСЯ — одна" + ожидается да + пример «A shown side is not a fault» + дано word равно "── одна ──\nбед 1" + ожидается нет + (word начинается с "ПОДЛОГ НЕ ПОЙМАН") или (word начинается с "ПОДЛОГ НЕ СОБРАЛСЯ") + +тотальная функция «Caught word» + возвращает строка + "подлог пойман: все пять сторон показаны прогоном, ни один файл дерева не тронут." + +тотальная функция «Hollow word» + возвращает строка + "ПРОБА ХОЛОСТА: сверка промолчала там, где обязана была покраснеть." + +тотальная функция «Forgery verdict» + принимает stands: список «Post», entries: список «Entry» + возвращает «Продолжение» + пусть words равно («Forgery words» от stands и entries) + пусть faults равно (отфильтровать words где word → («Is fault» от word)) + пусть caught равно (соединить («Joined» от words и [(«Caught word»)]) по "\n\n") + пусть hollow равно (соединить («Joined» от words и [(«Hollow word»)]) по "\n\n") + если (длина faults) равен 0 + то вариант «Провал» с код равным "FLANG_FORGERY_PROBE_PODLOG" и сообщение равным caught + иначе вариант «Конец работы» с значение равным hollow + +примечание "── ПОРУЧЕНИЯ И ХОД РАБОТЫ ─────────────────────────────────────────────────" + +тотальная функция «Flows folder» + возвращает строка + обеспечивает «работы CI лежат у GitHub» результат содержит ".github/workflows" + "../../.github/workflows" + +тотальная функция «Flows order» + возвращает «Поручение» + пример «The folder of workflows is listed» + ожидается (вариант «Перечислить каталог» с путь равным "../../.github/workflows") + вариант «Перечислить каталог» с путь равным («Flows folder») + +тотальная функция «Flow order» + принимает name: строка + возвращает «Поручение» + пример «A workflow is read by its name» + дано name равно "ci.yml" + ожидается (вариант «Прочитать файл» с путь равным "../../.github/workflows/ci.yml") + вариант «Прочитать файл» с путь равным (соединить [(«Flows folder»), "/", name] по "") + +тотальная функция «Ledger order» + возвращает «Поручение» + пример «The ledger is read by an order, not by a grep» + ожидается (вариант «Прочитать файл» с путь равным "../../scripts/ledgers/guards-without-forgery-probe.json") + вариант «Прочитать файл» с путь равным (соединить ["../../", («Debt ledger»)] по "") + +тотальная функция «Settings order» + возвращает «Поручение» + пример «The settings file is read whole» + ожидается (вариант «Прочитать файл» с путь равным "../../.flangrc") + вариант «Прочитать файл» с путь равным "../../.flangrc" + +тотальная функция «Step on» + принимает order: «Поручение», stage: «Stage» + возвращает «Продолжение» + вариант «Сделать» с поручение равным order и потом равным stage + +тотальная функция «Nothing read» + принимает what: строка, code: строка, message: строка + возвращает «Продолжение» + пусть word равно (соединить [what, " не читается — перепись неполна и потому не считается: ", message] по "") + вариант «Не проверено» с код равным code и сообщение равным word + +тотальная функция «Wrong reply» + принимает what: строка + возвращает «Продолжение» + пример «A reply nobody asked for stops the census» + дано what равно "текст workflow" + ожидается вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали текст workflow" + вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным (соединить ["ждали ", what] по "") + +тотальная функция «Is flow» + принимает name: строка + возвращает признак + пример «A workflow is named by its ending» + дано name равно "ci.yml" + ожидается да + пример «A page is not a workflow» + дано name равно "README.md" + ожидается нет + «Ends with» от name и ".yml" + +тотальная функция «Ask settings» + принимает mode: строка, spots: список «Spot», entries: список «Entry» + возвращает «Продолжение» + пусть stage равно (вариант «Reading settings» с mode равным mode и spots равным spots и entries равным entries) + «Step on» от («Settings order») и stage + +тотальная функция «Ask debt» + принимает mode: строка, spots: список «Spot» + возвращает «Продолжение» + пусть stage равно (вариант «Reading the debt» с mode равным mode и spots равным spots) + если mode равен "list" + то «Ask settings» от mode и spots и (пустой список) + иначе «Step on» от («Ledger order») и stage + +тотальная функция «Ask flow» + принимает mode: строка, pending: список строки, spots: список «Spot», name: строка + возвращает «Продолжение» + пусть stage равно (вариант «Reading a flow» с mode равным mode и pending равным pending и spots равным spots) + «Step on» от («Flow order» от name) и stage + +тотальная функция «Reading on» + принимает mode: строка, pending: список строки, spots: список «Spot» + возвращает «Продолжение» + разбор pending + случай пусто + то «Ask debt» от mode и spots + случай голова и хвост + то «Ask flow» от mode и pending и spots и голова + +тотальная функция «After the folder» + принимает mode: строка, reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Пока ничего» + то «Step on» от («Flows order») и (вариант «Listing flows» с mode равным mode) + случай вариант «Перечислено» с имена как names + то «Reading on» от mode и (отфильтровать names где name → («Is flow» от name)) и (пустой список) + случай вариант «Сбой» с код как code и сообщение как message + то «Nothing read» от "каталог .github/workflows" и code и message + случай любое + то «Wrong reply» от "список каталога workflow" + +тотальная функция «After a flow read» + принимает mode: строка, pending: список строки, spots: список «Spot», reply: «Отклик» + возвращает «Продолжение» + разбор pending + случай пусто + то «Wrong reply» от "имя workflow, которого никто не спрашивал" + случай голова и хвост + то «After one flow» от mode и (голова) и хвост и spots и reply + +тотальная функция «After one flow» + принимает mode: строка, name: строка, rest: список строки, spots: список «Spot», reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Прочитано» с содержимое как text + то «Reading on» от mode и rest и («Joined» от spots и («Spots of» от name и text)) + случай вариант «Сбой» с код как code и сообщение как message + то «Nothing read» от (соединить [".github/workflows/", name] по "") и code и message + случай любое + то «Wrong reply» от "текст workflow" + +тотальная функция «No ledger» + принимает code: строка + возвращает «Продолжение» + пусть word равно (соединить ["ведомости ", («Debt ledger»), " нет — сверять не с чем"] по "") + вариант «Не проверено» с код равным code и сообщение равным word + +тотальная функция «Or census» + принимает mode: строка, spots: список «Spot», code: строка + возвращает «Продолжение» + если mode равен "census" + то «Ask settings» от mode и spots и (пустой список) + иначе «No ledger» от code + +тотальная функция «After debt» + принимает mode: строка, spots: список «Spot», reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Прочитано» с содержимое как text + то «Ask settings» от mode и spots и («Entries of» от text) + случай вариант «Сбой» с код как code и сообщение как message + то «Or census» от mode и spots и code + случай любое + то «Wrong reply» от "текст ведомости" + +тотальная функция «Told» + принимает mode: строка, stands: список «Post», entries: список «Entry» + возвращает «Продолжение» + пусть names равно (отобразить («In debt» от stands) как stand → stand.«name») + если mode равен "list" + то вариант «Конец работы» с значение равным (соединить names по "\n") + иначе вариант «Конец работы» с значение равным («Census» от stands и entries) + +тотальная функция «Or spoken» + принимает mode: строка, stands: список «Post», entries: список «Entry» + возвращает «Продолжение» + если mode равен "forgery" + то «Forgery verdict» от stands и entries + иначе «Told» от mode и stands и entries + +тотальная функция «Judged» + принимает mode: строка, stands: список «Post», entries: список «Entry» + возвращает «Продолжение» + если mode равен "check" + то «Judgement» от stands и («Troubles of» от stands и entries) + иначе «Or spoken» от mode и stands и entries + +тотальная функция «After settings» + принимает mode: строка, spots: список «Spot», entries: список «Entry», reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Прочитано» с содержимое как text + то «Judged» от mode и («Posts of» от («Commands of settings» от text) и spots) и entries + случай вариант «Сбой» с код как code и сообщение как message + то «Nothing read» от ".flangrc" и code и message + случай любое + то «Wrong reply» от "текст .flangrc" + +тотальная функция «Onward» + принимает stage: «Stage», reply: «Отклик» + возвращает «Продолжение» + разбор stage + случай вариант «Listing flows» с mode как mode + то «After the folder» от mode и reply + случай вариант «Reading a flow» с mode как mode и pending как pending и spots как spots + то «After a flow read» от mode и pending и spots и reply + случай вариант «Reading the debt» с mode как mode и spots как spots + то «After debt» от mode и spots и reply + случай вариант «Reading settings» с mode как mode и spots как spots и entries как entries + то «After settings» от mode и spots и entries и reply + +тотальная функция «Start check» + возвращает «Stage» + пример «The check compares the census with the ledger» + ожидается вариант «Listing flows» с mode равным "check" + вариант «Listing flows» с mode равным "check" + +тотальная функция «Start census» + возвращает «Stage» + пример «The census prints every count» + ожидается вариант «Listing flows» с mode равным "census" + вариант «Listing flows» с mode равным "census" + +тотальная функция «Start list» + возвращает «Stage» + пример «The list names the guards in debt only» + ожидается вариант «Listing flows» с mode равным "list" + вариант «Listing flows» с mode равным "list" + +тотальная функция «Start forgery» + возвращает «Stage» + пример «The forgery walks the same census» + ожидается вариант «Listing flows» с mode равным "forgery" + вариант «Listing flows» с mode равным "forgery" + +план «Check» + состояние «Stage» + начинает с «Start check» + обрабатывает «Onward» + +план «Census» + состояние «Stage» + начинает с «Start census» + обрабатывает «Onward» + +план «List» + состояние «Stage» + начинает с «Start list» + обрабатывает «Onward» + +план «Forgery» + состояние «Stage» + начинает с «Start forgery» + обрабатывает «Onward» + +тотальная функция «Объявление короткой команды forgery-probe:check» + возвращает строка + "bootstrap/flang io --plan Check — сторожа без пробы порчи сходятся с ведомостью в обе стороны" + +тотальная функция «Объявление короткой команды forgery-probe:census» + возвращает строка + "bootstrap/flang io --plan Census — перепись проб порчи целиком, код всегда 0" + +тотальная функция «Объявление короткой команды forgery-probe:list» + возвращает строка + "bootstrap/flang io --plan List — только имена беспробных, по одному в строке" + +тотальная функция «Объявление короткой команды forgery-probe:forgery» + возвращает строка + "bootstrap/flang io --plan Forgery — пять порч переписи в памяти краснят сверку, код 1" diff --git a/scripts/guards/guards-without-forgery-probe.sh b/scripts/guards/guards-without-forgery-probe.sh deleted file mode 100755 index 193e9a673..000000000 --- a/scripts/guards/guards-without-forgery-probe.sh +++ /dev/null @@ -1,275 +0,0 @@ -#!/bin/sh -# SPDX-FileCopyrightText: 2026 Digitable (Marat Zimnurov) -# SPDX-License-Identifier: BSD-2-Clause -# -# У КАКИХ СТОРОЖЕЙ НЕТ ПРОБЫ ПОРЧИ — поимённо, прибором, а не рукой. -# -# sh scripts/guards/guards-without-forgery-probe.sh # перепись целиком -# sh scripts/guards/guards-without-forgery-probe.sh --check # сверка с ведомостью, код 1 при расхождении -# sh scripts/guards/guards-without-forgery-probe.sh --список # только имена беспробных, по одному в строке -# -# ── Зачем ─────────────────────────────────────────────────────────────────── -# СТОРОЖ, КОТОРОГО НЕЛЬЗЯ ПОКРАСИТЬ, НЕОТЛИЧИМ ОТ ВЫКЛЮЧЕННОГО. За одни сутки -# 5 сентября 2026 эта порода поймана четыре раза, и ни разу прибором — всякий -# раз случайно: -# -# · `target-words:check` ПРОВЕРЯЛ ПУСТОТУ. Подделку, на которой он стоит, -# заменили тривиальным модулем без единого занятого слова — сторож остался -# зелёным и написал «занятые слова экранированы (8 из 8)». Раздел 1 не -# делал ничего, и сказать об этом было некому (задача 3223). -# · Шесть проверок чекера (`checker.c:1199`) НЕ ОТРАБАТЫВАЛИ НИ РАЗУ: они -# читают исходник по привязке `пример строка N`, а записи корпуса её не -# несут — напечатаны двоичным постарше (задача 8690). -# · Проба под правило 9999 ЛЕЖАЛА В ДЕРЕВЕ, а `run.sh` её не звал — -# сторож без зовущего (задача 9999). -# · Две пробы порчи у разных работников НЕ СОБРАЛИСЬ: правка не изменила -# файл, сторож честно остался зелёным, и заметно это было только по тому, -# что числа не сдвинулись (задачи 7855, 9751). -# -# Общее у всех четырёх — беспроверочная вера в то, что проверка работает. -# Прибор `who-calls-the-guards.sh` отвечает на вопрос «кого CI зовёт»; этот -# отвечает на второй, без которого первый мало стоит: «а показано ли, что -# позванный вообще способен покраснеть». -# -# ── Что считается пробой порчи ────────────────────────────────────────────── -# Проба — это то, что ЛОМАЕТ проверяемое и требует, чтобы сторож на этом -# покраснел. В дереве проба бывает ПОСТРОЕНА и отдельно — ПОЗВАНА, и путать -# эти два состояния нельзя: построенная, но никем не званная проба не -# срабатывает никогда, ровно как сторож без зовущего. -# -# ПРОБА ПОСТРОЕНА — в дереве есть парная команда `X:forgery` или `X:corrupt` -# рядом со сторожем `X:check`: -# "codes:check" … flang/scripts/code-guard.fscript --plan 'Коды целы' -# "codes:forgery" … flang/scripts/code-guard.fscript --plan 'Подлог кода' -# Такая команда портит вход изнутри сторожа: он не зависит от номеров строк -# и портит ровно то, что сторож смотрит. Лучший вид пробы. -# -# ПРОБА ПОЗВАНА — в теле `run:` какого-нибудь workflow стоит вызов сторожа -# В УСЛОВИИ `if`, и в том же теле есть `exit 1`: -# if sh scripts/guards/seed-knows-type-words-guard.sh --подлог; then exit 1; fi -# либо, для внешней порчи, — с правкой файла и откатом: -# sed -i '5s/|[0-9]*$/|9999/' "$podlog" -# if bootstrap/flang run-script proven:check; then git checkout -- "$podlog"; exit 1; fi -# Признак один и тот же и от вида порчи не зависит: шаг падает ровно -# тогда, когда сторож промолчал. -# -# Прибор считает оба и печатает раздельно. В долг («без пробы») попадает тот, -# у кого НЕТ НИ ОДНОГО из двух. -# -# ── Чего этот прибор НЕ говорит ───────────────────────────────────────────── -# Он НЕ говорит, что проба хороша. Проба бывает холостой: правка не собралась -# (строка съехала — `sed` смолчал), или испорчено не то, что сторож смотрит. -# Такую пробу прибор считает существующей, потому что отличить её от рабочей -# он не может — для этого надо прогнать сторожа с порчей и без. Это делает -# сама проба в CI; здесь считается только ЕЁ НАЛИЧИЕ. -# -# Отсюда же ловушка, о которой стоит знать: внешняя проба прибита к НОМЕРУ -# СТРОКИ. Съедет строка — `sed` смолчит, файл останется цел, сторож честно -# останется зелёным, и шаг покраснеет со словами «сторож промолчал», хотя -# виноват подлог. Поэтому у внешних проб в `ci.yml` стоит отдельная защита -# «ПОДЛОГ НЕ СОБРАЛСЯ» (сравнение файла до и после правки), и всякая новая -# внешняя проба обязана её нести. Прибор наличие этой защиты НЕ проверяет — -# это работа для следующего. -# -# ── Ведомость, а не запрет ────────────────────────────────────────────────── -# Беспробных сторожей больше половины; правило «беспробных быть не должно» -# красило бы CI всегда, а вечно красный сторож — это выключенный сторож. -# Поэтому `--check` сверяет с ведомостью `scripts/ledgers/guards-without-forgery-probe.json` -# В ОБЕ СТОРОНЫ, как заведено у сторожа ключей (flang/scripts/cli-keys-debt.json) -# и у переписи зова (scripts/ledgers/uncalled-guards.json): -# · беспробный, которого в ведомости НЕТ, — красно: появился новый долг; -# · запись, у которой проба УЖЕ есть, — тоже красно: долг закрыт, запись -# стала неправдой, и убрать её обязан тот, кто долг закрыл. -set -eu - -KOREN=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd) -cd "$KOREN" - -VEDOMOST=scripts/ledgers/guards-without-forgery-probe.json -REZHIM=${1:-} - -LC_ALL=C.UTF-8 python3 - "$REZHIM" "$VEDOMOST" <<'PY' -import glob, io, json, os, re, sys - -rezhim, vedomost = sys.argv[1], sys.argv[2] - -try: - import yaml -except ImportError: - print("нет модуля yaml — поставить: pip install pyyaml", file=sys.stderr) - sys.exit(3) - -SCRIPT_LINE = re.compile(r'^[ \t]*script\.([^\s=]+)[ \t]*=[ \t]*(\S.*?)[ \t\r]*$', re.M) -yarlyki = dict(SCRIPT_LINE.findall(io.open(".flangrc", encoding="utf-8").read())) - -storozha = sorted(i for i in yarlyki if i.endswith(":check")) - -# ── Тела `run:` целиком, а не построчно ───────────────────────────────────── -# Проба — конструкция из нескольких строк: порча, условие, откат. Резать её на -# строки значит потерять связь между вызовом и `exit 1`. -def tela_run(uzel, kuda): - if isinstance(uzel, dict): - for klyuch, znachenie in uzel.items(): - if klyuch == "run" and isinstance(znachenie, str): - kuda.append(znachenie) - else: - tela_run(znachenie, kuda) - elif isinstance(uzel, list): - for znachenie in uzel: - tela_run(znachenie, kuda) - -tela = [] -for fajl in sorted(glob.glob(".github/workflows/*.yml")): - # Сломанный workflow — не повод падать трассировкой, но и молча пропустить - # его нельзя: сторожа, чьи пробы он держит, стали бы «беспробными», и - # сверка покраснела бы, назвав не ту причину. - try: - derevo = yaml.safe_load(io.open(fajl, encoding="utf-8")) - except yaml.YAMLError as beda: - print(f"{fajl} не разбирается как YAML — перепись неполна и потому" - f" не считается:\n {beda}", file=sys.stderr) - sys.exit(3) - sobrano = [] - tela_run(derevo, sobrano) - for telo in sobrano: - tela.append((os.path.basename(fajl), telo)) - -# ── Признак пробы: вызов в условии `if`, и в том же теле `exit 1` ─────────── -ZOV_PO_IMENI = re.compile(r"bootstrap/flang run-script\s+([^\s;&|`\"')]+)") -PUT = re.compile(r"[\w./-]+\.(?:flang|fscript|mjs|sh|js)") -# Список запускающих снят с дерева тем же способом, что в переписи зова: путь, -# УПОМЯНУТЫЙ в строке, ещё не вызов — он бывает доводом echo, телом heredoc, -# целью перенаправления. Вызовом он считается, только если перед ним стоит -# запускающий. -ZAPUSKAYUSCHIE = {"sh", "bash", "io", "node", "python3", "python", - "check", "emit", "run", "--test", "--proof"} - -def zovy_v_stroke(stroka, puti_storozhey): - """Имена сторожей, которых зовёт эта строка — по имени и по файлу.""" - nashli = set() - for sovpalo in ZOV_PO_IMENI.finditer(stroka): - if sovpalo.group(1) in puti_storozhey["po_imeni"]: - nashli.add(sovpalo.group(1)) - slova = stroka.split() - for nomer, slovo in enumerate(slova): - slovo = slovo.strip("\"'`();&|") - if slovo not in puti_storozhey["po_fajlu"]: - continue - pered = slova[nomer - 1].strip("\"'`();&|") if nomer else None - if pered is None or pered in ZAPUSKAYUSCHIE: - nashli.update(puti_storozhey["po_fajlu"][slovo]) - return nashli - -# Разложение «путь файла → какие сторожа за ним стоят». Один файл бывает за -# двумя командами (у сторожа с ключом и без), поэтому значение — множество. -po_imeni = set(storozha) -po_fajlu = {} -for imya in storozha: - for put in PUT.findall(yarlyki[imya]): - po_fajlu.setdefault(put, set()).add(imya) -puti = {"po_imeni": po_imeni, "po_fajlu": po_fajlu} - -with_probe, where_probe = {}, {} -for fajl, telo in tela: - if "exit 1" not in telo: - continue # шаг не падает — требования покраснеть нет - for stroka in telo.split("\n"): - golaya = stroka.strip() - if golaya.startswith("#"): - continue # комментарий оболочки - # Вызов обязан стоять В УСЛОВИИ: `if <вызов>; then … exit 1`. - # Голый вызов в теле шага — это рабочий прогон, а не проба. - if not (golaya.startswith("if ") or golaya.startswith("elif ")): - continue - for imya in zovy_v_stroke(golaya, puti): - with_probe.setdefault(imya, (fajl, golaya[:70])) - -# ── Проба, ПОСТРОЕННАЯ короткой командой: `X:forgery` или `X:corrupt` рядом с `X:check` ─ -# Приставка берётся отбрасыванием последней доли имени: у «codes:check» это -# «codes», у «word:occupancy:check» — «word:occupancy». Так парность видна и у -# составных имён. -postroena = {} -for imya in storozha: - pristavka = imya.rsplit(":", 1)[0] - for hvost in ("forgery", "corrupt"): - parnyj = f"{pristavka}:{hvost}" - if parnyj in yarlyki: - postroena[imya] = parnyj - break - -# ── Долг: у кого проба НЕ ПОКАЗАНА ────────────────────────────────────────── -# Задача 1389 говорит «ПОКАЗАНО, что он краснеет». Показывает прогон, а не -# наличие: построенная, но никем не званная проба не срабатывает никогда и -# показывает ровно столько же, сколько её отсутствие. Поэтому в долг идут оба -# рода, а построенность отмечается причиной — она говорит, что доделать дёшево. -without_probe = [i for i in storozha if i not in with_probe] - -if rezhim == "--список": - for imya in without_probe: - print(imya) - sys.exit(0) - -if rezhim != "--check": - prichiny = {} - if os.path.exists(vedomost): - prichiny = {k: v for k, v in json.load(io.open(vedomost, encoding="utf-8")).items() - if not k.startswith("//")} - tolko_postroena = sorted(i for i in postroena if i not in with_probe) - print("ПЕРЕПИСЬ ПРОБ ПОРЧИ: у кого показано, что он краснеет\n") - print(f" сторожей в дереве {len(storozha)}") - print(f" ПРОБА ПОЗВАНА (CI требует красноты) {len(with_probe)}") - print(f" проба построена, но НЕ позвана {len(tolko_postroena)}") - print(f" ПРОБА НЕ ПОКАЗАНА (долг) {len(without_probe)}") - print("\nПРОБА ПОЗВАНА, и где стоит:\n") - for imya in sorted(with_probe): - fajl, stroka = with_probe[imya] - istochnik = postroena.get(imya, "порча внешняя, в самом шаге") - print(f" {imya:30} {fajl:12} {istochnik}") - if tolko_postroena: - print("\nПРОБА ПОСТРОЕНА, НО НИКТО ЕЁ НЕ ЗОВЁТ" - " — она не срабатывает никогда:\n") - for imya in tolko_postroena: - print(f" {imya:30} команда {postroena[imya]}") - print("\nДОЛГ — проба не показана, поимённо:\n") - for imya in without_probe: - prichina = prichiny.get(imya, "причина в ведомости не названа") - if imya in postroena: - prichina = f"проба ПОСТРОЕНА командой {postroena[imya]}, но её не зовут" - print(f" {imya:30} {prichina[:80]}") - print("\nСверка с ведомостью — тем же прибором:" - "\n sh scripts/guards/guards-without-forgery-probe.sh --check") - sys.exit(0) - -# ── Сверка с ведомостью в обе стороны ─────────────────────────────────────── -if not os.path.exists(vedomost): - print(f"ведомости {vedomost} нет — сверять не с чем", file=sys.stderr) - sys.exit(3) - -zapisano = json.load(io.open(vedomost, encoding="utf-8")) -zapisano = {k: v for k, v in zapisano.items() if not k.startswith("//")} - -novye = [i for i in without_probe if i not in zapisano] # долг вырос -zakrytye = [i for i in zapisano if i not in without_probe] # долг закрыт - -if not novye and not zakrytye: - print(f"сторожа без пробы порчи: {len(without_probe)}," - " все названы в ведомости — сходится") - sys.exit(0) - -for imya in sorted(novye): - print(f"НОВЫЙ БЕЗ ПРОБЫ: «{imya}» заведён, но ни один шаг CI не требует," - f" чтобы он покраснел на порче, и в {vedomost} его нет.", file=sys.stderr) - print(" Либо построить пробу, либо записать в ведомость с причиной:" - " сторож без пробы неотличим от выключенного.", file=sys.stderr) -for imya in sorted(zakrytye): - if imya in with_probe: - fajl, _ = with_probe[imya] - poyasnenie = f"проба стоит в {fajl}" - else: - poyasnenie = "команда уже не заведена" - print(f"ЗАПИСЬ СТАЛА НЕПРАВДОЙ: «{imya}» числится беспробным," - f" а {poyasnenie}.", file=sys.stderr) - print(f" Долг закрыт — убрать запись из {vedomost} обязан тот, кто закрыл.", - file=sys.stderr) -sys.exit(1) -PY diff --git a/scripts/guards/proved-share-vs-tree.fscript b/scripts/guards/proved-share-vs-tree.fscript new file mode 100644 index 000000000..0d3f76c76 --- /dev/null +++ b/scripts/guards/proved-share-vs-tree.fscript @@ -0,0 +1,1267 @@ +модуль «Proved share vs tree» + +примечание "СВЕРКА ВЕДОМОСТИ ДОКАЗАННОГО С ДЕРЕВОМ. Зовут тремя ярлыками:" +примечание " bootstrap/flang run-script proved-share-tree:check сверка, код 1 при беде" +примечание " bootstrap/flang run-script proved-share-tree:numbers только итоги, код 0" +примечание " bootstrap/flang run-script proved-share-tree:forgery четыре стороны порчи описи" + +примечание "ЗАЧЕМ. scripts/ledgers/proved-share-ledger.txt — опись, из которой берут числа" +примечание "для Г7 и для доли доказанного. Прибора, который снимал бы её заново и сверял с" +примечание "деревом, в репозитории НЕ БЫЛО: числа 13 347 и 13 399 ходили по документам" +примечание "разовым проходом, который в дерево не переехал. Порода та же, что в задачах 7298" +примечание "(сторожей считали рукой, и счёт был неверен в обе стороны) и 7855 (прибор" +примечание "кругооборота лежит во времянке)." + +примечание "ЧТО СВЕРЯЕТСЯ ТОЧНО, А ЧТО ТОЛЬКО ДАТИРУЕТСЯ. Разница не косметическая." +примечание "ЗНАМЕНАТЕЛЬ («написано», «без приговора») считается ПО ИСХОДНИКУ — это строки" +примечание "«обеспечивает», «утверждение», «требует», «закон». Двоичный для него не нужен," +примечание "счёт точен, и расхождение с описью есть ОШИБКА ОПИСИ здесь и сейчас." +примечание "ЧИСЛИТЕЛЬ («доказано», «сетка», «объявлено») — приговор ядра. Чтобы снять его" +примечание "заново, надо прогнать двоичный по каждому файлу; на ядре доказательств это часы" +примечание "и десятки гигабайт памяти. Прибор его НЕ пересчитывает и не делает вида, что" +примечание "пересчитал. Он сверяет md5 исходника и тем ДАТИРУЕТ строку: разошёлся md5 —" +примечание "приговор в строке относится к файлу, которого уже нет." + +примечание "СВЕРЯЕТСЯ В ОБЕ СТОРОНЫ, по образцу flang/scripts/cli-keys-debt.json:" +примечание " · файл дерева несёт обязательства, а строки в описи нет — красно;" +примечание " · строка описи есть, а файла в дереве нет — красно;" +примечание " · строка описи есть, а обязательств в файле не осталось — красно;" +примечание " · «написано» в описи не сходится со счётом по исходнику — красно;" +примечание " · md5 разошёлся, а «написано» сошлось — НЕ красно: это протухший приговор," +примечание " он печатается числом и ждёт того, кто перемерит." + +примечание "ДВЕ ФОРМЫ ОБЯЗАТЕЛЬСТВА, И ПЕРВАЯ РЕДАКЦИЯ ЗНАЛА ОДНУ. Кроме голого" +примечание "«обеспечивает» язык пишет обязательство с квантором, и имён за «для всех» —" +примечание "список (ADR-0026 К2/К6/К5). Третья форма — «утверждение» от края (К3b)." +примечание "Все три стоят в одном образце grep, и сумма по дереву сходится с описью." + +примечание "ЧЕМ ЭТОТ ФАЙЛ ОТЛИЧАЕТСЯ ОТ ПРЕЖНЕГО НА ОБОЛОЧКЕ. До 4 октября 2026 то же" +примечание "сверял scripts/guards/proved-share-vs-tree.sh, 139 строк. Довод переписи «место" +примечание "вызова — хук до сборки двоичного» УСТАРЕЛ: с задачи 1219 хук сам стал планом" +примечание "(.githooks/pre-push зовёт bootstrap/flang io .githooks/pre-push.fscript), и" +примечание "двоичный к этому часу уже собран. Перенос снял две вещи, которых у оболочки" +примечание "быть не могло. ПЕРВОЕ: разбор описи и счёт по строке проверяются ПРИМЕРАМИ на" +примечание "месте, а не прогоном на всём дереве. ВТОРОЕ: порча описи идёт В ПАМЯТИ, файл" +примечание "дерева не трогается и откатывать нечего, тогда как проба оболочки правила опись" +примечание "на диске и возвращала её копией. Слово согласия и каждая беда списаны у" +примечание "прежнего сторожа ЗНАК В ЗНАК: прогон обоих на этом дереве 4 октября 2026 дал" +примечание "одни и те же строки." + +примечание "ЧЕГО ЗДЕСЬ НЕТ. «Доказано», «сетка», «объявлено» не пересчитываются — их" +примечание "снимает scripts/ledgers/take-proof-ledger.fscript по одному файлу, и это часы." +примечание "Расхождение кода возврата названо: у плана нет кода 5, «описи нет» и «это не" +примечание "рабочая копия» отвечают кодом 3, а у оболочки был 5." + +объект «Count» + «path»: строка + «number»: число + +объект «Row» + «path»: строка + «written»: число + «unjudged»: число + +объект «Side» + «name»: строка + «rows»: список строки + «says»: строка + +тип «Step» + вариант «Listing» содержит mode: строка + вариант «Counting written» содержит mode: строка, paths: список строки + вариант «Counting unjudged» содержит mode: строка, written: список «Count» + вариант «Hashing» содержит mode: строка, rows: список «Row» + вариант «Reading ledger» содержит mode: строка, rows: список «Row», hashes: строка + +примечание "── РАЗБОР СТРОК ────────────────────────────────────────────────────────────" + +тотальная функция «Joined» от «Kind» + принимает front: список «Kind», back: список «Kind» + возвращает список «Kind» + пример «The back list follows the front one» + дано front равно ["one"] + дано back равно ["two", "three"] + ожидается ["one", "two", "three"] + свёртка back начиная с front как joined и piece → добавить piece к joined + +тотальная функция «Lines of» + принимает text: строка + возвращает список строки + пример «Empty lines are dropped» + дано text равно "раз\n\nдва\n" + ожидается ["раз", "два"] + отфильтровать (разделить text по "\n") где line → не (line равен "") + +тотальная функция «Piece number» + принимает which: число, pieces: список строки + возвращает строка + обеспечивает «куска за краем списка нет» если which больше (длина pieces) то (результат равен "") иначе да + пример «The second piece» + дано which равно 2 + дано pieces равно ["a", "b"] + ожидается "b" + пример «Beyond the edge there is nothing» + дано which равно 9 + дано pieces равно ["a"] + ожидается "" + пример «Before the first piece there is nothing» + дано which равно 0 + дано pieces равно пустой список + ожидается "" + пусть outside равно ((which больше (длина pieces)) или (which меньше 1)) + если outside то "" иначе (элемент which в pieces) + +тотальная функция «Last of» + принимает pieces: список строки + возвращает строка + пример «The last piece is taken» + дано pieces равно ["a", "b", "33"] + ожидается "33" + пример «Of nothing nothing is taken» + дано pieces равно пустой список + ожидается "" + «Piece number» от (длина pieces) и pieces + +тотальная функция «Without last» + принимает pieces: список строки + возвращает список строки + обеспечивает «список не длиннее прежнего» (длина результат) не больше (длина pieces) + пример «The last piece is dropped» + дано pieces равно ["a", "b", "33"] + ожидается ["a", "b"] + пример «Of one piece nothing is left» + дано pieces равно ["33"] + ожидается пустой список + разбор pieces + случай пусто + то пустой список + случай голова и хвост + то если (длина хвост) равен 0 + то пустой список + иначе приписать голова к («Without last» от хвост) + +тотальная функция «Digit kept» + принимает acc: признак, sign: строка + возвращает признак + пример «A digit keeps the answer» + дано acc равно да + дано sign равно "7" + ожидается да + пример «Another sign breaks the answer» + дано acc равно да + дано sign равно "a" + ожидается нет + acc и притом ("0123456789" содержит sign) + +тотальная функция «Is digits» + принимает text: строка + возвращает признак + пример «A count is digits» + дано text равно "33" + ожидается да + пример «A cross is not digits» + дано text равно "×" + ожидается нет + пример «An empty text is not digits» + дано text равно "" + ожидается нет + пусть digits равно (свёртка (разложить text на символы) начиная с да как acc и sign → «Digit kept» от acc и sign) + ((длина text) больше 0) и притом digits + +тотальная функция «Number of» + принимает text: строка + возвращает число + обеспечивает «что не цифры — то ноль» если («Is digits» от text) то да иначе (результат равен 0) + пример «Digits become a number» + дано text равно "33" + ожидается 33 + пример «A cross counts as nothing» + дано text равно "×" + ожидается 0 + если («Is digits» от text) то (к числу text) иначе 0 + +тотальная функция «Is measured» + принимает text: строка + возвращает признак + пример «A number is a measured field» + дано text равно "19" + ожидается да + пример «A cross is not measured» + дано text равно "×" + ожидается нет + пример «A dash is not measured» + дано text равно "-" + ожидается нет + не ((text равен "×") или (text равен "-")) + +тотальная функция «Measured number» + принимает text: строка + возвращает число + обеспечивает «неизмеренного поля не складывают» если («Is measured» от text) то да иначе (результат равен 0) + пример «A measured field gives its number» + дано text равно "19" + ожидается 19 + пример «An unmeasured field gives nothing» + дано text равно "×" + ожидается 0 + если («Is measured» от text) то («Number of» от text) иначе 0 + +тотальная функция «Without front» + принимает text: строка, front: строка + возвращает строка + пример «The front of the path is cut off» + дано text равно "../../scripts/one.flang" + дано front равно "../../" + ожидается "scripts/one.flang" + пример «A text no longer than the front stays as it is» + дано text равно "../../" + дано front равно "../../" + ожидается "../../" + если (text начинается с front) и притом ((длина text) больше (длина front)) + то подстрока text с ((длина front) плюс 1) по (длина text) + иначе text + +примечание "── МЕТКИ: НАБОР СТРОК ДЛЯ ПОИСКА ПО ЦЕЛОМУ КУСКУ ──────────────────────────" + +тотальная функция «Marked» + принимает pieces: список строки + возвращает строка + пример «Every piece stands on a line of its own» + дано pieces равно ["one", "two"] + ожидается "\none\ntwo\n" + соединить ["\n", (соединить pieces по "\n"), "\n"] по "" + +тотальная функция «Is marked» + принимает marks: строка, piece: строка + возвращает признак + пример «A whole piece is found» + дано marks равно "\na.flang\nb.flang\n" + дано piece равно "b.flang" + ожидается да + пример «A part of a piece is not found» + дано marks равно "\nscripts/one.flang\n" + дано piece равно "one.flang" + ожидается нет + marks содержит (соединить ["\n", piece, "\n"] по "") + +тотальная функция «Keyed» + принимает path: строка + возвращает строка + пример «The key of a path stands between a line break and a tab» + дано path равно "a.flang" + ожидается "\na.flang\t" + соединить ["\n", path, "\t"] по "" + +тотальная функция «At mark» + принимает index: строка, key: строка + возвращает строка + пример «What stands behind the mark is taken» + дано index равно "\na.flang\t3\nb.flang\t7\n" + дано key равно "\nb.flang\t" + ожидается "7" + пример «Without the mark nothing is taken» + дано index равно "\na.flang\t3\n" + дано key равно "\nb.flang\t" + ожидается "" + пусть pieces равно (разделить index по key) + если (длина pieces) меньше 2 + то "" + иначе голова (разделить («Piece number» от 2 и pieces) по "\n") + +примечание "── СЧЁТ ПО ДЕРЕВУ: ВЫВОД grep -c РАЗБИРАЕТСЯ В ПАРЫ «ПУТЬ — ЧИСЛО» ────────" + +тотальная функция «Count of line» + принимает line: строка, front: строка + возвращает «Count» + пример «The count stands after the last colon» + дано line равно "../../a.flang:33" + дано front равно "../../" + ожидается (запись «Count» с «path» равным "a.flang" и «number» равным 33) + пример «A colon inside the path stays in the path» + дано line равно "../../a:b.flang:7" + дано front равно "../../" + ожидается (запись «Count» с «path» равным "a:b.flang" и «number» равным 7) + пусть pieces равно (разделить line по ":") + пусть whole равно (соединить («Without last» от pieces) по ":") + пусть path равно («Without front» от whole и front) + запись «Count» с «path» равным path и «number» равным («Number of» от («Last of» от pieces)) + +тотальная функция «Counts of» + принимает text: строка, front: строка + возвращает список «Count» + пример «Every line of the output is a pair» + дано text равно "../../a.flang:3\n../../b.flang:0\n" + дано front равно "../../" + ожидается [(запись «Count» с «path» равным "a.flang" и «number» равным 3), + (запись «Count» с «path» равным "b.flang" и «number» равным 0)] + отобразить («Lines of» от text) как line → («Count of line» от line и front) + +тотальная функция «Count mark» + принимает count: «Count» + возвращает строка + пример «A pair is marked by its path» + дано count равно (запись «Count» с «path» равным "a.flang" и «number» равным 3) + ожидается "a.flang\t3" + соединить [(count.«path»), "\t", (к строке (count.«number»))] по "" + +тотальная функция «Count index» + принимает counts: список «Count» + возвращает строка + пример «The index holds every pair» + дано counts равно [(запись «Count» с «path» равным "a.flang" и «number» равным 3)] + ожидается "\na.flang\t3\n" + «Marked» от (отобразить counts как count → («Count mark» от count)) + +тотальная функция «Number at» + принимает index: строка, path: строка + возвращает число + пример «The number of the path is taken from the index» + дано index равно "\na.flang\t3\n" + дано path равно "a.flang" + ожидается 3 + пример «A path outside the index carries nothing» + дано index равно "\na.flang\t3\n" + дано path равно "b.flang" + ожидается 0 + «Number of» от («At mark» от index и («Keyed» от path)) + +тотальная функция «Row of count» + принимает count: «Count», unjudged: строка + возвращает «Row» + пример «A row takes its two counts» + дано count равно (запись «Count» с «path» равным "a.flang" и «number» равным 3) + дано unjudged равно "\na.flang\t2\n" + ожидается (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 2) + пусть laws равно («Number at» от unjudged и (count.«path»)) + запись «Row» с «path» равным (count.«path») и «written» равным (count.«number») и «unjudged» равным laws + +тотальная функция «Carries obligations» + принимает row: «Row» + возвращает признак + пример «A file with a postcondition carries obligations» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0) + ожидается да + пример «A file with a precondition only carries obligations too» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 0 и «unjudged» равным 1) + ожидается да + пример «An empty file carries none» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 0 и «unjudged» равным 0) + ожидается нет + ((row.«written») больше 0) или ((row.«unjudged») больше 0) + +тотальная функция «Rows of» + принимает written: список «Count», unjudged: строка + возвращает список «Row» + пример «Only the files that carry obligations become rows» + дано written равно [(запись «Count» с «path» равным "a.flang" и «number» равным 3), + (запись «Count» с «path» равным "b.flang" и «number» равным 0)] + дано unjudged равно "\na.flang\t0\nb.flang\t0\n" + ожидается [(запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0)] + пусть all равно (отобразить written как count → («Row of count» от count и unjudged)) + отфильтровать all где row → («Carries obligations» от row) + +тотальная функция «Row paths» + принимает rows: список «Row» + возвращает строка + пример «The paths of the rows stand one on a line» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0)] + ожидается "\na.flang\n" + «Marked» от (отобразить rows как row → row.«path») + +примечание "── md5 ИСХОДНИКОВ: ВЫВОД md5sum РАЗБИРАЕТСЯ В ПАРЫ «ПУТЬ — ОТПЕЧАТОК» ─────" + +тотальная функция «Hash mark» + принимает line: строка, front: строка + возвращает строка + пример «The sum stands before the path» + дано line равно "0eb8181532ae602de4c212cbde33749e ../../a.flang" + дано front равно "../../" + ожидается "a.flang\t0eb8181532ae602de4c212cbde33749e" + пусть whole равно (соединить (хвост (разделить line по " ")) по " ") + соединить [(«Without front» от whole и front), "\t", (голова (разделить line по " "))] по "" + +тотальная функция «Hash index» + принимает text: строка, front: строка + возвращает строка + пример «The index holds every sum» + дано text равно "aa ../../a.flang\n" + дано front равно "../../" + ожидается "\na.flang\taa\n" + «Marked» от (отобразить («Lines of» от text) как line → («Hash mark» от line и front)) + +примечание "── ОПИСЬ: «md5|написано|доказано|сетка|объявлено|без приговора|путь» ───────" + +тотальная функция «Is ledger line» + принимает text: строка + возвращает признак + пример «A row of the ledger carries bars» + дано text равно "aa|1|1|0|0|0|a.flang" + ожидается да + пример «A note of the ledger is not a row» + дано text равно "// опись" + ожидается нет + пример «A line without bars is not a row» + дано text равно "опись" + ожидается нет + (не (text начинается с "//")) и притом (text содержит "|") + +тотальная функция «Field» + принимает which: число, line: строка + возвращает строка + пример «The second field is what is written» + дано which равно 2 + дано line равно "aa|33|19|5|1|0|a.flang" + ожидается "33" + пример «The seventh field is the path» + дано which равно 7 + дано line равно "aa|33|19|5|1|0|a.flang" + ожидается "a.flang" + «Piece number» от which и (разделить line по "|") + +тотальная функция «Path of» + принимает line: строка + возвращает строка + пример «The path of a row is its seventh field» + дано line равно "aa|33|19|5|1|0|a.flang" + ожидается "a.flang" + «Field» от 7 и line + +тотальная функция «Ledger rows of» + принимает text: строка + возвращает список строки + пример «Notes are dropped and rows are kept» + дано text равно "// опись\naa|1|1|0|0|0|a.flang\n" + ожидается ["aa|1|1|0|0|0|a.flang"] + отфильтровать («Lines of» от text) где line → («Is ledger line» от line) + +тотальная функция «Ledger mark» + принимает line: строка + возвращает строка + пример «A row is found by its path and is kept whole» + дано line равно "aa|1|1|0|0|0|a.flang" + ожидается "a.flang\taa|1|1|0|0|0|a.flang" + соединить [(«Path of» от line), "\t", line] по "" + +тотальная функция «Ledger index» + принимает lines: список строки + возвращает строка + пример «Every row is found by its path» + дано lines равно ["aa|1|1|0|0|0|a.flang"] + ожидается "\na.flang\taa|1|1|0|0|0|a.flang\n" + «Marked» от (отобразить lines как line → («Ledger mark» от line)) + +тотальная функция «Line at» + принимает index: строка, path: строка + возвращает строка + пример «The row of the path is taken whole» + дано index равно "\na.flang\taa|1|1|0|0|0|a.flang\n" + дано path равно "a.flang" + ожидается "aa|1|1|0|0|0|a.flang" + пример «A path outside the index gives nothing» + дано index равно "\na.flang\taa|1|1|0|0|0|a.flang\n" + дано path равно "b.flang" + ожидается "" + «At mark» от index и («Keyed» от path) + +примечание "── ИТОГИ ───────────────────────────────────────────────────────────────────" + +тотальная функция «Tree written» + принимает rows: список «Row» + возвращает число + пример «The postconditions of the tree are summed» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0)] + ожидается 3 + свёртка rows начиная с 0 как total и row → total плюс (row.«written») + +тотальная функция «Tree unjudged» + принимает rows: список «Row» + возвращает число + пример «The preconditions and the laws of the tree are summed» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 0 и «unjudged» равным 2)] + ожидается 2 + свёртка rows начиная с 0 как total и row → total плюс (row.«unjudged») + +тотальная функция «Summed field» + принимает which: число, lines: список строки + возвращает число + пример «Only measured fields are summed» + дано which равно 3 + дано lines равно ["aa|1|7|0|0|0|a.flang", "bb|1|×|×|×|0|b.flang"] + ожидается 7 + свёртка lines начиная с 0 как total и line → total плюс («Measured number» от («Field» от which и line)) + +тотальная функция «Judged» + принимает lines: список строки + возвращает число + пример «A row with a verdict is judged» + дано lines равно ["aa|1|7|0|0|0|a.flang", "bb|1|×|×|×|0|b.flang"] + ожидается 1 + длина (отфильтровать lines где line → («Is measured» от («Field» от 3 и line))) + +тотальная функция «Hash at» + принимает hashes: строка, path: строка + возвращает строка + пример «The sum of the file is taken from the index» + дано hashes равно "\na.flang\taa\n" + дано path равно "a.flang" + ожидается "aa" + «At mark» от hashes и («Keyed» от path) + +тотальная функция «Is stale» + принимает row: «Row», index: строка, hashes: строка + возвращает признак + пример «A row whose sum has moved is stale» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0) + дано index равно "\na.flang\taa|1|7|0|0|0|a.flang\n" + дано hashes равно "\na.flang\tbb\n" + ожидается да + пример «A row whose sum stands is fresh» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0) + дано index равно "\na.flang\taa|1|7|0|0|0|a.flang\n" + дано hashes равно "\na.flang\taa\n" + ожидается нет + пусть line равно («Line at» от index и (row.«path»)) + пусть moved равно (не ((«Field» от 1 и line) равен («Hash at» от hashes и (row.«path»)))) + (не (line равен "")) и притом moved + +тотальная функция «Stale lines» + принимает rows: список «Row», index: строка, hashes: строка + возвращает список строки + пример «The stale rows of the ledger are named» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0)] + дано index равно "\na.flang\taa|1|7|0|0|0|a.flang\n" + дано hashes равно "\na.flang\tbb\n" + ожидается ["aa|1|7|0|0|0|a.flang"] + пусть stale равно (отфильтровать rows где row → («Is stale» от row и index и hashes)) + отобразить stale как row → («Line at» от index и (row.«path»)) + +примечание "── БЕДЫ ────────────────────────────────────────────────────────────────────" + +тотальная функция «Missing word» + принимает row: «Row» + возвращает строка + пример «A file without a row of its own is named with its count» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0) + ожидается "НЕТ СТРОКИ: a.flang несёт 3 обязательств, а в описи его нет" + соединить ["НЕТ СТРОКИ: ", (row.«path»), " несёт ", (к строке (row.«written»)), + " обязательств, а в описи его нет"] по "" + +тотальная функция «Extra word» + принимает path: строка + возвращает строка + пример «A row without a file of its own is named» + дано path равно "a.flang" + ожидается "ЛИШНЯЯ СТРОКА: a.flang есть в описи, а в дереве обязательств не несёт" + соединить ["ЛИШНЯЯ СТРОКА: ", path, " есть в описи, а в дереве обязательств не несёт"] по "" + +тотальная функция «Differing word» + принимает row: «Row», written: строка + возвращает строка + пример «Both counts are named» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0) + дано written равно "4" + ожидается "«НАПИСАНО» НЕ СХОДИТСЯ: a.flang — 4 против 3" + соединить ["«НАПИСАНО» НЕ СХОДИТСЯ: ", (row.«path»), " — ", written, " против ", + (к строке (row.«written»))] по "" + +тотальная функция «Is missing» + принимает row: «Row», index: строка + возвращает признак + пример «A file the ledger does not know is missing» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0) + дано index равно "\nb.flang\tbb|1|1|0|0|0|b.flang\n" + ожидается да + («Line at» от index и (row.«path»)) равен "" + +тотальная функция «Is differing» + принимает row: «Row», index: строка + возвращает признак + пример «A measured count that does not meet the source is differing» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0) + дано index равно "\na.flang\taa|4|1|0|0|0|a.flang\n" + ожидается да + пример «An unmeasured count is not differing» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0) + дано index равно "\na.flang\taa|×|1|0|0|0|a.flang\n" + ожидается нет + пусть line равно («Line at» от index и (row.«path»)) + пусть written равно («Field» от 2 и line) + пусть apart равно (не ((«Number of» от written) равен (row.«written»))) + пусть off равно ((«Is measured» от written) и притом apart) + (не (line равен "")) и притом off + +тотальная функция «Missing troubles» + принимает rows: список «Row», index: строка + возвращает список строки + пример «Every file without a row is named» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0)] + дано index равно "\nb.flang\tbb|1|1|0|0|0|b.flang\n" + ожидается ["НЕТ СТРОКИ: a.flang несёт 1 обязательств, а в описи его нет"] + пусть found равно (отфильтровать rows где row → («Is missing» от row и index)) + отобразить found как row → («Missing word» от row) + +тотальная функция «Extra troubles» + принимает lines: список строки, paths: строка + возвращает список строки + пример «Every row without a file is named» + дано lines равно ["aa|1|1|0|0|0|a.flang"] + дано paths равно "\nb.flang\n" + ожидается ["ЛИШНЯЯ СТРОКА: a.flang есть в описи, а в дереве обязательств не несёт"] + пусть found равно (отфильтровать lines где line → не («Is marked» от paths и («Path of» от line))) + отобразить found как line → («Extra word» от («Path of» от line)) + +тотальная функция «Differing of» + принимает row: «Row», index: строка + возвращает строка + пример «The word names what the ledger says» + дано row равно (запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0) + дано index равно "\na.flang\taa|4|1|0|0|0|a.flang\n" + ожидается "«НАПИСАНО» НЕ СХОДИТСЯ: a.flang — 4 против 3" + «Differing word» от row и («Field» от 2 и («Line at» от index и (row.«path»))) + +тотальная функция «Differing troubles» + принимает rows: список «Row», index: строка + возвращает список строки + пример «Every count that does not meet the source is named» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 3 и «unjudged» равным 0)] + дано index равно "\na.flang\taa|4|1|0|0|0|a.flang\n" + ожидается ["«НАПИСАНО» НЕ СХОДИТСЯ: a.flang — 4 против 3"] + пусть found равно (отфильтровать rows где row → («Is differing» от row и index)) + отобразить found как row → («Differing of» от row и index) + +тотальная функция «Troubles of» + принимает rows: список «Row», lines: список строки + возвращает список строки + пример «A ledger that meets the tree has no troubles» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0)] + дано lines равно ["aa|1|1|0|0|0|a.flang"] + ожидается пустой список + пусть index равно («Ledger index» от lines) + пусть missing равно («Missing troubles» от rows и index) + пусть extra равно («Extra troubles» от lines и («Row paths» от rows)) + пусть front равно («Joined» от missing и extra) + «Joined» от front и («Differing troubles» от rows и index) + +тотальная функция «Summary word» + принимает rows: список «Row», lines: список строки + возвращает строка + пример «The troubles are counted apart» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0)] + дано lines равно ["bb|1|1|0|0|0|b.flang"] + ожидается "бед 2: нет строки 1, лишних 1, «написано» не сходится 0" + пусть index равно («Ledger index» от lines) + пусть missing равно (длина («Missing troubles» от rows и index)) + пусть extra равно (длина («Extra troubles» от lines и («Row paths» от rows))) + пусть differing равно (длина («Differing troubles» от rows и index)) + соединить ["бед ", (к строке ((missing плюс extra) плюс differing)), ": нет строки ", (к строке missing), + ", лишних ", (к строке extra), ", «написано» не сходится ", (к строке differing)] по "" + +примечание "── ОТЧЁТ ───────────────────────────────────────────────────────────────────" + +тотальная функция «Report» + принимает rows: список «Row», lines: список строки, hashes: строка + возвращает строка + пусть index равно («Ledger index» от lines) + пусть stale равно («Stale lines» от rows и index и hashes) + пусть judged равно («Judged» от lines) + соединить ["ПОЛ ДОКАЗАННОГО: опись против дерева\n\n", + " ЗНАМЕНАТЕЛЬ — счёт по исходнику, точен\n", + " файлов с обязательствами в дереве ", (к строке (длина rows)), "\n", + " строк в описи ", (к строке (длина lines)), "\n", + " «обеспечивает» по дереву ", (к строке («Tree written» от rows)), "\n", + " «написано» по описи ", (к строке («Summed field» от 2 и lines)), "\n", + " «требует»+«закон» по дереву ", (к строке («Tree unjudged» от rows)), "\n", + " «без приговора» по описи ", (к строке («Summed field» от 6 и lines)), "\n", + "\n ЧИСЛИТЕЛЬ — приговор ядра, прибор его НЕ пересчитывает\n", + " файлов с ведомостью ", (к строке judged), "\n", + " файлов без ведомости (× или прочерк) ", (к строке ((длина lines) минус judged)), "\n", + " доказано ", (к строке («Summed field» от 3 и lines)), "\n", + " на сетке ", (к строке («Summed field» от 4 и lines)), "\n", + " объявлено ", (к строке («Summed field» от 5 и lines)), "\n", + "\n ПРОТУХЛОСТЬ — md5 исходника разошёлся с описью\n", + " строк протухло ", (к строке (длина stale)), " из ", + (к строке (длина lines)), "\n", + " из них несут «доказано» ", (к строке («Summed field» от 3 и stale)), "\n", + " и «написано» ", (к строке («Summed field» от 2 и stale))] по "" + +примечание "── ПРИГОВОР ────────────────────────────────────────────────────────────────" + +тотальная функция «Verdict» + принимает report: строка, troubles: список строки, summary: строка + возвращает «Продолжение» + пример «A ledger that meets the tree ends the work» + дано report равно "ПОЛ ДОКАЗАННОГО" + дано troubles равно пустой список + дано summary равно "бед 0" + ожидается вариант «Конец работы» с значение равным "ПОЛ ДОКАЗАННОГО\n\nопись сходится с деревом" + пусть agreed равно (соединить [report, "\n\nопись сходится с деревом"] по "") + пусть red равно (соединить [report, "\n\n", (соединить troubles по "\n"), "\n\n", summary] по "") + если (длина troubles) равен 0 + то вариант «Конец работы» с значение равным agreed + иначе вариант «Провал» с код равным "FLANG_PROVED_SHARE_RAZOSHLIS" и сообщение равным red + +тотальная функция «Judge» + принимает mode: строка, rows: список «Row», lines: список строки, hashes: строка + возвращает «Продолжение» + пусть report равно («Report» от rows и lines и hashes) + пусть troubles равно («Troubles of» от rows и lines) + пусть summary равно («Summary word» от rows и lines) + если mode равен "numbers" + то вариант «Конец работы» с значение равным report + иначе «Verdict» от report и troubles и summary + +примечание "── ПОРЧА ОПИСИ В ПАМЯТИ: ЧЕТЫРЕ СТОРОНЫ ───────────────────────────────────" + +примечание "ФАЙЛ ОПИСИ НЕ ТРОГАЕТСЯ: порча идёт над уже прочитанным списком строк, и" +примечание "откатывать нечего. Это то же решение, что у плана «Подлог» описи дерева" +примечание "(scripts/guards/tree-inventory.fscript): подлог в памяти не оставляет грязи в" +примечание "рабочей копии, если прогон убьют на середине. Проба оболочки правила опись на" +примечание "диске и возвращала её копией — на убитом прогоне опись оставалась порченой." + +примечание "КОДЫ ПЕРЕВЁРНУТЫ, как у пары про опись дерева: код 1 — подлог пойман, сверка" +примечание "жива; код 0 — сверка промолчала хотя бы на одной стороне. Оба случая обязаны" +примечание "красить шаг CI, и шаг написан как «if … then exit 1»." + +тотальная функция «Side made» + принимает name: строка, rows: список строки, says: строка + возвращает «Side» + пример «A side carries its name, its ledger and the words it wants» + дано name равно "одна" + дано rows равно пустой список + дано says равно "" + ожидается (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "") + запись «Side» с «name» равным name и «rows» равным rows и «says» равным says + +тотальная функция «Is bumpable» + принимает line: строка + возвращает признак + пример «A row with a measured count can be bumped» + дано line равно "aa|33|19|5|1|0|a.flang" + ожидается да + пример «A row without a measured count cannot» + дано line равно "aa|×|19|5|1|0|a.flang" + ожидается нет + «Is digits» от («Field» от 2 и line) + +тотальная функция «Bumped line» + принимает line: строка + возвращает строка + пример «The count of the row grows by one» + дано line равно "aa|33|19|5|1|0|a.flang" + ожидается "aa|34|19|5|1|0|a.flang" + пусть pieces равно (разделить line по "|") + пусть grown равно (к строке ((«Number of» от («Field» от 2 и line)) плюс 1)) + пусть rest равно (соединить (хвост (хвост pieces)) по "|") + соединить [(«Piece number» от 1 и pieces), grown, rest] по "|" + +тотальная функция «Bumped» + принимает lines: список строки, which: строка + возвращает список строки + пример «Only the named row grows» + дано lines равно ["aa|33|19|5|1|0|a.flang", "bb|1|1|0|0|0|b.flang"] + дано which равно "a.flang" + ожидается ["aa|34|19|5|1|0|a.flang", "bb|1|1|0|0|0|b.flang"] + отобразить lines как line → (если («Path of» от line) равен which то («Bumped line» от line) иначе line) + +тотальная функция «Dropped» + принимает lines: список строки, which: строка + возвращает список строки + обеспечивает «строк не стало больше» (длина результат) не больше (длина lines) + пример «The named row leaves the ledger» + дано lines равно ["aa|33|19|5|1|0|a.flang", "bb|1|1|0|0|0|b.flang"] + дано which равно "a.flang" + ожидается ["bb|1|1|0|0|0|b.flang"] + отфильтровать lines где line → не ((«Path of» от line) равен which) + +тотальная функция «Ghost line» + возвращает строка + обеспечивает «подложная строка говорит о файле, которого нет» результат содержит "there-is-no-such-file" + "00000000000000000000000000000000|1|×|×|×|0|docs/there-is-no-such-file.flang" + +тотальная функция «Added» + принимает lines: список строки + возвращает список строки + обеспечивает «строк стало на одну больше» (длина результат) равен ((длина lines) плюс 1) + пример «A row about a file that is not there joins the ledger» + дано lines равно ["bb|1|1|0|0|0|b.flang"] + ожидается ["bb|1|1|0|0|0|b.flang", + "00000000000000000000000000000000|1|×|×|×|0|docs/there-is-no-such-file.flang"] + добавить («Ghost line») к lines + +тотальная функция «First path» + принимает rows: список «Row» + возвращает строка + пример «The first row of the tree names its file» + дано rows равно [(запись «Row» с «path» равным "a.flang" и «written» равным 1 и «unjudged» равным 0)] + ожидается "a.flang" + пример «Of no rows no file is named» + дано rows равно пустой список + ожидается "" + разбор rows + случай пусто + то "" + случай голова и хвост + то голова.«path» + +тотальная функция «First bumpable» + принимает lines: список строки + возвращает строка + пример «The first row with a measured count is named» + дано lines равно ["aa|×|19|5|1|0|a.flang", "bb|1|1|0|0|0|b.flang"] + ожидается "b.flang" + пример «Without such a row nothing is named» + дано lines равно ["aa|×|19|5|1|0|a.flang"] + ожидается "" + разбор (отфильтровать lines где line → («Is bumpable» от line)) + случай пусто + то "" + случай голова и хвост + то «Path of» от голова + +тотальная функция «Title zero» + возвращает строка + "сторона нулевая: опись как она есть, бед быть не должно" + +тотальная функция «Title one» + возвращает строка + "сторона первая: «написано» первой мерной строки описи +1" + +тотальная функция «Title two» + возвращает строка + "сторона вторая: строка о первом файле дерева вынута из описи" + +тотальная функция «Title three» + возвращает строка + "сторона третья: в опись вписана строка о файле, которого в дереве нет" + +тотальная функция «Sides of» + принимает rows: список «Row», lines: список строки + возвращает список «Side» + пусть bumped равно («Bumped» от lines и («First bumpable» от lines)) + пусть dropped равно («Dropped» от lines и («First path» от rows)) + пусть zero равно («Side made» от («Title zero») и lines и "") + пусть one равно («Side made» от («Title one») и bumped и "«НАПИСАНО» НЕ СХОДИТСЯ") + пусть two равно («Side made» от («Title two») и dropped и "НЕТ СТРОКИ") + пусть three равно («Side made» от («Title three») и («Added» от lines) и "ЛИШНЯЯ СТРОКА") + [zero, one, two, three] + +тотальная функция «Side shown» + принимает side: «Side», found: список строки + возвращает строка + пример «A shown side names its words and how many troubles it raised» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "НЕТ СТРОКИ") + дано found равно ["НЕТ СТРОКИ: a.flang"] + ожидается "── одна ──\nбед 1, сказано «НЕТ СТРОКИ»" + соединить ["── ", (side.«name»), " ──\nбед ", (к строке (длина found)), ", сказано «", + (side.«says»), "»"] по "" + +тотальная функция «Says it» + принимает found: список строки, telling: строка + возвращает признак + пример «The words of the side stand among the troubles» + дано found равно ["НЕТ СТРОКИ: a.flang несёт 1 обязательств, а в описи его нет"] + дано telling равно "НЕТ СТРОКИ" + ожидается да + пример «No trouble says it» + дано found равно пустой список + дано telling равно "НЕТ СТРОКИ" + ожидается нет + (длина (отфильтровать found где trouble → trouble содержит telling)) больше 0 + +тотальная функция «Side answered» + принимает side: «Side», found: список строки + возвращает признак + пример «The clean side wants no trouble at all» + дано side равно (запись «Side» с «name» равным "нулевая" и «rows» равным пустой список и «says» равным "") + дано found равно пустой список + ожидается да + пример «A forged side wants its own words» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "НЕТ СТРОКИ") + дано found равно ["НЕТ СТРОКИ: a.flang"] + ожидается да + пример «A forged side that raised nothing has not answered» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "НЕТ СТРОКИ") + дано found равно пустой список + ожидается нет + если (side.«says») равен "" + то (длина found) равен 0 + иначе «Says it» от found и (side.«says») + +тотальная функция «Side fault» + принимает side: «Side», found: список строки + возвращает строка + пример «A side that stayed silent is named» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "НЕТ СТРОКИ") + дано found равно пустой список + ожидается "ПОДЛОГ НЕ ПОЙМАН — одна: ждали слова «НЕТ СТРОКИ», а бед найдено 0" + соединить ["ПОДЛОГ НЕ ПОЙМАН — ", (side.«name»), ": ждали слова «", (side.«says»), + "», а бед найдено ", (к строке (длина found))] по "" + +тотальная функция «Side assembled» + принимает side: «Side», lines: список строки + возвращает признак + пример «A forged side differs from the ledger it came from» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным ["y"] и «says» равным "НЕТ СТРОКИ") + дано lines равно ["x"] + ожидается да + пример «A forgery that changed nothing did not assemble» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным ["x"] и «says» равным "НЕТ СТРОКИ") + дано lines равно ["x"] + ожидается нет + пример «The clean side is the ledger itself» + дано side равно (запись «Side» с «name» равным "нулевая" и «rows» равным ["x"] и «says» равным "") + дано lines равно ["x"] + ожидается да + пусть moved равно (не ((соединить (side.«rows») по "\n") равен (соединить lines по "\n"))) + если (side.«says») равен "" то да иначе moved + +тотальная функция «Not assembled» + принимает side: «Side» + возвращает строка + пример «A forgery that changed nothing is named» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "НЕТ СТРОКИ") + ожидается "ПОДЛОГ НЕ СОБРАЛСЯ — одна: опись не изменилась, проверять ею нечего" + соединить ["ПОДЛОГ НЕ СОБРАЛСЯ — ", (side.«name»), + ": опись не изменилась, проверять ею нечего"] по "" + +тотальная функция «Side judged» + принимает side: «Side», found: список строки + возвращает строка + пример «A side that answered is shown» + дано side равно (запись «Side» с «name» равным "одна" и «rows» равным пустой список и «says» равным "НЕТ СТРОКИ") + дано found равно ["НЕТ СТРОКИ: a.flang"] + ожидается "── одна ──\nбед 1, сказано «НЕТ СТРОКИ»" + если («Side answered» от side и found) + то «Side shown» от side и found + иначе «Side fault» от side и found + +тотальная функция «Side words» + принимает side: «Side», rows: список «Row», lines: список строки + возвращает строка + пусть found равно («Troubles of» от rows и (side.«rows»)) + если не («Side assembled» от side и lines) + то «Not assembled» от side + иначе «Side judged» от side и found + +тотальная функция «Forgery words» + принимает rows: список «Row», lines: список строки + возвращает список строки + отобразить («Sides of» от rows и lines) как side → («Side words» от side и rows и lines) + +тотальная функция «Is fault» + принимает word: строка + возвращает признак + пример «A side that was not shown is a fault» + дано word равно "ПОДЛОГ НЕ ПОЙМАН — первая" + ожидается да + пример «A forgery that did not assemble is a fault» + дано word равно "ПОДЛОГ НЕ СОБРАЛСЯ — первая" + ожидается да + пример «A shown side is not a fault» + дано word равно "── первая ──\nбед 1" + ожидается нет + (word начинается с "ПОДЛОГ НЕ ПОЙМАН") или (word начинается с "ПОДЛОГ НЕ СОБРАЛСЯ") + +тотальная функция «Caught word» + возвращает строка + "подлог пойман: все четыре стороны показаны прогоном, опись на диске не тронута." + +тотальная функция «Hollow word» + возвращает строка + "ПРОБА ХОЛОСТА: сверка промолчала там, где обязана была покраснеть." + +тотальная функция «Forgery verdict» + принимает rows: список «Row», lines: список строки + возвращает «Продолжение» + пусть words равно («Forgery words» от rows и lines) + пусть faults равно (отфильтровать words где word → («Is fault» от word)) + пусть caught равно (соединить («Joined» от words и [(«Caught word»)]) по "\n\n") + пусть hollow равно (соединить («Joined» от words и [(«Hollow word»)]) по "\n\n") + если (длина faults) равен 0 + то вариант «Провал» с код равным "FLANG_PROVED_SHARE_PODLOG" и сообщение равным caught + иначе вариант «Конец работы» с значение равным hollow + +примечание "── ПОРУЧЕНИЯ ───────────────────────────────────────────────────────────────" + +тотальная функция «Front» + возвращает строка + обеспечивает «корень дерева стоит двумя шагами выше плана» результат равен "../../" + "../../" + +тотальная функция «Ledger file» + возвращает строка + обеспечивает «опись лежит у ведомостей» результат содержит "scripts/ledgers/" + "../../scripts/ledgers/proved-share-ledger.txt" + +тотальная функция «Git arguments» + возвращает список строки + обеспечивает «кириллические пути не прячутся в кавычки» результат содержит "core.quotepath=false" + ["-C", "../..", "-c", "core.quotepath=false", "ls-files", "*.flang", "*.fscript"] + +тотальная функция «Written pattern» + возвращает строка + обеспечивает «образец знает и квантор, и утверждение» результат содержит "утверждение" + соединить ["^ *(для всех [^ ]+( и [^ ]+)*( для всех [^ ]+( и [^ ]+)*)*( таких что .*)? )?", + "обеспечивает |^утверждение «"] по "" + +тотальная функция «Unjudged pattern» + возвращает строка + обеспечивает «без приговора — предусловие и закон» результат содержит "закон" + "^ *(требует|закон) " + +тотальная функция «Prefixed» + принимает paths: список строки + возвращает список строки + обеспечивает «путей столько же» (длина результат) равен (длина paths) + пример «Every path is taken from the root of the tree» + дано paths равно ["a.flang"] + ожидается ["../../a.flang"] + отобразить paths как path → соединить [(«Front»), path] по "" + +тотальная функция «Git order» + возвращает «Поручение» + пример «The list of the tree is asked of git» + ожидается (вариант «Запустить процесс» с программа равным "git" и аргументы равным ["-C", "../..", + "-c", "core.quotepath=false", "ls-files", "*.flang", "*.fscript"]) + вариант «Запустить процесс» с программа равным "git" и аргументы равным («Git arguments») + +тотальная функция «Grep order» + принимает pattern: строка, paths: список строки + возвращает «Поручение» + пример «The files are counted by one grep over all of them» + дано pattern равно "^закон " + дано paths равно ["a.flang"] + ожидается (вариант «Запустить процесс» с программа равным "grep" и аргументы равным ["-acE", "^закон ", + "../../a.flang"]) + пусть arguments равно («Joined» от ["-acE", pattern] и («Prefixed» от paths)) + вариант «Запустить процесс» с программа равным "grep" и аргументы равным arguments + +тотальная функция «Md5 order» + принимает paths: список строки + возвращает «Поручение» + пример «The sums are taken by one md5sum over all the files» + дано paths равно ["a.flang"] + ожидается (вариант «Запустить процесс» с программа равным "md5sum" и аргументы равным ["../../a.flang"]) + вариант «Запустить процесс» с программа равным "md5sum" и аргументы равным («Prefixed» от paths) + +тотальная функция «Ledger order» + возвращает «Поручение» + пример «The ledger is read by an order, not by a grep» + ожидается (вариант «Прочитать файл» с путь равным "../../scripts/ledgers/proved-share-ledger.txt") + вариант «Прочитать файл» с путь равным («Ledger file») + +тотальная функция «Step on» + принимает order: «Поручение», step: «Step» + возвращает «Продолжение» + вариант «Сделать» с поручение равным order и потом равным step + +примечание "── СЛОВА ОТКАЗА ────────────────────────────────────────────────────────────" + +тотальная функция «Nothing word» + принимает what: строка + возвращает строка + пример «An empty answer of a tool is named» + дано what равно "grep" + ожидается "СВЕРКА НЕ НАЧАТА: grep не назвал ни одной строки — считать нечем" + соединить ["СВЕРКА НЕ НАЧАТА: ", what, " не назвал ни одной строки — считать нечем"] по "" + +тотальная функция «Nothing to count» + принимает what: строка + возвращает «Продолжение» + вариант «Не проверено» с код равным "FLANG_PROVED_SHARE_NECHEM" и сообщение равным («Nothing word» от what) + +тотальная функция «Broken word» + принимает what: строка, code: строка, message: строка + возвращает строка + пример «A tool that did not run is named with its code» + дано what равно "md5sum" + дано code равно "FLANG_IO_DENIED" + дано message равно "нельзя" + ожидается "СВЕРКА НЕ НАЧАТА: md5sum не запустился (FLANG_IO_DENIED): нельзя" + соединить ["СВЕРКА НЕ НАЧАТА: ", what, " не запустился (", code, "): ", message] по "" + +тотальная функция «Broken tool» + принимает what: строка, code: строка, message: строка + возвращает «Продолжение» + пусть word равно («Broken word» от what и code и message) + вариант «Не проверено» с код равным "FLANG_PROVED_SHARE_NECHEM" и сообщение равным word + +тотальная функция «Not a copy» + принимает errors: строка + возвращает «Продолжение» + пусть word равно (соединить ["ни одного файла языка — это не рабочая копия: ", errors] по "") + «Broken tool» от "git ls-files" и "FLANG_PROVED_SHARE_NECHEM" и word + +тотальная функция «Wrong reply» + принимает what: строка + возвращает «Продолжение» + пример «A reply nobody asked for stops the check» + дано what равно "вывод grep" + ожидается вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным "ждали вывод grep" + вариант «Провал» с код равным "FLANG_IO_ORDER" и сообщение равным (соединить ["ждали ", what] по "") + +примечание "── ХОД РАБОТЫ ──────────────────────────────────────────────────────────────" + +тотальная функция «Ask tree» + принимает mode: строка + возвращает «Продолжение» + «Step on» от («Git order») и (вариант «Listing» с mode равным mode) + +тотальная функция «Ask written» + принимает mode: строка, paths: список строки + возвращает «Продолжение» + пусть step равно (вариант «Counting written» с mode равным mode и paths равным paths) + «Step on» от («Grep order» от («Written pattern») и paths) и step + +тотальная функция «Ask unjudged» + принимает mode: строка, written: список «Count», paths: список строки + возвращает «Продолжение» + пусть step равно (вариант «Counting unjudged» с mode равным mode и written равным written) + если (длина written) равен 0 + то «Nothing to count» от "grep" + иначе «Step on» от («Grep order» от («Unjudged pattern») и paths) и step + +тотальная функция «Ask hashes» + принимает mode: строка, rows: список «Row» + возвращает «Продолжение» + пусть step равно (вариант «Hashing» с mode равным mode и rows равным rows) + если (длина rows) равен 0 + то «Nothing to count» от "счёт обязательств" + иначе «Step on» от («Md5 order» от (отобразить rows как row → row.«path»)) и step + +тотальная функция «Ask ledger» + принимает mode: строка, rows: список «Row», hashes: строка + возвращает «Продолжение» + пусть step равно (вариант «Reading ledger» с mode равным mode и rows равным rows и hashes равным hashes) + «Step on» от («Ledger order») и step + +тотальная функция «After tree» + принимает mode: строка, paths: список строки, errors: строка + возвращает «Продолжение» + если (длина paths) равен 0 + то «Not a copy» от errors + иначе «Ask written» от mode и paths + +тотальная функция «After listing» + принимает mode: строка, reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Пока ничего» + то «Ask tree» от mode + случай вариант «Процесс завершён» с код как code и вывод как output и ошибки как errors + то «After tree» от mode и («Lines of» от output) и errors + случай вариант «Сбой» с код как code и сообщение как message + то «Broken tool» от "git ls-files" и code и message + случай любое + то «Wrong reply» от "список файлов дерева" + +тотальная функция «After written» + принимает mode: строка, paths: список строки, reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Процесс завершён» с код как code и вывод как output и ошибки как errors + то «Ask unjudged» от mode и («Counts of» от output и («Front»)) и paths + случай вариант «Сбой» с код как code и сообщение как message + то «Broken tool» от "grep" и code и message + случай любое + то «Wrong reply» от "счёт обязательств" + +тотальная функция «After unjudged» + принимает mode: строка, written: список «Count», reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Процесс завершён» с код как code и вывод как output и ошибки как errors + то «Ask hashes» от mode и («Rows of» от written и («Count index» от («Counts of» от output и («Front»)))) + случай вариант «Сбой» с код как code и сообщение как message + то «Broken tool» от "grep" и code и message + случай любое + то «Wrong reply» от "счёт без приговора" + +тотальная функция «After hashes» + принимает mode: строка, rows: список «Row», reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Процесс завершён» с код как code и вывод как output и ошибки как errors + то «Ask ledger» от mode и rows и («Hash index» от output и («Front»)) + случай вариант «Сбой» с код как code и сообщение как message + то «Broken tool» от "md5sum" и code и message + случай любое + то «Wrong reply» от "отпечатки исходников" + +тотальная функция «Spoken» + принимает mode: строка, rows: список «Row», lines: список строки, hashes: строка + возвращает «Продолжение» + если mode равен "forgery" + то «Forgery verdict» от rows и lines + иначе «Judge» от mode и rows и lines и hashes + +тотальная функция «After ledger» + принимает mode: строка, rows: список «Row», hashes: строка, reply: «Отклик» + возвращает «Продолжение» + разбор reply + случай вариант «Прочитано» с содержимое как text + то «Spoken» от mode и rows и («Ledger rows of» от text) и hashes + случай вариант «Сбой» с код как code и сообщение как message + то «Broken tool» от "опись доказанного" и code и message + случай любое + то «Wrong reply» от "текст описи" + +тотальная функция «Next» + принимает step: «Step», reply: «Отклик» + возвращает «Продолжение» + разбор step + случай вариант «Listing» с mode как mode + то «After listing» от mode и reply + случай вариант «Counting written» с mode как mode и paths как paths + то «After written» от mode и paths и reply + случай вариант «Counting unjudged» с mode как mode и written как written + то «After unjudged» от mode и written и reply + случай вариант «Hashing» с mode как mode и rows как rows + то «After hashes» от mode и rows и reply + случай вариант «Reading ledger» с mode как mode и rows как rows и hashes как hashes + то «After ledger» от mode и rows и hashes и reply + +тотальная функция «Begin check» + возвращает «Step» + пример «The check compares the ledger with the tree» + ожидается вариант «Listing» с mode равным "check" + вариант «Listing» с mode равным "check" + +тотальная функция «Begin numbers» + возвращает «Step» + пример «The numbers are only told» + ожидается вариант «Listing» с mode равным "numbers" + вариант «Listing» с mode равным "numbers" + +тотальная функция «Begin forgery» + возвращает «Step» + пример «The forgery walks the same measurement» + ожидается вариант «Listing» с mode равным "forgery" + вариант «Listing» с mode равным "forgery" + +план «Check» + состояние «Step» + начинает с «Begin check» + обрабатывает «Next» + +план «Numbers» + состояние «Step» + начинает с «Begin numbers» + обрабатывает «Next» + +план «Forgery» + состояние «Step» + начинает с «Begin forgery» + обрабатывает «Next» + +тотальная функция «Объявление короткой команды proved-share-tree:check» + возвращает строка + "bootstrap/flang io --plan Check — опись доказанного сходится с деревом в обе стороны" + +тотальная функция «Объявление короткой команды proved-share-tree:numbers» + возвращает строка + "bootstrap/flang io --plan Numbers — те же числа без приговора, код всегда 0" + +тотальная функция «Объявление короткой команды proved-share-tree:forgery» + возвращает строка + "bootstrap/flang io --plan Forgery — четыре порчи описи в памяти краснят сверку, код 1" diff --git a/scripts/guards/proved-share-vs-tree.sh b/scripts/guards/proved-share-vs-tree.sh deleted file mode 100755 index 038e24b1d..000000000 --- a/scripts/guards/proved-share-vs-tree.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/sh -# СВЕРКА ВЕДОМОСТИ ДОКАЗАННОГО С ДЕРЕВОМ. -# -# ЗАЧЕМ. `scripts/ledgers/proved-share-ledger.txt` — опись, из которой берут числа для -# Г7 и для доли доказанного. Прибора, который снимал бы её заново и сверял с -# деревом, в репозитории НЕ БЫЛО: числа 13 347 и 13 399 ходят по документам -# разовым проходом, который в дерево не переехал. Порода та же, что в задачах -# 7298 (сторожей считали рукой, и счёт был неверен в обе стороны) и 7855 -# (прибор кругооборота лежит во времянке). -# -# ЧТО СВЕРЯЕТСЯ ТОЧНО, А ЧТО ТОЛЬКО ДАТИРУЕТСЯ. Разница не косметическая: -# -# ЗНАМЕНАТЕЛЬ («написано», «без приговора») считается ПО ИСХОДНИКУ — это -# строки `обеспечивает`, `требует`, `закон`. Двоичный для него не нужен, -# счёт точен, и расхождение с описью есть ОШИБКА ОПИСИ здесь и сейчас. -# -# ЧИСЛИТЕЛЬ («доказано», «сетка», «объявлено») — приговор ядра. Чтобы снять -# его заново, надо прогнать двоичный по каждому файлу; на ядре доказательств -# это часы и десятки гигабайт памяти (шапка описи: sets-oracle — 999 с и -# 16,6 ГиБ на один файл). Прибор его НЕ пересчитывает и не делает вида, что -# пересчитал. Он делает другое: сверяет md5 исходника и тем ДАТИРУЕТ строку. -# Разошёлся md5 — приговор в строке относится к файлу, которого уже нет. -# -# СВЕРЯЕТСЯ В ОБЕ СТОРОНЫ, по образцу flang/scripts/cli-keys-debt.json и -# scripts/ledgers/uncalled-guards.json: -# · файл дерева несёт обязательства, а строки в описи нет — красно; -# · строка описи есть, а файла в дереве нет — красно; -# · строка описи есть, а обязательств в файле не осталось — красно; -# · «написано» в описи не сходится со счётом по исходнику — красно; -# · md5 разошёлся, а «написано» сошлось — НЕ красно: это протухший приговор, -# он печатается числом и ждёт того, кто перемерит. -# -# ЗВАТЬ: sh scripts/guards/proved-share-vs-tree.sh сверка, код 1 при беде -# sh scripts/guards/proved-share-vs-tree.sh --числа только итоги, код 0 -set -u -REZHIM=сверка -for d in "$@"; do - case "$d" in - --числа) REZHIM=числа ;; - *) printf 'непонятный ключ: %s (знаю только --числа)\n' "$d" >&2; exit 2 ;; - esac -done -ROOT=$(cd "$(dirname "$0")/../.." && pwd) -cd "$ROOT" || exit 5 -OPIS=scripts/ledgers/proved-share-ledger.txt -[ -f "$OPIS" ] || { printf 'нет описи %s\n' "$OPIS" >&2; exit 5; } -RAB=${FLANG_TMP:-/srv/tmp}/pol-dokazannogo.$$ -mkdir -p "$RAB" || exit 5 -trap 'rm -rf "$RAB"' EXIT INT TERM - -# ── дерево: md5, обеспечивает, требует, закон — по каждому .flang ──────────── -# core.quotepath=false ОБЯЗАТЕЛЕН: без него git отдаёт кириллические пути в -# кавычках с восьмеричными кодами, и прибор молча пропускает 508 файлов из 955. -# Именно на этом первая редакция считала знаменатель по одним латинским именам. -git -c core.quotepath=false ls-files '*.flang' '*.fscript' | while IFS= read -r f; do - [ -f "$f" ] || continue - # grep -c при нуле совпадений печатает 0 И ВЫХОДИТ КОДОМ 1. Поэтому «|| echo 0» - # дописывал бы второй ноль и портил счёт; берём вывод как есть. - # ДВЕ ФОРМЫ ОБЯЗАТЕЛЬСТВА, и первая редакция знала одну. Кроме голого - # «обеспечивает» язык пишет обязательство с квантором: - # для всех элементы обеспечивает «длина неотрицательна» результат не меньше 0 - # Их в дереве 165 в 94 файлах, и 79 файлов несут ТОЛЬКО такую форму — прибор - # считал их пустыми и объявлял их строки в описи лишними. Все 69 «лишних» - # живых файлов оказались этой породы: врал прибор, а не опись. - # ИМЁН ЗА «для всех» — СПИСОК (ADR-0026 К2/К6/К5, 10 сентября 2026): `для всех - # а и б обеспечивает`, вложенное `для всех а для всех б обеспечивает`, - # ограничение `для всех н таких что … обеспечивает`. Прежний образец брал ОДНО - # слово за «для всех», и такое постусловие молча выпадало из знаменателя: - # `tests/families/quantifier/two-names.flang` (три постусловия) считался 2, а не 3. - OB=$(LC_ALL=C.UTF-8 grep -acE '^ *(для всех [^ ]+( и [^ ]+)*( для всех [^ ]+( и [^ ]+)*)*( таких что .*)? )?обеспечивает ' "$f" 2>/dev/null); OB=${OB:-0} - # УТВЕРЖДЕНИЕ БЕЗ ФУНКЦИИ (ADR-0026 К3b, 10 сентября 2026) — тоже обязательство: - # `утверждение «И»` от края. Считается вместе с «обеспечивает» с того же коммита, - # что сверщик переигрывает его доказательство, — знаменатель описи честен ровно - # с того часа, как такое обязательство может быть проверено (решение overagent'а). - ST=$(LC_ALL=C.UTF-8 grep -ac '^утверждение «' "$f" 2>/dev/null); OB=$((OB + ${ST:-0})) - TR=$(LC_ALL=C.UTF-8 grep -ac '^ *требует ' "$f" 2>/dev/null); TR=${TR:-0} - ZA=$(LC_ALL=C.UTF-8 grep -ac '^ *закон ' "$f" 2>/dev/null); ZA=${ZA:-0} - [ "$OB" = 0 ] && [ "$TR" = 0 ] && [ "$ZA" = 0 ] && continue - printf '%s|%s|%s|%s|%s\n' "$(md5sum "$f" | cut -d' ' -f1)" "$OB" "$TR" "$ZA" "$f" -done > "$RAB/derevo" - -LC_ALL=C.UTF-8 grep -av '^//' "$OPIS" | LC_ALL=C.UTF-8 grep -a '|' > "$RAB/opis" - -awk -F'|' -v rezhim="$REZHIM" ' - FILENAME ~ /derevo$/ { - d_md5[$5]=$1; d_ob[$5]=$2; d_tr[$5]=$3; d_za[$5]=$4; d_est[$5]=1; next - } - { - p=$7; o_md5[p]=$1; o_nap[p]=$2; o_dok[p]=$3; o_set[p]=$4; o_obj[p]=$5; o_bez[p]=$6; o_est[p]=1 - strok++ - if($2!="×" && $2!="-") o_nap_sum+=$2 - if($3!="×" && $3!="-"){ o_dok_sum+=$3; s_vedom++ } else bez_vedom++ - if($4!="×" && $4!="-") o_set_sum+=$4 - if($5!="×" && $5!="-") o_obj_sum+=$5 - if($6!="×" && $6!="-") o_bez_sum+=$6 - } - END{ - for(p in d_est){ - d_nap_sum += d_ob[p]; d_bez_sum += d_tr[p]+d_za[p]; d_fajlov++ - if(!(p in o_est)){ net_stroki[p]=d_ob[p]; net_n++; beda++ ; continue } - if(o_nap[p]!="×" && o_nap[p]!="-" && o_nap[p]+0 != d_ob[p]+0){ - raz_nap[p]=o_nap[p]" против "d_ob[p]; raz_n++; beda++ - } - if(o_md5[p]!=d_md5[p]){ prot[p]=1; prot_n++ - if(o_dok[p]!="×" && o_dok[p]!="-") prot_dok+=o_dok[p] - if(o_nap[p]!="×" && o_nap[p]!="-") prot_nap+=o_nap[p] - } - } - for(p in o_est){ - if(!(p in d_est)){ lishn[p]=1; lishn_n++; beda++ } - } - printf "ПОЛ ДОКАЗАННОГО: опись против дерева\n\n" - printf " ЗНАМЕНАТЕЛЬ — счёт по исходнику, точен\n" - printf " файлов с обязательствами в дереве %d\n", d_fajlov - printf " строк в описи %d\n", strok - printf " «обеспечивает» по дереву %d\n", d_nap_sum - printf " «написано» по описи %d\n", o_nap_sum - printf " «требует»+«закон» по дереву %d\n", d_bez_sum - printf " «без приговора» по описи %d\n", o_bez_sum - printf "\n ЧИСЛИТЕЛЬ — приговор ядра, прибор его НЕ пересчитывает\n" - printf " файлов с ведомостью %d\n", s_vedom - printf " файлов без ведомости (× или прочерк) %d\n", bez_vedom - printf " доказано %d\n", o_dok_sum - printf " на сетке %d\n", o_set_sum - printf " объявлено %d\n", o_obj_sum - printf "\n ПРОТУХЛОСТЬ — md5 исходника разошёлся с описью\n" - printf " строк протухло %d из %d\n", prot_n, strok - printf " из них несут «доказано» %d\n", prot_dok - printf " и «написано» %d\n", prot_nap - if(rezhim=="числа"){ exit 0 } - if(beda==0){ printf "\nопись сходится с деревом\n"; exit 0 } - printf "\n" - for(p in net_stroki) printf "НЕТ СТРОКИ: %s несёт %d обязательств, а в описи его нет\n", p, net_stroki[p] > "/dev/stderr" - for(p in lishn) printf "ЛИШНЯЯ СТРОКА: %s есть в описи, а в дереве обязательств не несёт\n", p > "/dev/stderr" - for(p in raz_nap) printf "«НАПИСАНО» НЕ СХОДИТСЯ: %s — %s\n", p, raz_nap[p] > "/dev/stderr" - printf "\nбед %d: нет строки %d, лишних %d, «написано» не сходится %d\n", beda, net_n+0, lishn_n+0, raz_n+0 > "/dev/stderr" - exit 1 - } -' "$RAB/derevo" "$RAB/opis" diff --git a/scripts/ledgers/link-guard-known-not-a-path.tsv b/scripts/ledgers/link-guard-known-not-a-path.tsv index 5d299e3a6..e8a6d5ddc 100644 --- a/scripts/ledgers/link-guard-known-not-a-path.tsv +++ b/scripts/ledgers/link-guard-known-not-a-path.tsv @@ -184,3 +184,7 @@ docs/tasks/0049-the-last-javascript-leaves-the-tree.md flang/scripts/word-occupa docs/tasks/1219-comments-in-shell-scripts-fall-below-a-fifth.md scripts/guards/version-derivations-guard.sh история: замер доли комментариев того дня считал этот файл; он снят 4 октября 2026 (задача 5821), сверка стала планом scripts/guards/version-derivations-guard.fscript docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md scripts/seed/seed-freshness.sh история: пункт задачи про снятый переходник; имя оставлено зачёркнутым, чтобы было видно, ЧТО снято docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md version-derivations-guard.sh история: пункт задачи про снятый сторож; имя оставлено зачёркнутым, чтобы было видно, ЧТО снято +docs/tasks/3593-the-proved-share-collapses-on-code-that-touches-the-world.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда +docs/tasks/4416-the-checker-rejects-an-honest-instantiation-proof.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда +docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md proved-share-vs-tree.sh история: список кандидатов на перенос, снятый до переноса; сам перенос сделан 4 октября 2026 в scripts/guards/proved-share-vs-tree.fscript +docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md guards-without-forgery-probe.sh история: список кандидатов на перенос, снятый до переноса; сам перенос сделан 4 октября 2026 в scripts/guards/guards-without-forgery-probe.fscript diff --git a/scripts/ledgers/proved-share-ledger.txt b/scripts/ledgers/proved-share-ledger.txt index bfed5db88..82b5a88ec 100644 --- a/scripts/ledgers/proved-share-ledger.txt +++ b/scripts/ledgers/proved-share-ledger.txt @@ -1544,6 +1544,7 @@ d45fead194fa7d93bc7afffb0f6b2a04|12|12|0|0|0|scripts/guards/delivery-guard.flang 9a1d779542ab08a5a1416bbdc99c0563|10|10|0|0|0|scripts/guards/dictionary-guard.fscript 35bc4b6ceba5235a93625a25ded7023f|12|12|0|0|0|scripts/guards/emit-promises-guard.fscript bb9f8dadc0aa937a5fc4dbda79707edd|18|16|2|0|0|scripts/guards/file-extensions.fscript +ce0f26e8f64ce11b7f2f8e559d0f090b|11|11|0|0|0|scripts/guards/guards-without-forgery-probe.fscript d29d464d969d58822bc10e6e696017ef|14|14|0|0|0|scripts/flangrc.fscript 001c0ecd7217d8ae84b4133d3dca9085|4|4|0|0|0|scripts/guards/flangrc-guard.fscript baa3170dc90958c56352eb9b3f49ab9b|62|49|10|3|0|scripts/guards/homebrew-formula-guard.fscript @@ -1560,6 +1561,7 @@ b227c0ad335b884661247019d31270e6|22|22|0|0|0|scripts/guards/name-splicing-guard. c5506e0d519db2384994e5edb50f9ad8|13|7|6|0|0|scripts/guards/no-comments-guard.fscript 323f8525a0746bf647873edd7ba3eaf7|9|9|0|0|0|scripts/guards/no-package-json-guard.fscript 76e306cbb502d04abaef8d8b0807eb8d|7|7|0|0|0|scripts/guards/occupancy-check.fscript +01aef169c0bbf946d103d0efc22f3d7e|13|13|0|0|0|scripts/guards/proved-share-vs-tree.fscript 7feca661ed8e0a679823c1b6f0a431fe|24|24|0|0|0|scripts/guards/occupied-names-guard.fscript bcb9a4bd2f77da1cc1fdfe50b7385bed|2|2|0|0|0|scripts/guards/record-follows-its-source.fscript 1083cc30fab03e5f16e2060519b7c8c1|8|8|0|0|0|scripts/guards/release-guard.fscript From 07ae688cd970a69f084665439924c4485181db55 Mon Sep 17 00:00:00 2001 From: Marat Zimnurov Date: Sun, 4 Oct 2026 16:36:14 +0000 Subject: [PATCH 2/5] docs: the census and three counted marks follow the two moved guards The move took 414 lines of shell out of the tree, and every counted mark that names them was re-measured by its own instrument, not guessed: docs/tree-inventory.md shell 56/9875 files/lines -> 54/9461, shell debt 50/5431 -> 48/5017 three places files of all non-flang languages 193 -> 191 docs/javascript-inventory.md and the title of tree-inventory.md say 191 inventory:check answers code 0 (17 languages, four columns each) and prose-numbers-guard answers code 0 (209 marks, all 209 agree with the tree). The marks in binary.yml and ci.yml ride in the previous commit, where the steps that call the two plans stand. docs/shell-to-flang-census.md loses the argument it held the proved share back with, and keeps the measurement that killed it. Both guards move from the "it is stuck on" tables into "moved to flang", so the section counts become 7 and 4. The "left in scripts/" total of the summary table is NOT touched: the whole table is a snapshot of 23 September, and 41 - 2 would be arithmetic over a stale base dressed up as a measurement. The same instrument run today gives 9 files and 6169 lines in scripts/**, because other work shrank that folder too, and the census now says so with both dates. --- docs/javascript-inventory.md | 4 ++-- docs/shell-to-flang-census.md | 42 ++++++++++++++++++++++++++--------- docs/tree-inventory.md | 6 ++--- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/docs/javascript-inventory.md b/docs/javascript-inventory.md index c605cb21c..20c8c5fd8 100644 --- a/docs/javascript-inventory.md +++ b/docs/javascript-inventory.md @@ -68,8 +68,8 @@ JavaScript стало 55, строк 29 733; в трёх каталогах о Эта опись считает ОДИН язык. Остальные шестнадцать — оболочка, C, C++, Python, HTML, CSS, awk, Erlang, Java, C#, Elixir, Go, Rust, Lua, vimscript, Ruby — -считает [`tree-inventory.md`](tree-inventory.md) (4 октября 2026: 192 файлов вне flang, - +считает [`tree-inventory.md`](tree-inventory.md) (4 октября 2026: 190 файлов вне flang, + долг вне JavaScript — **97 файлов, 18 427 строк при потолке 63**: храповик красен, разбор — задачи 4838 и 7405). Там же названы 569 строк JavaScript, лежащих ВНУТРИ файлов `.html`: счёт по именам файлов их не видит, и diff --git a/docs/shell-to-flang-census.md b/docs/shell-to-flang-census.md index 0e8b9fe2a..bb0816215 100644 --- a/docs/shell-to-flang-census.md +++ b/docs/shell-to-flang-census.md @@ -67,8 +67,18 @@ done Файлов, у которых НИ ОДНОГО из этих семи признаков, — **три**: `scripts/guards/proved-share-vs-tree.sh`, `scripts/guards/seed-knows-type-words-guard.sh` -и `scripts/release/bump-version.sh`. Первые два держит не язык, а место вызова -(хук до сборки двоичного; сторож судит семя). Третий перенесён. +и `scripts/release/bump-version.sh`. Третий был перенесён тогда же. + +**Довод про «место вызова» у первого УСТАРЕЛ, и это проверено прогоном +4 октября 2026.** Он звучал так: «сторожа держит хук перед пушем, а хук идёт до +сборки двоичного». С задачи 1219 хук САМ СТАЛ ПЛАНОМ: `.githooks/pre-push` — это +две строки `exec bootstrap/flang io .githooks/pre-push.fscript`, то есть к +моменту, когда хук зовёт сторожа, двоичный обязан уже существовать, иначе не +стартует и сам хук. Второе место вызова, `binary.yml`, зовёт `./bootstrap/flang` +на двенадцати шагах выше. Оба довода мертвы, и сторож перенесён +(`scripts/guards/proved-share-vs-tree.fscript`, 13 обязательств, все доказаны +ядром; прогон обоих на одном дереве дал одни и те же 14 чисел и одни и те же +слова на трёх порчах описи). ### Пять новых границ, найденных пересчётом @@ -141,7 +151,7 @@ done Столбец «упирается во что» — теперь ДВЕ причины там, где их две. Порядок — по причине. -### Перенесено на flang — 7 (3 в первой работе, 4 в этой) +### Перенесено на flang — 9 (3 в первой работе, 4 во второй, 2 в третьей) | файл | строк | стало | чем доказано равенство | |---|---:|---|---| @@ -152,13 +162,14 @@ done | `scripts/seed/print-progress.sh` | 88 | `print-progress.fscript` | 13 пар прогонов, из них 4 НАСТОЯЩИХ журнала печати (1,5–147 КБ) | | `scripts/cell-work-preserved.sh` | 97 | `cell-work-preserved.fscript` | 5 пар прогонов на построенных ячейках, сверка заведённых ссылок | | `scripts/release/bump-version.sh` | 145 | `bump-version.fscript` | показ + подъём на двух деревьях-близнецах, пять файлов сверены побайтово | +| `scripts/guards/proved-share-vs-tree.sh` | 139 | `…-vs-tree.fscript`, планы «Check», «Numbers», «Forgery» | отчёт сошёлся ЗНАК В ЗНАК (14 чисел), три порчи описи дали одни и те же слова и код 1 у обоих | +| `scripts/guards/guards-without-forgery-probe.sh` | 275 | `…-probe.fscript`, планы «Check», «Census», «List», «Forgery» | перепись и список сошлись ЗНАК В ЗНАК, две порчи ведомости дали одни и те же слова и код 1 у обоих | -### Упирается в чужой прибор, которого у языка нет — 8 +### Упирается в чужой прибор, которого у языка нет — 7 | файл | строк | во что именно | |---|---:|---| -| `scripts/guards/guards-without-forgery-probe.sh` | 323 | разборщик YAML (`pyyaml`); подстрочный счёт уже давал ложные записи | -| `scripts/guards/who-calls-the-guards.sh` | 269 | то же: ключ `run:` берётся разбором YAML, подстрочный счёт давал 115 ярлыков вместо 111 | +| `scripts/guards/who-calls-the-guards.sh` | 269 | то же: ключ `run:` берётся разбором YAML, подстрочный счёт давал 115 ярлыков вместо 111 — довод снят переносом самого соседа 4 октября 2026 | | `scripts/seed/seed-runtime-is-source.fscript` | 80 | `diff` считает по наибольшей общей подпоследовательности; построчное сличение даст ДРУГОЕ число | | `scripts/guards/seed-knows-type-words-guard.sh` | 311 | ПОРОЖДАЕТ программу на awk и гоняет её лексером по сотням файлов; mawk против gawk дал 30 ложных находок — это мера, а не счёт | | `scripts/targets/target-collisions.sh` | 248 | `jq` и awk-программа построения дерева | @@ -166,7 +177,7 @@ done | `scripts/guards/bad-octet-guard.sh` | 340 | сырые негодные октеты: литерал flang их не несёт | | `scripts/guards/one-string-measure-guard.sh` | 119 | то же | -### Упирается в порядок сборки: зовётся до того, как собран двоичный — 5 +### Упирается в порядок сборки: зовётся до того, как собран двоичный — 4 Хук `.githooks/pre-push` нарочно не собирает `bootstrap/flang` (2 минуты на раннере, 5–6 на слабой машине). **Это граница порядка сборки, а не языка.** Её @@ -179,7 +190,6 @@ done | `scripts/guards/task-numbers-guard.sh` | 284 | ярлыки.flang (и это ЗАМЫСЕЛ: запасной путь на свежем клоне) | | `scripts/guards/flangrc-guard.sh` | 238 | ярлыки.flang, ci.yml | | `scripts/guards/version-derivations-guard.sh` | 195 | хук, .flangrc | -| `scripts/guards/proved-share-vs-tree.sh` | 139 | хук, binary.yml | ### Судит двоичный, семя или печать — 7 @@ -268,8 +278,9 @@ done | причина | файлов | строк | |---|---:|---:| | перенесено на flang (в этой работе) | 4 | 415 | -| чужой прибор, которого у языка нет | 8 | 1772 | -| зовётся до сборки двоичного | 5 | 1272 | +| перенесено на flang (4 октября 2026) | 2 | 414 | +| чужой прибор, которого у языка нет | 7 | 1449 | +| зовётся до сборки двоичного | 4 | 1133 | | судит двоичный, семя или печать | 7 | 1402 | | собирает сам двоичный | 5 | 4269 | | экран, терминал, ssh | 3 | 693 | @@ -281,6 +292,17 @@ done | прочее | 3 | 1462 | | **осталось в `scripts/`** | **41** | **12 705** | +**Вся таблица — замер 23 сентября 2026, и трогать её числа задним числом +нельзя.** Два переноса 4 октября 2026 сняли из неё 2 файла и 414 строк +(`proved-share-vs-tree.sh` 139 и `guards-without-forgery-probe.sh` 275), но +сложить 41 − 2 и 12 705 − 414 значило бы выдать арифметику над протухшей базой +за замер: за эти одиннадцать суток `scripts/**` похудел и чужими работами. +Замер того же прибором 4 октября 2026 — **9 файлов и 6 169 строк** +(`git ls-files 'scripts/*.sh' 'scripts/**/*.sh' | wc -l` и `| xargs wc -l`), +то есть долг оболочки в `scripts/` убыл вчетверо, а не на два файла. Четвёртый +столбец «Числа» этим замером не заводится: он требует перепись целиком, а не +одну строку. + ## Что сдвинуло бы перепись дальше, числом Порядок — по числу освобождаемых файлов на одно изменение. diff --git a/docs/tree-inventory.md b/docs/tree-inventory.md index 720b0986f..a412eea85 100644 --- a/docs/tree-inventory.md +++ b/docs/tree-inventory.md @@ -1,5 +1,5 @@ -# Опись дерева по языкам: 192 файлов вне flang, долг вне JavaScript — 93 при потолке 63 - +# Опись дерева по языкам: 190 файлов вне flang, долг вне JavaScript — 93 при потолке 63 + ⚠ **ХРАПОВИК ДОЛГА КРАСЕН, и заголовок это теперь говорит.** Прогон `bootstrap/flang run-script inventory:languages` **5 сентября 2026** отвечает кодом 1: «ДОЛГ ВНЕ @@ -76,7 +76,7 @@ $ bootstrap/flang io scripts/guards/tree-inventory.fscript --max-steps 50000000 | язык | файлов | строк | долг файлов | долг строк | |---|---:|---:|---:|---:| -| оболочка | 55 | 9661 | 50 | 5 431 | +| оболочка | 53 | 9 247 | 48 | 5 017 | | C | 39 | 882 835 | 0 | 0 | | C++ | 1 | 404 | 0 | 0 | | Python | 5 | 2 906 | 0 | 0 | From 95588ba83d0fb7d6ba09208f7889080f07f67315 Mon Sep 17 00:00:00 2001 From: Marat Zimnurov Date: Sun, 4 Oct 2026 16:42:47 +0000 Subject: [PATCH 3/5] chore(ledgers): four more dead paths of the moved guards are records The link guard names one broken target per file, so the first four records of the two removed shells hid four more behind them: tasks 1177, 1188 and 2277 cite scripts/guards/proved-share-vs-tree.sh, task 4433 cites guards-without-forgery-probe.sh. All four are closed task records, where the file is named as it was named then, so rewriting them would be a lie about the past; they go into the ledger with that as the reason. Measured, not guessed: links:check gives 88 broken of 7130 on the base (origin/dev in a worktree of its own) and 88 on this branch with these eight records in place. Without them the branch gave 92. --- scripts/ledgers/link-guard-known-not-a-path.tsv | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/ledgers/link-guard-known-not-a-path.tsv b/scripts/ledgers/link-guard-known-not-a-path.tsv index e8a6d5ddc..75c19f81f 100644 --- a/scripts/ledgers/link-guard-known-not-a-path.tsv +++ b/scripts/ledgers/link-guard-known-not-a-path.tsv @@ -188,3 +188,7 @@ docs/tasks/3593-the-proved-share-collapses-on-code-that-touches-the-world.md scr docs/tasks/4416-the-checker-rejects-an-honest-instantiation-proof.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md proved-share-vs-tree.sh история: список кандидатов на перенос, снятый до переноса; сам перенос сделан 4 октября 2026 в scripts/guards/proved-share-vs-tree.fscript docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md guards-without-forgery-probe.sh история: список кандидатов на перенос, снятый до переноса; сам перенос сделан 4 октября 2026 в scripts/guards/guards-without-forgery-probe.fscript +docs/tasks/1177-a-quantifier-is-refused-inside-a-formula-and-binds-only-a-whole-goal.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда +docs/tasks/1188-existence-without-a-named-witness-has-no-rule.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда +docs/tasks/2277-the-law-judges-of-monoid-functor-and-monad-are-written-and-called-by-nobody.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда +docs/tasks/4433-the-uncalled-checks-guard-does-not-see-a-judge-in-the-closure.md guards-without-forgery-probe.sh история: сторож перенесён на план scripts/guards/guards-without-forgery-probe.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда From a4984717989aeb5ae3837cc639c6af2bcee131ad Mon Sep 17 00:00:00 2001 From: Marat Zimnurov Date: Sun, 4 Oct 2026 16:51:20 +0000 Subject: [PATCH 4/5] fix(ledgers): the record of task 4433 names the path the guard reports The record was written with the bare name guards-without-forgery-probe.sh while task 4433 cites it as scripts/guards/guards-without-forgery-probe.sh, and the link guard keys a record by the pair (file, target) exactly. With the wrong key the run said both things at once: "the path leads nowhere" AND "this record no longer fires - clean it out". Measured: links:check gives 88 broken of 7130 and 0 stale records on this branch, the same 88 of 7130 and 0 as origin/dev in a worktree of its own. With the wrong key it was 89 and 1. --- scripts/ledgers/link-guard-known-not-a-path.tsv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ledgers/link-guard-known-not-a-path.tsv b/scripts/ledgers/link-guard-known-not-a-path.tsv index 75c19f81f..4c069d34d 100644 --- a/scripts/ledgers/link-guard-known-not-a-path.tsv +++ b/scripts/ledgers/link-guard-known-not-a-path.tsv @@ -191,4 +191,4 @@ docs/tasks/5821-shell-scripts-that-can-become-flang-are-counted-and-moved.md gua docs/tasks/1177-a-quantifier-is-refused-inside-a-formula-and-binds-only-a-whole-goal.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда docs/tasks/1188-existence-without-a-named-witness-has-no-rule.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда docs/tasks/2277-the-law-judges-of-monoid-functor-and-monad-are-written-and-called-by-nobody.md scripts/guards/proved-share-vs-tree.sh история: сторож перенесён на план scripts/guards/proved-share-vs-tree.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда -docs/tasks/4433-the-uncalled-checks-guard-does-not-see-a-judge-in-the-closure.md guards-without-forgery-probe.sh история: сторож перенесён на план scripts/guards/guards-without-forgery-probe.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда +docs/tasks/4433-the-uncalled-checks-guard-does-not-see-a-judge-in-the-closure.md scripts/guards/guards-without-forgery-probe.sh история: сторож перенесён на план scripts/guards/guards-without-forgery-probe.fscript 4 октября 2026; в задаче он назван тем именем, какое носил тогда From 57d1787e7deadf5c02377fcb73a77728efa2ea87 Mon Sep 17 00:00:00 2001 From: Marat Zimnurov Date: Sun, 4 Oct 2026 18:03:46 +0000 Subject: [PATCH 5/5] fix(ledger): the shell row marks follow both removals of today Two removals landed the same day: PR 310 took flang/translation/run.sh and this branch takes two guards. The shell row of the census kept the marks of only one of them: 55 files instead of 53, 9661 lines instead of 9247. Numbers come from the guard run, not from arithmetic: marks 209, agreed 209, diverged 0. --- docs/tree-inventory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tree-inventory.md b/docs/tree-inventory.md index a412eea85..722a6e9aa 100644 --- a/docs/tree-inventory.md +++ b/docs/tree-inventory.md @@ -76,7 +76,7 @@ $ bootstrap/flang io scripts/guards/tree-inventory.fscript --max-steps 50000000 | язык | файлов | строк | долг файлов | долг строк | |---|---:|---:|---:|---:| -| оболочка | 53 | 9 247 | 48 | 5 017 | +| оболочка | 53 | 9 247 | 48 | 5 017 | | C | 39 | 882 835 | 0 | 0 | | C++ | 1 | 404 | 0 | 0 | | Python | 5 | 2 906 | 0 | 0 |