mandrock-files / ai

primary-source-reader

Прочитати першоджерело і прочитати чужу думку про нього — різні задачі. Що технічно треба, щоб рідер допомагав формувати власну позицію, а не зручно показував текст: п'ять шарів приватного study-рідера.

Читати першоджерела, а не переказ про них

«Прочитати Прудона» і «прочитати статтю про Прудона» — це не одна задача з двома рівнями якості. Це дві різні задачі. Переказ уже несе чужий відбір: що важливо, що викинути, під яким кутом дивитись — і економить час рівно тим, що ухвалив рішення замість мене. Для довідки ок. Для власної позиції — ні: не можна не погодитись з аргументом, який до тебе не дійшов у своєму вигляді.

Різниця тут не в тексті, а в інструменті. Переказ споживають лінійно й забувають. Першоджерело треба перечитувати, розмічати й повертатись — інакше воно теж стає лінійним споживанням, просто довшим. Тобто рідер, який справді допомагає думати, — не «зручна читалка», а окремий клас інструмента: приватний, з нотатками на рівні секцій, зі станом, що переживає зміну пристрою, і з експортом того, що читач написав сам.

Нижче — п'ять шарів такого рідера. Кожен корисний окремо; будувати приблизно в цьому порядку. Розмежування, яке тримає всю конструкцію: асистент будує риштування, читач формує позицію. Асистент дзеркалить чужий текст, перекладає його, робить поля під нотатки — і ніколи не пише самі думки. Щойно з нього вилазить «а ось головна ідея цього розділу» — це вже переказ, і задача підмінена.


Шар 1 — дзеркалення джерел з copyright-дисципліною

Перше, що ламає наївну реалізацію, — не техніка, а право. Тут дві незалежні осі, які постійно злипаються в одну:

Технічно перед дзеркаленням варто мацнути саму сторінку: curl -sS -D - і подивитись, чи немає X-Frame-Options / CSP frame-ancestors, які ріжуть вбудовування, і чи це повний текст, а не тизер або paywall-заглушка. Неочевидний URL — спробувати передбачуваний slug-патерн сайту, потім його власний пошук. А якщо тексту там немає (він існує деінде, просто не на очікуваному сайті) — зупинитись і сказати це прямо. Підставити інший текст і назвати його тим самим — гірше за відсутність тексту.

Структуру сторінки закладаю одразу під двомовність: блок мовою оригіналу, порожня заглушка під переклад, перемикач між ними і один спільний маленький скрипт-тоглер на всі тексти рідера — не копіпаст на кожну сторінку.


Шар 2 — переклад як писання, а не копіювання

Робоча мова читача відрізняється від мови більшості джерел — треба перекладати, а не резюмувати. Стиснутий дайджест убиває весь сенс читання першоджерел: він знову ухвалює рішення замість читача. Допустимий він рівно тоді, коли людина явно сказала, що повний переклад конкретного тексту не вартий зусиль.

Правила, які роблять переклад придатним для звірки, а не просто читабельним:

І головне: це справжня писальна задача, а не механічний крок копіювання. Ресурс під неї закладати відповідно — сильніший, повільніший прохід моделі, не найдешевший, — надто для довгих чи аргументативно щільних текстів. Дешевий прохід віддає граматично правильний текст, з якого зникла половина авторської інтонації, — і читач формує позицію вже проти каліченого опонента.


Шар 3 — секції, нотатки й позиція читання

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

Позицію читання (яку секцію читач востаннє відкривав) треба зберігати серверно — щоб продовжити з іншого пристрою. Показувати маленький банер «продовжити з секції N», ніколи не автоскролити без кліку.

Де це зберігати — визначальний вибір. Браузерний localStorage вмирає разом з очищенням кешу, не переживає зміну пристрою і не читається жодним іншим інструментом. Тому — маленька БД. У референсній реалізації це три таблиці Postgres, розділені за роллю: секційні нотатки, фінальні нотатки на текст і позиція читання. Розділення не косметичне — саме секційні нотатки потім стають сирим матеріалом для синтезу (шар 5), і їх треба діставати окремо від позиції та фінального вердикту.

Рішення про сховище нотаток Вибір
Нотатки мають пережити очищення кешу браузера серверна БД, не localStorage
Читач ходить з телефону і з ноута серверна БД + серверна позиція читання
Нотатки потім підуть у синтез окремо від позиції окремі таблиці за роллю, не один blob
Прототип на один вечір, один пристрій, викидний localStorage припустимий, але сказати про обмеження

Шар 4 — візуальний шар як носій прогресу

Генеративний візуальний шар тут — не декор. Це носій прогресу, який заміняє звичайний прогрес-бар. Якщо в людини вже є ембіент-шар, що їй подобається деінде на власному сайті, — переюзати його; інакше взяти будь-який легкий генеративний візуал (частинки, градієнтне поле, шум) з reseed-подібним API.

Три правила перетворюють візуал з фону на індикатор:

У референсній реалізації reseed зроблено найдешевшим можливим способом: сторінка тримає data-seed атрибут (детермінований на текст), а при вході в секцію N викликається reseed((seed + idx)) уже наявного ембіент-модуля. Не форкати й не переписувати сторонню візуальну бібліотеку заради цього — конфігурувати її через ті публічні параметри/атрибути, які вона вже віддає. Форк заради прогрес-індикатора — це технічний борг, який переживе саму мотивацію читати.


Шар 5 — експорт нотаток як сирий матеріал для синтезу

Одна кнопка на індексній/оглядовій сторінці рідера (не на кожному тексті), яка збирає всі нотатки, що написав читач, — і фінальну нотатку на текст, і кожну секційну — у канонічному порядку читання і віддає markdown-файлом.

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


Антипатерни


Таблиця рішень

Ситуація Дія
Джерело ще під копірайтом, рідер приватний і запаролений назвати ненульовий ризик вголос, рішення per text
Джерела немає на очікуваному сайті сказати прямо, не підставляти інший текст під тією ж назвою
Робоча мова читача ≠ мова джерел повний переклад 1:1 по абзацах, не дайджест
Термін має кілька усталених перекладів обрати один, тримати константним, зафіксувати вибір
Довгий чи аргументативно щільний текст сильніший прохід моделі на переклад, не найдешевший
Треба розбити текст на секції клієнтський скрипт, межі по заголовках, розмір узгодити наперед
Нотатки мають пережити зміну пристрою серверна БД (окремі таблиці за роллю), не localStorage
Потрібен індикатор прогресу детермінований seed на текст + reseed на межі секції
Читач хоче зібрати все написане одна кнопка експорту на індексі, вірна тексту, без домішок
Access control мовчки зник з приватної локації відновити за замовчуванням, потім питати

Чекліст

P.S. — хто насправді прочитав книжку

Є стійка ілюзія, що прочитати книжку — це дійти до останньої сторінки. За цим критерієм переказ на чотири абзаци «прочитав» усі першоджерела за тебе, ще й швидше і без нудних місць.

Справжній критерій готовності інший, і він незручний: чи змінилась позиція від зіткнення з текстом у його власному вигляді, а не з чиїмось відбором з нього. Рідер на п'ять шарів існує рівно для того, щоб зробити цей незручний критерій дешевшим за зручний. Секційні нотатки — це слід того, що аргумент таки дійшов. Порожній експорт наприкінці означає рівно одне: сторінки гортались, а думати ще не почали.