# Capordia — вправа з перемикання та відновлення, версія 1.0.0

Ця вправа на CPU порівнює безперервну обробку з перерваною обробкою,
скопійованою в іншу теку та відновленою в новому процесі. Вона дає змогу
побачити, які партії завершено, які виконуються, а які потрібно відновити.
Вона не вимірює жодного GPU і не демонструє міграцію без переривання.

## Підготувати вправу

Використовуйте Python 3.10 або новіший із стандартними модулями `sqlite3` та
`hashlib` на локальному диску з правом запису. Жодних пакетів, доступу до
мережі, облікового запису, секрету чи прав адміністратора не потрібно.
Розпакуйте всі файли з теки, а потім відкрийте термінал у цій теці. Якщо
система використовує `python3` або `py -3`, замініть `python` у командах.
Скрипт і набір вхідних даних залишаються окремо від робочих тек, які він
створює.

Не виконуйте цю вправу в робочій теці або на мережевому ресурсі. Виберіть
ім'я робочої теки, якої не існує: програма відмовляється повторно
використовувати або перезаписувати наявну теку.

```text
python exercice.py demonstration --dossier essai-capordia
```

Ця команда створює `essai-capordia/rapport-verification.json` і теки
кожного сценарію. Вона завершується кодом 0 лише тоді, коли всі перевірки
успішні. Запустіть знову з новим ім'ям для нової спроби. Команда не
стирає жодної попередньої спроби.

## Наш приклад: вісім партій вигаданих купонів

Вісім CSV містять кожен по шість оригінальних і вигаданих розмірних
вимірювань. Кожен рядок містить `coupon`, `cible_um` та `mesure_um`.
Одиниці — це цілі мікрометри. Жодне число не походить із виробничої машини
чи від клієнта. Для кожної партії обробка обчислює кількість купонів, суму
та максимум абсолютних відхилень, а також кількість відхилень, що менші або
дорівнюють 15 µm. Цей поріг є правилом вправи, а не рекомендованим
промисловим допуском.

Результат містить номер партії, версію рецептури та відбиток SHA-256
вхідних даних. Використання цілих чисел дає тут змогу для точного
порівняння. Навантаження GPU з обчисленнями з плаваючою комою вимагало б
власного правила порівняння та обґрунтованих допусків.

## Читати стани

| Стан у реєстрі | Значення в цій вправі | Обробка під час відновлення |
|---|---|---|
| `termine` | Результат прийнято й стан збережено в одній транзакції | Перевірити; не перераховувати |
| `en_cours` | Спроба оголошена, жодного результату не прийнято | Переглянути попередній повноважний стан, потім дозволити відновлення |
| `a_reprendre` | Партію не розпочато або спробу явно повернуто в чергу | Виконати спробу |

Після ін'єктованого розриву на LOT-004: LOT-001 — LOT-003 завершено,
LOT-004 виконується, LOT-005 — LOT-008 потрібно відновити. Жодного
результату LOT-004 не прийнято. Після `preparer-reprise` залишається три
завершених і п'ять таких, що потрібно відновити. Наприкінці всі вісім
результатів мають дорівнювати результатам з еталона. Лише LOT-004 має дві
спроби.

## Відтворити перемикання крок за кроком

Наведені далі шляхи відносні до теки, що містить `exercice.py`.
Розрив — це ін'єктований виняток після обчислення й перед прийняттям;
код 75 на цьому етапі очікуваний. Процес зупиняється й звільняє своє
блокування. Це не аварійне завершення роботи комп'ютера й не збій
електроживлення.

```text
python exercice.py initialiser --dossier manuel/reference --proprietaire reference
python exercice.py executer --dossier manuel/reference
python exercice.py initialiser --dossier manuel/source --proprietaire atelier-source
python exercice.py executer --dossier manuel/source --interrompre-sur LOT-004
python exercice.py etat --dossier manuel/source
python exercice.py basculer --source manuel/source --destination manuel/cible --proprietaire atelier-cible
python exercice.py preparer-reprise --dossier manuel/cible
python exercice.py executer --dossier manuel/cible
python exercice.py comparer --reference manuel/reference --candidat manuel/cible
```

`basculer` бере локальне блокування, перевіряє набір, закриває джерело,
закриває з'єднання SQLite й копіює теку. Копія залишається закритою до
завершення її перевірки; далі лише цілі дозволено створювати результати.
Команда виконання, запущена для закритого джерела, повертає код 2
з `SOURCE_CLOTUREE`.

