nanobot: 2026-09-10 12:33:37
This commit is contained in:
@@ -3126,3 +3126,332 @@ a zabránit opakování driftu.
|
||||
- `notes.md`: `ssh nanobot@nanobot.hell 'cd ~/.nanobot/workspace && git revert f136f50'`
|
||||
- `AGENTS.md` / `projects/proxmox/state.md`: `git checkout -- AGENTS.md projects/proxmox/state.md` v serverovém workspace repu (pozor: vrátí i případné cizí necommitnuté změny).
|
||||
- `skills/keep/`: `git revert a96a5c6` v tomto repu + rsync `skills/keep/` na server.
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-04 07:20 — `keep` skill: description podle oficiálního formátu + přenositelnost
|
||||
|
||||
**Cíl:** Uživatel reklamoval `description` u `skills/keep/SKILL.md` — čeština uvnitř a špatně
|
||||
napsaná proti tomu, jak má `description` vypadat. V průběhu doplnil druhou vadu: absolutní
|
||||
cesta v těle skillu ho dělá nepřenositelným.
|
||||
|
||||
**Co jsem zkusil:**
|
||||
|
||||
1. Porovnal serverovou verzi s repem (`ssh nanobot@nanobot.hell cat …`) — **identické**,
|
||||
žádný drift od Dreamu k dotažení.
|
||||
2. Dostudoval dokumentaci. `nanobot.wiki` (0.3.0) frontmatter skillů **nedokumentuje** —
|
||||
`/docs/0.3.0/` nemá stránku o skillech, `use-nanobot/concepts` je zmiňuje jen jako obsah
|
||||
workspace. WebFetch na wiki vrací 403, curl s UA projde. Autoritou je proto
|
||||
[Anthropic Skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices)
|
||||
(formát je identický) + naše zjištění ze zdrojáku v `knowledge.md`.
|
||||
3. Změřil současnou verzi proti pravidlům: ✗ CZ triggery (EN-only + ověřeno, že
|
||||
dvojjazyčné nic nepřidají), ✗ otevírá noun-phrase definicí místo slovesné fráze,
|
||||
✗ obsahuje *jak* funguje (dedup/compaction/cesta), ✗ interní architektura
|
||||
(MEMORY.md / Dream), ✗ duplicita, ~ chybí odlišení od `/project`.
|
||||
Třetí osoba porušená nebyla.
|
||||
4. Přepsal `description` do oficiálního tvaru `<co dělá>. Use when <triggery>.` (385 znaků,
|
||||
limit 1 024), opravil poslední češtinu v těle (`"udělej compaction"` → `the user asks
|
||||
for compaction`) a absolutní cestu → `workspace/keep.md`.
|
||||
5. Nasadil rsyncem, ověřil vlastníka.
|
||||
|
||||
**Co fungovalo a proč:**
|
||||
|
||||
- Grepy čisté: žádná čeština, žádné `/home/nanobot` v `skills/keep/SKILL.md`.
|
||||
- **Funkční test routingu:** `nanobot agent -m "zapamatuj si, že testovací server pro
|
||||
staging je stag-07"` → odpověď `Kept: …`, záznam v `keep.md`. Skill se tedy trefil
|
||||
i bez českých triggerů — potvrzuje ověřený předpoklad z `/plan` (2026-05-31), že
|
||||
dvojjazyčné triggery jsou zbytečný token cost.
|
||||
- Testovací záznam z `keep.md` smazán (záloha `/tmp/keep.md.bak` na serveru).
|
||||
- `nanobot` binárka není v PATH non-login shellu — volat `~/.local/bin/nanobot`
|
||||
(stejná gotcha jako u `uv`).
|
||||
|
||||
**Co zbývá:**
|
||||
|
||||
- `skills/plan/SKILL.md:45` má stejnou absolutní cestu, přitom řádky 69 a 75 v témže
|
||||
souboru už jsou relativní. `bookmark` má absolutní cesty ve spouštěcích příkazech —
|
||||
tam opodstatněné (PATH gotcha u `uv`). Neřešeno, mimo scope zadání.
|
||||
- Ostatní skilly nebyly proti oficiálnímu tvaru `description` proměřeny.
|
||||
|
||||
**Jak vrátit zpět:** `git revert 18ab382` + rsync `skills/keep/` na server.
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-09 20:20 — Final wiki: zhodnocení draftu hybrid RAG a přepis do `final-wiki-hybrid-rag.md`
|
||||
|
||||
**Cíl:** Zhodnotit serverový draft `plans/notes-search-hybrid-rag.md` (hybrid RAG index nad
|
||||
uživatelovými git poznámkami), rozhodnout, jestli by to tak šlo, a přepsat do finálního plánu.
|
||||
|
||||
**Co jsem zkusil:**
|
||||
|
||||
1. Přečetl draft a proměřil prostředí místo věření odhadům v něm:
|
||||
- Ollama na `nvidia.hell` dosažitelná; `qwen3-embedding` tam zpočátku nebyl (uživatel dodal).
|
||||
- Cold load modelu 1,81 s vs. warm 0,043 s; throughput 8,9 chunk/s po jednom vs.
|
||||
**108 chunk/s v batchi 32**.
|
||||
- Cosine nad 10⁵×1024 v BLOB+numpy: **594 ms** = read 382 + pack 190 + **dot jen 22**.
|
||||
Přes `.npy` + `mmap_mode='r'` 35 ms.
|
||||
- FTS5: `remove_diacritics 1`+ foldí diakritiku, `záloh*` pokryje českou flexi.
|
||||
- Korpus workspace: 234 md mimo `tmp/` → ~800 chunků (draft počítal 10⁴–10⁵).
|
||||
2. Ověřil `sqlite-vec` smoke testem celého navrženého schématu (`chunks` + `files` +
|
||||
`chunks_fts` + triggery + `vec_chunks`) — včetně toho, na čem D3 stálo.
|
||||
3. Ověřil model na reálném obsahu: cross-jazyk retrieval test + vliv instruct prefixu.
|
||||
4. Přepsal plán do `final-wiki-hybrid-rag.md`, nasadil na server i do repa, starý draft
|
||||
označil `> Superseded by`.
|
||||
|
||||
**Co fungovalo a proč:**
|
||||
|
||||
- **Díra v návrhu draftu**: RRF slučoval file-level BM25 s chunk-level cosine. Rank-merge dvou
|
||||
různých jednotek nemá definovaný význam. Fix: `chunks` je jediná retrieval jednotka, FTS5 je
|
||||
external-content nad ní, `vec0` má `rowid = chunks.id`, RRF slučuje `chunks.id`. Ověřeno.
|
||||
- **`vec0` obstálo ve všech kritických testech**: `DELETE`/re-`INSERT`/`UPDATE` po `rowid`,
|
||||
transakční `ROLLBACK`, `distance_metric=cosine`, `vec0` v témže souboru jako běžné tabulky.
|
||||
KNN k=20: **19 ms @ 10k, 212 ms @ 100k**. Kdyby `DELETE` nešel, D3 by padlo a vracel by se BLOB.
|
||||
- **Zdůvodnění D3 v draftu bylo špatné** — stavěl `sqlite-vec` jako „indexovaný KNN" (ANN).
|
||||
Není; dokumentovaná cesta je průchod (lineární 19 → 212 ms to potvrzuje). Skutečná výhoda je,
|
||||
že skenuje v C a odřízne těch 96 % Python režie.
|
||||
- **Ollama Cloud embeddingy neexistují** — 18 cloud modelů, žádný s capability `embedding`;
|
||||
`/api/embed` na cloud modelu vrací `unauthorized`, zatímco `/api/generate` na tomtéž projde
|
||||
(takže to není o autorizaci). Katalog na ollama.com potvrzuje: všech 12 embedding modelů
|
||||
je jen ke stažení.
|
||||
- **D1 potvrzeno měřením**, ne argumentem: dotaz „jak snížit elektroodpad ze stavebnic" →
|
||||
BM25 **1/5**, embeddingy **3/5**; lexikální dotaz naopak BM25 4/5. Obě poloviny si vydělávají.
|
||||
- **`exec` timeout 60 s** vs. plný index ~77 s → indexace nesmí běžet v tahu agenta. V draftu to
|
||||
nebylo; uživatel zvolil offline cron s lockem, čímž `fetch-on-query` z draftu vypadl.
|
||||
- **Whitelist místo blacklistu** (na dotaz uživatele): ve workspace je 234 md mimo `tmp/` a
|
||||
použitelných ~99 — zbytek `.venv/` 27, `cml/` 39, `skills/` 32, `backup/` 20, `tasks/` 16;
|
||||
`tmp/` drží dalších 135. Blacklist by musel trvale pokrývat právě adresář určený k balastu.
|
||||
Rozhodující je ale směr selhání: u blacklistu nový adresář *tiše vstoupí* do indexu.
|
||||
- DDL vytažené přímo z hotového dokumentu spuštěno proti `:memory:` — prošlo, a FTS5 i `vec0`
|
||||
vrátily shodné `rowid`.
|
||||
|
||||
**Co jsem měl špatně (korekce vlastních tvrzení):**
|
||||
|
||||
- Tvrdil jsem, že vynechání **instruct prefixu** stojí víc než přechod na menší model. Test na
|
||||
178 chunkách to vyvrátil: recall@5 s prefixem i bez něj **identický** (5/5 vs 5/5, 3/5 vs 3/5),
|
||||
similarita s prefixem dokonce nižší. Prefix zlepšil jen top-1 nejtěžšího dotazu. V plánu
|
||||
zůstává (je zdarma), ale zdůvodnění je teď „bitová identita indexace a dotazu", ne kritičnost.
|
||||
- Cold load jsem extrapoloval na 4–6 s; naměřeno **1,81 s**. `keep_alive: -1` je tedy výhodný,
|
||||
ne nutný.
|
||||
- Dvě chyby v mých vlastních test skriptech, obě mě zdržely: chybějící
|
||||
`isolation_level=None` (→ „cannot start a transaction within a transaction") a bufferovaný
|
||||
stdout Pythonu, kvůli kterému 9 minut běžící skript neukázal, že visí na síťovém čtení.
|
||||
|
||||
**Nálezy pro implementaci:**
|
||||
|
||||
- **`ON DELETE CASCADE` z `files` uklidí `chunks` i FTS5 (trigger se na kaskádě spustí), ale
|
||||
řádek ve `vec_chunks` osiří** — `vec0` není cílem foreign key. Indexer musí mazat `vec_chunks`
|
||||
explicitně. Je to v plánu jako regresní test; jinak by index při mazání souborů tiše hnil.
|
||||
- `keep_alive` musí být **číslo** `-1` (nebo `"24h"`); string `"-1"` vrací HTTP 400.
|
||||
|
||||
**Co zbývá:**
|
||||
|
||||
- **Seznam rep** (URL + kam mirrorovat) — jediná věc, kterou musí doplnit autor; bez toho
|
||||
nelze naplnit `config/notes-search.yaml`.
|
||||
- Zopakovat cross-jazyk benchmark na reálných repech (proběhl na workspace obsahu).
|
||||
- Návrh 6 vět do `decisions.md` je v plánu — **čeká na souhlas autora**, nezapsáno.
|
||||
- Mimo scope a jen hlášeno: `llm-wiki` řeší autor sám (zazálohuje a smaže);
|
||||
`wiki-compile` existuje jen na serveru a v žádném commitu (drift, pravděpodobně Dream).
|
||||
|
||||
**Jak vrátit zpět:** `git revert 36259d7`; na serveru smazat
|
||||
`plans/final-wiki-hybrid-rag.md` a odstranit vložený `> **Superseded by` řádek (druhý řádek)
|
||||
z `plans/notes-search-hybrid-rag.md`.
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-09 — Oprava plánu final-wiki-hybrid-rag po plan-review
|
||||
|
||||
**Cíl:** Projet `final-wiki-hybrid-rag.md` skrz `/lab:plan-review` a opravit, co review najde,
|
||||
aby byl plán implementovatelný bez hádání.
|
||||
|
||||
**Co jsem zkusil:**
|
||||
|
||||
Review vrátila verdikt „vrátit k přepracování": 5 blokujících nálezů, 7 k doplnění, 3 poznámky.
|
||||
Všechny kotvy, které plán uváděl jako existující, jsem ověřil a všechny sedí
|
||||
(`remind/scripts/db.py` symboly, `note_capture.py:25`, `_ascii_fold`, `.compile.lock`,
|
||||
`llm-wiki/scripts/wiki_search.py`, `develop/history.md` + `knowledge.md` na serveru, crontab
|
||||
vzor, `db/` v `.gitignore`). Plán nebyl superseded — skill neexistoval.
|
||||
|
||||
Pět blokujících nálezů:
|
||||
|
||||
1. Vrstva 2 (TOC) byla vyhlášená, ale sync ji negeneroval, schéma pro ni nemělo tabulku
|
||||
a Verifikace ji netestovala.
|
||||
2. `git clone --mirror` je **bare** repo → vrstva 1 (`rg`) nemá working tree, co grepovat,
|
||||
a chunker neměl řečeno, jak se z mirroru dostane obsah souboru.
|
||||
3. Chunky s `embedded_at IS NULL` se nikdy nedobraly: krok 3 syncu končí „nic se nezměnilo
|
||||
→ exit 0", jenže po degradovaném běhu se soubory nezměnily. Verifikace bod 4 přitom
|
||||
tvrdila opak a partial index `idx_chunks_pending` nikdo nečetl.
|
||||
4. Skupinové klíče v YAML (`sources.git.*`, `sources.nanobot.*`) nešly namapovat na
|
||||
`CHECK(kind IN ('git','workspace'))` — `nanobot` by CHECK odmítl.
|
||||
5. RRF neměl jediný parametr: chybělo `k` pro KNN, počet kandidátů z BM25, RRF konstanta,
|
||||
výstupní top-k i váhy.
|
||||
|
||||
**Co fungovalo a proč:**
|
||||
|
||||
Před opravou jsem si nechal od autora rozhodnout adresářovou strukturu a jméno skillu, protože
|
||||
na tom visí deploy cesta, cron řádek i testy — a pak dvě věci **naměřil místo hádání**, když
|
||||
padla otázka „jak se to bude chovat, když do `include` dám i `*.py` a `*.cs`":
|
||||
|
||||
- markdown-it-py nad Python souborem: komentář `# TODO: fix this` se parsuje jako **ATX
|
||||
heading h1**. Chunker by řezal soubor v komentářích a stavěl breadcrumb
|
||||
`foo.py > TODO: fix this` — ne horší kvalita, ale nesmysl.
|
||||
- FTS5 `unicode61`: `send`/`async` uvnitř `SendAsync` → **miss** (camelCase se nedělí);
|
||||
`migrate` i `_migrate` → oba hit, nerozlišitelné. `tokenchars '_'` problém jen převrátí
|
||||
(`get_db` hit, `get` miss). Jediný použitelný tokenizer je `trigram` — a ten je vlastnost
|
||||
**tabulky**, ne řádku, takže smíšený korpus = druhá FTS tabulka a dvojí dotaz.
|
||||
|
||||
Tohle rozhodlo D15 (index zůstává md-only) měřením, ne názorem. Náhradou je, že grep vrstva
|
||||
jede přes celý klon včetně kódu — soubory už na disku leží, takže to stojí nula.
|
||||
|
||||
Dvě zjednodušení nálezy zrušila místo záplatování: **plochá konfigurace** s explicitním `kind`
|
||||
(padá nález 4) a **sloučení `workspace` + `develop`** do jednoho zdroje (stejný kořen, stejný
|
||||
kind, nebyl důvod je mít dva).
|
||||
|
||||
Autor dodal URL obou rep, ověřeno z `nanobot.hell`: obě dostupná klíčem uživatele `nanobot`,
|
||||
obě `HEAD → refs/heads/master`. Otevřená otázka 1 tím padla.
|
||||
|
||||
**Nálezy pro implementaci:**
|
||||
|
||||
- Workspace na serveru **je git repo** a `wiki/` v jeho `.gitignore` chybí. Nasazení musí
|
||||
přidat `wiki/*` + `!wiki/config.yaml`, jinak se do gitu commitne index (komprimovaná kopie
|
||||
osobního obsahu) i klony. Původní plán se opíral o to, že `db/` je gitignorované —
|
||||
přesunem pod `wiki/` ta záruka zmizela.
|
||||
- `note_compile.py:85-108` má stale-lock reclaim (mrtvý PID nebo stáří > 30 min). Plán měl
|
||||
jen holý `O_EXCL`, což by po pádu procesu navždy umlčelo minutový cron bez jediného řádku
|
||||
v logu. Převzato doslova.
|
||||
- Aritmetika v plánu byla špatně: 10⁴ chunků / 108 chunk/s je ~93 s, ne 77 s. Závěr
|
||||
(> 60 s `exec` timeout) drží.
|
||||
|
||||
**Co zbývá:**
|
||||
|
||||
- **Pustit `/lab:plan-review` znovu** — skill se nedá vyvolat přes `Skill` tool
|
||||
(`disable-model-invocation`), musí ho spustit autor. Cíl: 0 blokujících nálezů.
|
||||
- Návrh 4 vět do `decisions.md` — čeká na souhlas autora, nezapsáno: kořen runtime dat
|
||||
`workspace/wiki/`, non-bare klon místo `--mirror`, plochá konfigurace s explicitním `kind`,
|
||||
index výhradně nad markdownem.
|
||||
- Benchmark modelu na uživatelských datech zůstává jako výstup etapy 6.
|
||||
|
||||
**Jak vrátit zpět:** `git revert 43688c5`. Na server se nesahalo.
|
||||
|
||||
## 2026-09-09 22:10 — implementace a nasazení skillu `wiki` (hybrid RAG index)
|
||||
|
||||
**Cíl:** Vykonat plán [plans/final-wiki-hybrid-rag.md](plans/final-wiki-hybrid-rag.md),
|
||||
etapy 1–7 včetně nasazení na server.
|
||||
|
||||
**Co jsem zkusil / co fungovalo a proč:**
|
||||
|
||||
- **Etapy 1–6 implementované a otestované lokálně** (`skills/wiki/`, commit `aecf597`):
|
||||
87 testů, `ruff` i `ty` čisté. Pokrývají body 1–6 a 8 z Verifikace v plánu.
|
||||
- **Etapa 7 nasazena** na `nanobot.hell`: rsync skillu, `wiki/config.yaml`,
|
||||
`.gitignore` (`wiki/*` + `!wiki/config.yaml`), první plný index a minutový cron.
|
||||
Plný index: **152 souborů, 601 chunků, 601 vektorů, 0 pending za 45 s**
|
||||
(index 55/123, travel 5/9, workspace 92/469).
|
||||
- **Dotaz end-to-end 53–62 ms** (cíl plánu byl pod 1 s). Rozpad odpovídá plánu:
|
||||
embed dotazu ~55 ms, KNN 2–5 ms, BM25 < 1 ms, RRF zanedbatelné.
|
||||
- **Odchylky od plánu (mechanické, ne věcné):** moduly nesou prefix `wiki_`, protože
|
||||
`db.py`/`store.py` kolidují s `remind` a `wiki_search.py` s `llm-wiki` ve `ty.toml`
|
||||
`extra-paths` (ploché jmenné prostory, vyhrává první cesta). Přidány dva moduly nad
|
||||
pětici z plánu — `wiki_config.py` (layout + rozsah) a `wiki_embed.py` (Ollama klient
|
||||
+ `meta` guard), protože obě vstupní body je potřebují a guard **musí** být identický
|
||||
na obou stranách. `numpy` z dependency setu vypuštěno — `sqlite_vec.serialize_float32`
|
||||
stačí, normalizace je jeden `math.sqrt`.
|
||||
- **Reálné selhání sítě ověřeno neplánovaně:** z mého stroje nemá SSH klíč právo na
|
||||
`travel-notes.git`, takže první lokální běh doslova předvedl bod 8 — `WARN`, zdroj
|
||||
přeskočen, `index` dojel. Na serveru (klíč uživatele `nanobot`) projde.
|
||||
|
||||
**Nalezené a opravené vady (moje, ne plánu):**
|
||||
|
||||
1. **Sekce obsahující jen svůj nadpis vytvářela prázdný chunk.** U běžného tvaru
|
||||
`# Titul` → `## Sekce` by šum lezl skoro do každého dokumentu. Fix: taková sekce se
|
||||
zahodí, nadpis se do indexu dostane přes breadcrumb potomků a `files.headings`.
|
||||
2. **Víceřádkový git stderr v logu.** Trvale nedostupný zdroj sype WARN každou minutu;
|
||||
šestiřádkový stderr = tisíce řádků denně. Fix: `_one_line()` + strop 300 znaků.
|
||||
Plán mluví o „řádku WARN" — teď to řádek skutečně je.
|
||||
3. **Coverage report hlásil i `wiki/`** (klony v `wiki/remote/` obsahují md).
|
||||
Strukturálně nikdy nekandidát, ne rozhodnutí k revizi → z reportu vyřazen.
|
||||
|
||||
**Otevřená otázka č. 1 plánu (benchmark modelu) — uzavřena.** 12 parafrázových dotazů
|
||||
s jednoznačným cílovým souborem nad reálnými 123 chunky repa `index`:
|
||||
|
||||
| Varianta | recall@5 | recall@10 | MRR |
|
||||
|---|---|---|---|
|
||||
| BM25 sám | 5/12 | 5/12 | 0,257 |
|
||||
| qwen3-embedding:0.6b + instruct prefix | 4/12 | **8/12** | 0,261 |
|
||||
| qwen3-embedding:0.6b bez prefixu | 2/12 | 3/12 | 0,204 |
|
||||
| mxbai-embed-large | 6/12 | 6/12 | 0,261 |
|
||||
| nomic-embed-text | 3/12 | 4/12 | 0,170 |
|
||||
| **RRF hybrid** | 6/12 | 6/12 | **0,367** |
|
||||
|
||||
D1 i D2 platí: hybrid má lepší MRR než obě poloviny samostatně, `nomic` je nejhorší
|
||||
(plán ho zamítal správně). V top-10 najde cíl **jen vektory u 3 dotazů, jen BM25 u 0** —
|
||||
vektorová polovina na tomhle korpusu lexikální pokrytím dominuje, BM25 ale dává lepší
|
||||
top-1 rank když trefí. Čtyři dotazy nenašel nikdo, protože cílové soubory jsou stuby
|
||||
(50–483 B, většinou shell příkazy) — chyba mých labelů, ne retrievalu; na odpověďorelných
|
||||
dotazech je hybrid 6/8.
|
||||
|
||||
**Co nesouhlasí s plánem:**
|
||||
|
||||
- **Instruct prefix NENÍ „nekritická vlastnost"** (plán, Query kontrakt). Naměřeno
|
||||
recall@10 **8/12 s prefixem vs. 3/12 bez** na uživatelských datech. Plán měřil
|
||||
5/5 vs 5/5 na 178 chuncích jiného korpusu. Prefix je load-bearing; je zapsán
|
||||
v `meta.query_prefix` a jeho změna vyžaduje `--full`.
|
||||
- **D6 („prefix wildcard pokryje českou flexi") platí jen na půl.** Prokázáno na
|
||||
serveru: `cestu*` → 0 chunků v `travel/packaging-list.md`, `cesty*` → 3, `cest*` → 4.
|
||||
Wildcard je **prefixový**, takže pomůže jen když je dotazové slovo prefixem tvaru
|
||||
v dokumentu; „cestu" prefixem „cesty" není. Plán to dokládal dotazem `záloh*`, což
|
||||
je už samotný **kmen**, ne skloněné slovo. Důsledek: na dotaz „co si vzít na cestu
|
||||
do zahraničí" se doslovný seznam věcí na cestu nedostal ani do top 10.
|
||||
|
||||
**Co zbývá:** viz [todo.md](todo.md) — rozhodnout o dotazové vrstvě u české flexe
|
||||
a návrh 4 vět do `decisions.md` (čeká na souhlas autora, nezapsáno).
|
||||
|
||||
**Jak vrátit zpět:** na serveru `crontab ~/.nanobot/backup/crontab.bak-20260909-220814`,
|
||||
pak `rm -rf ~/.nanobot/workspace/wiki ~/.nanobot/workspace/skills/wiki` a vrátit řádky
|
||||
`wiki/*` + `!wiki/config.yaml` z `.gitignore`. Lokálně `git revert aecf597`.
|
||||
|
||||
## 2026-09-09 23:25 — README ke skillu `wiki` + oprava prázdných titulků
|
||||
|
||||
**Cíl:** Doplnit ke skillu `wiki` lidsky psaný `README.md` (mentální model, proč je co tak,
|
||||
operátorský runbook), protože vysvětlení bylo rozeseté po `history.md`, result dokumentu
|
||||
a konverzaci. `SKILL.md` je záměrně EN instrukce pro agenta — tohle do něj nepatří.
|
||||
|
||||
**Co jsem zkusil / co fungovalo a proč:**
|
||||
|
||||
- **`skills/wiki/README.md`** (214 řádků), česky, druhá osoba, ve stylu existujících
|
||||
`skills/reflect/README.md` a `skills/compact-memory/README.md` — což jsou jediné dva
|
||||
README v repu, takže konvence se dala odečíst přímo z nich. Sekce: tři vrstvy, offline
|
||||
indexace a proč, co se v tiku děje, proč hybrid, česká flexe, index jako nápověda,
|
||||
rozsah indexace, kde co leží, ruční spuštění, hlášky, ověření.
|
||||
- **Ze `SKILL.md` na README záměrně nevede odkaz.** Ani `reflect`, ani `compact-memory` ho
|
||||
nemají; README je pro člověka a nesmí stát agenta kontext. (`detach/architecture.md`
|
||||
odkaz má, ale to je anglický dokument jiného žánru.)
|
||||
- **Každé tvrzení v README ověřeno proti kódu**, ne napsáno z hlavy: hlášky doslova
|
||||
grepem z `wiki_search.py`/`wiki_embed.py`, cesty vyhodnocením konstant z `wiki_config.py`,
|
||||
flagy z `parse_args()`. Příkazy ze sekce „Ruční spuštění" spuštěny naostro na serveru
|
||||
včetně `--source` s neexistujícím id (exit 1, `WARN unknown source`).
|
||||
|
||||
**Nalezená a opravená vada — `files.title` byl NULL u všech 152 souborů.**
|
||||
|
||||
Vyšlo to při ověřování příkladu z README: `toc` tiskl prázdný sloupec s titulkem pro
|
||||
**celý korpus**, přitom plán ho ukazuje jako podstatnou část výstupu. Příčina: `title` se
|
||||
bral výhradně z frontmatteru `title:`, ale uživatelovy poznámky nesou titulek jako `# H1`.
|
||||
|
||||
Fix: fallback na první nadpis. Po `--full` je pokrytí **117/152** (`index` 55/55,
|
||||
`travel` 5/5, `workspace` 57/92); zbylých 35 jsou raw zachyty `/note` v `notes/done/`
|
||||
bez jediného H1–H3 nadpisu — tam není z čeho titulek vzít a slug v názvu souboru ho nese.
|
||||
|
||||
Podstatné rozhodnutí u toho fixu: fallback plní **jen katalog, ne breadcrumb root**.
|
||||
Kdyby šel do rootu, přepsal by se text všech chunků (breadcrumb je součástí embedovaného
|
||||
textu) a musel by se bumpnout `chunker_version` s vynuceným `--full` u každého uživatele.
|
||||
Takhle je to změna jednoho sloupce v `files`.
|
||||
|
||||
**Vedlejší nález:** padl existující test `test_malformed_frontmatter_stays_body`. Nebyla to
|
||||
regrese — u rozbitého frontmatteru (`---\ntitle: [unclosed\n---`) udělá markdown-it z toho
|
||||
řádku **setext nadpis**, takže ho fallback vezme jako titulek. Frontmatter se opravdu
|
||||
nespotřeboval (tagy zůstaly prázdné, text zůstal v těle), jen test tvrdil něco jiného,
|
||||
než byl jeho záměr. Přepsán na to, co má tvrdit.
|
||||
|
||||
**Co zbývá:** nic z tohoto zásahu. Otevřené položky skillu `wiki` v `todo.md` (česká flexe,
|
||||
návrh do `decisions.md`) se nemění.
|
||||
|
||||
**Jak vrátit zpět:** `git revert 3adc2ef`, pak na serveru rsync skillu a
|
||||
`wiki_sync.py --full` (titulky se vrátí na NULL). Index se tím nerozbije — `title` je
|
||||
jen sloupec v katalogu, retrieval na něm nestojí.
|
||||
|
||||
Reference in New Issue
Block a user