18ae28f918
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.
214 lines
11 KiB
Markdown
214 lines
11 KiB
Markdown
# 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 |
|