Команда порівняння вимагає вісім прийнятих результатів з кожного боку,
перевіряє їхні входи та виходи, а потім порівнює канонічну серіалізацію JSON
результатів. Текстові експорти можна відтворити з SQLite: вони не є
авторитетом, який вирішує, чи результат прийнято.

## Створені файли

| Файл | Роль |
|---|---|
| `registre.sqlite` | Еталонний стан, спроби, власник, закриття та прийняті результати |
| `manifeste.json` і `donnees/` | Зафіксований набір входів з очікуваними відбитками |
| `etat.json` | Читабельний стан і підрахунок трьох статусів |
| `registre-lots.csv` | Експорт: id, etat, tentatives, entree_sha256, sortie_sha256 |
| `resultats.json` | Експорт прийнятих результатів у порядку ідентифікаторів |
| `rapport-verification.json` | У глобальній теці демонстрації: перевірки, середовище та виводи команд |
| `worker.lock` | Тимчасове блокування нашої програми, знімається під час її нормального завершення або інжектованого переривання |

Файл `registre-lots-vierge.csv`, наданий у ресурсі, є ширшим шаблоном
для вашої команди. Він додає відповідального, дозволену машину,
критерій прийняття та причину відновлення. Він не замінює базу
вправи й не імпортується програмою.

## Перевірені помилки

Демонстрація також тестує повторний запуск завершеної роботи, відхилення
другого прийняття того самого лота, змінений вхід, дубльований ідентифікатор
у маніфесті, зіпсований вихід, уже наявне блокування та виняток
усередині транзакції прийняття. Останній випадок залишає три
прийняті виходи, не чотири, а потім відновлює вісім результатів після
відновлення. Повернення тестується копіюванням недавнього стану цілі
в третю теку із закриттям цілі. Старий знімок не активують.

Коди виходу: 0 — успіх; 2 — очікувана бізнес-відмова; 75 — очікуване
інжектоване переривання; 1 — помилка читання або бази. Глобальний сценарій
явно очікує відмов, які він спричиняє. Інша помилка призводить до невдачі тесту.

## Обмеження, які слід зберігати разом із результатами

У цій вправі бере участь лише один worker. Блокування та поле закриття
працюють у локальних теках, якими керує ця програма. Вони не заважають
людині скопіювати базу або іншій програмі проігнорувати блокування.
Це не розподілене fencing. Перед справжнім перемиканням стара машина
повинна втратити право публікувати через незалежний і перевірений механізм.
Якщо її зупинку не підтверджено, другу інстанцію не запускають.

Транзакція тут об'єднує результат і статус у **тій самій локальній базі**.
Вона не охоплює надсилання до зовнішньої системи, сповіщення або
файл, уже спожитий деінде. Відсутність перевіреного подвійного прийняття
обмежується цією базою та цією вправою. SHA-256 виявляє тут розбіжність між
байтами та очікуваним відбитком; маніфест, який можна змінити разом із даними,
не засвідчує їхнє походження.

Якщо процес убито різко, блокування може залишитися. Перевірте
його фактичну зупинку перед будь-яким ручним втручанням; вправа ніколи
автоматично не видаляє блокування, яке вважається застарілим. Переривання копіювання
залишає джерело закритим: збережіть теки й розгляньте інцидент,
не повертаючи дві копії до роботи. Втрата живлення, мережеві файлові
системи, конкуренція між машинами, драйвери GPU, контрольні точки
фреймворків і продуктивність тут не кваліфікуються.

## Результат нашої перевірки

24 вересня 2026 року, під Windows AMD64, Python 3.14.6 і SQLite 3.50.4:
16 успішних перевірок, 37 виконаних команд, 8 прийнятих результатів, ідентичних
після перемикання. Доказ для ознайомлення — `preuve-execution-cpu.json`.
Відбиток канонічних результатів —
`bde1bc833092cc8ca481cda5f44cfef36f14f0a94dff3f856624e169f5456660`.
Ці цифри описують цей набір із 48 рядків і не є GPU-бенчмарком.

Дивіться [PROCEDURE.md](PROCEDURE.md) щодо обов'язків і повернення,
[SOURCES.md](SOURCES.md) щодо первинних джерел і [LICENSE.txt](LICENSE.txt)
щодо умов повторного використання.
