Chemenu 2.1.0 - deterministischer Wissenskompiler
Chemenu kompiliert Rohnotizen zu einem verlinkten, quellengebundenen Wiki: raw/ -> types/ + tools/ -> kb/ -> reports/. Was mechanisch ist, macht tools/wikitool; was Urteil braucht, macht ein Agent unter Contracts, deren Grenzen in Code durchgesetzt sind statt im Prompt. Dieser Commit ist der Startpunkt der oeffentlichen Historie. Die vorherige Entwicklung fand in einer privaten Instanz statt und ist nicht Teil dieses Repositorys; ihre Erzaehlung steht vollstaendig in CHANGES.md, das mit 44 Eintraegen von 0.1.0 bis 2.1.0 erhalten geblieben ist. Der mitgelieferte Korpus ist ein Testbett und eine Demo: 170 Seiten ueber den Stack selbst - Gates, Lint, Versionierung, Suche, das Wiki-Muster. Er dokumentiert das Werkzeug mit den eigenen Mitteln des Werkzeugs. Lizenz: AGPL-3.0 fuer den Stack (tools/, types/), CC-BY-4.0 fuer die Inhalte. Die Grenze zwischen beiden ist der Dateiplan, den dist export berechnet - siehe NOTICE.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# Arch Linux Cheat Sheet
|
||||
|
||||
## AUR / Aura / Makepkg
|
||||
|
||||
Alternative Build Directory:
|
||||
|
||||
```zsh
|
||||
export BUILDDIR=/var/cache/makepkg-local
|
||||
sudo --preserve-env=BUILDDIR aura -Axac proton --build $BUILDDIR
|
||||
```
|
||||
|
||||
GPG Keys für AUR müssen im User-GPG eingefügt werden, nicht im Root GPG:
|
||||
|
||||
```sh
|
||||
gpg --recv-key B94556F81C85D0D5
|
||||
```
|
||||
|
||||
## SSD Trim + DMCrypt
|
||||
|
||||
https://wiki.archlinux.org/title/Dm-crypt/Specialties#Discard/TRIM_support_for_solid_state_drives\_(SSD)
|
||||
|
||||
## Online resize Crypt+LVM Disk
|
||||
|
||||
```zsh
|
||||
# Expand the disc in ESXi
|
||||
# Rescan SCSI to see expanded disk
|
||||
echo "1" > /sys/class/block/sdb/device/rescan
|
||||
# Check if everything went well
|
||||
fdisk -l /dev/xyz
|
||||
# if it didn't, you might have to reboot
|
||||
cryptsetup status crypted
|
||||
# Expand the LUKS partition and verify size
|
||||
cryptsetup status crypted
|
||||
cryptsetup resize crypted
|
||||
cryptsetup status crypted
|
||||
# Resize the LVM PV, check
|
||||
pvresize /dev/mapper/crypted
|
||||
pvsdisplay
|
||||
# Now allocate space to the volume
|
||||
lvresize -L+750g /dev/isp/owncloud
|
||||
lvs
|
||||
# And resize the fs
|
||||
resize2fs /dev/mapper/isp-owncloud
|
||||
df -h
|
||||
```
|
||||
|
||||
### References
|
||||
|
||||
- https://www.versedaily.net/how-can-i-rescan-hardware-on-linux/
|
||||
- https://unix.stackexchange.com/questions/320957/extend-a-luks-encrypted-partition-to-fill-disk
|
||||
|
||||
## User Management
|
||||
|
||||
[UNIX / Linux : How to lock or disable an user account](https://www.thegeekdiary.com/unix-linux-how-to-lock-or-disable-an-user-account/)
|
||||
|
||||
To lock a users account use the command **usermod -L** or **passwd -l**. Both the commands adds an exclamation mark **(“!”)** in the second field of the file **/etc/passwd**. For example :
|
||||
|
||||
```
|
||||
# usermod -L testuser
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
# passwd -l testuser
|
||||
```
|
||||
|
||||
**Check if the user account is locked.** Check for the flag ***LK*** in the below command output which indicates that the account is locked.
|
||||
|
||||
```
|
||||
# passwd --status root
|
||||
root ***LK*** 2017-07-19 0 45 7 -1 (Password set, SHA512 crypt.)
|
||||
```
|
||||
|
||||
## Alle AUR Python Pakete reinstallieren (Python Version Update)
|
||||
|
||||
```bash
|
||||
aura -A $(pacman -Qqm | xargs -I {} pacman -Ql {} | grep "/usr/lib/python3.12/site-packages" | cut -d'/' -f1)
|
||||
```
|
||||
|
||||
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
# Conversation Transcript - AGENTS.md Skill Restructuring Session
|
||||
|
||||
> Source: GitHub Copilot chat session (Claude Sonnet 5), this workspace
|
||||
> Collected: 2026-08-04
|
||||
> Participant: Torben
|
||||
|
||||
Faithful summary transcript of a single chat session covering: analysis of whether to split
|
||||
`AGENTS.md` into discrete agent skills, fact-checking of a pasted "instruction set" proposing a
|
||||
concrete cross-platform restructuring, and the resulting implementation.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - Query: should AGENTS.md become a number of skills like Farza's gist?
|
||||
|
||||
User asked whether transforming `AGENTS.md` into several skills (as popularized by Farza's
|
||||
personal-wiki gist) would create more specificity and less context impact, referencing prior
|
||||
ingested sources ("LLM Improvements Sonnet/Codex Analysis").
|
||||
|
||||
Assistant research and findings:
|
||||
- Farza's gist (`gist.github.com/farzaa/c35ac0cfbeb957788650e36aabea836d`) is actually **one**
|
||||
skill file (`name: wiki`) with an `argument-hint` dispatching sub-commands
|
||||
(`ingest|absorb|query|cleanup|breakdown|status`) - not several independently-discovered skills.
|
||||
A community comment by "pascalandy" in the same gist proposes a separate, unrelated "Wiki
|
||||
Schema (Global)" with its own tag taxonomy (`area/kind/topic/status/pty`) and hard rules
|
||||
(page split >200 lines, INDEX scaling >50 entries/200 pages, mass-update confirmation gate at
|
||||
10+ pages, Session Orientation Protocol).
|
||||
- VS Code's own bundled Copilot documentation (via the `agent-customization` skill,
|
||||
`references/skills.md`) confirms a **true multi-skill, progressive-disclosure mechanism**:
|
||||
`SKILL.md` files under `.github/skills/<name>/`, `.agents/skills/<name>/`, or
|
||||
`.claude/skills/<name>/` (project scope), discovered in 3 tiers - Discovery (~100 tokens:
|
||||
name+description) -> Instructions (<5000 tokens: body loads only when relevant) -> Resources
|
||||
(loaded only if referenced).
|
||||
- The root `AGENTS.md` in this repo was measured at **745 lines**, attached in full on every
|
||||
chat turn regardless of task (confirmed by grep of `^#{1,3} ` headings and `^## Version
|
||||
History` line number). VS Code's own `agent-instructions.md` reference explicitly calls a
|
||||
kitchen-sink AGENTS.md an anti-pattern ("Minimal by default: only what's relevant to *every*
|
||||
task").
|
||||
- Conclusion: a **true multi-skill split** (Option C: thin always-on core + one skill per
|
||||
workflow + shared reference files) would meaningfully cut always-resident context and sharpen
|
||||
per-workflow specificity, more so than Farza's literal one-skill design (which buys nothing in
|
||||
a repo that is entirely a wiki, since almost every session touches it).
|
||||
|
||||
---
|
||||
|
||||
## Turn 2 - "How is the situation with Claude Code, Mistral Vibe? Do they understand such skill separation too?"
|
||||
|
||||
Assistant began fetching primary docs for Claude Code (`code.claude.com/docs/en/skills`) and
|
||||
searched for "Mistral Vibe" (initial attempts to guess a marketing URL 404'd) before the user
|
||||
interrupted with a pasted "web search result, synthesized" instruction set (Turn 3).
|
||||
|
||||
---
|
||||
|
||||
## Turn 3 - User pastes a synthesized "Instruction Set: Restructure AGENTS.md into Cross-Platform Agent Skills" and asks for a plan
|
||||
|
||||
The pasted document claimed:
|
||||
1. Token economics: "a full ingest costs roughly 5-8x the source token count"; a documented
|
||||
"RTFM / retrieval-layer approach" cut token usage by 61% and improved resolve rate from
|
||||
~55-64% to 100% on an 8,260-file corpus.
|
||||
2. Precedents: `kfchou/wiki-skills` (6 Claude Code skills: wiki-init/ingest/query/lint/update/
|
||||
audit/merge), `vanillaflava/llm-wiki-skills` (6 skills, cross-platform installer), Farza's
|
||||
gist (single-file precedent), `yugasun/llm-wiki-skills` (single skill, Chinese-language,
|
||||
sync-mirror-verify script pattern).
|
||||
3. Target layout: `.agents/skills/wiki-{ingest,query,lint,create,update}/SKILL.md` as canonical,
|
||||
with per-tool wiring: Claude Code via `~/.claude/skills/` symlink, Codex CLI via
|
||||
`~/.codex/skills/` symlink, Mistral Vibe reads `.agents/skills/` natively (no action), GitHub
|
||||
Copilot via a new `.vscode/settings.json` `chat.agentSkillsLocations` setting.
|
||||
4. Retain-in-root vs move-to-skills split for AGENTS.md content, and an execution checklist.
|
||||
|
||||
**Assistant fact-checked every concrete claim against primary sources before planning**, per this
|
||||
repo's own "no confident answer without a source" rule:
|
||||
|
||||
- **Confirmed correct:** `kfchou/wiki-skills` and `vanillaflava/llm-wiki-skills` are real
|
||||
repositories (verified via `github_text_search`/`github_repo`) implementing this pattern with
|
||||
5-6 discrete skills each. `yugasun/llm-wiki-skills` is real too - single skill, Chinese-
|
||||
language, demonstrating a canonical-source + `sync-skill-layout.sh`/`verify-skill-layout.sh`
|
||||
mirroring pattern into `.github/skills/`, `.agents/skills/`, `.claude-plugin/`.
|
||||
- **Confirmed correct:** Mistral Vibe (`github.com/mistralai/mistral-vibe`, listed on
|
||||
`agentskills.io`'s client showcase as "a command-line coding assistant powered by Mistral's
|
||||
models") natively reads `.vibe/skills/` and **`.agents/skills/`** (project, trusted-folder-
|
||||
gated) plus `~/.vibe/skills/`/`~/.agents/skills/` (user) - confirmed directly in
|
||||
`mistralai/mistral-vibe`'s source (`vibe/core/skills/builtins/skill_creator.py`,
|
||||
`vibe/core/skills/builtins/vibe.py`, `CHANGELOG.md`: "Load skills from `~/.agents/skills` so
|
||||
they can be shared across agents").
|
||||
- **Confirmed correct:** Claude Code only reads `.claude/skills/<name>/SKILL.md` (project) or
|
||||
`~/.claude/skills/` (personal/plugin) per official docs (`code.claude.com/docs/en/skills`) -
|
||||
it does **not** read `.agents/skills/` natively, so a mirror/symlink really is required.
|
||||
- **CORRECTED - Codex CLI:** the pasted claim of `~/.codex/skills/` + symlink is **wrong**.
|
||||
OpenAI's own docs (`learn.chatgpt.com/docs/build-skills`, "Where Codex loads local skills")
|
||||
confirm Codex natively scans **`.agents/skills`** from the current working directory up to the
|
||||
repository root, plus `$HOME/.agents/skills` - no symlink needed at all.
|
||||
- **CORRECTED/FLAGGED - GitHub Copilot:** VS Code's own bundled skill docs say `.agents/skills/`
|
||||
is a native project-scope location, no settings.json required - conflicting with the pasted
|
||||
claim that `chat.agentSkillsLocations` must be configured. `vanillaflava/llm-wiki-skills`'s own
|
||||
README repeats the `chat.agentSkillsLocations` claim too, so it isn't fabricated, but may be
|
||||
stale for the currently-installed Copilot Chat version. Flagged as needing an empirical check
|
||||
rather than asserted either way.
|
||||
- **NOT verified / explicitly flagged as unsourced, not to be repeated as fact:** the "5-8x"
|
||||
token-cost multiplier and the "61% reduction / 100% resolve rate on an 8,260-file corpus"
|
||||
statistic, and "Leo Alexandru's production setup" - no source found for any of the three; the
|
||||
assistant explicitly told the user these would not be carried into the plan as facts.
|
||||
|
||||
**Net conclusion:** `.agents/skills/` is a better canonical choice than the pasted plan assumed -
|
||||
3 of 4 target tools (Copilot, Codex, Mistral Vibe) read it natively with zero extra wiring; only
|
||||
Claude Code needs a generated mirror.
|
||||
|
||||
The assistant then asked three clarifying questions before finalizing the plan:
|
||||
1. How to handle the conflicting Copilot `chat.agentSkillsLocations` evidence -> user chose
|
||||
**"Test first"** (empirical check before assuming either way).
|
||||
2. How to keep `.claude/skills/` in sync with `.agents/skills/` -> user chose **"new wikitool
|
||||
subcommand"** (`tools/wikitool skills sync`/`verify`) over a standalone script or a one-off
|
||||
manual symlink.
|
||||
3. Whether the skill set should map 1:1 to the 5 existing AGENTS.md workflows, merge
|
||||
create+update, and/or add a 6th read-only status skill -> user chose **both**: merge
|
||||
create+update into one `wiki-manage` skill AND add a new `wiki-status` skill, netting 5 total
|
||||
skills: `wiki-ingest`, `wiki-query`, `wiki-lint`, `wiki-manage`, `wiki-status`.
|
||||
|
||||
A detailed plan was written to `/memories/session/plan.md` and presented to the user.
|
||||
|
||||
---
|
||||
|
||||
## Turn 4 - "start implementation"
|
||||
|
||||
The assistant implemented the plan:
|
||||
|
||||
1. **Phase 0 (empirical check):** created a throwaway `.agents/skills/probe/SKILL.md`, later
|
||||
deleted after use; the fresh-session discovery result could not be conclusively observed
|
||||
within the same turn (no new skill-listing update surfaced before deletion) - left as an open
|
||||
follow-up.
|
||||
2. **Phase 1:** wrote the 5 skill files verbatim-extracted from AGENTS.md's INGEST/QUERY/LINT
|
||||
workflows (`wiki-ingest`, `wiki-query`, `wiki-lint`), a merged CREATE+UPDATE
|
||||
(`wiki-manage`, two labeled procedures), and a new read-only `wiki-status` skill built on
|
||||
existing `wikitool lint`/`sources coverage` read paths (no new CLI logic).
|
||||
3. **Phase 2:** slimmed root `AGENTS.md` from 745 to ~573 lines - replaced the 5 full workflow
|
||||
sections with a compact "## Skills" pointer table, trimmed "## Git Automation" to policy-only
|
||||
(moved the per-workflow "when does this publish" detail into each skill's Output section),
|
||||
added a new Version History row.
|
||||
4. **Phase 3:** added `tools/wiki_tools/commands/skills_sync.py` (`sync` copies
|
||||
`.agents/skills/*` into `.claude/skills/*`; `verify` checks frontmatter `name`/`description`,
|
||||
mirror staleness, and that AGENTS.md's Skills table still references every skill), registered
|
||||
via `app.add_typer(skills_sync.app, name="skills")` in `cli.py`, following the exact pattern
|
||||
of the existing `xref`/`new_page`/`provenance_cmd` command modules.
|
||||
5. **Phase 4 (verification):** `tools/wikitool skills sync` then `tools/wikitool skills verify`
|
||||
passed clean (5 skills, canonical/mirrored/referenced). `tools/wikitool lint` ran across 236
|
||||
pages and surfaced **pre-existing, unrelated** issues (duplicate titles / broken links among
|
||||
`wiki/entities/projects/{kfchou,vanillaflava,yugasun}/...`, originating from an earlier ingest
|
||||
of a page called "Source - Copilot Skill Restructure Instructions") - confirmed via
|
||||
`git status --porcelain` that those files were already committed and untouched by this
|
||||
session, so left alone as out of scope. `pytest` (tools/) passed 46/46. Published via
|
||||
`tools/wikitool publish` at commit `ae2024d`.
|
||||
|
||||
**Noteworthy side-finding during this session:** the wiki already contained a source page,
|
||||
"Source - Copilot Skill Restructure Instructions", plus derived entity/concept pages
|
||||
(`Codex CLI`, `Mistral Vibe`, `GitHub Copilot`, `Cross-platform Agent Skills`, `Token Economics`,
|
||||
`Scale Ceiling`, `Workflow Extraction`, `Context Isolation`, `kfchou/wiki-skills`,
|
||||
`vanillaflava/llm-wiki-skills`, `yugasun/llm-wiki-skills`, `llm-wiki-test1`) - created from an
|
||||
earlier, unverified ingest of the exact same pasted instruction set discussed in Turn 3, **before**
|
||||
this session's fact-checking happened. Several of those pages repeat claims this session
|
||||
specifically found unverified (the "5-8x"/"61%/100%" statistics in `Token Economics.md`) or
|
||||
factually wrong (`Codex CLI.md`'s `~/.codex/skills/` + symlink claim). This source/ingest is
|
||||
filed specifically to supersede those points with the verified facts above.
|
||||
@@ -0,0 +1,122 @@
|
||||
# Conversation Transcript - Auto Mode and Tool Choice Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Reconstructed by the assistant
|
||||
> at the end of the session. Torben's question is quoted verbatim; the assistant's reasoning is
|
||||
> condensed. Command outputs quoted below are real.
|
||||
> **The findings in the "documented" section below come from a `claude-code-guide` subagent that
|
||||
> searched the Claude Code documentation during this session.** They are second-hand relative to
|
||||
> this transcript and are marked as such where it matters.
|
||||
> No credentials appeared in the session.
|
||||
> One of three transcripts cut from the same session; the other two cover the tooling fixes for
|
||||
> issues #12/#13, and issue triage and planning.
|
||||
|
||||
Covers a correction to the assistant's own working method, and what could and could not be
|
||||
established about the harness behaviour that caused it. This is about **Claude Code**, the
|
||||
harness - not about the wiki stack. No commit resulted; the outcome was a persisted preference
|
||||
and a queued product feedback draft.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - "Warum verwendest du seit neuestem immer die Shell um Dateien zu editieren?"
|
||||
|
||||
Torben's full message: *"Warum verwendest du seit neuestem immer die Shell um Dateien zu
|
||||
editieren anstelle der file edit Tools? Das macht die Session schwer nachvollziehbar."*
|
||||
|
||||
The cause was an instruction injected into the session by the active permission mode:
|
||||
|
||||
> While auto mode is active: Do your work through the Bash tool wherever it can accomplish the
|
||||
> job: read files with `cat`, `head`, or `sed -n`, search with `grep` and `find`, and make file
|
||||
> changes with `sed`, heredocs, or short scripts, rather than using the dedicated Read, Edit, or
|
||||
> Write tools. Fall back to a dedicated tool only when Bash genuinely cannot do the job.
|
||||
|
||||
The assistant had followed it and, in doing so, rewritten `lint.py`, `frontmatter_io.py` and
|
||||
`run_budget.py` through heredoc'd `python3 - <<'PY'` blocks performing `s.replace(old, new)`.
|
||||
|
||||
**The cost Torben identified is real and specific:** such a block shows the reader two string
|
||||
literals and no diff. What was in the file before, and what is in it now, is not visible. The
|
||||
`Edit` tool shows exactly that. For a one-line `sed` the difference is immaterial; for a
|
||||
multi-block rewrite of a compiler module it is not.
|
||||
|
||||
Resolution: the user's explicit instruction outranks a mode default, and the mode's own text
|
||||
carries the qualifier - *"wherever it can accomplish the job"*. An edit whose diff nobody can
|
||||
review does not accomplish the job. Reading with `cat`/`sed -n` stays fine; writing does not.
|
||||
The preference was written to the assistant's persistent memory so it survives the session, and
|
||||
the working rule became: `Edit`/`Write` for file changes, Bash for `git`, `pytest`,
|
||||
`tools/wikitool`, `grep`, `find`.
|
||||
|
||||
---
|
||||
|
||||
## Turn 2 - "Was ist denn der Hintergrund zu dieser Vorgabe des Auto Modus?"
|
||||
|
||||
The assistant separated what it could establish from what it could not, rather than
|
||||
constructing a plausible rationale - the failure mode `SOUL.md` names as the cardinal one.
|
||||
|
||||
**Established locally**, from `claude --help` on Claude Code 2.1.251:
|
||||
|
||||
- `auto` is one of six values for `--permission-mode`, alongside `acceptEdits`,
|
||||
`bypassPermissions`, `manual`, `dontAsk` and `plan`. It is a *permission* mode, not a
|
||||
performance mode.
|
||||
- The Bash tool in this session carries a `dangerouslyDisableSandbox` parameter, so it is
|
||||
sandboxed by default, and the session's scratchpad directory is described as usable "without
|
||||
permission prompts".
|
||||
|
||||
**Explicitly marked as speculation at the time:** that the Bash preference exists because
|
||||
sandboxed shell work is the path the mode can approve without asking, while `Write`/`Edit` are
|
||||
what a permission system most wants to gate. Congruent with the mechanics, but unsourced.
|
||||
|
||||
Torben asked for the documented answer, and a `claude-code-guide` subagent was dispatched with
|
||||
an explicit brief to separate documentation from inference and to name gaps as gaps.
|
||||
|
||||
### What the subagent found documented
|
||||
|
||||
- **`auto` mode** runs a separate classifier model (default Claude Sonnet 5) that evaluates
|
||||
actions before execution instead of prompting. It auto-approves read operations and file
|
||||
changes *inside the working directory*, checks everything else against a fixed blocklist
|
||||
(deletes, force-pushes, credential exposure), and falls back to a prompt when uncertain -
|
||||
except in `-p` non-interactive runs. Built-in default on Pro/Max/Team plans from v2.1.228
|
||||
(macOS/Linux/WSL) and v2.1.233 (Windows).
|
||||
- **Switching it:** `Shift+Tab` cycles modes in a running session; `claude --permission-mode
|
||||
auto` at startup; `permissions.defaultMode` in `~/.claude/settings.json` for a machine, or
|
||||
managed settings for an organisation. **There is no `/auto` slash command** - the assistant
|
||||
had claimed one existed earlier in the session and corrected itself here.
|
||||
- **A documented trap:** a `"auto"` value for `permissions.defaultMode` in a *project*
|
||||
`.claude/settings.json` or `.claude/settings.local.json` is **ignored**. Only the global file
|
||||
and managed settings accept it.
|
||||
- Configuration surface for the mode: `autoMode.environment`, `permissions.allow`/`deny`,
|
||||
`disableAutoMode`.
|
||||
|
||||
### What the subagent could not find
|
||||
|
||||
**The Bash preference itself is not in the public documentation** - neither its text nor a
|
||||
rationale - and no setting was found that disables it without leaving `auto` mode entirely.
|
||||
|
||||
### State of this instance
|
||||
|
||||
`~/.claude/settings.json` contains only `theme`, `inputNeededNotifEnabled` and
|
||||
`agentPushNotifEnabled` - no `permissions.defaultMode`. So `auto` was the built-in default for
|
||||
the plan and version, not a choice anyone made here.
|
||||
|
||||
### Recommendation given
|
||||
|
||||
Stay in `auto` mode. Leaving it costs permission prompts on everything, for a problem a standing
|
||||
preference already solves. The alternative named for completeness:
|
||||
`permissions.defaultMode: "acceptEdits"` in the global settings file, which approves edits and
|
||||
prompts on shell commands - practically the inverse of the complaint.
|
||||
|
||||
One judgment was stated as a judgment: an injected instruction that changes visible working
|
||||
behaviour ought to be documented and individually disableable. That was drafted as product
|
||||
feedback, queued locally for Torben to send or discard.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Working method | `Edit`/`Write` for file changes; Bash for `git`, `pytest`, `wikitool`, `grep`. Persisted to the assistant's memory |
|
||||
| Corrections made | The claim that a `/auto` slash command exists was wrong and was retracted |
|
||||
| Documentation status | `auto` mode documented; its Bash preference not |
|
||||
| Repo | No change. This turn produced no commit |
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
# Conversation Transcript - Comma Bug, Budget Refund and Lint Report Path Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Reconstructed by the assistant
|
||||
> at the end of the session. Torben's instructions are quoted verbatim where they are short;
|
||||
> the assistant's reasoning is condensed. Command outputs quoted below are real.
|
||||
> No credentials appeared in the session.
|
||||
> One of three transcripts cut from the same session; the other two cover issue triage and
|
||||
> planning, and the harness's `auto` permission mode.
|
||||
|
||||
Covers the fix for Gitea issues #12 and #13, the second defect it uncovered in frontmatter
|
||||
serialization, and the restoration of a raw file that had been renamed to work around the bug.
|
||||
Resulting commits: `40adbb7` (stack `1.2.0`), `5426a6e` (content correction). Gitea issues #12
|
||||
and #13 were closed by this session; issue #14 was opened from a gap it exposed.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - `/stack-dev` "Fixe 12 und 13. verdopple die Tool call Limits zusätzlich."
|
||||
|
||||
Torben had just received a rough prioritisation of all open issues (see the companion transcript
|
||||
on issue triage) and picked the top two off it. The added instruction: *"verdopple die Tool call
|
||||
Limits zusätzlich. Wir sind da schon immer sehr knapp unterwegs."*
|
||||
|
||||
The assistant read the affected code before touching it: `commands/_util.py`,
|
||||
`commands/new_page.py`, `commands/run_budget.py`, `commands/lint.py`, `cli.py`,
|
||||
`tools/CONTRACT.md`, `instructions/gates.md`.
|
||||
|
||||
### Issue #12 - `--set` cannot express an array value containing a comma
|
||||
|
||||
`parse_list()` split hard on `,` with no escape. Shell quoting is no help: the quotes are gone
|
||||
long before the value reaches the parser. A `raw_files:` path with a comma in the filename was
|
||||
therefore not expressible, and during the ingest of 2026-08-30 the raw file had been **renamed**
|
||||
to fit the flag - a violation of `raw/CONTRACT.md`'s immutability rule.
|
||||
|
||||
Both proposals from the issue were implemented, because they serve different cases:
|
||||
|
||||
- `\,` is a literal comma that survives the split, implemented as a lookbehind
|
||||
(`re.compile(r"(?<!\\),")`) plus an unescape per element. This also reaches
|
||||
`xref add --entities`, which uses the same helper.
|
||||
- Repeating `--set` for an *array* field now appends instead of replacing. Scalar fields keep
|
||||
"last one wins" - there is nothing to append to. This is the separator-free form and therefore
|
||||
the right one when an element contains a comma.
|
||||
- `_check_raw_files_exist` now names the comma split as the cause and both ways out, explicitly
|
||||
including "never rename the raw file to fit the flag".
|
||||
|
||||
### The second defect, found by the test rather than by the issue
|
||||
|
||||
The end-to-end test - create a raw file whose name contains a comma, reference it with `\,`,
|
||||
read the written page back - still failed. Escape and append were correct; the file was not.
|
||||
|
||||
`dump_frontmatter` writes lists in flow style (`[a, b]`), but `_format_scalar` decided on
|
||||
quoting using a document-level round-trip probe, where a comma is an ordinary character. Inside
|
||||
`[...]` it is an indicator:
|
||||
|
||||
```
|
||||
raw_files: [raw/notes/Versioning, CI-CD.md] # reads back as two elements
|
||||
```
|
||||
|
||||
So `--set` would have parsed the value correctly and the write would have taken it apart again.
|
||||
Fixed in `frontmatter_io.py`:
|
||||
|
||||
- `_round_trips_as_string(text, flow=True)` probes in the context the value is actually written
|
||||
in - it still asks the YAML loader rather than enumerating rules, which is the file's stated
|
||||
design principle.
|
||||
- A new `_quote()` helper asks the dumper for a one-element flow sequence and strips the
|
||||
brackets, because a bare plain scalar from `safe_dump` comes back carrying a `...`
|
||||
document-end marker - correct for a document, nonsense inside a list.
|
||||
|
||||
Verified that existing output is unchanged: `tags: [k8s, ci-cd]` stays unquoted, `year: '1945'`
|
||||
stays quoted exactly as before. Only values that used to break silently are now quoted.
|
||||
|
||||
### Issue #13 - the budget counted friction rather than iteration
|
||||
|
||||
**Refund on a declined call.** The design decision was where to draw the line. Keying the refund
|
||||
on exit code 1 alone would have made `lint --fail-on-error` free whenever it found something.
|
||||
The assistant keyed it on `_util.fail()` instead:
|
||||
|
||||
- `fail()` means the command *declined* - a rejected argument, or a read-only check reporting
|
||||
findings. Nothing happened; refund.
|
||||
- A command that already did its work and then reports a non-zero result raises
|
||||
`typer.Exit(1)` directly and stays counted. `lint --fail-on-error` is exactly that case: it
|
||||
has written its report first.
|
||||
|
||||
`record_and_check()` now returns whether it charged, and `cli._run_traced` calls
|
||||
`run_budget.refund()` in its `finally` block when the process left through `fail()`. The call
|
||||
stays in `recent`, so the loop-breaker still sees it - the issue itself argues that the
|
||||
loop-breaker, not the counter, is the right instrument for a repeated broken invocation.
|
||||
|
||||
Considered and rejected: marking mutations at the write sites (35 sites across 15 files) so the
|
||||
refund could be keyed on "nothing was written". Rejected as fail-open - a new write site that
|
||||
forgets the marker would silently weaken a gate.
|
||||
|
||||
**Ceiling 30 → 60**, per Torben's instruction. The calibration band (5-15 simple, 15-25 complex)
|
||||
was left alone: it describes the work. The ceiling described nothing - it sat so close to the
|
||||
band that the overhead of a real ingest reached it on its own. Pulled through `AGENTS.md`,
|
||||
`instructions/gates.md`, `tools/CONTRACT.md`, `README.md`, the `work plan` template, and the
|
||||
unit sizing in `migrate-corpus.md` (now "near 55 pages; aim for 48 or fewer").
|
||||
|
||||
**The loop-breaker was deliberately left at 3.** The assistant flagged this back to Torben
|
||||
rather than doubling it silently: it is a detector for three identical calls, not a budget, and
|
||||
doubling it would let a stuck agent spin twice as long.
|
||||
|
||||
### Issue #13 - `lint` forced a second call
|
||||
|
||||
The finding turned out sharper than the issue's headline. Without `--markdown`, `lint` wrote no
|
||||
file at all - it dumped the full report to stdout. So there was no path to name, and no way back
|
||||
to a skipped section except a second run.
|
||||
|
||||
- The full report is now always written, by default to `reports/Lint Report <date>.md`, and the
|
||||
path is printed. `--markdown` still overrides the target.
|
||||
- Only sections that found something are printed. `--full` prints everything; `--json` prints
|
||||
the findings and writes nothing.
|
||||
- `wiki-lint` and `wiki-status` were both updated to say: read the file, do not run `lint`
|
||||
again. `wiki-status` step 3 now takes the hub statistic from the report file, because it is a
|
||||
statistic rather than a finding and no longer appears in the printed summary.
|
||||
|
||||
Not implemented: exempting `lint` from the budget entirely (the issue's third proposal). The
|
||||
issue itself says that should be decided separately, and the case has moved - `lint` now writes
|
||||
a file.
|
||||
|
||||
### Verification
|
||||
|
||||
658 tests pass. Two of the new tests initially failed under the hardened environment from issue
|
||||
#8 (`GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null HOME=<empty>`) with
|
||||
`ERROR No author configured for this instance` - the third and fourth instance of that same
|
||||
silent environment dependency. Both now set `WIKI_AUTHOR` themselves, and the suite is green in
|
||||
both environments.
|
||||
|
||||
The refund was measured against the real tool rather than only in tests:
|
||||
|
||||
```
|
||||
$ tools/wikitool new source --name "Refund Probe" --set "raw_files=raw/notes/Versioning, CI-CD.md"
|
||||
ERROR raw_files path does not exist: raw/notes/Versioning
|
||||
This is one element after splitting the value on commas. ...
|
||||
|
||||
$ tools/wikitool budget status
|
||||
Calls so far: 0 (limit 60)
|
||||
Recent calls:
|
||||
- new source --name Refund Probe --set raw_files=raw/notes/Versioning, CI-CD.md
|
||||
```
|
||||
|
||||
`docs verify`, `instructions verify` and `doctor` all clean. `lint` clean over 255 pages.
|
||||
|
||||
---
|
||||
|
||||
## Turn 2 - the Mass-Update Gate fires, and Torben clears it
|
||||
|
||||
`publish` refused with exit 42 on a 21-file changeset, printing the breakdown by area and the
|
||||
`--confirm 8c3ee8ff0ad6` line. The assistant reproduced the full file list in its reply - the
|
||||
groups, the paths and the per-file line counts - and stopped, as the gate's own output demands.
|
||||
|
||||
Torben replied: *"Freigegeben"*. The confirmed publish produced `40adbb7`:
|
||||
|
||||
```
|
||||
[main 40adbb7] fix: --set-Arraywerte mit Komma, lint nennt Reportpfad, Budget-Refund und Ceiling 60 (1.2.0)
|
||||
21 files changed, 593 insertions(+), 73 deletions(-)
|
||||
```
|
||||
|
||||
Verified afterwards that `HEAD` equals `origin/main`, the tree is clean, and `VERSION` reads
|
||||
`1.2.0` - rather than trusting the tool's own success line.
|
||||
|
||||
---
|
||||
|
||||
## Turn 3 - "Benenne die Referenz mit Komma um, damit sie wieder stimmt"
|
||||
|
||||
The raw file renamed during the 2026-08-30 ingest got its original name back:
|
||||
|
||||
`raw/notes/Conversation Transcript - Versioning, CI-CD and Content Migration Session 2026-08-30.md`
|
||||
|
||||
Done with `git mv` (100% similarity, history preserved). The source page's `raw_files:` entry
|
||||
and its `**Raw-Dateien:**` prose line were corrected, `sources rebuild-index` rebuilt the
|
||||
provenance index, `sources coverage` reported 0 uncovered and 0 broken references, `lint` was
|
||||
clean over 255 pages, and a `log append --op update` entry recorded what happened and why.
|
||||
|
||||
Worth noting: the corrected value is now written **quoted** in the frontmatter -
|
||||
`raw_files: ['raw/notes/…Versioning, CI-CD…']` - which is exactly the second defect fixed
|
||||
earlier in the session. Without that fix the rename would have taken itself apart again on
|
||||
write.
|
||||
|
||||
Published as `5426a6e`, five files, below the Mass-Update Gate threshold.
|
||||
|
||||
### The gap this exposed - issue #14
|
||||
|
||||
**No `wikitool` command writes `raw_files:` on an existing page.** `touch` handles the fields
|
||||
that describe the page itself; `xref` handles the page-reference arrays
|
||||
(`related:`/`sources:`/`entities:`/`concepts:`), and `raw_files:` is none of those - it points
|
||||
at a path, not a page title. `new source --set raw_files=…` writes the field once, at creation,
|
||||
and never again.
|
||||
|
||||
`AGENTS.md` invariant 1 does not forbid hand-editing it - its list names the catalog, `log.md`,
|
||||
`provenance.md`, the skill directories, the two JSON files and the page-reference arrays, and
|
||||
`raw_files:` is in none of them. But it contradicts the core principle that anything mechanical
|
||||
is done by the tool. `lint` and `sources coverage` **report** broken `raw_files:` references
|
||||
reliably; nothing can repair them. That asymmetry sends an agent into exactly the hand-edits the
|
||||
rest of the stack is built against.
|
||||
|
||||
Filed as issue #14, proposing `sources relink` or, more closely, a `raw rename` that does the
|
||||
`git mv` and every referencing source page in one step - the only form where the intermediate
|
||||
state "file gone, reference dangling" never exists.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Stack version | `1.2.0` (MINOR - new capability, backwards compatible) |
|
||||
| Commits | `40adbb7` (fix), `5426a6e` (content correction) |
|
||||
| Tests | 658 passing, in the normal and the hardened environment |
|
||||
| Gitea | #12 and #13 closed with the reasoning; #14 opened |
|
||||
| CI | Runs 62, 63, 64 all green |
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
# Conversation Transcript - ENVIRONMENT.md as an Optional Third Session-Level File Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's instructions and
|
||||
> decisions are quoted verbatim; issue text, file excerpts, tool output and the Mass-Update
|
||||
> Gate's printout are real, taken from the session; the assistant's reasoning is condensed.
|
||||
> No second-hand material - no subagent was used. No credentials appeared; the Gitea MCP calls
|
||||
> used the session's own configured access, not a token pasted into chat.
|
||||
> One of two transcripts cut from this session; the other covers coverage reporting in CI
|
||||
> (Gitea #10) and the `dist export` leak it uncovered - bundled into the same publish, but a
|
||||
> different subject.
|
||||
|
||||
Covers Gitea issue #24: a third root document alongside `USER.md` and `SOUL.md`, recording what
|
||||
*this checkout* works through - harness, published skills, MCP servers, connectors, git remotes,
|
||||
where CI runs. Shipped as stack **1.8.0** in commit `a243a4a`, issue closed. The session opened
|
||||
with a mismatch between the issue number Torben named and the work he described, and resolving
|
||||
that by asking is the first turn.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - the issue number did not match the task
|
||||
|
||||
Torben's instruction, verbatim:
|
||||
|
||||
> `/stack-dev implementiert #10`
|
||||
>
|
||||
> "Implementiere eine kleine Erweiterung im dev skillset: eine checkout spezifische Datei soll
|
||||
> verzeichnen, über welche skills/connectoren/mcp-server/remotes gearbeitet wird. Das sind für
|
||||
> Entwicklungen tendenziell konstante Werte, du musst sie aber immer wieder abfragen. Das wäre
|
||||
> also Ein File, was beim bootstrapping vom jeweiligen harness (hier: Claude Code) verlinkt
|
||||
> wird. Es soll optional sein."
|
||||
|
||||
The assistant read #10 first. Its title is **"Coverage-Reporting: erst messen, dann eine
|
||||
Schwelle setzen"** - pytest-cov in CI, no threshold until the number is known. Nothing to do
|
||||
with a checkout-specific environment file. A scan of all twelve open issues found no issue
|
||||
matching the description either.
|
||||
|
||||
**Decision: ask rather than guess.** Two readings led to materially different work, and both
|
||||
were plausible - a transposed digit, or two requests in one message. The alternative considered
|
||||
and rejected was implementing the described feature and treating "#10" as a slip, which would
|
||||
have silently dropped a work package Torben may have meant.
|
||||
|
||||
Torben's answers to the three questions:
|
||||
|
||||
- Scope: **"Beides in dieser Session"** - both work packages, not one.
|
||||
- Placement: **"Root, für jede Instanz"** - not dev-only.
|
||||
- Name: **"ENVIRONMENT.md"**.
|
||||
|
||||
The described feature had no issue, so one was filed as **#24** (`prio/2`, `size/M`) before the
|
||||
changelog entry was written, so the entry could name a number that already existed.
|
||||
|
||||
## Turn 2 - why not `instructions/dev/`
|
||||
|
||||
Torben's phrasing was "eine kleine Erweiterung im dev skillset", which points at
|
||||
`instructions/dev/`. The assistant surfaced a hard constraint from
|
||||
`instructions/CONTRACT.md` before offering the choice:
|
||||
|
||||
> `tools/wikitool instructions verify` also reports anything under it that is referenced from
|
||||
> **outside** it, because such a reference would dangle the moment `dist export` runs.
|
||||
|
||||
So a `CLAUDE.md` link into `instructions/dev/` is a boundary violation unless it is wrapped in
|
||||
`<!-- dist:strip-start/end -->` markers - the one sanctioned crossing, used today by exactly one
|
||||
routing line in `AGENTS.md`. That is more mechanism for less reach.
|
||||
|
||||
**Rejected: dev-only placement.** The content - which MCP server answers which question, which
|
||||
remote `publish` talks to - is not development-specific. A distributed instance running content
|
||||
sessions has the same questions. Torben chose root.
|
||||
|
||||
## Turn 3 - the three properties that separate it from the Personalization Plane
|
||||
|
||||
The existing pattern (`kb/concepts/Personalization Plane.md`, stack 1.1.0) is: ship a
|
||||
`.template`, fill it during setup, check it with `doctor`. `ENVIRONMENT.md` reuses the shape and
|
||||
diverges on three points, each deliberate.
|
||||
|
||||
**Optional, and `doctor` never FAILs.** `check_environment()` returns `OK` when the file is
|
||||
absent, `OK` when filled, and `WARN` only for a renamed-but-unfilled template. Quoting the
|
||||
docstring written for it:
|
||||
|
||||
> Missing it costs a session some questions, not correctness, so this check never FAILs - the
|
||||
> whole point of the file is that it is optional, and a FAIL would make it mandatory by the
|
||||
> back door.
|
||||
|
||||
**Rejected: `FAIL` on missing**, which is what `personalization` does. That check is right for
|
||||
`USER.md`/`SOUL.md`, which are an operating requirement; here it would have converted "optional"
|
||||
into "mandatory with a nicer word".
|
||||
|
||||
The one case still worth reporting is the failure mode a plain existence check misses: a file
|
||||
that is present, loaded into every session, and answers nothing. Same sentinel as the
|
||||
personalization pair, `wikitool:template-unfilled`.
|
||||
|
||||
**Gitignored, not committed.** `USER.md`/`SOUL.md` are committed here and excluded from
|
||||
`dist export` by the root allowlist. `ENVIRONMENT.md` goes further and is gitignored, on the
|
||||
argument that two clones of one repo are two different environments - a committed copy would
|
||||
hand the second clone answers that are *wrong* rather than missing, and wrong is worse here
|
||||
because the file gets believed.
|
||||
|
||||
That created a trap worth pinning: the careless pattern `ENVIRONMENT.md*` swallows the template
|
||||
too. `docs verify` now asserts both halves - `ENVIRONMENT.md` in `REQUIRED_IGNORE_CANARIES`,
|
||||
`ENVIRONMENT.md.template` in `REQUIRED_TRACKED_PATHS`. The `.gitignore` entry is anchored
|
||||
(`/ENVIRONMENT.md`) per that file's own header rule.
|
||||
|
||||
**Context, not authority.** Written into the template, `AGENTS.md` and the file itself: it
|
||||
describes what is *there*, not what is permitted. A remote listed in it does not authorize a
|
||||
`git push` - invariant 5 still routes through `wikitool publish` - an MCP server listed in it
|
||||
opens no gate, and nothing in it is a source under invariant 3. No credentials: it sits in
|
||||
plaintext in the working tree and in every agent's context.
|
||||
|
||||
## Turn 4 - import or link in CLAUDE.md
|
||||
|
||||
`instructions/CONTRACT.md` frames this as a question about *when the decision is made*: an
|
||||
import for what is decided in passing, a link for what is looked up deliberately. An import is
|
||||
the strongest and most expensive load in the layer, charged to every session on that harness.
|
||||
|
||||
**Decision: `@ENVIRONMENT.md`, an import.** The reasoning written into `CLAUDE.md`:
|
||||
|
||||
> a session that has to go look the answer up will instead ask the user again, which is the
|
||||
> cost the file exists to remove.
|
||||
|
||||
The file is also the first import that may legitimately never exist. `CLAUDE.md` already
|
||||
tolerates unresolved imports - `USER.md`/`SOUL.md` do not exist during the setup session - so
|
||||
the tolerance was already proven; here it becomes a permanent state rather than a transitional
|
||||
one.
|
||||
|
||||
Two knock-on edits the change forced: `CLAUDE.md`'s closing paragraph said "The fourth import is
|
||||
the harness-specific one", which the new import made wrong, so both ordinals became "the last
|
||||
import". `AGENTS.md` got a file-naming row *and* a separate `## Environment` section, because
|
||||
the other harnesses read `AGENTS.md` and never see `CLAUDE.md`.
|
||||
|
||||
**Rejected: a `wikitool environment` command** to scaffold or query the file. It is read often
|
||||
and written rarely; a command for it would be machinery with no consumer. The template plus two
|
||||
instruction steps is the whole surface.
|
||||
|
||||
## Turn 5 - where the file gets created
|
||||
|
||||
Two entry points, both optional, both with the same rule:
|
||||
|
||||
- `instructions/bootstrap.md` step 5 (new), for a clone - which never has the file, because it
|
||||
is gitignored.
|
||||
- `instructions/setup-instance.md` step 9 (new), for a fresh distribution.
|
||||
|
||||
Inserting a step into `setup-instance.md` meant renumbering 9-13 to 10-14, and one cross-
|
||||
reference inside step 6 pointed at the `doctor` step by number ("Schritt 11") and had to move to
|
||||
12. Three other documents reference "Schritt 6 (Personalization)" - `INSTALL.md` twice,
|
||||
`bootstrap.md` once, `CHANGES.md` three times - and step 6 did not move, so those stayed correct.
|
||||
|
||||
The rule written into both steps, and into the template:
|
||||
|
||||
> eintragen was ablesbar ist, einmal fragen, "weiß ich nicht" akzeptieren, einen leeren
|
||||
> Abschnitt löschen statt ihn mit Plausiblem zu füllen
|
||||
|
||||
A guessed line is worse than a missing one, for the same reason the file is gitignored.
|
||||
|
||||
## Turn 6 - human docs, then publish
|
||||
|
||||
Per the `stack-dev` skill's rule that a stack change is unfinished until the human docs describe
|
||||
it: `README.md`'s architecture tree gained a row and its `CLAUDE.md` line was corrected;
|
||||
`INSTALL.md` gained a paragraph in "Weg C", a line in the `doctor` summary and a troubleshooting
|
||||
entry for `environment: WARN`; `tools/CONTRACT.md`'s `doctor` row names the new check.
|
||||
|
||||
Verification before publishing: 730 tests, `docs verify`, `instructions verify`,
|
||||
`lint --fail-on-error`, and a full replay of the CI smoke test - `dist export` into a scratch
|
||||
directory, `git init`, stub personalization, venv, `instructions sync`, `index rebuild`,
|
||||
`sources rebuild-index`, then `doctor`/`docs verify`/`instructions verify`/`lint`/
|
||||
`migrate status`. `doctor` reported `environment: ENVIRONMENT.md absent (optional)` there, which
|
||||
is the intended answer for a fresh instance.
|
||||
|
||||
`publish` exited **42** at the Mass-Update Gate (23 files, threshold 10). Per invariant 6 the
|
||||
full breakdown was reproduced to Torben and the session stopped. His clearance, verbatim:
|
||||
|
||||
> "Wenn wir im Rahmen der ci scripts nichts mehr brauchen ist der aktuelle publish freigegeben"
|
||||
|
||||
The assistant checked `nightly.yml` and `release.yml` first - neither runs pytest, and the new
|
||||
`doctor` check can never FAIL, so neither needed anything - then published with the token.
|
||||
|
||||
## Turn 7 - the file for this checkout
|
||||
|
||||
Torben, verbatim:
|
||||
|
||||
> "Erstelle eine Environment.md für diese Session. Sei kurz und prägnant, die meisten Infos
|
||||
> solltest du ja haben."
|
||||
|
||||
A first version had carried the template's full preamble. Rewritten to 40 lines holding only
|
||||
values: Claude Code primary with Codex/Copilot/Vibe alongside, six published skills including
|
||||
`stack-dev`, the `gitea-mcp` server (with the standing rule that Gitea is read through it and
|
||||
not through curl), `origin` at `ssh://git@gitea.nehmer.net:10101/torben/llm-wiki-test1.git` with
|
||||
the private-repo token note, CI on Gitea Actions with its three workflows, plus two standing
|
||||
facts - this repo is a testbed rather than the production instance, and contracts/instructions
|
||||
are English while `kb/` content and changelog entries are German.
|
||||
|
||||
`doctor` then reported `environment: ENVIRONMENT.md present and filled`, and
|
||||
`git check-ignore -v` confirmed `.gitignore:111:/ENVIRONMENT.md` keeps it out of every commit.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Version | 1.8.0 (`--minor`: new capability, backwards compatible) |
|
||||
| Commit | `a243a4a` (shared with the coverage work, 23 files, +589/-24) |
|
||||
| Issue | #24 filed and closed in this session |
|
||||
| Tests | 730 passing; new tests for three `doctor` outcomes, the `dist export` split, both ignore-canary halves |
|
||||
| Verified | `docs verify`, `instructions verify`, `lint --fail-on-error`, full `setup-instance` replay against a fresh export |
|
||||
| CI | Run 87 green, all nine steps; release run 88 green |
|
||||
| Gate | Mass-Update Gate, exit 42, cleared by Torben after the file list was shown |
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
# Conversation Transcript - Gate Counting and Measured Calibration Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's instruction is quoted
|
||||
> verbatim; the call counts and the before/after file counts are real measurements taken during
|
||||
> the session, not estimates; the assistant's reasoning is condensed.
|
||||
> No second-hand material. No credentials appeared in the session.
|
||||
> One of two transcripts cut from this stretch of the session; the other covers
|
||||
> `touch --set/--add/--remove` and the write-once frontmatter gap.
|
||||
|
||||
Covers two calibrations of limits that had never been measured against real use: the
|
||||
Mass-Update Gate's file count, and the iteration budget's guidance band. Stack `1.5.0`
|
||||
(`3166c31`). No issue - Torben raised both directly from what he had watched happen.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - the observation
|
||||
|
||||
Torben, after watching three ordinary ingests each stop at the Mass-Update Gate:
|
||||
|
||||
> Passe die approval gate publish an:
|
||||
> - automatic erzeugte files wie Index.md können wir Raus nehmen. Wir hatten drei normale
|
||||
> ingests und alle liegen ins Gate wo immer ein Haufen Datenbank files dazu kommen
|
||||
> - schau sich mal auf. Die Anzahl der Tool ops. Von denen wir ausgehen. Ich habe den Eindruck,
|
||||
> dass die Maßgabe 15-20/29-25 zu gering ist
|
||||
|
||||
Both halves turned out to be measurable rather than matters of taste, and the measurements were
|
||||
already lying in the repository.
|
||||
|
||||
---
|
||||
|
||||
## Part 1 - generated files no longer count
|
||||
|
||||
### What was already there
|
||||
|
||||
`git_publish.py` already knew which files are generated - `is_generated()` covers
|
||||
`kb/index.md`, `kb/log.md`, `kb/provenance.md` and every `INDEX.md` - and already had an
|
||||
exemption mechanism: `GATE_EXEMPT_PREFIXES = ("work/",)`, with `counted_files()` filtering by
|
||||
prefix. The two facts had simply never been connected. `is_generated` was used only to *group*
|
||||
the file list for display, under the heading "rebuilt by wikitool - no review needed" - a note
|
||||
that said the reviewer need not read them while the count still made them approve them.
|
||||
|
||||
### The change
|
||||
|
||||
Generated files are now exempt from the count for the same reason `work/` is: they carry no
|
||||
decision. Each is recomputable from the tree by `index rebuild` / `sources rebuild-index`, so
|
||||
approving one decides nothing - it only produces the review fatigue the threshold exists to
|
||||
prevent. They are still staged, committed and pushed.
|
||||
|
||||
Measured against the three real changesets from earlier the same day:
|
||||
|
||||
| Ingest | Files | Counted before | Counted now |
|
||||
|---|---|---|---|
|
||||
| Comma Bug | 14 | 14 → gate | **9 → passes** |
|
||||
| Issue Triage | 16 | 16 → gate | **9 → passes** |
|
||||
| Auto Mode | 11 | 11 → gate | **5 → passes** |
|
||||
|
||||
None of the three was a mass update, and none would now stop.
|
||||
|
||||
The gate stays armed: ten real pages still trip it however much index churn rides along, and a
|
||||
test asserts exactly that so the exemption cannot quietly become a disarming.
|
||||
|
||||
### Two consequences worth recording
|
||||
|
||||
**The refusal line accounts for both reasons separately** - "3 under work/ and 5 generated by
|
||||
wikitool committed but not counted". A reviewer who sees "9 counted" against a 14-file commit
|
||||
otherwise reads the difference as a bug. Keeping the reasons distinct also keeps them honest:
|
||||
scratch state and derived output are not the same thing.
|
||||
|
||||
**The `--confirm` token now digests only what a human actually read.** A rebuilt `INDEX.md` no
|
||||
longer invalidates a clearance that was already given.
|
||||
|
||||
### Test coverage found missing
|
||||
|
||||
All 67 gate tests passed *before* the tests for the new behaviour were written - meaning no test
|
||||
had ever asserted that generated files were counted. The old behaviour was untested, which is
|
||||
part of how it survived unexamined.
|
||||
|
||||
---
|
||||
|
||||
## Part 2 - the calibration band was demonstrably too low
|
||||
|
||||
### Where the evidence was
|
||||
|
||||
`tools/.wikitool_session/budget.json` holds the per-session `wikitool` call counts. It had been
|
||||
recording them all along. Four real ingests:
|
||||
|
||||
| Session | Calls |
|
||||
|---|---|
|
||||
| `ingest-comma-bug-2026-08-31` | **30** |
|
||||
| `ingest-transcript-personalization-plane` | **29** |
|
||||
| `ingest-issue-triage-2026-08-31` | **26** |
|
||||
| `ingest-auto-mode-2026-08-31` | **24** |
|
||||
| `issue-14-2026-08-31` (stack work) | 9 |
|
||||
|
||||
The documented band for a complex multi-tool workflow was **15-25**. Every single ingest sat at
|
||||
or above its ceiling while doing nothing unusual.
|
||||
|
||||
### Why that matters beyond the number
|
||||
|
||||
A guideline the normal case exceeds is not a guideline. It teaches an agent that the numbers are
|
||||
decorative - which is precisely the failure the iteration budget was built to be immune to,
|
||||
since a prompt-level limit is one an agent can talk itself past.
|
||||
|
||||
New: **~5-15** for a simple task (measured 5-9), **~20-35** for a complex multi-tool workflow.
|
||||
Pulled through `run_budget.py`, `instructions/gates.md`, and the `wiki-ingest` and `wiki-lint`
|
||||
skills. The ceiling of 60 was left alone - it is not a target but the point past which a session
|
||||
is presumed stuck.
|
||||
|
||||
### The provenance distinction that was preserved
|
||||
|
||||
The old band was an inherited industry rule of thumb, and `kb/concepts/Iteration and Cost
|
||||
Limits.md` cites it as exactly that, with a source. It was **not** rewritten: it is a sourced
|
||||
claim about the state of the art, not about this instance. What this instance measures is a
|
||||
different claim needing its own source, which is why it waited for this transcript rather than
|
||||
being edited into the page directly.
|
||||
|
||||
`gates.md` now also records *where the number comes from and how to re-measure it*, naming
|
||||
`tools/.wikitool_session/budget.json`. A guideline with no measurement procedure goes stale
|
||||
silently - which is what had happened.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Stack version | `1.5.0` (MINOR - no content has to migrate) |
|
||||
| Commit | `3166c31` - 9 files |
|
||||
| Tests | 678 passing, in the normal and the hardened environment |
|
||||
| Gate | Generated files committed, not counted; threshold unchanged at 10 |
|
||||
| Budget | Band 15-25 → 20-35 for complex workflows; ceiling unchanged at 60 |
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
# Conversation Transcript - Hardening the Test Suite Against Silent Environment Dependencies Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** The user's instructions,
|
||||
> command output, test counts, commit hashes and CI log excerpts are quoted verbatim. The
|
||||
> assistant's reasoning and the order in which files were read are condensed. All numbers and
|
||||
> paths below were observed in the session, not reconstructed afterwards.
|
||||
> No second-hand material: no subagent was spawned, and every claim was verified in-session by
|
||||
> running the command that shows it.
|
||||
> No credentials appeared in the session.
|
||||
|
||||
Covers the implementation of Gitea issue #8 - an autouse pytest fixture that cuts every test off
|
||||
from the machine it runs on - shipped as `1.7.1` (`31c9b81`, tag `v1.7.1`), plus the two
|
||||
follow-up issues the work exposed (#22, #23). The session ran under the `stack-dev` skill
|
||||
throughout.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - the instruction
|
||||
|
||||
> implementiere issue #8
|
||||
|
||||
Issue #8, `prio/1` `size/M`, titled "Testsuite gegen stille Umgebungsabhängigkeiten härten". Read
|
||||
in full along with its one comment, before any code was opened.
|
||||
|
||||
### What the issue said
|
||||
|
||||
The first CI run that ever reached `pytest` (run 52, 2026-08-30) failed two tests that had been
|
||||
green on every developer machine for months:
|
||||
|
||||
```
|
||||
FAILED wiki_tools/tests/test_new_page.py::test_new_source_author_falls_back_to_git_config
|
||||
FAILED wiki_tools/tests/test_provenance.py::test_new_source_with_multiple_raw_files
|
||||
AssertionError: ERROR No author configured for this instance.
|
||||
2 failed, 628 passed
|
||||
```
|
||||
|
||||
Cause: `config.default_author()` runs `git config user.name` with `cwd=config.ROOT`. The fixture
|
||||
root is not a repository, so the answer came from the **global** git configuration of whoever
|
||||
started pytest. As `root` in the job container there is none.
|
||||
|
||||
Both were repaired in `1.0.1`. The issue's own framing of what remained: the suite "hat nicht
|
||||
gewarnt, sie war einfach grün, weil die Umgebung zufällig passte."
|
||||
|
||||
The comment, added 2026-08-31 during the `1.2.0` work on #12, is the load-bearing part:
|
||||
|
||||
> Das ist der dritte und vierte Fall derselben Abhängigkeit, geschrieben von jemandem, der das
|
||||
> Issue vorher gelesen hatte. Die Frage aus dem Issue-Text — „wie viele unbekannte gibt es" —
|
||||
> ist damit weniger interessant als die andere: **die Suite lädt neue Fälle schneller ein, als
|
||||
> jemand sie findet.**
|
||||
|
||||
Two options were on the table, and the issue had already ranked them: an autouse fixture in
|
||||
`conftest.py` (preferred), or a second hardened `pytest` step in CI (fallback, "schwächer, weil
|
||||
es die Abhängigkeit erst nach dem Push meldet").
|
||||
|
||||
### The decision, and why the fallback was rejected
|
||||
|
||||
The fixture. The comment settles it: a guard that reports after the push loses to a suite that
|
||||
acquires new cases faster than anyone finds them. A CI-only guard also never protects the
|
||||
developer's own run, which is where the cases are written.
|
||||
|
||||
This was not a close call and was not re-litigated. What the session did add was a reason the
|
||||
issue could not have known - see Turn 6.
|
||||
|
||||
## Turn 2 - measuring before changing
|
||||
|
||||
Rather than start from the issue's list, the environment surface was measured directly:
|
||||
|
||||
```bash
|
||||
grep -rn "environ\|getenv" wiki_tools/*.py | grep -v tests/
|
||||
```
|
||||
|
||||
Which yields the tool's own reads: `WIKI_AUTHOR` (`config.py:59`), `WIKITOOL_SESSION_ID`
|
||||
(`session.py:17`), `WIKITOOL_UPDATE_URL` / `WIKITOOL_UPDATE_TOKEN` (`version.py:50,53`), and the
|
||||
telemetry set `WIKI_TRACE`, `WIKI_TRACE_DIR`, `WIKI_TRACE_CONTENT`, `WIKI_TRACE_MAX_CONTENT`
|
||||
(`telemetry/writer.py`, `telemetry/scrub.py`).
|
||||
|
||||
Then the baseline, which turned out to matter:
|
||||
|
||||
```bash
|
||||
env -u WIKI_AUTHOR GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null HOME=<empty> \
|
||||
.venv/bin/python -m pytest -q
|
||||
→ 695 passed in 10.30s
|
||||
```
|
||||
|
||||
**The suite was already green under the hardened environment.** The four known cases had all
|
||||
been patched in `1.0.1` and `1.2.0`, and no fifth existed at that moment. This reframed the
|
||||
change: it is not a repair, it is a guard - and a guard whose value has to be demonstrated
|
||||
separately, because "everything still passes" proves nothing about it.
|
||||
|
||||
## Turn 3 - what was built
|
||||
|
||||
### The fixture
|
||||
|
||||
`hermetic_environment`, autouse, in `tools/wiki_tools/tests/conftest.py`, next to the existing
|
||||
`isolated_trace_dir`. Per test: `HOME` and `XDG_CONFIG_HOME` into that test's own `tmp_path`,
|
||||
`GIT_CONFIG_GLOBAL` and `GIT_CONFIG_SYSTEM` to `/dev/null`, and two lists cleared.
|
||||
|
||||
**Beyond the issue's list**, git's own identity and location variables were added: `GIT_DIR`,
|
||||
`GIT_WORK_TREE`, `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,
|
||||
`GIT_COMMITTER_EMAIL`, `EMAIL`. The reasoning, recorded in the code comment: `GIT_AUTHOR_NAME`
|
||||
outranks `git config user.name`, so it is literally the same failure the issue describes through
|
||||
a different door; and a stray `GIT_DIR` would point every fixture repo at the developer's own
|
||||
checkout.
|
||||
|
||||
### The ordering problem between two autouse fixtures
|
||||
|
||||
`hermetic_environment` clears `WIKI_TRACE`. `isolated_trace_dir` sets `WIKI_TRACE_DIR`. If the
|
||||
clearing ran second it would not touch `WIKI_TRACE_DIR`, so the suite would still work - but the
|
||||
correctness would rest on pytest's declaration order rather than on anything stated.
|
||||
|
||||
`isolated_trace_dir` now takes `hermetic_environment` as a parameter. Not for its value, for the
|
||||
ordering. Both docstrings say so.
|
||||
|
||||
`WIKI_TRACE_DIR` is deliberately the one variable left **set**. Acceptance criterion 4 of the
|
||||
issue: tracing must never be disabled suite-wide, because two telemetry tests assert that a
|
||||
trace gets written.
|
||||
|
||||
### What was deliberately not done
|
||||
|
||||
**No `WIKI_AUTHOR` in the fixture base.** This was the cheaper fix and the wrong one, and the
|
||||
issue had pre-empted it in acceptance criterion 2: a shared default would make
|
||||
`default_author()`'s `None` branch untestable, because that branch only exists on a machine that
|
||||
knows nobody. The suite would look greener and prove less.
|
||||
|
||||
**`test_new_source_fails_hard_without_any_author` keeps patching `default_author` directly.**
|
||||
Under the fixture the environment would now resolve to `None` on its own, so the patch could
|
||||
have been deleted as redundant. It was kept: the patch pins the value regardless of what the
|
||||
environment does, which keeps the test about the CLI's error path rather than about the
|
||||
environment. Criterion 3 asked exactly this and the reasoning is recorded in
|
||||
`testing-conventions.md`'s decision points.
|
||||
|
||||
## Turn 4 - proving the guard actually guards
|
||||
|
||||
A fixture nothing asserts against can be weakened or lose a variable, and everything stays green
|
||||
until the next run on a foreign machine - the same failure one level up. So
|
||||
`tools/wiki_tools/tests/test_hermetic_env.py` was written: the cleared variables, the empty
|
||||
`HOME` inside `tmp_path`, that `git config user.name` answers nothing outside a repo with a local
|
||||
identity, that tracing stays on and redirected.
|
||||
|
||||
Plus all three branches of `config.default_author()`, including the `None` branch **that the
|
||||
hardening makes writable for the first time**.
|
||||
|
||||
The counter-proof that this means something, run in-session:
|
||||
|
||||
```
|
||||
default_author() with the ambient environment: 'Torben Nehmer'
|
||||
```
|
||||
|
||||
Without the fixture, `default_author()` in a non-repository returns the developer's global git
|
||||
identity. With it, `None`. The new test would have failed before the change and passes after -
|
||||
which is the demonstration the Turn 2 baseline could not provide.
|
||||
|
||||
## Turn 5 - verification across four environments
|
||||
|
||||
Three locally, all producing the identical count:
|
||||
|
||||
| Environment | Before | After |
|
||||
|---|---|---|
|
||||
| Developer shell | green | `702 passed` |
|
||||
| Deliberately poisoned: `WIKI_AUTHOR`, `WIKI_TRACE=0`, `WIKITOOL_*`, `GIT_*` set to junk | untested | `702 passed` |
|
||||
| `env -i`, empty `HOME`, no git configuration | **red** (historically) | `702 passed` |
|
||||
|
||||
Plus `docs verify`, `instructions verify`, `lint --fail-on-error`, `instructions sync` - all OK.
|
||||
|
||||
The poisoned run is the one the issue did not ask for. It tests the opposite direction from the
|
||||
empty-machine run: not "does the suite survive having nothing", but "does it survive having the
|
||||
wrong thing". A fixture that only unsets on an already-clean machine would pass the third row and
|
||||
fail the second.
|
||||
|
||||
## Turn 6 - publish, and what CI revealed
|
||||
|
||||
> publish ist freigegeben
|
||||
> aktualisiere den issue gleich mit.
|
||||
|
||||
`tools/wikitool publish` first refused with `Missing option '--message'` (exit 2), then:
|
||||
|
||||
```
|
||||
[main 31c9b81] test: autouse-Fixture härtet die Suite gegen stille Umgebungsabhängigkeiten (1.7.1, #8)
|
||||
8 files changed, 327 insertions(+), 3 deletions(-)
|
||||
OK Published changes to origin/main.
|
||||
```
|
||||
|
||||
Per `SOUL.md`, the tool's success line was not taken as proof. `git ls-remote` confirmed
|
||||
`31c9b81` on `origin/main` and tag `v1.7.1` at the same commit.
|
||||
|
||||
CI run 79: green, all eight steps, **`702 passed in 15.84s`** - the fourth environment, and the
|
||||
same number as the three local ones. Run 80 tagged the release. The `dist export` step reported
|
||||
11 instructions and 5 skills against 14 and 6 in the dev tree, confirming that
|
||||
`instructions/dev/testing-conventions.md` stays out of the distribution.
|
||||
|
||||
### The finding that retroactively justified the choice
|
||||
|
||||
Reading the run-79 log turned up something the issue could not have known:
|
||||
|
||||
```
|
||||
Copying '/root/.gitconfig' to '/tmp/b93ea7a3-.../.gitconfig'
|
||||
Temporarily overriding HOME='/tmp/b93ea7a3-...' before making global git config changes
|
||||
[command]/usr/bin/git config --global --add safe.directory /workspace/torben/llm-wiki-test1
|
||||
```
|
||||
|
||||
`actions/checkout@v7` now creates a global git configuration inside the container itself, and the
|
||||
Tool-environment step writes `safe.directory` globally on top.
|
||||
|
||||
**The job container is therefore no longer reliably "the machine without a global
|
||||
configuration".** It had that property in run 52 by accident. The rejected fallback - a second
|
||||
hardened CI step - would have depended on that accident and would eventually have stopped
|
||||
catching anything, silently, with no red run to say so. The fixture depends on none of it.
|
||||
|
||||
This was recorded in the CI comment on `.gitea/workflows/ci.yml`'s Tests step, so nobody adds the
|
||||
second job back for the reason it was once needed.
|
||||
|
||||
## Turn 7 - the two open threads, filed rather than written down
|
||||
|
||||
Following `capture-session.md` step 4, both went to the tracker before the transcript:
|
||||
|
||||
- **#22** (`prio/3` `size/XS`) - `lint.py:157` counts `>` *lines*, not quote blocks. The
|
||||
`--fail-on-error` run during verification flagged
|
||||
`Source - Conversation - Auto Mode and Tool Choice Session 2026-08-31` for "4 quoted lines"
|
||||
when the page holds exactly one quote wrapped over four lines. The rule as written rewards
|
||||
overlong lines and punishes the repo's own wrap width. Not fixed in this session: different
|
||||
file, different rule, different change.
|
||||
- **#23** (`prio/2` `size/S`) - nothing enforces that a newly introduced tool environment
|
||||
variable reaches `_WIKITOOL_ENV`. `testing-conventions.md` step 4 says to add it, but the
|
||||
premise of #8 was that a prose rule does not prevent this class of mistake. Noticed while
|
||||
writing that very step: the rule could be written down but not enforced.
|
||||
|
||||
## Outcome
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Version | `1.7.1` (PATCH - no command changes behaviour) |
|
||||
| Commit | `31c9b81`, tag `v1.7.1` |
|
||||
| Files | 8 changed, 327 insertions, 3 deletions |
|
||||
| New | `tools/wiki_tools/tests/test_hermetic_env.py`, `instructions/dev/testing-conventions.md` |
|
||||
| Changed | `conftest.py`, `test_new_page.py` (`git init -q -b main`), `.gitea/workflows/ci.yml`, `stack-dev/SKILL.md`, `CHANGES.md`, `VERSION` |
|
||||
| Tests | 702 passed in four environments: developer shell, poisoned, `env -i`, CI container |
|
||||
| Issues | #8 closed with two comments; #22 and #23 opened |
|
||||
| CI | Run 79 green (all 8 steps), run 80 tagged the release |
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
# Conversation Transcript - Issue Triage, Labels and TODO Retirement Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Reconstructed by the assistant
|
||||
> at the end of the session. Torben's instructions are quoted verbatim where they are short;
|
||||
> the assistant's reasoning is condensed. Command outputs and issue titles quoted below are real.
|
||||
> No credentials appeared in the session.
|
||||
> One of three transcripts cut from the same session; the other two cover the tooling fixes for
|
||||
> issues #12/#13, and the harness's `auto` permission mode.
|
||||
|
||||
Covers the prioritisation of the whole open issue board, the observation that closed issue #11,
|
||||
and the decision to retire `TODO.md` in favour of Gitea issues carrying `prio/` and `size/`
|
||||
labels. Resulting commit: `9fa70f3` (stack `1.2.1`). Issues #11 closed, #14 and #15 opened.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - `/stack-dev` "lies alle offenen issues aus dem repo ... grob priorisiert"
|
||||
|
||||
Eleven open issues, all authored by Torben, none labelled. The assistant read every issue body
|
||||
through the Gitea MCP server rather than working from titles, then measured the corpus (255 kb
|
||||
pages, 65 raw files, 47 test files, stack at `1.1.1`) so the ranking rested on facts rather than
|
||||
impressions.
|
||||
|
||||
Ranking criterion chosen and stated: **what blocks or damages work in progress**, not effort.
|
||||
|
||||
The two issues placed at the top were argued as a single unit:
|
||||
|
||||
> #12 and #13 belong first because both bent a rule rather than merely annoying someone. The
|
||||
> comma bug caused a raw file to be renamed - against `raw/CONTRACT.md`'s immutability rule -
|
||||
> and the budget accounting pushed the session into `--override-budget`, against invariant 6. A
|
||||
> tool that regularly pushes its user against the stack's own invariants is the most expensive
|
||||
> class of bug here.
|
||||
|
||||
Other judgments recorded at the time:
|
||||
|
||||
- #8 (test hardening) before #10 (coverage): measuring coverage on a suite that depends on the
|
||||
measurer's environment measures the environment too.
|
||||
- #11 named as the cheapest item on the board - no code, one `list_runs` observation.
|
||||
- #7 (`dist upgrade`) called the best-written issue on the board and still not top: it pays off
|
||||
only once a second instance exists. Its trigger was named - the production instance.
|
||||
- #6 (backlink ranking) placed last, not because it is unimportant but because it is the only
|
||||
one that changes core search logic, and no search query is on record as ranking wrongly today.
|
||||
Without that "before" case the issue's own before/after acceptance criterion cannot be met.
|
||||
- #3 (product name) described as "keine Priorität, sondern eine Uhr" - technically blocking
|
||||
nothing, but growing more expensive with every commit that adds another `llm-wiki-test1`
|
||||
reference.
|
||||
|
||||
Torben took the top two and instructed the fix (see the companion transcript).
|
||||
|
||||
---
|
||||
|
||||
## Turn 2 - the observation that closed #11
|
||||
|
||||
While verifying the `1.2.0` publish, the run list answered a question a separate issue had been
|
||||
opened to ask. #11 wanted proof that Gitea evaluates `paths-ignore` the way GitHub does - the
|
||||
issue existed precisely because an assumption in this area had already cost six failed runs.
|
||||
|
||||
| Commit | Content | Runs |
|
||||
|---|---|---|
|
||||
| `6f54c31` | Stack (1.1.0) | 59 |
|
||||
| `adfa220` | Stack (1.1.1) | 60, 61 |
|
||||
| **`f916376`** | **only `kb/` and `raw/`** | **none** |
|
||||
| `40adbb7` | Stack (1.2.0) | 62, 63 |
|
||||
|
||||
`f916376` was a pure content publish from an ingest: `kb/index.md`, `kb/log.md`,
|
||||
`kb/provenance.md`, eight pages under `kb/*/**`, one file under `raw/notes/`. Every path is on
|
||||
the ignore list, and no run exists for its `head_sha`. The stack commits on either side each
|
||||
produced two runs (CI plus release, because `VERSION` moved), so the difference is the filter
|
||||
and not an idle runner.
|
||||
|
||||
The finding was written into the comment header of `.gitea/workflows/ci.yml` as the issue's
|
||||
second acceptance criterion required - "damit die nächste Person ihn nicht erneut für eine
|
||||
Annahme hält":
|
||||
|
||||
```
|
||||
# That the filter works is now observed, not assumed (Gitea issue #11): commit
|
||||
# f916376 published only kb/ and raw/ paths and produced no run at all, while
|
||||
# the stack commits on either side of it (adfa220, 40adbb7) each produced two.
|
||||
# Gitea evaluates these patterns the way GitHub does. Do not re-derive this.
|
||||
```
|
||||
|
||||
Consequence recorded on #9: the interaction its text worried about resolves in its favour. Since
|
||||
the filter does work, `lint --fail-on-error` genuinely no longer runs on a content publish, so
|
||||
the nightly drift check keeps the strongest half of its justification. #9's own prerequisite -
|
||||
whether this Gitea build evaluates `on: schedule` at all - is untouched and still open.
|
||||
|
||||
A note was also left on #8, recording that two tests written *during* the #12 fix, by someone
|
||||
who had read #8 first, still introduced the same silent environment dependency - which shifts
|
||||
the interesting question from "how many unknown cases are there" to "the suite acquires new ones
|
||||
faster than anyone finds them".
|
||||
|
||||
---
|
||||
|
||||
## Turn 3 - "Übernehme den Punkt Recherchefähigkeit aus der todo.md vollständig in ein issue"
|
||||
|
||||
Torben's full instruction added the decision he wanted made: *"Damit müsste in der todo nichts
|
||||
mehr sein, was nicht auf Gitea steht. Falls das so ist, entscheide wie wir zukünftig Prioritäten
|
||||
und t-Shirt sizes führen und ob wir die todo weiterhin brauchen. An ihrer Historie bin ich nicht
|
||||
interessiert."*
|
||||
|
||||
`TODO.md` held two sections. The first was already only a link list to issues #7-#11, moved
|
||||
there on 2026-08-30. The second was the research note - the substantial part.
|
||||
|
||||
### Issue #15 - research capability
|
||||
|
||||
Ported in full: the sources, the finding, the A/B/C table with the decision for **C**, the cut
|
||||
that keeps the network call out of `wikitool`, instruction-rather-than-skill, the `work/`
|
||||
friction, the Perplexity specifics including the `/v1/sonar` deprecation date of 2026-09-27, the
|
||||
six open contract changes and the three open decisions. Acceptance criteria were added - the
|
||||
note had none, and without them an issue is not a work package.
|
||||
|
||||
The substance worth carrying: the research capability is framed not as a feature but as **the
|
||||
missing exit from invariant 3**. Today "the wiki has no confident source for this" is a dead
|
||||
end; research is the answer "then go and get one". The design question is not "skill yes/no" but
|
||||
where a Perplexity report falls, given that `raw/` forbids "anything the LLM wrote" and `kb/`
|
||||
requires every claim to trace to a file under `raw/`.
|
||||
|
||||
### The label scheme
|
||||
|
||||
With nothing left in `TODO.md` that was not already on Gitea, the assistant decided:
|
||||
|
||||
**Two axes, both mandatory on every issue, and deliberately no third.**
|
||||
|
||||
| Priority | Means |
|
||||
|---|---|
|
||||
| `prio/1` | Blocks or damages work in progress. Next. |
|
||||
| `prio/2` | Accrues interest. Planned. |
|
||||
| `prio/3` | Worth doing, waiting on a named trigger. |
|
||||
|
||||
| Size | Means |
|
||||
|---|---|
|
||||
| `size/XS` | Minutes. Often just a decision or an observation. |
|
||||
| `size/S` | One session, one publish, a clear cut. |
|
||||
| `size/M` | Several files; a contract or instruction change; its own test effort. |
|
||||
| `size/L` | Several sessions, or open design questions before the first commit. |
|
||||
|
||||
Reasoning recorded: a priority without a cost is half a decision, so both are required; size is
|
||||
effort and not importance, so `prio/1 size/XS` is the best thing on a board and `prio/3 size/L`
|
||||
is a thing to discuss before anyone starts. `prio/3` is explicitly not a graveyard - the trigger
|
||||
must be named in the issue, or the label is a polite no. A third axis (kind, area, status) was
|
||||
rejected as the point where a taxonomy starts needing maintenance of its own, on a board with
|
||||
one maintainer.
|
||||
|
||||
Seven labels were created and applied to all ten open issues. The resulting board:
|
||||
|
||||
| # | Title | prio | size |
|
||||
|---|---|---|---|
|
||||
| 8 | Testsuite gegen Umgebungsabhängigkeiten härten | 1 | M |
|
||||
| 3 | Produktname | 2 | XS |
|
||||
| 9 | Nächtlicher Drift-Check | 2 | M |
|
||||
| 10 | Coverage messen | 2 | S |
|
||||
| 14 | `raw_files:` einer bestehenden Seite schreiben | 2 | S |
|
||||
| 4 | Link-Disziplin & xref-Auto-Scan | 3 | M |
|
||||
| 5 | `wiki-verify`-Skill | 3 | M |
|
||||
| 6 | Backlink-boosted Ranking | 3 | M |
|
||||
| 7 | `wikitool dist upgrade` | 3 | L |
|
||||
| 15 | Recherche-Fähigkeit | 3 | L |
|
||||
|
||||
### Where the rule lives
|
||||
|
||||
`TODO.md` was deleted. The scheme was written to `instructions/dev/issue-tracking.md` and linked
|
||||
from step 2 of the `stack-dev` skill.
|
||||
|
||||
The placement was the load-bearing decision. `README.md` and `AGENTS.md` both ship to every
|
||||
distributed instance, and a distributed instance has no issues at
|
||||
`gitea.nehmer.net/torben/llm-wiki-test1`. `instructions/dev/` is the only location that is both
|
||||
agent-readable and never distributed - `dist export` excludes it wholesale. For the same reason
|
||||
the release was a **PATCH** (`1.2.1`) rather than a MINOR: nothing changes for an existing
|
||||
instance.
|
||||
|
||||
Two kb pages state that the open work items live as Gitea issues "statt als Prosa in
|
||||
`TODO.md`". Both were checked and left alone: the claim stays true after the deletion, and more
|
||||
so.
|
||||
|
||||
Note on the CI version gate: it matches `^(tools/|types/|instructions/|AGENTS\.md$|…)`, so a
|
||||
change under `instructions/dev/` demands a version bump even though it reaches no instance.
|
||||
That was verified in `ci.yml` before the bump rather than assumed.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Stack version | `1.2.1` (PATCH - dev-repo process, no instance-visible change) |
|
||||
| Commit | `9fa70f3` - 5 files, `TODO.md` deleted, `instructions/dev/issue-tracking.md` added |
|
||||
| Gitea | #11 closed with the run-table evidence; #14 and #15 opened; 7 labels created and applied to all 10 open issues |
|
||||
| Repo | No `TODO.md`. Open work exists only as issues |
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
# Conversation Transcript - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's instructions and
|
||||
> decisions are quoted verbatim; issue text, workflow YAML, and Gitea API/job-log output shown
|
||||
> below are real, taken from the session; the assistant's reasoning is condensed.
|
||||
> No second-hand material. No credentials appeared in the session; the Gitea MCP tool calls used
|
||||
> the session's own configured access, not a token pasted into chat.
|
||||
> One of two transcripts cut from this session; the other covers `lint`'s blindness to
|
||||
> code-shown notation and the quote-limit miscount (Gitea #20, #22) - a different part of the
|
||||
> stack, bundled into the same publish but a separate subject.
|
||||
|
||||
Covers Gitea issue #9: a nightly scheduled workflow closing the gap `ci.yml`'s content
|
||||
`paths-ignore` opened, where `lint --fail-on-error` no longer runs on a content-only publish.
|
||||
Workflow added in commit `49bd7d4`, a bootstrap gap in it fixed by `397d8af`. **Issue left open**
|
||||
- the one fact this session could not establish is whether Gitea actually fires the `schedule`
|
||||
trigger on this instance; only manual `workflow_dispatch` runs were observed.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - reading the issue and its precedent
|
||||
|
||||
Torben's instruction (`/stack-dev implementiere #9, #22, #20`) covered this issue alongside two
|
||||
unrelated lint fixes (see the sibling transcript). The assistant read #9 in full, including its
|
||||
one existing comment, which had already confirmed (Gitea #11) that `ci.yml`'s content
|
||||
`paths-ignore` genuinely suppresses CI on a content-only publish - commit `f916376` produced no
|
||||
run while stack commits on either side produced two each. The issue's acceptance criteria
|
||||
included a specific one worth quoting, since it shaped the whole implementation:
|
||||
|
||||
> "Ein absichtlich gebrochener Korpus (ein `[[Ziel]]`, das nicht auflöst) macht den Lauf rot -
|
||||
> sonst ist er Dekoration."
|
||||
|
||||
The issue named the exact runner shape to reuse from `ci.yml` (Debian trixie-slim, `nodejs`
|
||||
installed *before* `actions/checkout@v7` because act_runner executes that action's JavaScript
|
||||
inside the job container and a slim image has no `node`), and named
|
||||
`WIKITOOL_SESSION_ID`/`WIKI_TRACE_DIR` as required environment. It also flagged an open
|
||||
precondition explicitly: whether this Gitea instance evaluates `on: schedule` at all, which - per
|
||||
Gitea's own behavior - only fires on the default branch, so a test branch would prove nothing.
|
||||
|
||||
## Turn 2 - checking the one fact that could be checked immediately
|
||||
|
||||
The assistant queried the instance directly rather than assuming a version:
|
||||
|
||||
```
|
||||
$ curl -s https://gitea.nehmer.net/api/v1/version
|
||||
{"version":"1.26.1"}
|
||||
```
|
||||
|
||||
1.26.1 is well past the 1.20 release that introduced Actions schedules, which makes the feature
|
||||
*plausible* on this instance - not proven, since evaluating a workflow file and actually firing
|
||||
its cron are different claims. This was stated as such to Torben rather than treated as
|
||||
confirmation.
|
||||
|
||||
## Turn 3 - decision point: how should a failed run become visible
|
||||
|
||||
The issue left "how failure surfaces without visiting the Actions page" explicitly open, so the
|
||||
assistant asked via `AskUserQuestion` rather than picking silently, offering:
|
||||
|
||||
1. **"Gitea-Issue anlegen" (labeled Recommended, listed first)**: an `if: failure()` step files or
|
||||
comments on a `prio/1 size/S` issue via the Gitea API, deduplicated by title search.
|
||||
2. "Nur Gitea-Notification": no extra step; rely on Gitea's own run-failure notification/mail.
|
||||
3. "Erst beobachten": ship with no visibility mechanism yet, observe whether the schedule fires at
|
||||
all first, and treat visibility as a follow-up.
|
||||
|
||||
Torben chose **option 2**, explicitly against the assistant's own recommendation:
|
||||
|
||||
> "Nur Gitea-Notification."
|
||||
|
||||
The workflow was built with **no** failure-reporting step. The reasoning for the omission -
|
||||
issue-filing needs an Actions token with `issues: write` and a dedup rule, more machinery than a
|
||||
red run already carries - was written into the workflow's own header comment specifically so a
|
||||
later reader would not mistake the omission for something forgotten.
|
||||
|
||||
## Turn 4 - writing the workflow
|
||||
|
||||
`.gitea/workflows/nightly.yml`: `on: schedule` (`17 3 * * *`, UTC - Gitea evaluates cron in UTC)
|
||||
plus `workflow_dispatch`, no push trigger. The runner block is copied from `ci.yml` rather than
|
||||
re-derived, per the issue's own instruction not to re-derive it. The six commands from the issue
|
||||
were grouped into four steps so a red run's step name alone would indicate which layer broke:
|
||||
tool-environment setup; `doctor`; `docs verify` + `instructions verify`; `lint --fail-on-error`;
|
||||
`sources coverage` + `migrate status`. `migrate verify --from <rev>` was deliberately left out,
|
||||
matching the issue's own reasoning: "yesterday" is not a meaningful comparison revision, and a
|
||||
changed page between two arbitrary points in time is the desired outcome of normal operation, not
|
||||
a finding.
|
||||
|
||||
The first draft set `WIKI_AUTHOR: Nightly` as an environment variable, reasoning that `doctor`
|
||||
FAILs without an author and a container has no git configuration to read one from. This turned
|
||||
out to be an incomplete fix, discovered in Turn 7.
|
||||
|
||||
## Turn 5 - proving the acceptance criterion locally, before any push
|
||||
|
||||
Before publishing, the assistant ran `doctor`, `docs verify`, `instructions verify`,
|
||||
`sources coverage`, and `migrate status` locally - all green. Then, to satisfy the issue's own
|
||||
"a broken corpus must turn the run red, or it's decoration" criterion, it deliberately appended
|
||||
an unresolvable wikilink to `kb/entities/systems/Nathan.md`:
|
||||
|
||||
```
|
||||
$ tools/wikitool lint --fail-on-error >/dev/null 2>&1; echo "exit=$?"
|
||||
exit=1
|
||||
$ # (Nathan.md restored from backup)
|
||||
$ tools/wikitool lint --fail-on-error >/dev/null 2>&1; echo "restored exit=$?"
|
||||
restored exit=0
|
||||
```
|
||||
|
||||
This was shown to Torben as evidence, not asserted as fact - the distinction the issue's
|
||||
acceptance criterion was written to force.
|
||||
|
||||
## Turn 6 - shipping and dispatching
|
||||
|
||||
The workflow was published together with the two lint fixes from the sibling transcript, as part
|
||||
of the same 16-file changeset Torben approved with "Freigegeben." (commit `49bd7d4`). Because the
|
||||
actual `schedule` trigger cannot be observed inside a single session - it fires on a clock the
|
||||
session doesn't control - the assistant instead dispatched the workflow manually via the Gitea
|
||||
MCP tool (`actions_run_write` / `dispatch_workflow`) to at least prove the job itself runs. This
|
||||
was stated to Torben as proving "the job, not the timer."
|
||||
|
||||
## Turn 7 - the first dispatch failed, and correctly so
|
||||
|
||||
Run 83 (`workflow_dispatch` on `49bd7d4`) failed at the `doctor` step. Real job log excerpt:
|
||||
|
||||
```
|
||||
OK author: 'Nightly' (from WIKI_AUTHOR)
|
||||
FAIL git-identity: `git config user.name` is not set
|
||||
...
|
||||
FAIL skills: No skills published yet
|
||||
```
|
||||
|
||||
Both FAILs were genuine gaps in the workflow, not wiki drift: `doctor` checks a *working
|
||||
instance*, and a bare `actions/checkout` is not one yet - it's the fresh clone
|
||||
`instructions/bootstrap.md` describes. `.agents/skills/` and `.claude/skills/` are generated and
|
||||
deliberately not committed, so they don't exist until `wikitool instructions sync` runs; and
|
||||
`WIKI_AUTHOR` had covered only the `author` check, not the separate `git-identity` check, because
|
||||
a container has no git configuration at all. Notably, `instructions verify` - which checks the
|
||||
same "published copies match source" fact `docs verify`/`doctor` do - never even ran: the
|
||||
`doctor` failure aborted the job before reaching it, meaning the run's real purpose (checking the
|
||||
corpus) was never attempted. This was the value of running it at all: the failure sat in front of
|
||||
what the run exists to observe, not inside it.
|
||||
|
||||
## Turn 8 - the fix
|
||||
|
||||
`397d8af`: added `git config --global user.name "Nightly"` / `user.email` and
|
||||
`tools/wikitool instructions sync` to the *Tool environment* step, before `doctor` runs. Removed
|
||||
`WIKI_AUTHOR` entirely - one mechanism (a real git identity) now covers both checks instead of
|
||||
two mechanisms covering one each. The reasoning was written into the step's own comment, matching
|
||||
the pattern already used for the failure-visibility omission in Turn 3: recorded at the point of
|
||||
the decision, not only in this transcript, so a future edit doesn't strip the bootstrap step as
|
||||
apparently-redundant ballast.
|
||||
|
||||
## Turn 9 - re-verifying
|
||||
|
||||
Re-dispatched via the same MCP call. Run 85 (`workflow_dispatch` on `397d8af`): all seven steps
|
||||
`success`. Run 84, the ordinary push-triggered `ci.yml` run on the same commit, was also
|
||||
`success` - confirming the shared runner shape still holds for both workflows.
|
||||
|
||||
| Step | Result |
|
||||
|---|---|
|
||||
| System dependencies | success |
|
||||
| `actions/checkout@v7` | success |
|
||||
| Tool environment (incl. bootstrap) | success |
|
||||
| `doctor` | success |
|
||||
| `docs verify` + `instructions verify` | success |
|
||||
| `lint --fail-on-error` | success |
|
||||
| `sources coverage` + `migrate status` | success |
|
||||
|
||||
## Turn 10 - reporting, and leaving the issue open on purpose
|
||||
|
||||
The assistant posted the full diagnosis (Turn 7's log excerpt, the fix, and Run 85's table) as a
|
||||
comment on #9, and explicitly did **not** close it. The unresolved half of the issue's own
|
||||
acceptance criterion - "läuft tatsächlich ohne Push" - cannot be verified from inside this
|
||||
session: both observed runs were `workflow_dispatch`, which proves the job executes but says
|
||||
nothing about whether Gitea 1.26.1 evaluates the cron trigger at all. First possible real
|
||||
observation: `2026-09-01 03:17 UTC`. The assistant recorded this as a persistent-memory note
|
||||
(`project_nightly_schedule_unverified.md`) specifically so that a future session checking on #9
|
||||
looks for a run whose `"event"` is `"schedule"` rather than mistaking a `workflow_dispatch`
|
||||
success for proof the timer fires - a distinction easy to blur once the job itself is known to
|
||||
work.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Workflow | `.gitea/workflows/nightly.yml` added: `schedule` (`17 3 * * *` UTC) + `workflow_dispatch`, no failure-reporting step (Torben's explicit choice) |
|
||||
| Commits | `49bd7d4` (initial, bundled with #20/#22); `397d8af` (bootstrap fix: git identity + `instructions sync` before `doctor`) |
|
||||
| Runs observed | 83 (`workflow_dispatch`, failed at `doctor` - genuine bootstrap gap); 84 (push-triggered `ci.yml`, success); 85 (`workflow_dispatch` post-fix, all 7 steps success) |
|
||||
| Acceptance criteria | Broken-corpus-turns-run-red: proven locally. Failure visibility without the Actions page: Gitea's own notification, as chosen. Green + job-executes: proven (run 85). Green + fires on schedule with no push: **not yet proven** |
|
||||
| Issue | #9 left **open**; a project memory records exactly what to check and when (2026-09-01 03:17 UTC or later, look for `"event":"schedule"`) |
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
# Conversation Transcript - Two Round-Trip Defects Found by an Ingest Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Command output and measured
|
||||
> counts quoted below are real. The subagent's findings are **second-hand relative to this
|
||||
> session** and were independently verified before being acted on - where that verification
|
||||
> changed or extended the claim, the transcript says so.
|
||||
> No credentials appeared in the session.
|
||||
|
||||
Covers two defects an ingest exposed, both fixed the same day: `cite add` deleting any content
|
||||
behind the Footnotes block (`1.5.1`, `bb4123b`, issue #17) and a source page's reference arrays
|
||||
being unreachable while `xref add` wrote a field the schema rejects (`1.6.0`, `ce03749`, issue
|
||||
#18). Both were `prio/1`. Both had lived under a fully green test suite.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - the ingest reports two tool defects
|
||||
|
||||
A subagent ingesting the `touch --set` transcript published successfully (`8524bce`) and then
|
||||
reported two things it had run into. The assistant did **not** act on the report directly.
|
||||
`SOUL.md` treats a confidently asserted fact as the cardinal error, and a subagent's finding is
|
||||
second-hand; both claims were reproduced first.
|
||||
|
||||
### Verification of the first claim - and a hold
|
||||
|
||||
`split_cite_block()` was read directly. The mechanism was exactly as reported: everything from
|
||||
the `## Fußnoten` heading to the end of file is taken as the block, only `[^id]:` lines are kept
|
||||
from it, and every caller reassembles the page as `head + rendered block`.
|
||||
|
||||
A scan over the corpus then measured the exposure rather than estimating it: **8 pages carrying
|
||||
74 lines** in the doomed position, `Detect-Repair Asymmetry` worst at 14.
|
||||
|
||||
**The second ingest was held at this point.** It would have called `cite add` on pages in that
|
||||
list. Continuing would have destroyed content to save a few minutes.
|
||||
|
||||
### Verification of the second claim - and a correction of scope
|
||||
|
||||
`xref_link_source` was read: it writes only the target pages and never the source page's own
|
||||
arrays. Confirmed. `types/source.md` declares `page_ref_fields: [entities, concepts]`, so the
|
||||
`related:` that `xref add` had written was undeclared, and `strip_frontmatter_ref()` swept only
|
||||
declared fields - so nothing could remove it. One command creating a state another could not
|
||||
undo.
|
||||
|
||||
Both were filed as issues (#17, #18) before any code was touched, per
|
||||
`instructions/capture-session.md`: what is still open belongs in the tracker, not in a
|
||||
transcript or in someone's head.
|
||||
|
||||
---
|
||||
|
||||
## Turn 2 - "Korrigiere zunächst #17"
|
||||
|
||||
### The fix, and the option that was rejected
|
||||
|
||||
The block now ends at the **next heading** instead of at end of file. Everything after it - and
|
||||
anything inside it that is not a citation definition - is folded back on to the head.
|
||||
|
||||
Two properties turned out to matter more than the repair itself:
|
||||
|
||||
- **The page self-heals.** Because the rendered block is always emitted last, the first citation
|
||||
operation puts a page that had drifted into the broken layout back in order. `xref add` may
|
||||
keep appending at end of file without doing harm - the contradiction between the two commands
|
||||
is defused rather than merely avoided.
|
||||
- **Loose text inside the block is rescued, not rejected.** The issue's own third acceptance
|
||||
criterion asked for an abort. That was declined with a reason: the same code path runs under
|
||||
`lint` and `corpus_diff`, where raising would refuse to *read* a page instead of reporting it.
|
||||
Rescuing is strictly better than aborting and satisfies the intent - nothing is discarded
|
||||
silently.
|
||||
|
||||
Reading the code added a third affected command the issue had not named: **`rename`** uses the
|
||||
same path and would have deleted the same content. And a second loss path with the same cause -
|
||||
a `[^id]` referenced only in a section *behind* the block counted as unreferenced, so `cite
|
||||
sync` would have pruned its definition as an orphan.
|
||||
|
||||
### The test was proved red before it was trusted
|
||||
|
||||
Rather than asserting that the new test would have caught the defect, the old implementation was
|
||||
reconstructed and run against it:
|
||||
|
||||
```
|
||||
ALTER Code -> Beziehungen erhalten: False
|
||||
NEUER Code -> Beziehungen erhalten: True
|
||||
```
|
||||
|
||||
### Corpus repaired and measured
|
||||
|
||||
`cite sync --all` normalised eleven pages (the eight at risk plus three needing only a
|
||||
re-ordering). Afterwards: **0 pages** with content behind the block, and per page an unchanged
|
||||
count of citation definitions and bullets - checked, not assumed. The line-count asymmetry in
|
||||
the diff came from `summary:` being re-wrapped on to one line, not from lost content.
|
||||
|
||||
---
|
||||
|
||||
## Turn 3 - "Mache mit 18 weiter"
|
||||
|
||||
Three defects, one cause.
|
||||
|
||||
**`xref link-source` writes both directions.** Which field a target lands in follows its
|
||||
**collection**: `kb/entities/` → `entities:`, `kb/concepts/` → `concepts:`. The directory *is*
|
||||
the field name, so a new collection needs no code change here - it needs a type declaring the
|
||||
matching field. That was chosen over a type-to-field map precisely because a map is a second
|
||||
copy of something the type-specs already say.
|
||||
|
||||
**`xref add` refuses an undeclared `related:`**, checking both pages before writing either, so a
|
||||
refusal cannot leave half a link. The message names the fields the type does declare and the
|
||||
command that fills them.
|
||||
|
||||
**`xref remove` sweeps undeclared leftovers**, with the field names taken from the type-specs
|
||||
rather than a constant. An undeclared field that ends up empty is dropped outright: the key was
|
||||
never valid for that type, and `related: []` would keep the page failing validation.
|
||||
|
||||
### The repair, done with the tool
|
||||
|
||||
No `rm --yes`, no hand-edited frontmatter. `xref remove` cleared the leftover, `xref
|
||||
link-source` recorded both concepts in both directions. `lint` reports no schema error in the
|
||||
corpus.
|
||||
|
||||
The referencing concept page came through the cycle **byte-identical** - `xref remove` cleared
|
||||
its back-reference bidirectionally and `link-source` restored it exactly. That was the real
|
||||
proof that the two commands are inverses.
|
||||
|
||||
---
|
||||
|
||||
## What the session concluded about itself
|
||||
|
||||
**The denylist shipped in `1.4.0` that morning was right; its pointer was not.** It refused
|
||||
page-reference fields with "use `xref add` / `xref remove`" - an unverified claim about another
|
||||
command's capabilities, and false for exactly the fields a source page has. A refusal that
|
||||
routes to another command should ship with a test showing that command covers the case.
|
||||
|
||||
**Both defects lived under a fully green suite.** 678 tests passed before the `cite add` tests
|
||||
were written; 67 gate tests passed before the counting change earlier the same day. In each case
|
||||
no test had ever asserted the wrong behaviour, which is how it survived. The same finding
|
||||
strengthens the premise of issue #8: a suite verifies what it knows about.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Stack versions | `1.5.1` (PATCH), `1.6.0` (MINOR) |
|
||||
| Commits | `bb4123b`, `ce03749` |
|
||||
| Tests | 689 passing, in the normal and the hardened environment (11 new) |
|
||||
| Corpus | 8 pages de-risked and normalised; the schema error on `main` repaired |
|
||||
| Gitea | #17 and #18 closed |
|
||||
+360
@@ -0,0 +1,360 @@
|
||||
# Conversation Transcript - Versioning, CI/CD and Content Migration Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-30 (session spanned 2026-08-29 to 2026-08-30)
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Reconstructed by the assistant
|
||||
> at the end of the session. Torben's questions and decisions are rendered closely; the
|
||||
> assistant's reasoning is condensed. Command outputs quoted below are real. No credentials
|
||||
> appeared in the session; internal hostnames mentioned are already documented in `kb/`.
|
||||
> Revised 2026-08-30 with turns 10-13, which happened after the first version was written; the
|
||||
> model attribution was corrected at the same time (the first version said "Claude Sonnet 5",
|
||||
> the session log records `claude-opus-5` for all 501 messages).
|
||||
|
||||
Covers three pieces of work that turned out to be the same mechanism seen from different ends:
|
||||
stack versioning with CI and release artifacts (shipped as `0.1.0`, then `1.0.0`), a content
|
||||
migration strategy built on top of it, and finally getting the pipeline to actually run.
|
||||
Resulting commits: `2508f7a`, `7d63d61`, `c3034ab`, `db03b08`, `aace3e7`, `401d700`, `b94166b`.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - "Bearbeite den CI/CD-Punkt aus todo.md ... Was denkst du?"
|
||||
|
||||
Torben invoked the `stack-dev` skill and asked for the CI/CD item from `TODO.md` to be built
|
||||
such that semantic versioning comes with it, that the version then drives update detection, and
|
||||
that release files come out with which a wiki can be set up.
|
||||
|
||||
Assistant proposal, after reading `TODO.md`, `tools/CONTRACT.md`, `dist_cmd.py`, `cli.py`,
|
||||
`docs_verify.py` and `.gitignore`:
|
||||
|
||||
- A root `VERSION` file versioning the **stack**, not the content. Key argument: no auto-bump
|
||||
from commit messages, because `publish --message "ingest: ..."` writes content commits into
|
||||
the same repository, so a conventional-commit reading would turn every ingest into a release.
|
||||
- A `wikitool version` command group; `.gitea/workflows/ci.yml` with the four steps from the
|
||||
TODO plus a version gate and an export smoke test; `.gitea/workflows/release.yml` triggered by
|
||||
a `VERSION` change, tagging and publishing a `dist export` tarball.
|
||||
- Update detection via a stamp file written into every export, compared against the origin's
|
||||
release feed.
|
||||
- Explicitly *not* shipping CI into a distributed instance, because `runs-on: linux-docker` is a
|
||||
site-specific runner label.
|
||||
|
||||
## Turn 2 - Three design decisions
|
||||
|
||||
The assistant asked three questions with recommendations. Torben's answers:
|
||||
|
||||
| Question | Decision |
|
||||
|---|---|
|
||||
| Network call in `wikitool` vs. strictly offline | **`version check` may make the network call** - own command, no key, timeout, injectable fetch so tests never touch a network |
|
||||
| Build the upgrade path now, or detection only | **Detection first**, `dist upgrade` later |
|
||||
| Start at `1.0.0` or `0.1.0` | **`0.1.0`** (against the assistant's recommendation) |
|
||||
|
||||
Because `0.x` was chosen, the assistant defined compatibility as "same leftmost non-zero
|
||||
component" (the rule Cargo's caret ranges use), so that `0.1.x -> 0.2.0` carries the
|
||||
migration signal that `MAJOR` carries from `1.0.0` on.
|
||||
|
||||
## Turn 3 - "Prüfe die Actions gegen den Gitea Runner, die Doku liegt im Wiki"
|
||||
|
||||
Sent mid-turn. The assistant ran `wiki-query` against the corpus before writing the workflow
|
||||
YAML. **The wiki corrected two assumptions:**
|
||||
|
||||
1. Authentication is `${{ gitea.token }}`, documented on the `Act Runner` page under
|
||||
"Gitea-Token" - not `secrets.GITEA_TOKEN`, and not a 1Password secret, since nothing in these
|
||||
workflows leaves the instance.
|
||||
2. The label-to-image mapping for `linux-docker` is **the one thing the wiki does not record**,
|
||||
and it decides whether a `python3` exists at all. The job image was therefore named
|
||||
explicitly (`container: image: debian:trixie-slim`, the base Scenario B already proves works
|
||||
with `actions/checkout@v4`).
|
||||
|
||||
Also confirmed from the corpus: routing labels are `linux-docker`, `container-builder`,
|
||||
`k3s-deploy`; `actions/upload-artifact@v3` (v4 support is limited).
|
||||
|
||||
A local finding of the same kind: setting `WIKI_TRACE=0` job-wide breaks two telemetry tests
|
||||
that assert a trace is written, so CI sets `WIKI_TRACE_DIR` outside the workspace instead.
|
||||
|
||||
## Turn 4 - Publish, and the Mass-Update Gate
|
||||
|
||||
`wikitool publish` exited 42 with a 21-file breakdown, which was reproduced in full for Torben.
|
||||
He replied "Freigegeben", and the clearance line published `2508f7a`.
|
||||
|
||||
## Turn 5 - A correction: the origin repository is private
|
||||
|
||||
Attempting to verify whether CI had run, the assistant discovered that its own earlier inference
|
||||
was wrong. Before the push, `version check` had returned HTTP 404 and this was read as "no
|
||||
release published yet, so the feed is anonymously readable". It is not:
|
||||
|
||||
```
|
||||
$ curl -s -w "\nHTTP:%{http_code}\n" ".../api/v1/repos/torben/llm-wiki-test1"
|
||||
{"message":"not found",...} HTTP:404
|
||||
$ curl -s -w "\nHTTP:%{http_code}\n" ".../api/v1/repos/torben/definitely-not-a-repo-xyz"
|
||||
{"message":"not found",...} HTTP:404
|
||||
```
|
||||
|
||||
Gitea answers an anonymous caller identically for an invisible repository and a non-existent
|
||||
one. Consequence: `WIKITOOL_UPDATE_TOKEN` is a requirement rather than an exception while the
|
||||
repo stays private, and **no conclusion about CI state can be drawn from outside**. Corrected in
|
||||
`CHANGES.md` and `INSTALL.md`, published as `7d63d61`.
|
||||
|
||||
## Turn 6 - "Die Runner laufen nicht" + the next task
|
||||
|
||||
Torben: the runners do not run; he will debug it later at his PC and will provide a **Gitea MCP
|
||||
server** for it. (Dictated "kaufen" for "laufen".) Then the new task:
|
||||
|
||||
> "Wie gehen wir denn mit semantischen Änderungen am Content um, die machen wir ja gerade
|
||||
> mehrfach. Lass uns eine Migrationsstrategie erarbeiten und umsetzen. Wir brauchen erst mal
|
||||
> einen Plan."
|
||||
|
||||
## Turn 7 - Research: the methodology already existed and had been deleted
|
||||
|
||||
The assistant recovered the closed `translate-kb-de` workshop from git history
|
||||
(`git show de0862f:work/translate-kb-de/README.md` and `plan.md`) and found a complete working
|
||||
methodology that had been thrown away when the workshop closed:
|
||||
|
||||
- Units sized by the **iteration budget** (30 calls → ceiling near 24 pages, target ≤ 21), and
|
||||
batches sized separately by the **Mass-Update Gate** - conflating the two "cost eleven
|
||||
unnecessary clearances in the first cut of this plan".
|
||||
- Per unit, **before anything else**: frontmatter, H1, wikilink targets and cite-ids compared
|
||||
against `HEAD`.
|
||||
- `lint` read in full every unit, not just the plausibly-affected sections - unit 1's
|
||||
frontmatter bug surfaced as a schema error on a field nobody had edited.
|
||||
- Summaries written by the orchestrating session, never pasted from a subagent ("they
|
||||
embellish: one turned 'measuring application performance and responsiveness' into 'Latenz und
|
||||
Durchsatz unter Lastbedingungen'").
|
||||
|
||||
Two further findings from reading the code:
|
||||
|
||||
- `kb_scan.extract_wikilinks()` returns a **set**. That is correct for `lint` (does the
|
||||
reference resolve?) and wrong for a migration check (did one go missing?). Three of the four
|
||||
defects the translation found had unchanged link sets and only changed counts.
|
||||
- `sections.py` already documents a named migration pattern in its docstring: canonical name
|
||||
plus aliases is "what lets a corpus migrate page by page instead of all at once", and removing
|
||||
an alias is a breaking change rather than a cleanup.
|
||||
|
||||
## Turn 8 - Plan rejected, with three substantive points
|
||||
|
||||
Torben rejected the first plan:
|
||||
|
||||
> "Lass uns doch mit Version 1.0.0 anfangen, damit wir den 0.* Sonderfall nicht implementieren
|
||||
> müssen.
|
||||
> Wo speichern wir denn die aktuelle Version einer KB?
|
||||
> Wie decken wir ab, dass eine KB ggf. über mehrere Versionen aktualisiert werden muss? Wir
|
||||
> müssen ja eigentlich sowas wie 'migrate from 1.3.1 to 1.4.0' und dann 'migrate from 1.4.7 to
|
||||
> 2.0.0' in Sequenz ausführen?
|
||||
> In diesem Kontext müssen wir keine Beta oder ähnliche Version Keys unterstützen. x.y.z ist die
|
||||
> maximale Granularität, die wir brauchen."
|
||||
|
||||
The second question exposed a real error in the plan: it had **conflated the stack version with
|
||||
the content version**. An instance can carry machinery 1.4.0 while its content is still in 1.2.0
|
||||
shape - and that is the state every upgrade passes through. The first plan had written this off
|
||||
as a "known limitation" instead of solving it.
|
||||
|
||||
Revised design:
|
||||
|
||||
| Fact | File | Written by | Answers |
|
||||
|---|---|---|---|
|
||||
| Stack version | `VERSION` | `version bump` | which machinery is installed |
|
||||
| Release stamp | `.wikitool-release.json` | `dist export` | where that machinery came from |
|
||||
| **KB version** | `.wikitool-kb.json` | `migrate done` | what shape the content is in |
|
||||
|
||||
Separate files because the two have opposite rules - the stamp is generated and must never be
|
||||
hand-edited, the KB state is mutable instance state.
|
||||
|
||||
On sequencing: `migrate status` builds the interval `(kb_version, VERSION]` from the migration
|
||||
documents and orders it ascending; 1.3.1 → 2.0.0 runs 1.4.0, then 1.7.0, then 2.0.0. That no
|
||||
migration targets 1.3.x is not a special case - it is simply not in the interval. `migrate done`
|
||||
refuses any version that is not the next link, making a skip impossible and an interrupted
|
||||
multi-step upgrade resumable.
|
||||
|
||||
Starting at `1.0.0` also removed a self-contradiction the assistant had shipped in `0.1.0`: the
|
||||
guidance in `stack-dev/SKILL.md` assigned `--minor` to both "new capability" and "requires
|
||||
migration", which cannot both be true under `0.x`. The `compat_key` code needed no change - it
|
||||
is stated uniformly - only the guidance did.
|
||||
|
||||
Plan approved on the second attempt.
|
||||
|
||||
## Turn 9 - Implementation and verification
|
||||
|
||||
Built: `corpus_diff.py`, `kb_state.py`, `migrate_cmd.py` (`list`/`status`/`verify`/`done`/
|
||||
`baseline`), `instructions/migrate-corpus.md`, the `migrates_to:`/`migration_kind:` schema
|
||||
fields, boundary enforcement in both `version bump` and `docs verify`, and a `kb-version` check
|
||||
in `doctor`. Deliberately not built: mechanical runner primitives (a DSL for zero migrations)
|
||||
and `dist upgrade`.
|
||||
|
||||
**Verification against the real corpus, which unit tests cannot replace:**
|
||||
|
||||
1. `migrate verify --from 1c3ca39` over 248 pages: zero invariant violations in 2.2 s - but 13
|
||||
reported "removed pages" that are not pages. The historical side listed every `.md` under
|
||||
`kb/` while the working-tree side used `iter_kb_pages`, which skips `COLLECTION.md`,
|
||||
`INDEX.md` and the kb-root meta files. **Two different definitions of "page."** Fixed with a
|
||||
shared `kb_scan.is_page_path`, and pinned by a regression test.
|
||||
2. Negative control: one of two `[[Docker]]` occurrences removed from `kb/entities/tools/Act
|
||||
Runner.md`, leaving the link *set* unchanged.
|
||||
|
||||
```
|
||||
$ tools/wikitool migrate verify --from HEAD --fail-on-error
|
||||
248 page(s) compared, 0 added, 0 removed, 1 finding(s).
|
||||
- kb/entities/tools/Act Runner.md: wikilinks - 'Docker' 2->1
|
||||
$ tools/wikitool lint --fail-on-error # exit 0, all 21 checks silent
|
||||
```
|
||||
|
||||
This is the claim the whole strategy rests on: `lint` reads a single revision, so a reference
|
||||
that went missing leaves a corpus that is still perfectly consistent.
|
||||
|
||||
3. `version bump --major` correctly refused without a migration document, then succeeded with
|
||||
`--no-migration "no distributed instance exists yet; 1.0.0 is the migration baseline"` - the
|
||||
new mechanism's first real use.
|
||||
4. The dev tree itself became the first `migrate baseline` case: it predates `.wikitool-kb.json`,
|
||||
but its content never lagged its machinery, so `1.0.0`.
|
||||
5. 630 tests, `docs verify`, `instructions verify`, `lint --fail-on-error`, and a full
|
||||
`setup-instance.md` replay against a fresh `dist export`.
|
||||
|
||||
Published as `c3034ab` after the Mass-Update Gate breakdown (29 counted files) was reproduced
|
||||
and cleared.
|
||||
|
||||
---
|
||||
|
||||
## Turn 10 - "Store this conversation in the wiki as raw source in /raw/notes"
|
||||
|
||||
The first version of this file. `raw/CONTRACT.md` lists "conversation transcripts" under
|
||||
`notes/` explicitly, and a sibling already existed (`Conversation Transcript - AGENTS.md Skill
|
||||
Restructuring Session 2026-08-04.md`), so the format was inherited rather than invented. Labelled
|
||||
a summary rather than a log, because a verbatim reconstruction would have been fabrication.
|
||||
Published as `db03b08`.
|
||||
|
||||
Immediately afterwards the Gitea MCP server became available, and a read-only diagnosis of the
|
||||
long-standing "the runners don't run" item produced the opposite of what had been assumed:
|
||||
|
||||
```
|
||||
list_runs -> 6 runs; 46-51 all conclusion: failure
|
||||
OCI runtime exec failed: exec: "node": executable file not found in $PATH
|
||||
❌ Failure - Main actions/checkout@v4
|
||||
exitcode '127': command not found
|
||||
```
|
||||
|
||||
The runners had been picking the workflows up all along. `actions/checkout` is a JavaScript
|
||||
action that act_runner executes with `node` **inside the job container**, and the pinned
|
||||
`debian:trixie-slim` has none. The image was pinned precisely as a precaution against the
|
||||
undocumented `linux-docker` label mapping - the precaution caused the failure.
|
||||
|
||||
## Turn 11 - "Check the gitea-mcp repo, branch ci-build"
|
||||
|
||||
Torben pointed at two working workflows on another repo and asked for their shape to be picked
|
||||
up, plus: the wiki workflows must not run on content changes.
|
||||
|
||||
`torben/gitea-mcp@ci-build`, `ci-build.yaml`, runs 42-45 green. The whole answer was one
|
||||
line in an apt list:
|
||||
|
||||
```yaml
|
||||
- name: Install CI Dependencies
|
||||
run: apt-get install -y --no-install-recommends git nodejs curl unzip ca-certificates build-essential
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v7
|
||||
```
|
||||
|
||||
`nodejs` installed **before** the checkout, and checkout at `@v7`. Both were adopted in `ci.yml`
|
||||
and `release.yml`. `runs-on: linux-docker` was kept: runs 46-51 proved it routes and starts the
|
||||
container, so the label was never the problem.
|
||||
|
||||
For the second half, `paths-ignore` on everything `publish` touches. Three choices are worth
|
||||
recording because they are all *refusals to infer*: `kb/CONTRACT.md` is deliberately not
|
||||
excluded (it lives under a content directory but belongs to the stack); no `!**/CONTRACT.md`
|
||||
negation, because Gitea's support for negated filter patterns is undocumented; and the list is
|
||||
written twice instead of shared through a YAML anchor, because GitHub's parser rejects anchors
|
||||
outright and Gitea's is not documented to accept them. The patterns fail open - anything
|
||||
unanticipated still triggers CI. Published as `aace3e7`.
|
||||
|
||||
## Turn 12 - The first green run finds a real bug
|
||||
|
||||
Run 52 got past checkout and reached `pytest` for the first time ever. Two of 630 tests failed:
|
||||
|
||||
```
|
||||
FAILED test_new_page.py::test_new_source_author_falls_back_to_git_config
|
||||
FAILED test_provenance.py::test_new_source_with_multiple_raw_files
|
||||
AssertionError: ERROR No author configured for this instance.
|
||||
2 failed, 628 passed in 13.85s
|
||||
```
|
||||
|
||||
`config.default_author()` runs `git config user.name` with `cwd=config.ROOT`; the fixture root
|
||||
is not a repository, so the answer came from the **global git config of whoever ran the suite**.
|
||||
In the container, as root, there is none. Both tests had been green on every developer machine
|
||||
for months without ever testing what their names claimed.
|
||||
|
||||
Fixed in the tests rather than by giving CI an identity: the first now makes its fixture root a
|
||||
real repository with a *local* `user.name` and asserts the concrete name, which tests the
|
||||
fallback more sharply than before; the second sets `WIKI_AUTHOR`, since it is a `raw_files:`
|
||||
test and authorship was only a precondition. Verified locally with
|
||||
`GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null pytest` - 630 passed.
|
||||
|
||||
That made it `1.0.1`, and because `VERSION` moved, `release.yml` fired on its own. It answered
|
||||
the last open question of the session without being asked:
|
||||
|
||||
```
|
||||
Created release v1.0.1 (id 54).
|
||||
Uploaded llm-wiki-stack-1.0.1.tar.gz.
|
||||
Uploaded llm-wiki-stack-1.0.1.tar.gz.sha256.
|
||||
```
|
||||
|
||||
`${{ gitea.token }}` may create releases and tags and upload assets. No Actions secret with
|
||||
`write:repository` is needed. Published as `401d700`.
|
||||
|
||||
## Turn 13 - "Can we take the CI/CD part out of todo.md?" then: move it to issues
|
||||
|
||||
Two cleanups. First `TODO.md`: the entire retrospective went out (64 lines), because the same
|
||||
history was already in the `0.1.0`, `1.0.0` and `1.0.1` changelog entries and a second copy is
|
||||
exactly the drifting duplicate the stack avoids everywhere else. Published as `b94166b`.
|
||||
|
||||
Then the remaining work moved to Gitea issues #7-#11 - `dist upgrade`, hardening the suite
|
||||
against silent environment dependencies, the nightly drift check, coverage, and confirming
|
||||
`paths-ignore` actually matches. `TODO.md` now links to them instead of describing them.
|
||||
|
||||
The split was made along a line worth naming: issue #11 is explicitly *an observation, not a
|
||||
build task* - the proof arrives on its own with the next content-only publish. Filing it as work
|
||||
would have invited someone to build machinery for a question that answers itself.
|
||||
|
||||
---
|
||||
|
||||
## Decisions worth carrying forward
|
||||
|
||||
- **The version describes the stack; content has its own version.** Conflating them makes the
|
||||
mid-upgrade state unrepresentable.
|
||||
- **Compatibility = leftmost non-zero component.** Uniform across `0.x` and `1.x`; from `1.0.0`
|
||||
it reads as plain semver. No pre-release suffixes - a second ordering rule would have to be
|
||||
honoured by the release feed, the migration chain and the compatibility check alike.
|
||||
- **Migrations are `manual: true` instructions** under `instructions/migrations/`, so they ship
|
||||
with `dist export` without a second export path. Baseline is `1.0.0`; anything older is
|
||||
re-exported, not migrated.
|
||||
- **Count, never set**, when asking whether a rewrite dropped something.
|
||||
- **CI tags, never an agent** - which is what keeps AGENTS.md invariant 5 intact.
|
||||
- **The wiki corrected the assistant twice** in this session (the Gitea token form, the runner
|
||||
image), and the assistant's own inference was wrong twice more: anonymous API access, and the
|
||||
claim that the runners never accepted the workflows. Checking the corpus before writing
|
||||
infrastructure code paid for itself; inferring past what the corpus actually said did not.
|
||||
- **A CI run is evidence; a local run is a habit.** Two tests asserted a fallback they never
|
||||
exercised, and stayed green for months, because every machine that ran them happened to
|
||||
satisfy the precondition. Nothing short of a foreign environment would have found it.
|
||||
- **The failure and the fix lived in different places.** The symptom was in CI, the defect was
|
||||
in the tests. Giving CI a git identity would have made the run green and left the bug.
|
||||
|
||||
## What this changed about the runner, in one place
|
||||
|
||||
For anyone writing the next workflow against the CI runner - do not re-derive this:
|
||||
|
||||
- A pinned `container:` image must `apt-get install nodejs` **as the first step, before
|
||||
checkout**. act_runner executes JavaScript actions with `node` inside the job container.
|
||||
- `actions/checkout@v7`, `actions/upload-artifact@v3` (v4 is limited on this instance).
|
||||
- `debian:trixie-slim` works and carries python3 3.13. Labels `linux-docker` and
|
||||
`container-builder` both accept a job that names its own image.
|
||||
- `${{ gitea.token }}` suffices for releases, tags and asset uploads.
|
||||
- The repo is **private**, and Gitea answers anonymous callers with an identical `404` for an
|
||||
invisible repo and a non-existent one - so `curl` proves nothing. Read runs through the MCP
|
||||
server.
|
||||
|
||||
## Open at the end of the session
|
||||
|
||||
The pipeline runs. `v1.0.1` is published with tarball and `.sha256`. What remains is tracked as
|
||||
Gitea issues rather than prose: **#7** `dist upgrade`, **#8** hardening the test suite, **#9**
|
||||
the nightly drift check, **#10** coverage, **#11** confirming `paths-ignore` matches.
|
||||
|
||||
One item is genuinely unresolved rather than merely unbuilt: whether Gitea evaluates the
|
||||
`paths-ignore` patterns as expected. It needs no work, only a look at `list_runs` after the next
|
||||
content-only publish - and after this session, that is exactly the kind of claim that should not
|
||||
be assumed.
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
# Conversation Transcript - Write-Once Frontmatter Fields and touch --set Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), llm-wiki-test1 workspace
|
||||
> Collected: 2026-08-31
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's three design
|
||||
> decisions are recorded verbatim as the options he was shown and the ones he chose; command
|
||||
> output quoted below is real; the assistant's reasoning is condensed.
|
||||
> No second-hand material. No credentials appeared in the session.
|
||||
> One of two transcripts cut from this stretch of the session; the other covers the
|
||||
> Mass-Update Gate's counting rule and the measured iteration-budget calibration.
|
||||
|
||||
Covers Gitea issue #14, implemented as `touch --set/--add/--remove` in stack `1.4.0`
|
||||
(`dbe2f73`). Issue #14 closed, #16 opened for the part deliberately left out.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - "Führe 14 aus und lege mir die nötigen Entscheidungen jeweils mit Hintergrund vor"
|
||||
|
||||
The assistant read `touch.py` before proposing anything, and found the groundwork already in
|
||||
place: `validate_fields()` validates **per field** rather than per document, which is exactly
|
||||
what a `--set` needs. Its docstring explains why - whole-document validation would refuse to
|
||||
bump `modified:` on a page that is invalid for some unrelated reason, "which is exactly the page
|
||||
most in need of maintenance".
|
||||
|
||||
Three decisions were put to Torben, each with the trade-off spelled out.
|
||||
|
||||
### Decision 1 - which fields may `--set` write?
|
||||
|
||||
| Option | Consequence |
|
||||
|---|---|
|
||||
| **Denylist** (chosen) | Everything the schema declares, minus a short reasoned block list. A field added to a type-spec works immediately. |
|
||||
| Allowlist | A maintained set of writable fields. Safer against surprises, but every new schema field needs a code change. |
|
||||
| Denylist minus the already-flagged fields | Also blocks `summary`/`provenance`/`confidence-base`, which have their own options. Prevents two ways to do one thing, at the cost of a surprising refusal. |
|
||||
|
||||
**Torben chose the denylist.** The argument that carried it: an allowlist is a second copy of
|
||||
the schema, and the copy is the one that drifts - AGENTS.md invariant 8 applied to a constant.
|
||||
|
||||
Blocked, each naming the command that owns the field instead:
|
||||
|
||||
- `type:` - changes the page's schema *and* its directory; that is `page-lifecycle.md`.
|
||||
- `confidence:` - derived from `confidence_base` by decay, not authored.
|
||||
- `related:`/`sources:`/`entities:`/`concepts:` - `xref` maintains the reverse direction and
|
||||
the body bullets; a bare frontmatter write would leave the other half stale.
|
||||
|
||||
### Decision 2 - what does `--set tags=a,b` mean for a list that already has values?
|
||||
|
||||
| Option | Consequence |
|
||||
|---|---|
|
||||
| Replace only | One rule. Adding a single tag means naming the whole list. |
|
||||
| **Replace plus `--add`/`--remove`** (chosen) | Three options instead of one, but a single element can be changed without reading the list first. Leaves open what `--remove` does with an absent element. |
|
||||
|
||||
**Torben chose replace plus `--add`/`--remove`.**
|
||||
|
||||
The open sub-question - `--remove` on an element that is not there - the assistant decided
|
||||
itself and said so: **it succeeds and reports it.** Idempotent like `xref remove`, because a
|
||||
repair command that refuses to run twice is one nobody dares script; but never silent, because a
|
||||
silent no-op looks exactly like a successful removal, and that is how a mistyped element name
|
||||
hides.
|
||||
|
||||
### Decision 3 - does this pass also deliver `raw rename`?
|
||||
|
||||
| Option | Consequence |
|
||||
|---|---|
|
||||
| **`touch --set` only** (chosen) | Stays `size/S`. The file move becomes possible in two steps (`git mv`, then `touch --set raw_files=…`). The remaining gap gets its own issue. |
|
||||
| Both in one release | Closes #14 fully and removes the intermediate state, at `size/M`: backward search over all `raw_files:` references, behaviour with multiple owners, contract lines for two commands. |
|
||||
|
||||
**Torben chose the narrower pass.** `raw rename` became issue #16 (`prio/2`, `size/S`).
|
||||
|
||||
---
|
||||
|
||||
## Turn 2 - implementation
|
||||
|
||||
### What moved
|
||||
|
||||
`_coerce_set_value`, `_parse_set_fields` and `_check_raw_files_exist` left `new_page.py` for
|
||||
`commands/_util.py` and lost their leading underscores. Two commands, one implementation -
|
||||
otherwise `touch --set` would have inherited the comma bug from #12 on day one. A test covers
|
||||
exactly that: an existing raw file whose name contains a comma, referenced through `\,`, read
|
||||
back as a single path.
|
||||
|
||||
`raw_files:` written by `touch` gets the same filesystem existence check `new` performs. It is
|
||||
I/O, not a data shape, so no schema can express it.
|
||||
|
||||
### Two refusals, deliberately worded differently
|
||||
|
||||
A blocked field is a routing problem, so the message names the command that owns it. An unknown
|
||||
field is a typo or the wrong page type, so the message lists what the page actually has - the
|
||||
value is learning that `tags` was meant:
|
||||
|
||||
```
|
||||
$ tools/wikitool touch --page "Diff-Reviewable Agent Edits" --set "sources=Source - X"
|
||||
ERROR `sources` cannot be set with --set: page-reference field - use `wikitool xref add` / `xref remove`
|
||||
|
||||
$ tools/wikitool touch --page "Diff-Reviewable Agent Edits" --set "tag=x"
|
||||
ERROR Type types/concept.md declares no field 'tag'.
|
||||
Settable fields for this page: concept_type, confidence_base, created,
|
||||
modified, provenance, summary, tags
|
||||
```
|
||||
|
||||
### A test-harness trap, fixed once
|
||||
|
||||
The existing `test_touch.py` called the Typer callback directly with a full argument list, so
|
||||
three new options broke seven call sites with `TypeError: 'OptionInfo' object is not iterable`.
|
||||
A callback invoked directly receives `OptionInfo` objects for whatever the caller omits - the
|
||||
same hazard `dist_cmd.py` avoids by keeping its logic beside the wrapper. The tests now go
|
||||
through a `_touch(**overrides)` helper that supplies every option, so the next option costs one
|
||||
line rather than seven.
|
||||
|
||||
---
|
||||
|
||||
## Turn 3 - the repair that proves it
|
||||
|
||||
`kb/concepts/Diff-Reviewable Agent Edits.md` had been created hours earlier by an ingest whose
|
||||
`--set tags=` value carried a trailing comma; everything after the separator was lost. That
|
||||
subagent correctly worked through all three ways out and rejected each: `touch` could not set
|
||||
`tags:`, hand-editing frontmatter comes too close to invariant 1, and `rm` + `new` would have
|
||||
broken the `concepts:` reference the source page already held. The page kept `[agent-workflow]`
|
||||
permanently, because of a comma.
|
||||
|
||||
Against the real corpus:
|
||||
|
||||
```
|
||||
$ tools/wikitool touch --page "Diff-Reviewable Agent Edits" --add "tags=context-engineering,tooling"
|
||||
tags: added 'context-engineering', 'tooling'
|
||||
OK Touched kb/concepts/Diff-Reviewable Agent Edits.md
|
||||
|
||||
$ tools/wikitool touch --page "Diff-Reviewable Agent Edits" --add "tags=context-engineering" --no-date
|
||||
OK 'Diff-Reviewable Agent Edits' already up to date; nothing to change.
|
||||
|
||||
$ tools/wikitool touch --page "Diff-Reviewable Agent Edits" --remove "tags=vertippt" --no-date
|
||||
tags: not present, nothing removed: 'vertippt'
|
||||
OK 'Diff-Reviewable Agent Edits' already up to date; nothing to change.
|
||||
```
|
||||
|
||||
The page now carries `[agent-workflow, context-engineering, tooling]`.
|
||||
|
||||
---
|
||||
|
||||
## The defect this closed, stated once
|
||||
|
||||
A field `new` wrote once - `tags:`, `raw_files:`, `source_url:` - was afterwards unreachable.
|
||||
`touch` did not know it; hand-editing frontmatter is what the tool exists to prevent; deleting
|
||||
and recreating the page breaks every reference already pointing at it. And `new` is **not
|
||||
idempotent**, so the window to get the value right was exactly one command wide.
|
||||
|
||||
The evidence that this was a rate rather than an accident: three failures across three
|
||||
consecutive ingests on the same day, at two different fields, by three different agents. One of
|
||||
them was a trailing comma.
|
||||
|
||||
---
|
||||
|
||||
## Outcome
|
||||
|
||||
| Artifact | Result |
|
||||
|---|---|
|
||||
| Stack version | `1.4.0` (MINOR - new capability, backwards compatible) |
|
||||
| Commit | `dbe2f73` - 9 files |
|
||||
| Tests | 674 passing, in the normal and the hardened environment |
|
||||
| Gitea | #14 closed with the three decisions recorded; #16 opened (`prio/2`, `size/S`) |
|
||||
| Corpus | The unrepairable page repaired |
|
||||
@@ -0,0 +1,25 @@
|
||||
# Docker Cheatsheet
|
||||
|
||||
## Volume Management
|
||||
|
||||
### Resolve Overlay FS ID
|
||||
|
||||
```bash
|
||||
for container in $(docker ps --all --quiet --format '{{ .Names }}'); do
|
||||
echo "$(docker inspect $container --format '{{.GraphDriver.Data.MergedDir }}' | grep -Po '^.+?(?=/merged)' ) = $container"
|
||||
done
|
||||
```
|
||||
|
||||
Listet die Overlay-Verzeichnisse in `/var/lib/docker/overlay2` auf und ordnet sie den Containern zu, so kann z.B. bei Fehlern in Backups oder gelockten Dateien etc. auf den Container zurück geschlossen werden.
|
||||
|
||||
Ausgabebeispiel:
|
||||
|
||||
```
|
||||
/var/lib/docker/overlay2/768... = starwars
|
||||
/var/lib/docker/overlay2/e7e... = nextcloud-hpb_janus_1
|
||||
/var/lib/docker/overlay2/bb5... = nextcloud-hpb_spreedbackend_1
|
||||
/var/lib/docker/overlay2/475... = nextcloud-hpb_nats_1
|
||||
/var/lib/docker/overlay2/e85... = grafana
|
||||
/var/lib/docker/overlay2/d0a... = privatebin
|
||||
...
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
# Wine
|
||||
|
||||
## Configuratoin
|
||||
|
||||
Change in `pacman.conf:`
|
||||
|
||||
```
|
||||
[options]
|
||||
# Prevent wine file bindings
|
||||
NoExtract = usr/lib/binfmt.d/wine.conf
|
||||
NoExtract = usr/share/applications/wine.desktop
|
||||
```
|
||||
|
||||
## Bottles Runtimes
|
||||
|
||||
* Soda: Wine Valve, +Staging, +Proton
|
||||
* Caffe: Wine Upstream, +Staging, +Proton
|
||||
* GE Wine
|
||||
* Lutris
|
||||
* Lutris-Ge-Lol
|
||||
* Vaniglia, Wine Upstream, +Staging
|
||||
* GE Proton: Wine Valve, +Staging, +Proton, +Steam
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
# Instruction Set: Restructure AGENTS.md into Cross-Platform Agent Skills
|
||||
|
||||
You are restructuring the `llm-wiki-test1` repository's monolithic `AGENTS.md` (~30KB) into a set of discrete, invocable agent skills that work identically across **GitHub Copilot (VS Code)**, **Claude Code**, **Codex CLI**, and **Mistral Vibe**. This document contains all background context, rationale, and concrete requirements needed to do this restructuring correctly. Read it fully before making changes.
|
||||
|
||||
---
|
||||
|
||||
## 1. Why this restructuring is happening
|
||||
|
||||
### 1.1 Current state
|
||||
|
||||
`AGENTS.md` is a single file describing five workflows (INGEST, QUERY, LINT, CREATE, UPDATE), the wiki's frontmatter schema, entity/concept type tables, provenance/citation rules, naming conventions, and a confidence-scoring formula. It is loaded in full regardless of which workflow the LLM is actually executing.
|
||||
|
||||
The repo already has a deterministic CLI, `tools/wikitool` (Python, backed by `tools/wiki_tools/`), which handles all mechanical operations: frontmatter scaffolding (`new_page.py`), structural linting (`lint.py`), link-graph analysis (`repo_scan.py`), and source/citation provenance tracking (`provenance.py`). The LLM's job is prose and judgment; `wikitool` guarantees structural correctness. This split (deterministic tool + LLM judgment) is already correct and should be preserved and reinforced, not undone.
|
||||
|
||||
### 1.2 The problem with the monolith
|
||||
|
||||
Evidence from the LLM-wiki ecosystem (see `awesome-llm-wiki`, https://github.com/gavischneider/awesome-llm-wiki) converges on the same diagnosis:
|
||||
|
||||
- **Token economics**: a full ingest against a compiled wiki costs roughly 5–8× the source token count because the agent reads the entire relevant instruction set plus target pages; a query against just an index plus 2–4 pages costs a fraction of that. A monolithic instructions file loaded on every task pays the higher cost even for simple queries.
|
||||
- **Scale ceiling**: single-context approaches (one big instructions file, full index re-read every session) start degrading in quality once a wiki passes roughly 100–200 pages — the LLM starts missing connections and quality drops. One documented case (RTFM / retrieval-layer approach) cut token usage by 61% and improved resolve rate from ~55-64% to 100% on an 8,260-file corpus by serving metadata first and expanding only what's needed, instead of loading everything.
|
||||
- **Governance vs. procedure**: not everything needs splitting. Declarative rules (schema, provenance requirements, confidence formula, naming conventions) are cheap to keep centralized. It's the **procedural workflows** (multi-step operations like INGEST or LINT) that benefit from being isolated, because each is only relevant to one task at a time.
|
||||
|
||||
### 1.3 The precedent this restructuring follows
|
||||
|
||||
Several implementations in the ecosystem already do exactly this split for a Karpathy-pattern wiki:
|
||||
|
||||
- **`kfchou/wiki-skills`**: six standalone Claude Code skills — `wiki-init`, `wiki-ingest`, `wiki-query`, `wiki-lint`, `wiki-update`, `wiki-audit` — each its own file, loaded only when invoked. This is the closest 1:1 structural analog to what we're building (general-purpose/IT wiki, not a personal journal).
|
||||
- **Leo Alexandru's production setup**: twelve skills total, organized by cadence (daily/capture/maintenance), each a subfolder with its own `skill.md`, invoked via `/skill-name`. Demonstrates this scales in real daily use.
|
||||
- **Farza's personal wiki skill** (https://gist.github.com/farzaa/c35ac0cfbeb957788650e36aabea836d): the origin of the command-scoped pattern (`/wiki ingest`, `/wiki absorb`, `/wiki query`, `/wiki cleanup`, `/wiki breakdown`, `/wiki status`), though it keeps everything in one file — useful for the *command taxonomy* idea, not for the context-isolation mechanism itself.
|
||||
- **`vanillaflava/llm-wiki-skills`**: the reference implementation for **cross-platform distribution** — six wiki skills tested against Claude Code, Gemini CLI, Codex CLI, and GitHub Copilot simultaneously, installed via a shared CLI that symlinks skills into each tool's native location.
|
||||
- **`yugasun/llm-wiki-skills`**: another cross-platform repo explicitly targeting Claude Code, GitHub Copilot, and Codex.
|
||||
|
||||
---
|
||||
|
||||
## 2. Target skill set
|
||||
|
||||
Split `AGENTS.md`'s five workflows into five (optionally six) standalone skills. Each skill file must be self-contained: a user or agent invoking it should not need to have read the other skill files first, only the shared root context (section 4).
|
||||
|
||||
| Skill name | Replaces AGENTS.md section | Core `wikitool` commands it drives |
|
||||
|---|---|---|
|
||||
| `wiki-ingest` | INGEST Workflow (11 steps) | `new source`, `new entity`, `new concept`, `xref add`, `xref link-source`, `sources rebuild-index`, `index rebuild`, `sources coverage`, `log append`, `publish` |
|
||||
| `wiki-query` | QUERY Workflow | (read-only; no wikitool mutation commands — reads `wiki/index.md`, entity/concept/source pages) |
|
||||
| `wiki-lint` | LINT Workflow | `lint --markdown`, `sources coverage`, `confidence decay --apply`, `sources rebuild-index`, `index rebuild`, `log append` |
|
||||
| `wiki-create` | CREATE Workflow | `new entity`\|`concept`\|`source`\|`comparison`, `xref add`, `sources rebuild-index`, `index rebuild`, `log append`, `publish` |
|
||||
| `wiki-update` | UPDATE Workflow | `xref add`, `sources rebuild-index`, `index rebuild`, `log append`, `publish` |
|
||||
| `wiki-status` (optional, new) | not currently in AGENTS.md — add if useful | read-only stats: page counts, orphans, uncovered raw files |
|
||||
|
||||
Each skill file should follow this internal structure:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: wiki-<name>
|
||||
description: <one-line, third-person, describes when to invoke this skill>
|
||||
---
|
||||
|
||||
# <Skill Title>
|
||||
|
||||
**Purpose:** <one sentence>
|
||||
**Trigger:** <when this skill should be invoked>
|
||||
|
||||
## Steps
|
||||
|
||||
<the numbered steps from the corresponding AGENTS.md workflow section, unchanged in substance>
|
||||
|
||||
## wikitool commands used
|
||||
|
||||
<the exact CLI invocations, copied from AGENTS.md's command reference table>
|
||||
|
||||
## Output
|
||||
|
||||
<what this skill produces>
|
||||
```
|
||||
|
||||
Preserve the exact step-by-step content, command syntax, and rules currently in each AGENTS.md workflow section — this is a structural extraction, not a rewrite of the logic. Do not change what the workflows do, only where they live.
|
||||
|
||||
---
|
||||
|
||||
## 3. Cross-platform file layout
|
||||
|
||||
Use a single shared skill directory so all four target tools resolve to the same files without duplication:
|
||||
|
||||
```
|
||||
llm-wiki-test1/
|
||||
├── AGENTS.md # slimmed root file (see section 4)
|
||||
├── .agents/
|
||||
│ └── skills/
|
||||
│ ├── wiki-ingest/
|
||||
│ │ └── SKILL.md
|
||||
│ ├── wiki-query/
|
||||
│ │ └── SKILL.md
|
||||
│ ├── wiki-lint/
|
||||
│ │ └── SKILL.md
|
||||
│ ├── wiki-create/
|
||||
│ │ └── SKILL.md
|
||||
│ └── wiki-update/
|
||||
│ └── SKILL.md
|
||||
├── tools/
|
||||
│ └── wiki_tools/ # unchanged
|
||||
└── wiki/ # unchanged
|
||||
```
|
||||
|
||||
`.agents/skills/` is the emerging shared convention across agent tools (used natively by Mistral Vibe as a project-shared skill location, and adopted by `vanillaflava/llm-wiki-skills` as the canonical install target that gets symlinked into tool-specific directories). Putting skills here once avoids maintaining four copies.
|
||||
|
||||
### Per-tool wiring
|
||||
|
||||
| Tool | How it finds `.agents/skills/` | Action needed |
|
||||
|---|---|---|
|
||||
| **Claude Code** | Native skill discovery in `.claude/skills/` | Symlink or copy: `~/.claude/skills/wiki-*` → `.agents/skills/wiki-*` (or configure Claude Code to point at `.agents/skills/` directly if supported in your version) |
|
||||
| **Codex CLI** | Native skill discovery in `~/.codex/skills/` | Same symlink pattern as Claude Code |
|
||||
| **Mistral Vibe** | Reads `.agents/skills/` directly as a shared project location (also supports `.vibe/skills/` project-local or `~/.vibe/skills/` global) | No action needed if using `.agents/skills/` — Vibe resolves it natively |
|
||||
| **GitHub Copilot (VS Code)** | Reads skill locations configured via the `chat.agentSkillsLocations` VS Code setting | Add to `.vscode/settings.json`: `"chat.agentSkillsLocations": ["${workspaceFolder}/.agents/skills"]` |
|
||||
|
||||
If a symlink-based install script is wanted, model it after `vanillaflava/llm-wiki-skills`'s installer pattern: a small script that creates the shared directory once and symlinks it into each tool's native skill path, so a single source of truth is edited and all four tools stay in sync.
|
||||
|
||||
---
|
||||
|
||||
## 4. What stays in the root `AGENTS.md` (slimmed)
|
||||
|
||||
Keep only the **declarative, cross-cutting** content that every skill needs regardless of task. Do not duplicate this into each skill file — skills should reference it, not repeat it.
|
||||
|
||||
Retain in root `AGENTS.md`:
|
||||
- Repository architecture diagram (raw/, wiki/, tools/ layout)
|
||||
- Entity Types table (Project, System, Tool, Technology, Person + directories)
|
||||
- Concept Types table (Architecture, Pattern, Protocol, Workflow, Decision, Problem)
|
||||
- Relationship Types list (depends on, uses, implements, etc.)
|
||||
- Page Formats (Entity/Concept/Source/Comparison templates, Index Entry Format, Log Entry Format)
|
||||
- Naming Conventions (file naming, wikilinks, IDs/references)
|
||||
- Provenance and Citation rules (`raw_files:`, `provenance:` field, inline `^[[Source - X]]` citation marker, `wiki/provenance.md` reverse index, "no confident answer without a source" rule)
|
||||
- Confidence Scoring formula and decay rule
|
||||
- Quality Standards checklists (Content Quality, Cross-Reference Quality)
|
||||
- IT-Specific Guidelines (per-entity-type documentation expectations)
|
||||
- Maintenance Schedule table
|
||||
- User Preferences section
|
||||
- Version History
|
||||
|
||||
Remove from root `AGENTS.md` (move into individual skills per section 2):
|
||||
- The full step-by-step INGEST Workflow
|
||||
- The full step-by-step QUERY Workflow
|
||||
- The full step-by-step LINT Workflow
|
||||
- The full step-by-step CREATE Workflow
|
||||
- The full step-by-step UPDATE Workflow
|
||||
- The Git Automation section's operational steps (keep the *policy* — e.g. "never call raw `git commit`/`git push`" — in root; move the per-workflow "when to call `wikitool publish`" instruction into each relevant skill)
|
||||
|
||||
The result should shrink root `AGENTS.md` from ~30KB to roughly a third of that, containing only schema and policy, while all executable workflow logic lives in `.agents/skills/`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Execution checklist
|
||||
|
||||
1. Create `.agents/skills/wiki-ingest/SKILL.md` through `.agents/skills/wiki-update/SKILL.md`, each populated per section 2, using the frontmatter format shown there.
|
||||
2. Extract the five workflow sections verbatim from the current `AGENTS.md` into their corresponding skill files, converting from `### N. WORKFLOW Workflow` headings to the skill file structure in section 2. Preserve every numbered step, every `wikitool` command, and every rule (e.g., "never hand-edit `wiki/index.md`").
|
||||
3. Rewrite root `AGENTS.md` to contain only the sections listed as "retain" in section 4. Add a short new section near the top: "## Skills" listing the five skill names, one-line purpose each, and a pointer to `.agents/skills/`.
|
||||
4. Create `.vscode/settings.json` (or update it if it exists) with the `chat.agentSkillsLocations` entry from section 3.
|
||||
5. Do not modify anything under `tools/wiki_tools/` or `tools/wikitool` — this restructuring is documentation/skill-layer only, no CLI behavior changes.
|
||||
6. Verify: read back the new root `AGENTS.md` and each skill file, and confirm no workflow step, `wikitool` invocation, or hard rule ("never hand-edit X", "always run Y before Z") was dropped during extraction. This is a lossless move, not a summarization.
|
||||
7. Update the Version History table at the bottom of `AGENTS.md` with a new row describing this restructuring (date, "Split workflow sections into `.agents/skills/` for cross-platform skill support (Claude Code, Codex, Mistral Vibe, GitHub Copilot); slimmed root AGENTS.md to schema/policy only", author).
|
||||
|
||||
Do not invent new workflows, commands, or rules beyond what already exists in the current `AGENTS.md` and `tools/wiki_tools/` codebase. This task is a structural reorganization for context efficiency and cross-tool compatibility, not a redesign of the wiki's logic.
|
||||
@@ -0,0 +1,145 @@
|
||||
> @gitea-mcp getzt schau dir die AGENTS.md an, ob wir hier Potential haben. Diverse analoge Wiki Skills habe ich über [https://github.com/gavischneider/awesome-llm-wiki](https://github.com/gavischneider/awesome-llm-wiki) gefnunden, z. B. [https://gist.github.com/farzaa/c35ac0cfbeb957788650e36aabea836d](https://gist.github.com/farzaa/c35ac0cfbeb957788650e36aabea836d). berücksichtige dabei, dass wir unser wikitool haben. Analysere das mal und schau, ob wir da Potential haben. GEhe davon aus, dass der Content, der derzeit in diesem Repo liegt, reiner Test-Content ist, mit dem ich gerade das Konzept teste.
|
||||
|
||||
|
||||
Ich analysiere jetzt die bestehende AGENTS.md im Repo und vergleiche sie mit den verlinkten externen Wiki-Skill-Ideen, mit Fokus darauf, was trotz vorhandenem wikitool noch sinnvoll ergänzt werden kann. Danach gebe ich dir eine konkrete Potential-Liste mit priorisierten Empfehlungen für dein Test-Setup.
|
||||
|
||||
Ich hole jetzt parallel den aktuellen Wortlaut aus AGENTS.md und die beiden externen Referenzen, damit ich die Lücken und Überschneidungen sauber gegenüberstellen kann.
|
||||
|
||||
|
||||
|
||||
Fetched 2 resourcesthere are two solutions for what
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/AGENTS.md#1-1), lines 1 to 420
|
||||
|
||||
Ich habe die Kerninhalte schon erkannt, hole jetzt noch die Raw-Versionen der beiden Dateien, damit die Analyse nicht durch GitHub-Navigationsrauschen verzerrt ist.
|
||||
|
||||
|
||||
|
||||
Fetched 2 resources
|
||||
|
||||
Zwischenstand: Die externen Vorlagen bringen viele Ideen, aber teils auch viel Meinung und Ballast; als Nächstes prüfe ich direkt den Umfang von wiki_tools, um nur realistische Potenziale relativ zu eurem eigenen CLI zu bewerten.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools)
|
||||
|
||||
Searched for regex `def cmd_|@click.command|subparsers|argparse|COMMAND|def main\(` (`**/tools/wiki_tools/**/*.py`), 40 results
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/cli.py)
|
||||
|
||||
Ich lese jetzt die Kernkommandos von commands, um konkret zu sehen, was bereits automatisiert ist und wo zusätzliche Skills wirklich Mehrwert liefern würden.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/lint.py)
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/new_page.py)
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/provenance_cmd.py)
|
||||
|
||||
Ich prüfe noch die Verlinkungs-, Index- und Publish-Kommandos, damit die Empfehlungen nicht an vorhandenen Features vorbeigehen.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/xref.py)
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/index_build.py)
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/git_publish.py)
|
||||
|
||||
Ich habe genug Kontext für die Richtung; ich ziehe jetzt noch präzise Stellen aus AGENTS.md, damit die Empfehlungen direkt auf konkrete Abschnitte gemappt sind.
|
||||
|
||||
Searched for regex `Core Principle|Hard rule|No confident answer without a source|INGEST Workflow|QUERY Workflow|LINT Workflow|CREATE Workflow|UPDATE Workflow|Git Automation|wikitool|Provenance and Citation|Inline citation marker|confidence decay|sources coverage|publish` (`**/AGENTS.md`), 79 results
|
||||
|
||||
Jetzt sammele ich noch punktuelle Code-Stellen aus dem CLI selbst, um Potenziale wie Gates, Drift-Checks und Automationslücken belastbar zu benennen.
|
||||
|
||||
Searched for regex `fail_on_error|fail-on-error|uncovered_raw_files|citation_frontmatter_drift|Semantic Review|provenance|dry_run|--dry-run|source_url` (`**/tools/wiki_tools/commands/*.py`), 52 results
|
||||
|
||||
Searched for regex `publish_command|--push/--no-push|git add -A|git push|full_message|Nothing to commit` (`**/tools/wiki_tools/commands/git_publish.py`), 6 results
|
||||
|
||||
Searched for regex `def xref_link_source|--entities|sources.append|add_see_also_bullet|def xref_add` (`**/tools/wiki_tools/commands/xref.py`), 8 results
|
||||
|
||||
Ich ziehe noch kurz die Konfiguration aus config.py, um zu sehen, welche Typen und Defaults heute hart kodiert sind und wo Standardisierungspotenzial liegt.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/config.py)
|
||||
|
||||
Abschließend prüfe ich noch log_append.py, um zu bestätigen, wie streng das Logging heute strukturiert ist.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/log_append.py)
|
||||
|
||||
Ich schaue kurz in README.md, damit die Potential-Einschätzung auch zur aktuellen Projekt-Intention passt und nicht nur zu den externen Vorlagen.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/README.md)
|
||||
|
||||
Mir ist bereits eine Inkonsistenz aufgefallen; ich prüfe noch README.md, um Doku-Drift zwischen Schema und CLI sauber zu erfassen.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/README.md)
|
||||
|
||||
Ich bin bei der finalen Auswertung; ich ziehe noch eine letzte konkrete Stelle zur internen Doku-Drift, damit die Empfehlung eindeutig ist.
|
||||
|
||||
No matches found. Your search pattern might be excluded completely by either the search.exclude settings or .*ignore files.
|
||||
If you believe that it should have results, you can check into the .*ignore files and the exclude setting (here are some excluded patterns for reference:[**/node_modules,**/bower_components,**/*.code-search]).
|
||||
Then if you want to include those files you can call the tool again by setting "includeIgnoredFiles" to true.
|
||||
|
||||
Ich habe die Drift schon gesehen, suche sie jetzt exakt in beiden Dateien separat, damit wir eine belastbare Referenz haben.
|
||||
|
||||
Searched for regex `kebab-case|Use wikilinks` (`**/README.md`), 2 results
|
||||
|
||||
Searched for regex `human-readable titles with spaces|Wikilinks should match file names exactly|kebab-case` (`**/AGENTS.md`), 2 results
|
||||
|
||||
Ich ergänze noch zwei Referenzen aus README.md, weil dort bereits sinnvolle nächste Ausbaustufen (CI/MCP) angedeutet sind.
|
||||
|
||||
Searched for regex `Future considerations|MCP server wrapper|pre-commit/CI hook|lint --fail-on-error` (`**/tools/README.md`), 3 results
|
||||
|
||||
Ja, hier ist klar Potential, aber nicht im Sinne von “noch ein Wiki-Skill drüberlegen”. Euer großer Vorteil ist schon da: ihr habt mit AGENTS.md plus wikitool eine deterministische Basis, die viele öffentliche Skills gar nicht haben.
|
||||
|
||||
**Was bereits sehr stark ist**
|
||||
- Strikte Trennung zwischen mechanisch und semantisch ist sauber definiert in AGENTS.md und technisch umgesetzt in new_page.py, index_build.py, log_append.py, xref.py.
|
||||
- Provenance-Regeln sind für ein Test-Repo schon ungewöhnlich reif: AGENTS.md, plus Coverage/Trace/Reverse-Index in provenance_cmd.py.
|
||||
- Lint deckt viele harte Fehler bereits ab (inkl. citation/frontmatter drift, uncovered raw, provenance marker) in lint.py.
|
||||
|
||||
**Höchstes Potential relativ zu Awesome + Farzaa, unter Berücksichtigung von wikitool**
|
||||
1. Workflow-Orchestrierung als ein Kommando pro Operation.
|
||||
- Heute sind in AGENTS.md lange Schrittketten dokumentiert, aber als einzelne CLI-Aufrufe verteilt.
|
||||
- Potenzial: ingest run, lint run, update run als orchestrierte Kommandos mit Dry-Run-Plan vor Write.
|
||||
- Mehrwert: weniger Agenten-Drift, weniger vergessene Zwischenschritte.
|
||||
|
||||
2. Harte Sicherheits-Gates vor Massenänderungen.
|
||||
- In externen Skills häufig: Confirm-Gates bei großen Writes.
|
||||
- Bei euch sinnvoll für “>= N Dateien geändert” vor publish.
|
||||
- Das passt gut zu Publish-Flow in git_publish.py.
|
||||
|
||||
3. Session-Orientation als Pflicht vor Query/Update.
|
||||
- Farzaa-ähnliche Orientierung (index + jüngste logs + scope check) würde gut zur QUERY-Qualität passen.
|
||||
- Bei euch noch als Verhalten beschrieben, aber nicht erzwungen.
|
||||
- Kandidat: preflight-Kommando, das Kontextbericht erzeugt.
|
||||
|
||||
4. Semantik-Lint teilautomatisieren, ohne Determinismus zu verlieren.
|
||||
- Ihr habt bereits “Semantic Review (LLM to complete)” in lint.py.
|
||||
- Potenzial: zusätzlich maschinelle Heuristiken für stale claims, hohe Änderungsdichte, schwache Verlinkung als Priorisierungsliste.
|
||||
|
||||
5. Split/Merge/Reclassify als dedizierte Kommandos.
|
||||
- Externe Skills sind stark bei Anti-Cramming und Reorg.
|
||||
- Bei euch ist das konzeptionell da, aber nicht als strukturierter CLI-Pfad.
|
||||
- Potenzial: page split, page merge, reclassify mit automatischer Link/Frontmatter-Korrektur.
|
||||
|
||||
6. CI-Absicherung jetzt schon einbauen.
|
||||
- Ihr habt fail-on-error in lint.py.
|
||||
- In README.md steht der richtige nächste Schritt bereits: Hook/CI vor publish.
|
||||
- Für Testphase ideal, weil du sofort siehst, welche Regeln wirklich stabil sind.
|
||||
|
||||
7. Optionales OKF-Kompatibilitätsprofil.
|
||||
- In awesome-llm-wiki ist OKF ein großer Strang.
|
||||
- Nicht als Ersatz, sondern als Export/Validate-Modus aus eurem Schema.
|
||||
- Vorteil: spätere Interop mit anderen Tools, ohne internes Modell aufzugeben.
|
||||
|
||||
**Was ich aus den externen Skills eher nicht übernehmen würde**
|
||||
- Personenzentrierte Taxonomien und Schreibstilregeln aus Farzaa (stark biografisch, weniger IT-operational).
|
||||
- Sehr aggressive “always rewrite everything”-Loops im Daily-Betrieb.
|
||||
- Große Multi-Agent-Orchestrierung zu früh, bevor eure lokalen Qualitätsmetriken stehen.
|
||||
|
||||
**Konkreter Drift, den ich zeitnah korrigieren würde**
|
||||
- Namenskonvention widerspricht sich:
|
||||
- README.md fordert kebab-case.
|
||||
- AGENTS.md fordert menschenlesbare Dateinamen mit Leerzeichen.
|
||||
- Für Test-Content ist das besonders wichtig, sonst verfälscht es jede Auswertung zu Konsistenz/Drift.
|
||||
|
||||
**Kurzfazit**
|
||||
Ihr seid konzeptionell bereits weiter als viele öffentliche “LLM Wiki Skills”, weil ihr Determinismus ernst nehmt. Das größte Potential liegt jetzt nicht in mehr Prompt-Text, sondern in 3 Dingen: orchestrierte End-to-End-Kommandos, harte Änderungs-Gates, und CI-gestützte Qualitätskontrolle auf Basis eures bestehenden wikitool.
|
||||
|
||||
1. Wenn du willst, kann ich dir als Nächstes eine priorisierte Roadmap (2 Wochen / 6 Wochen) speziell für dieses Test-Repo ausarbeiten.
|
||||
2. Alternativ kann ich eine Soll-Ist-Matrix AGENTS vs wikitool-Kommandos erstellen, damit sofort sichtbar wird, was nur dokumentiert und was wirklich automatisiert ist.
|
||||
@@ -0,0 +1,44 @@
|
||||
> Aspekt aus einer externen Analyse ("Production-Ready AI Agent in 2026"), vom Nutzer per Chat
|
||||
> eingebracht am 2026-08-07 zur Korrektur/Umsetzung im AGENTS.md/wikitool-Setup dieses Repos.
|
||||
> Referenz: [dzone.com - Building a Production-Ready AI Agent in 2026](https://dzone.com/articles/building-a-production-ready-ai-agent-in-2026)
|
||||
|
||||
**Keine Iterations-/Kostengrenzen.** Es gibt keine Regel wie "brich nach N Schritten ab" oder "bei
|
||||
Unsicherheit nach 3 Versuchen an Menschen eskalieren". Für ein Ingest/Lint, das potenziell über
|
||||
hunderte Seiten iteriert, ist das im 2026-Produktionsstandard ein Pflichtfeld.
|
||||
|
||||
## Lücke 3: Keine Iterations- oder Kostengrenzen
|
||||
|
||||
Der Hintergrund: Praktisch jeder dokumentierte Fall von "Agent hat über Nacht ein Budget verbrannt"
|
||||
hat dieselbe Ursache: Es gab keine hart im Code (nicht im Prompt) erzwungene Obergrenze für
|
||||
Tool-Calls, Tokens oder Kosten pro Lauf. Aktuelle Guidance nennt konkrete Richtwerte - 5 bis 15
|
||||
Tool-Calls pro einfacher Aufgabe, 15 bis 25 bei komplexeren Multi-Tool-Workflows, alles über 30 als
|
||||
Alarmsignal für schlechte Aufgabenzerlegung. Ein zusätzlicher, oft übersehener Schutz ist ein
|
||||
"Loop-Breaker": Wenn die letzten N Tool-Calls zu >90% identische Argumente haben, wird abgebrochen,
|
||||
auch wenn das Iterationslimit noch nicht erreicht ist - das fängt Fälle, in denen das Modell in
|
||||
einer Sackgasse "höflich weiterprobiert".
|
||||
|
||||
Warum das bei dir konkret zählt: Der wiki-ingest-Skill iteriert potenziell über viele
|
||||
Entity-/Concept-Seiten, Cross-Refs und Lint-Durchläufe pro einzelner Quelle. Ohne dokumentierte
|
||||
Obergrenze besteht das Risiko, dass ein einzelner Ingest-Lauf bei einer komplexen Quelle (z. B. dem
|
||||
2,4-MB-JSONL-Transkript, das im Repo liegt) unbegrenzt viele Seiten anlegt oder wiederholt an
|
||||
derselben Cross-Referenz-Verknüpfung "hängen bleibt", weil kein Mechanismus sagt "nach X
|
||||
erfolglosen Versuchen: abbrechen und Nutzer informieren". Das ist bei einem lokalen, kostenfreien
|
||||
CLI-Tool zwar kein Geld-Risiko wie bei einer API-abhängigen Produktionsanwendung, aber sehr wohl
|
||||
ein Qualitätsrisiko: unkontrolliertes Wachstum der wiki/-Struktur, das genau die
|
||||
"Anti-Cramming"- und "Index-Scaling"-Probleme erzeugt, die im Wiki selbst schon als Konzeptseiten
|
||||
dokumentiert, aber nicht durchgesetzt sind.
|
||||
|
||||
## Umsetzung (2026-08-07)
|
||||
|
||||
Implementiert als code-erzwungenes Gate in `tools/wikitool` (nicht nur als Prompt-Regel), analog
|
||||
zum bereits bestehenden Mass-Update Gate in `publish`:
|
||||
|
||||
- **Iteration Budget Gate:** Jede `wikitool`-Invocation wird pro Session gezählt
|
||||
(`tools/.wikitool_session/budget.json`, session-scoped via `WIKITOOL_SESSION_ID` oder PPID der
|
||||
aufrufenden Shell). Ab 30 Aufrufen in einer Session verweigert jeder weitere Aufruf die
|
||||
Ausführung (`ERROR`), bis der Nutzer explizit mit `--override-budget` zustimmt.
|
||||
- **Loop-Breaker:** Unabhängig vom Gesamtzähler wird ein Aufruf sofort verweigert, wenn die letzten
|
||||
3 Aufrufe in der Session Kommando + Argumente identisch waren.
|
||||
- **Sichtbarkeit:** `tools/wikitool budget status` / `budget reset [--all]`.
|
||||
- Dokumentiert in AGENTS.md unter "Iteration and Cost Limits", referenziert in den
|
||||
`wiki-ingest`/`wiki-lint`-Skills und in `tools/README.md`/`README.md`.
|
||||
@@ -0,0 +1,59 @@
|
||||
> @gitea-mcp getzt schau dir die AGENTS.md an, ob wir hier Potential haben. Diverse analoge Wiki Skills habe ich über [https://github.com/gavischneider/awesome-llm-wiki](https://github.com/gavischneider/awesome-llm-wiki) gefnunden, z. B. [https://gist.github.com/farzaa/c35ac0cfbeb957788650e36aabea836d](https://gist.github.com/farzaa/c35ac0cfbeb957788650e36aabea836d). berücksichtige dabei, dass wir unser wikitool haben. Analysere das mal und schau, ob wir da Potential haben. GEhe davon aus, dass der Content, der derzeit in diesem Repo liegt, reiner Test-Content ist, mit dem ich gerade das Konzept teste.
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands)
|
||||
|
||||
Fetched 2 resources
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/README.md)
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/wiki/index.md#1-1), lines 1 to 60
|
||||
|
||||
Searched for regex `stub|orphan|checkpoint|narrative|line count|150 lines|100 lines|bloat|tone|Wikipedia` (`**/AGENTS.md`), 3 results
|
||||
|
||||
Read [](file:///home/torben/src/llm-wiki-test1/tools/wiki_tools/commands/lint.py#1-1), lines 1 to 60
|
||||
|
||||
## Kurzfassung
|
||||
|
||||
Ja, es gibt Potential – aber eher an den **Rändern** (Qualitäts-/Wachstumskontrolle, Stil-Guide, Skalierungs-Schwellen), nicht am Kernkonzept. Euer AGENTS.md mit `wikitool` ist bereits eine der saubereren Umsetzungen des "Karpathy LLM-Wiki"-Patterns, das die awesome-list katalogisiert – insbesondere bei Provenance/Zitaten und deterministischer Tool-Unterstützung seid ihr strenger als das, was Farzas Gist beschreibt.
|
||||
|
||||
Ein Hinweis vorab: Im Farza-Gist steckt am Ende ein **Community-Kommentar** von "pascalandy" mit einem komplett anderen, eingefügten Schema ("Wiki Schema (Global)"). Das ist nicht Teil von Farzas eigentlichem Skill, sondern fremder Kommentar-Content mit eigener Tag-Taxonomie (`area/kind/topic/status/pty`). Ich habe ihn trotzdem mit ausgewertet, weil er ein paar brauchbare Ideen enthält – aber als separate Quelle, nicht als "das Gist".
|
||||
|
||||
## Wo ihr schon führt
|
||||
|
||||
- **Provenance/Zitate** (`raw_files:`, `provenance: sourced|general|mixed`, `^[[Source - X]]`, provenance.md-Reverse-Index) – das hat keines der beiden Referenzbeispiele in dieser Tiefe.
|
||||
- **Deterministisches CLI statt LLM-Freihand** für Frontmatter, Xref, Index, Log, Confidence-Decay, Publish – Farzas Skill delegiert das meiste an "schreib ein Python-Skript" ad hoc, ihr habt es schon als stabiles Tool (siehe commands).
|
||||
- **Confidence Scoring mit Decay-Formel** – existiert bei euch, im Gist nicht.
|
||||
|
||||
## Konkrete Lücken mit echtem Nutzen
|
||||
|
||||
**1. Keine Seitenlängen-/Qualitätsschwellen**
|
||||
Farzas Skill hat harte Regeln: Stub-Minimum (≥3 Sätze / 15 Zeilen), Split-Schwelle (>120–150 Zeilen), Längen-Zielwerte je Typ. Der Kommentar-Schema-Vorschlag nennt 200 Zeilen. Euer lint.py prüft Struktur (Broken Links, Orphans, Frontmatter), aber nicht Seitengröße/Dürftigkeit. Bei 201 Seiten und wachsendem index.md lohnt sich ein Lint-Check für "zu lang" / "zu dünn" als Hinweis für die Semantic-Review-Sektion.
|
||||
|
||||
**2. Kein Stil-/Ton-Leitfaden**
|
||||
Farza definiert explizit "Wikipedia, nicht AI-Ton" (keine Gedankenstriche, keine Blähwörter wie "groundbreaking", keine Floskeln wie "it should be noted", max. 2 Zitate/Seite). Euer AGENTS.md sagt nur "concise summaries" – ein kurzer Style-Abschnitt würde die Konsistenz der LLM-Prosa über viele Sessions hinweg verbessern.
|
||||
|
||||
**3. Anti-Cramming/Anti-Thinning-Heuristik fehlt**
|
||||
Farzas Regel "wenn du den 3. Absatz zu einem Unterthema in eine bestehende Seite anhängst, verdient das Unterthema eine eigene Seite" ist eine konkrete, überprüfbare Entscheidungsregel für CREATE vs. UPDATE, die bei euch aktuell reines Judgment ist.
|
||||
|
||||
**4. Kein Checkpoint-/Qualitäts-Audit-Rhythmus**
|
||||
Farza: alle 15 Einträge Index+Backlinks neu bauen, prüfen ob 0 neue Artikel entstanden sind ("cramming"-Alarm), 3 meistgeänderte Artikel als Ganzes neu lesen. Euer "Maintenance Schedule" hat nur "Full lint every 10 sources" – ergänzbar um einen echten Qualitäts-Audit-Schritt, nicht nur Struktur-Lint.
|
||||
|
||||
**5. Index-Skalierungsschwellen**
|
||||
Der Kommentar-Schema schlägt vor: Tabellen-Sektion splitten, wenn >50 Einträge; eine `_meta/topic-map.md` anlegen, wenn Gesamtseiten >200. Euer index.md hat jetzt 201 Seiten in teils langen Tabellen (z.B. "Systems" mit 20 Zeilen) – das ist der erste konkrete Punkt, wo ihr in absehbarer Zeit tatsächlich an eine Grenze stoßt.
|
||||
|
||||
**6. Mass-Update-Bestätigungsgate**
|
||||
"Wenn eine Operation ≥10 Seiten anlegt/ändert, anhalten und Bestätigung einholen" – eine sinnvolle Sicherheitsschranke, die z.B. bei `xref link-source --entities A,B,C,...` mit vielen Entities relevant werden könnte.
|
||||
|
||||
**7. Session-Orientierungsprotokoll**
|
||||
Explizit: vor jeder Operation Schema + Index + letzte N Log-Einträge lesen, um Drift zu erkennen. Bei euch ist das im QUERY/LINT-Workflow implizit vorhanden, aber nicht als fester erster Schritt für *jede* Session formuliert.
|
||||
|
||||
## Was ich **nicht** übernehmen würde
|
||||
|
||||
- Die personenbezogene Verzeichnis-Taxonomie aus Farzas Skill (`people/`, `eras/`, `philosophies/`, `tensions/` …) – passt zu einem persönlichen Lebens-Wiki, nicht zu eurem IT-Domain-Schema.
|
||||
- Die Subagent-Parallelisierung (Batches von 5 Subagenten pro Cleanup-Phase) – setzt eine Multi-Agent-Fähigkeit voraus, die hier (Ask-Mode/Copilot ohne Subagent-Orchestrierung) nicht direkt nachbildbar ist. Höchstens als "future consideration" vermerken.
|
||||
- Die alternative Tag-Achsen-Taxonomie aus dem Kommentar-Schema (`area/kind/topic/status/pty`) – überschneidet sich mit eurem bestehenden `entity_type`/`concept_type`/`tags`-Modell und würde nur Verwirrung stiften.
|
||||
- Das OKF (Open Knowledge Format, Google Cloud) aus der awesome-list – interessant als aufkommender Standard, aber für einen bewussten Test-Repo aktuell kein Mehrwert, den es zu jagen lohnt.
|
||||
|
||||
## Vorschlag für nächste Schritte
|
||||
|
||||
Da hier laut dir reiner Testcontent liegt, wäre mein Vorschlag, das AGENTS.md um einen kompakten neuen Abschnitt "Content Quality & Style" zu ergänzen (Stil-Regeln + Split-/Stub-Schwellen + Checkpoint-Kadenz) und lint.py um zwei neue mechanische Checks zu erweitern (Zeilenzahl-Ausreißer, Index-Sektionsgröße). Sag Bescheid, wenn ich das konkret ausformulieren soll – dazu müsste ich in den Edit-Modus wechseln, da ich hier im Ask-Modus nur analysieren, nicht schreiben darf.
|
||||
Reference in New Issue
Block a user