17 KiB
17 KiB
Context
Пакет D сверки follow-ups 25.10.2026 (sdlc-hub#135). Маркеры #94 T6.1–T6.5, T8.2, T8.3, T9.3 сверены с кодом
27.10.2026 и воспроизведены на convert.to_markdown:
| Маркер | Вход | Сейчас |
|---|---|---|
| T6.1 | <a href="…/f.xlsx"><span><img src="…/f.xlsx.meta/thumbnail.jpg"></span></a> текст |
текст — ссылки на вложение нет, строка вложения есть |
| T6.2 | <a href="project/Document/DOC-1"><img src="…/x.png"></a> |
[\[📎 x.png](attachment:@0)](page:DOC-1) — ссылка в ссылке |
| T6.3 | два attachments с одним ref |
побеждает последний (dict по ref) |
| T6.4 | <a href="http://ex.com/a b(c).html">док</a> |
[док](http://ex.com/a b(c).html) — не ссылка |
| T6.5 | <a href="project/Document/DOC-1">путь C:\</a> |
[путь C:\](page:DOC-1) — \] экранирует скобку |
T8.2: request_fetch отвечает ready по полю state, а GET …/content при пропавшем файле — 409 «запросите
скачивание»: тупик. T8.3: POST /wiki/sync проверяет active_sync, а POST /batches и POST /commands/{id}/retry
проходят только commands.check_batch, где этой проверки нет. T9.3: mcp.py склеивает шапку page, строки tree,
search и кандидатов из значений Eva без нормализации переводов строк.
Владелец 27.10.2026 согласился с предложенным поведением по всем восьми маркерам и добавил картинки в тексте страницы «Вики»: показ только после нажатия, уже скачанные — сразу.
Decisions
- T6.1 — предок, а не родитель.
convert_imgищет ближайшего предка<a>(el.find_parent("a")), а не толькоel.parent. Еслиhrefэтого<a>— вложение и картинка — то же вложение (совпадаетurlзаписей) или вообще не вложение, картинка не выводится: ссылку выведет<a>. Картинка — другое вложение (миниатюра файла Y внутри ссылки на файл X) выводит свою ссылку, аconvert_aдля вложения X сохраняет маркеры вложений изtextперед своей ссылкой (то же правило, что в решении 2): Y не теряется. - T6.2 — вложение перед ссылкой на страницу. В
convert_aдля ссылки на документ (codeнайден): если вtext(уже сконвертированное содержимое) есть маркеры вложений (_MARK), они выносятся перед ссылкой: результат —<ссылки вложений> [<остаток текста или код>](page:<код>). Остаток —textбез фрагментов[📎 …<маркер>; пустой послеstrip()— код. Через_labelкак сейчас. Внешняя ссылка (super().convert_a) с картинкой-вложением внутри — то же правило: вложение перед ссылкой, текст ссылки — остаток, пустой — адрес. Ссылка на вложение внутри ссылки на вложение уже покрыта решением 1. - T6.3 — первая запись.
_by_refи_linksсобираются сsetdefault: первая запись поrefпобеждает (порядок агента — порядок документа). - T6.4 — кодирование адреса. Для внешних ссылок и картинок (ветка
super().convert_a/convert_img) адрес проходит_href(url): пробел →%20,(→%28,)→%29; прочие символы не трогаются (уже закодированное не кодируется повторно). Ссылкиpage:/attachment:не затрагиваются — в них таких символов нет. - T6.5 — хвостовая черта.
_labelпосле текущих замен удваивает нечётную серию\в конце строки (одна\в конце →\\). То же в тексте внешней ссылки, если markdownify не экранировал её сам; проверять тестом обе ветки. - T8.2 — проверка файла в
request_fetch.request_fetch(conn, attachment_id, author, files_dir): приstate = readyиfiles.size(files_dir, row["file"]) is Noneвложение идёт по ветке «поставить скачивание» (statefetching, новый пакет). Маршрутh_attachment_fetchпередаётhub.files_dir; MCPattachmentходит через этот же маршрут и поведение получает без правок.GET /wiki/pages/{code}иGET /wiki/attachments/{id}по-прежнему отдаютstateиз базы (проверка файла на каждом чтении — лишние обращения к диску). - T8.3 — проверка в
check_batch. Для каждойwiki_syncв пакете: если у проекта есть командаwiki_syncвqueued/claimedс тем жеparams.root, —CommandError«у проекта <метка> уже идёт синхронизация корня (пакет #N)» → 422bad_batch. Тот жеroot, а не любой:projects.set_rootставит синхронизацию нового корня, пока команда старого может бытьclaimed(её отчёт будет отброшен по «корень сменился»).POST /wiki/syncпо-прежнему проверяетactive_syncраньше и отвечает 409; фоновая работа — тоже раньше (tick.py). Возврат корня (A → B → A, покаwiki_sync {root: A}ещёclaimed):projects.on_updatedотменяет толькоqueued, и новая синхронизация A упёрлась бы в проверку — PATCH получил бы 422. Поэтомуcommands.enqueue_syncперед постановкой ищет активнуюwiki_syncпроекта с тем жеrootи, если она есть, возвращает её пакет без нового: её отчёт не будет отброшен (корень снова совпадает). Ответ — в формеcreate_batch:{id, estimate_seconds, count}из строки пакета и числа его команд; для вызывающих (on_created,on_updated→ ответ PATCH,POST /wiki/sync,tick) это «пакет синхронизации проекта», новый он или идущий — не различается. Проверка вcheck_batchостаётся дляPOST /batchesи повтора команды;enqueue_syncс поиском иcheck_batchреализуются одной задачей, иначеenqueue_syncмежду шагами упирается в новую проверку. - T9.3 — одна функция строки. В
modules/wiki/mcp.py—_line(v):core.value(v), затемre.sub(r"\s*[\r\n]+\s*", " ", …). Применяется ко всем значениям из Eva внутри строк ответа:tree(название),page(название, путь, имена вложений, состояние), кандидаты_candidates(название и самtitleзапроса),search(название, путь, фрагмент),attachment(имя, код страницы),_summary/status(название корня, ошибка синхронизации). Тело страницы — как есть. - Признак картинки — от хаба по адресу. Имя вложения для этого не годится: проверка живого AWPCA 27.10.2026
показала имена без расширения («Схема расчёта суммы элиминации по тройке» — файл
vgo-matching-1.png; 14 вложений с именемattachment) — eva-agent берётalt/title/текст ссылки раньше имени файла. Хаб добавляет вattachmentsответаGET /wiki/pages/{code}полеimage: последний сегмент путиurl(без запроса,unquote) оканчивается на.png .jpg .jpeg .gif .webp .bmpбез учёта регистра. Функция — вmodules/wiki/attachments.py, схема базы не меняется. SVG исключён: файл из Eva недоверенный, а пользы в вики от него мало. - Картинки — устройство во фронте.
useWikiDownload.start(id, mode)получает режим:"save"(как сейчас) или"show". В режимеshowпоreadyсодержимое (api.blob) не сохраняется, а передаётся в хранилище картинок страницы.- Хранилище картинок страницы (новый хук рядом, например
useWikiImages(project, code, attachments)):id → objectURL. При загрузке страницы для каждого вложения-картинки вreadyодин раз запрашивает…/contentи кладёт objectURL; ошибка — молча, остаётся ссылка. При смене страницы/проекта и размонтировании —revokeObjectURLвсех адресов и отмена поздних ответов (поколение, как вuseWikiDownload). - Blob заворачивается с типом по расширению (
image/pngи т.д.): хаб отдаёт содержимое какapplication/octet-stream. - Один хук на страницу: хранилище картинок живёт внутри
useWikiDownload(или в хуке, который его оборачивает), режимshowкладёт objectURL туда же. Ссылка на объект, от которого зависитcomponentsвPageView, остаётся стабильной (как сейчас — см. комментарий вdownload.ts): карту картинокAttachmentLinkчитает черезstatus(id)-подобный геттер, меняющийся вместе с картой, как сейчасstatus, а не через пересозданиеcomponents. Перемонтирование вложений при появлении картинки не должно сбрасыватьbusy/errorдругих. - Источник картинки — либо автозапрос
contentпри загрузке страницы дляready-картинок, либо результатstart(id, "show"). Автозапрос — один раз на вложение за жизнь страницы; его неудача (409, сеть) оставляет ссылку в режимеshowбез текста ошибки. Нажатие на неё —start(id, "show"): после T8.2 хаб при пропавшем файле скачивает заново, поreadyкартинка кладётся в хранилище из ответаstart. Вложение вfailed— та же ссылка с текстом ошибки, нажатие — повторstart(id, "show"). AttachmentLink: картинка с objectURL —<span className="wiki-att-img"><img src alt={name}/></span>и под ней прежняя кнопка-ссылка в режимеsave; картинка без objectURL — кнопка в режимеshow; не картинка — как сейчас.- CSS:
.wiki-att-img img { max-width: 100%; height: auto; display: block }, токены AURA. - Правило «внешние картинки не загружаются» (
imgвcomponents) не меняется: картинки — только вложения хаба.
Risks / Trade-offs
- Картинки в памяти. objectURL держат blob до смены страницы; предел файла — 10 МБ, на странице AWPCA — единицы картинок. Приемлемо.
- Состояние вложения после скачивания. Ответ
GET /wiki/pages/{code}не перечитывается после скачивания: картинка показывается из хранилища страницы, при повторном открытии — поreadyиз нового ответа. - Корень сменился во время повтора. Повтор команды старого корня при идущей синхронизации нового проходит (корни
разные); его
doneбудет отброшен по «корень сменился». Лишний запрос в Eva, данных не портит.
Decisions made without discussion
- 2026-10-27 — T6.2: вложение выводится перед ссылкой на страницу, пустой текст ссылки — код страницы. Обоснование: Markdown не допускает ссылку в ссылке; порядок совпадает с порядком в HTML. Цена ошибки — вид одной строки текста.
- 2026-10-27 — T6.3: при повторе
refпобеждает первая запись. Обоснование: порядок агента — порядок документа, первое появление определяет имя. Цена ошибки — другое имя вложения в редком случае. - 2026-10-27 — T6.4: кодируются только пробел и круглые скобки. Обоснование: только они ломают разбор
[текст](адрес); прочее браузер разбирает сам. Цена ошибки — редкая внешняя ссылка не кликается. - 2026-10-27 — T8.2: проверка файла — только в
request_fetch, не при чтении состояния. Обоснование: тупик был в повторном запросе, не в показе. Цена ошибки — до нажатия вложение выглядит скачанным. - 2026-10-27 — T8.3: отказ только при активной синхронизации того же корня. Обоснование: смена корня ставит синхронизацию нового корня при выданной старой (спека «Синхронизация вики»). Цена ошибки — один лишний запрос дерева в Eva.
- 2026-10-27 — T9.3: все значения Eva в строках ответа MCP — через одну функцию
_line, тело страницы как есть. Цена ошибки — длинное значение в одну строку. - 2026-10-27 — картинки: признак
imageсчитает хаб по имени файла в адресе Eva (не по имени вложения), SVG не показывается; под картинкой остаётся ссылка сохранения файла. Обоснование: на живом AWPCA имена картинок бывают без расширения; SVG — недоверенный активный формат. Цена ошибки — картинка с необычным расширением остаётся ссылкой. - 2026-10-27 — T8.3: при возврате корня
enqueue_syncотдаёт идущий пакет того же корня в формеcreate_batch, не различая «новый/идущий». Цена ошибки — ответ PATCH называет уже идущий пакет. - 2026-10-27 — T6.1: картинка-другое-вложение внутри ссылки на вложение выводится своей ссылкой перед ссылкой внешнего вложения. Цена ошибки — порядок двух ссылок в строке.