Конвеєри¶
П'ять послідовностей, які покривають майже всю роботу. Порядок у них не косметичний: кожен наступний крок дорожчий за попередній, тому дешеве йде першим, а око людини — останнім.
Кроки названо іменами операцій: дістати будь-яку можна з командного рядка
(nysh op cases.list). Схема аргументів: nysh op <ім'я> --describe.
🔴 Крок −1 в усіх п'яти: подивись, що вже зроблено. cases.list,
pages.status, nysh text grep "<ключ>" --where all. Переробка — найдорожча
витрата в довгому дослідженні, і вона ніколи не виглядає як помилка: робота ж
іде.
Конвеєри починаються з матеріалу, який уже є. Якщо його ще немає і питання
звучить «де шукати», порядок джерел і правила зупинки — where-to-dig.md.
1. Взяти матеріал у роботу¶
Питання: людина дала теку зі сканами або посилання на архів. Що з цим робити.
| # | крок | ✅ приймач |
|---|---|---|
| 1 | material.look (nysh look <шлях>) |
скільки кадрів, це одна справа чи багато |
| 2 | якщо кадрів немає — це не матеріал | не вигадуй; скажи людині, що саме побачив |
| 3 | case.register — шифра, назва, роки |
справа отримала ключ |
| 4 | nysh cases build |
справа з'явилась у cases.list |
Без шифри тека лишається купою файлів: у неї немає ні місця в реєстрі, ні
обліку прочитаного, ні можливості послатись на знахідку. Шифру приймають у тих
формах, якими її справді пишуть — ДАХмО 315-1-8433, ф.315 оп.1 спр.8433,
Ф. 211 Оп. 3 Д. 140.
⚠ Опис пишеться в саму теку. Тека переїжджає між дисками й потрапляє до
колег — опис їде з нею. Якщо тека лежить поза простором, ти отримаєш
попередження outside_workspace: справа буде невидима в переліках, доки людина
не візьме теку під облік.
⚠ Опис входить у ключ кожної справи: ANRM/211/3/140. Номери справ між
описами повторюються, тож запит без опису, коли таких книг кілька, відмовить і
назве варіанти — це не поламка, це різні книги під одним номером. Опис не
встановлено — у ключі _ (DAOO/37/_/1235); вгадувати його не треба, його
дописують у паспорт.
Плівка на кілька справ. Плівка FamilySearch з українських архівів несе кілька справ підряд, кожну між чорними картками зйомки (початкова з шифрою, «END OF ITEM»). Межі не шукай очима кадр за кадром:
nysh cases cards <тека> --sheet <тека листів>— відтинки й лист карток, один на плівку;- на листі прочитай шифру з початкової картки (у парі вона друга) і повтори
команду з номерами в порядку плівки:
--prefix "ДАЧкО 931-1-" --numbers 923,924,…— карта вийде заповненою. Одиночний темний кадр посеред справи (попередженняlone_card) — чорний аркуш або справжня картка: подивись на листі й за потреби злий сусідні частини вmap.jsonруками; nysh cases split <тека> --map map.json --dry-run, потім без--dry-run.
Плівку спершу докачай: на пропущеному кадрі могла стояти саме картка
(попередження frames_missing).
Справа, розірвана між котушками («CONTINUED ON ANOTHER ROLL» на одній, «…FROM…»
на наступній), у карті кожної плівки лишається поза справами (-), а збирається
окремо: nysh cases join <тека справи> --part "<плівка 1>=<перший>..<останній>"
--part "<плівка 2>=…" — голова першою; далі nysh case <тека справи>.
2. Прочитати справу рукописним рушієм¶
Питання: є скани, потрібен машинний текст.
🔴 Читає команда, а не черга. read.start лише ставить завдання в чергу, а
черга є тільки в піднятому застосунку (nysh serve). Робочий шлях — і в цьому
немає нічого другосортного, так задумано:
nysh read <тека зі сканами>
| # | крок | ✅ приймач |
|---|---|---|
| 1 | nysh share pull "<шифра>" |
справи в пулі немає — або її прийнято з --take, і читати не треба |
| 2 | nysh doctor --json |
рушії стоять, карту видно |
| 3 | nysh read <тека> --dry-run |
план: скільки кадрів, яке письмо, яка модель |
| 4 | nysh read <тека> |
прогін пішов |
| 5 | порахувати .txt на диску проти .jpg |
ось це і є приймач |
🔴 Спершу пул, потім рушій. Прогін справи — години машинного часу, текст
із Супряги — хвилина. Пул відповідає лише з ключем (nysh share login,
разово). Прийняте лягає в текстовий стор саме, далі — nysh cases build і
пошук, як по своєму прочитаному. Мітку прив'язки (лише exact дає кропи на
ваших кадрах) і серію фонду розбирає скіл pull-case.
🔴 Приймач повноти — диск, а не код повернення. Є клас відмов, за якого сторінка вбиває процес: лог обривається без пояснення, перелік помилок порожній, прогін виглядає завершеним. Виміряний випадок: 14 сторінок із 18 при успішному коді повернення. Тому після прогону завжди звіряй кількість файлів.
⚠ Тека має бути пласкою. Тека з підтеками читається як порожня — «у теці немає сторінок jpg». Це коштувало прогонів, тому перевіряється до запуску, і повідомлення назве підтеки.
⚠ Читання — години. Не запускай його «щоб подивитись». Спершу --dry-run,
потім --limit 20 на розвідку, і аж тоді повний прогін.
🔋 Машина слабка? --shard, --gpu-lock, --no-gpu-sato, --seg-height —
важелі, якими прогін стискають під наявне залізо. Що з них безпечне, а що
коштує якістю прочитаного — htr-tuning.md.
3. Знайти прізвище в прочитаному¶
Питання: машинний текст є, треба знайти в ньому рід.
Це найтонший конвеєр, і саме тут агенти помиляються найчастіше
(antipatterns.md). Порядок економить не токени, а око людини: кроп дорогий,
тому він передостанній, а не перший.
| # | крок | чим | ✅ приймач |
|---|---|---|---|
| 1 | пошук | search.run |
знаменник у попередженні |
| 2 | контекст | уже в хіті (context, alt) |
вікно сусідів + читання другого голосу |
| 3 | відкинути явне | сам, без зображення | тільки за контекстом (нижче) |
| 4 | подивитись | page.view по line_index |
рядок із рамкою |
| 5 | 🛑 до людини | твій звіт | «кандидат», а не «знайдено» |
| 6 | ⚓ канали імен і запису | --anchors --record (у межах справи) |
рядки, де ім'я + по батькові роду поруч; записи, де ознаки родини зійшлись у різних колонках |
| 7 | 🎯 перед словом «немає» | --selfcheck |
recall на тому, що виписало око |
🔴 Кроки 6-7 — не «якщо лишився час», а умова звіту. Прізвищний канал бачить не все: рушій калічить довге прізвище сильніше за коротке формулярне слово, і рід буває цілий саме в іменах. А нуль без recall не відрізняється від непрацездатного пошуку.
Крок 1 — знаменник обов'язковий¶
Порожній результат читається разом із попередженням. zero_with_denominator
означає справжній нуль («не знайшлось у N прогонах, M сторінок»);
no_denominator означає, що не шукало ніщо, і звітувати «немає» не можна.
⚠ Пошук уже сам зшиває прізвище, розірване переносом, і сам нормалізує
кирилицю з латинкою — не роби цього руками. Що він уміє, а чого в ньому
немає (склад двору, вік) — search-channels.md. У розібраних записах питання
звужується полями: role (батько, восприємник, померлий), rtype (тип акту) і
axis=place — пошук по поселенню замість прізвища.
Крок 2 — вікно приходить саме¶
search.run віддає кожен хіт разом із сусідніми рядками (context) і, як
справу читано двома рушіями, з читанням другого (alt). Окремо просити
page.text для цього більше не треба — він потрібен, коли хочеш усю
сторінку (заголовок формуляра, ліва колонка, сусідні акти).
Рядок сам по собі не розрізняє трьох родів зі спільним коренем у одній парафії. Доказ живе на двох рядках: прізвище перенеслося, ім'я стоїть вище, роль — нижче. А розбіжність голосів на самому прізвищі означає, що ознака в пікселях — тобто крок 4 обов'язковий.
⚠ Класифікація по вузькому вікні — не розбір, а фільтр. Виміряний випадок: по вікну ±2 рядки ознака бачилась на 15 сторінках, по повному тексту — на 41. Найдорожчими виявились сторінки, де ознака взагалі не була прочитана: вони мовчки поїхали в «чуже».
Крок 3 — відкидати можна тільки за контекстом¶
🔴 Відсів за коренем слова заборонений. Рушій калічить саме середину слова, тож шукане прізвище виходить із нього невпізнанним. Список «поганих коренів» відріже рівно те, по що його кликали.
Три підстави закрити кандидата без зображення — і більше жодної:
- ім'я після формули спорідненості («сина …», «дочки …»);
- топонім: поруч стоїть «повіту», «губернії», «уїзду»;
- токен порожній, самі цифри або 1–3 літери.
Усе інше ранжується, а не відкидається. Ознаки, що піднімають ранг: поруч ім'я з відомого складу роду, по батькові перед токеном, токен відкриває рядок із великої літери. Ознаки, що знижують: стоїть після прийменника з малої, у рядку канцелярський штамп.
Крок 4 — кроп лише тому, що схоже на прізвище¶
Дефолт page.view — рядок: сторінка коштує приблизно вчетверо дорожче.
Бери line_index з хіта, не line_no (перше — з нуля, друге — з одиниці).
🛑 Крок 5 — межа¶
Якщо на кропі прізвище, схоже на шукане, — ти не виносиш вердикт. Клади кандидата людині з зображенням і контекстом. Закривати можеш лише те, що взагалі не є прізвищем.
Кандидат, від якого щось залежить, іде хітом у картку гіпотези
(data/canonical/hypotheses/, docs/agents/canon.md), а не в нотатку: звідти
його побачить nysh canon next у наступній сесії. Решта кандидатів заходу
лишається у звіті й у журналі гортача.
4. Записати результат¶
Питання: переглянув аркуші — що з цим робити, щоб робота не пропала.
| # | крок | ✅ приймач |
|---|---|---|
| 1 | pages.note на кожен переглянутий аркуш |
сторінка зникла з «ще не дивились» |
| 2 | records.add — розібрані записи |
хто/коли/батьки/восприємники окремими полями |
| 3 | nysh cases build (команда) |
реєстр знову свіжий |
| 4 | export.case — якщо просили таблицю |
кожен рядок несе скан |
| 5 | знахідку про рід, яку підтвердила людина, — у канон: text.crop → evidence.add → картка → canon.check → canon.index (canon.md) |
canon.check без помилок, факт у картці з цитатою й доказом |
🔴 Заносяться всі аркуші, а не тільки вдалі. Порожній, не той, хибне спрацювання пошуку — теж. Негативний результат коштує тих самих токенів, що й позитивний, а без запису наступна сесія передивиться той самий аркуш.
У коментарі пиши чому це не те («пошук подав як потрібне село — на скані інше»). У полі методу — чи ти дивився зображення, чи лише читав машинний текст.
⚠ status=full означає «виписані всі прізвища сторінки». Якщо виписав частину —
partial. Поставиш full без прізвищ — отримаєш попередження
full_without_surnames, і це не причіпка: від цього поля залежить, чи можна
довіряти нулю по всій справі.
⚠ Записи прози й переказу не заміняють структурованих полів. «Виписка без посилання на аркуш — це переказ», і в експорті вона нічого не варта.
5. Коли модель не бере цей почерк: розмітити й дотренувати¶
Питання: справа прочитана, але кожна п'ята літера неправильна, і пошук нічого не знаходить. Роздавана модель цього письма не бачила.
Цей конвеєр живе лише в командному рядку (секція lab, nysh train …):
tool'ів для нього немає навмисно — лабораторні дії в агентну поверхню не
йдуть. Два скіли ведуть по кроках: label-lines (мітки) і train-model
(корпус, трен, епоха, бойова модель).
| # | крок | ✅ приймач |
|---|---|---|
| 1 | nysh train cut <прогін> --name <набір> --pick 6 |
кропи з прогону, текст прогону — перший голос |
| 2 | nysh train voices --set <набір> --from-run <прогін>-diak_v6 |
≥2 голоси |
| 3 | nysh train export → арбітри → nysh train import |
злиття з conf, ворота пройдено |
| 4 | людина: 20–30 рядків у вкладці «Розмітка» | nysh train stats показує CER голосу проти людини |
| 5 | один-два набори з іншої справи — роль holdout |
nysh train doctor без попередження про holdout |
| 6 | nysh train build --name v1 --recipe own |
tgz, val не порожній |
| 7 | nysh train start --corpus v1 --dry-run, потім --yes |
план названий; status показує епохи |
| 8 | nysh train eval --models <чинна> |
таблиця з чинною моделлю, переможець за recall |
| 9 | nysh train promote … --why |
nysh models list показує нову бойову |
🔴 Найдорожче тут — мітки, звірені оком, а не карта. Мітка з помилкою гірша за відсутню. І епоху обирає holdout з іншої справи, не val трену: покращення val на тих самих справах — не доказ.