ingest: Public Release, Corpus Purge and History Squash Session 2026-09-01

Files changed:
- kb/concepts/Delete Rather Than Anonymize.md
- kb/concepts/Dual Licensing by File Plan.md
- kb/concepts/INDEX.md
- kb/entities/projects/Chemenu.md
- kb/entities/tools/wikitool.md
- kb/index.md
- kb/log.md
- kb/provenance.md
- kb/sources/INDEX.md
- kb/sources/Source - Public Release, Corpus Purge and History Squash Session 2026-09-01.md
- raw/notes/Conversation Transcript - Private-Instance Merge Correction and Issue 30 Session 2026-09-01.md
- raw/notes/Conversation Transcript - Public Release, Corpus Purge and History Squash Session 2026-09-01.md
- raw/notes/Conversation Transcript - Publish-Remote Gate and Issue Triage Session 2026-09-01.md
This commit is contained in:
2026-09-01 20:32:05 +02:00
parent 32a9b8eb3f
commit 00c2cf6ffe
13 changed files with 776 additions and 13 deletions
@@ -0,0 +1,128 @@
# Conversation Transcript - Private-Instance Merge Correction and Issue 30 Session
> Source: Claude Code session (`claude-opus-5`), chemenu workspace
> Collected: 2026-09-01
> Participant: Torben
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's questions and
> instructions are quoted verbatim; the assistant's reasoning is condensed. All shell output
> shown was produced by real, disposable test repositories built in a scratch directory during
> this session (not the chemenu repository itself) and is reproduced as run.
> No credentials appeared in the session.
> Third of three transcripts cut from this session; the first two cover the corpus/history work
> and the Publish-Remote Gate this one corrects a claim about.
Covers Torben asking what actually happens to the demo corpus in a private instance when the
upstream changes it - which exposed an unverified, incorrect claim the assistant had just
written into `instructions/private-instance.md` the same day. The claim was tested empirically,
found wrong, corrected in a released patch (2.2.1), and turned into a properly scoped, tested
merge procedure plus a new issue (#30) proposing the fix belongs in the tool itself, or that the
upstream should stop shipping content on the branch private instances pull machinery from.
---
## Turn 1 - "was passiert in der privaten instanz nach diesen schema wenn sich upstream der demo-korpus ändert?"
The assistant treated this as a request to verify, not answer from the existing text - the
previous transcript's `private-instance.md` had said a `git merge upstream/main` would see
*deleted-in-ours, unmodified-in-theirs* and resolve silently, which was written as an assumption
and never tested.
Built a throwaway upstream/private pair of git repos in the scratch directory to test it: private
instance deletes the demo corpus once, upstream then modifies one demo page, adds a new one, and
deletes another. Ran a plain `git merge upstream/main`. Result, measured rather than assumed:
- The upstream's **modified** page produced `CONFLICT (modify/delete)` and left the upstream's
version sitting in the working tree - resolving it the obvious way (`git add -A`) would commit
that version, bringing the deleted demo page back.
- The upstream's **new** page was staged silently. No conflict, no message.
- The upstream's **deleted** page (matching a page already deleted on the private side) produced
nothing - the one case that actually worked as claimed.
The middle case was the one the original claim missed entirely, and it is the dangerous one
because nothing announces it - a demo page the upstream adds simply arrives and starts showing
up in the private instance's own `lint`, `index`, `search` and `confidence decay`.
A second candidate fix was tested and also failed: a `.gitattributes` `merge=ours` driver for
`kb/**`/`raw/**`. Same three-scenario test showed the modify/delete conflict still occurred and
the new page still landed - the driver only resolves content conflicts on files both sides
touch, not modify/delete pairs or additions.
## Turn 2 - Fixing the instruction, in a released patch
`instructions/private-instance.md` was rewritten: the "Why a clone rather than a tarball"
section now states the measured three-case table instead of the wrong assumption. The update
procedure was rewritten to hold the merge open (`git merge --no-commit --no-ff`), force the
content stages (`kb/`, `raw/`) back to the pre-merge state while `HEAD` still points at the
commit before the merge, commit, and then run an explicit check
(`git diff --name-only $BEFORE HEAD -- kb raw` must be empty) - a check the reader cannot silently
skip past, unlike a claim they might trust. The bad advice in "Decision points" ("resolve a
conflict under kb/ as keep-deleted") was replaced, since that advice is exactly what leads
someone to `git add -A` the leaked content.
The corrected procedure was itself run against the same three-scenario test plus a fourth
(`raw/` alongside `kb/`), and against error paths (dirty working tree rejected, a second run
with nothing new to pull is a no-op) - all passing before publishing.
Version bumped `2.2.0 -> 2.2.1`. The changelog entry states plainly that the earlier text was
"nicht gemessen, sondern angenommen" (not measured, assumed) rather than framing it as a minor
wording fix. Published; tests green (752, unchanged in count - this was a documentation fix).
## Turn 3 - "stelle mal ein sauberes skripting hier exemplarisch dar. gibt es alternative setups? könnten wir die demo/test-seiten aus dem repo main irgendwie heraushalten? erstelle aus dem ganzen thema ein issue... aktualisiere/prüfe, ob #3 im gitea sauber ist. prüfe, ob wir sonst alle offenen enden verdrahtet haben."
Four asks in one message. Handled in order:
**A standalone script**, written and tested (not just described) against the same scenario:
rejects a dirty working tree, rejects a concurrent merge/rebase, holds the merge open the same
way the instruction's procedure now does, is a no-op on a second run with nothing new, and exits
non-zero with a rollback command if the post-merge diff check ever finds leaked content - the
check the manual procedure relies on a human to run, made unskippable.
**Alternative setups**, and the negative result from Turn 1 (`merge=ours` does not work) was kept
rather than omitted, since a rejected alternative is exactly the kind of finding this capture
procedure is meant to preserve.
**Whether the demo corpus can be kept out of `main` entirely** - assessed as the better fix in
principle: the private-instance script (and the instruction's manual procedure) treats a symptom
on every downstream instance, repeatedly; keeping content off the branch machinery is pulled from
would remove the need for either, by construction, for any new instance. Named as two variants
(a separate `demo` branch, or a separate demo repository) with the real cost stated rather than
glossed over - `main` becomes a content-free shell, which was the reason the corpus was kept in
the first place (as a walkable example), and `nightly.yml`'s corpus lint would need to move.
**Issue #30 opened**, carrying the measured table, the working script, both alternatives with
their tradeoffs, and the explicit note that it is not a duplicate of #28 but depends on it - #28
is why the corpus moves at all (demo and testbed sharing one `kb/`), #30 is what that movement
does to a downstream clone.
**Issue #3 checked against its own acceptance criteria** (all five, from the closed issue's own
text) rather than assumed closed-and-fine: a grep for the pre-rename name outside history/
changelog/transcripts, presence of a project entity page, the "Thoth" persona note in both
`SOUL.md` and its template, and no active technical identifier still using the old name. Found
clean - the handful of remaining mentions (`INSTALL.md`, two `kb/` pages) were all phrased as
history ("bis 2026-09-01", "damals"), which the criteria explicitly exempt.
**The wiring audit** turned up the two gaps described in the second transcript's closing turn
(`tools/CONTRACT.md` missing the new gate, `gates.md` not linking to `private-instance.md`) and
the stale project-page description - all three fixed in the same pass and published as 2.2.2,
verified with `docs verify`, `instructions verify`, `doctor` (16 checks OK), `lint` (clean but for
one pre-existing orphan page unrelated to this work), and the full test suite.
## Turn 4 - This capture
Torben asked for this session to be captured via `instructions/capture-session.md`, with an
explicit instruction to keep private and confidential material out - consistent with, not
separate from, everything the day's work had been about. Handled by generalizing every
infrastructure and personal-data reference that appeared during the day's audits rather than
reproducing the original identifiers, cutting the session into three topic transcripts (this
being the third), and filing this transcript's own existence as evidence rather than as new
open work - nothing in this turn required a new issue.
## Outcome
- **Version:** 2.2.0 -> 2.2.1 -> 2.2.2
- **Commits:** `private-instance.md` correction (2.2.1), documentation wiring + project-page
rewrite (2.2.2, shared with the second transcript's closing turn)
- **Tests:** 752, green throughout
- **Issues:** #30 opened; #3 verified against its own acceptance criteria and confirmed clean,
no action needed
- **CI:** green after each publish in this transcript's scope
@@ -0,0 +1,208 @@
# Conversation Transcript - Public Release, Corpus Purge and History Squash Session
> Source: Claude Code session (`claude-opus-5`), chemenu workspace
> Collected: 2026-09-01
> Participant: Torben
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's instructions and
> decisions are quoted verbatim; the assistant's reasoning and the exploration agents' findings
> are condensed. Command outputs shown are real, but every private hostname, IP address and
> personal detail that appeared during the audit has been **generalized rather than repeated** -
> reproducing them here would undo the point of the session. No secret values (tokens, keys)
> ever appeared.
> **Several passages are second-hand.** Three `Explore` subagents (private-data inventory,
> distribution mechanism, git-history audit) and three forked debate agents (hard-separation,
> shared-upstream, devil's-advocate positions) ran in the background; their findings are
> summarized here, not reproduced verbatim, and are named as such at each point they inform a
> decision.
> One of three transcripts cut from the same session; the other two cover building the
> Publish-Remote Gate and the private-instance procedure, and correcting a bug found in that
> procedure afterward (issue #30).
Covers turning the chemenu wiki stack from a private testbed into a publishable repository:
deciding what to delete versus anonymize, squashing the git history, choosing a license, and
verifying the result anonymously end to end. Resulted in the corpus purge (108 pages, ~90 raw
files removed), a single-commit public history, `LICENSE`/`LICENSE-CONTENT`/`NOTICE`, the
`dist export` leak canary (2.1.0), a CI fixture fix (2.1.1), and the repository going public on
Gitea.
---
## Turn 1 - "ich möchte die kb hier bereinigen, es soll nur noch test content sein, ich möchte das repo veröffentlichen..."
Torben's instruction, in substance: clean the KB down to test content, publish the repository,
falsify or remove IP addresses, keep the repo usable as a demo and a testbed going forward; he
would rebuild his real private instance separately. He asked for tips on three specific
questions - how a private fork could pull upstream fixes back, how to set up that private copy
and where to develop the stack, and whether a `kb/manual/` should ship with the distribution so
it documents itself - explicitly requested "mindestens ... teufels anwalt modus" and a small
multi-agent debate, and flagged himself as new to packaging/distributing an LLM application.
The session started in plan mode. Three `Explore` subagents ran in parallel:
- **Private-data inventory** - catalogued what in `raw/` and `kb/` was hard-private (a real
home-lab cluster's bootstrap manual, several personal notes, a 2.46 MB conversation transcript
full of infrastructure references), what was anonymizable (internal hostnames, private IP
ranges), and what was legitimately generic (the stack's own concepts, technologies, tools).
- **Distribution mechanism** - read `dist_cmd.py`, `INSTALL.md` and the version-check machinery;
confirmed `dist export` already ships no `kb/`/`raw/` content and that the update feed's
default URL pointed at the (then-private) origin repo.
- **Git-history audit** - measured `.git` size, largest blobs, deleted-file history, and
concluded the tree was "safe to publish" - a conclusion the session later disproved, see Turn 4.
## Turn 2 - The debate
Three forked debaters argued from the same context:
- **A (hard separation):** delete and rebuild the corpus rather than anonymize, because a page
title is the wiki's only identifier and lives in wikilinks/citations/frontmatter across the
corpus - renaming is the full page-lifecycle procedure, deleting is a supported command.
Squash history rather than selective `filter-repo`, because the history audit itself had just
been shown to under-report risk. No shared git ancestry between the public repo and the
private instance, ever.
- **B (shared upstream):** clone-with-`upstream`-remote instead, because the tarball update path
in `INSTALL.md` is `cp -r` with no three-way merge; argued the leak risk from shared history is
a mechanism problem (a remote allowlist), not a discipline problem, and that most of the
corpus (the ~190 generic pages) is worth keeping as real test data rather than deleting it all.
- **C (devil's advocate):** attacked both positions' shared premises - "just a testbed" was
false (`USER.md` is tracked and carries real personal data), "publish the repo" was
underspecified (which host, and what breaks), there was no `LICENSE` at all, a shipped manual
would decay under `confidence_decay.py` and mislead a new instance, and demo/testbed are
conflicting goals for one `kb/`.
The assistant's synthesis kept A's "delete, don't anonymize" and "squash the history" (C's
finding that the audit under-reported risk made this decisive), adopted B's clone-with-`upstream`
model but **conditioned it on a remote-allowlist gate existing first** (addressing C's leak
concern with code, not discipline), rejected the shipped manual per C's decay argument, and
decided the surviving corpus should lean toward the stack's own self-documentation rather than
Torben's real infrastructure - which the actual corpus math later validated (Turn 5).
## Turn 3 - Clarifying questions and plan approval
The assistant asked Torben to choose among concrete options (`AskUserQuestion`) rather than
picking on his behalf:
- **Publish target:** "Gitea öffentlich schalten" (chosen) over mirroring to GitHub or keeping
Gitea private with a GitHub mirror - smallest change, CI/release feed stay correct as-is.
- **Corpus:** "Chirurgisch löschen (Empfehlung)" (chosen) over full synthetic rebuild or
anonymization.
- **Private instance:** "Clone mit upstream, Gate zuerst (Empfehlung)" (chosen) over hard
separation or a later migration.
- **License:** first pass "Was wäre CC-BY-4 für content und eine GPL oder LGPL fürs Tooling?
Berate mich hier noch mal" - the assistant advised against LGPL (no library-linking use case
here to justify the fetch-only variant), and named the real choice as GPL vs. **AGPL**, because
issue #19 (an MCP frontend for `wikitool`) points toward running the stack as a network
service, which is exactly the gap GPL leaves and AGPL closes. Torben chose **AGPL-3.0 +
CC-BY-4.0**.
The written plan covered: publish blockers (license, `dist export` allowlist, `INSTALL.md`
token wording), the corpus purge, the history squash, the private-instance model with the gate
as a precondition, why the manual idea was declined, and a leak-canary for `dist export`. Torben
approved it via `ExitPlanMode` without further changes.
## Turn 4 - Executing the license and leak-canary work (2.1.0)
Before touching content: a full repo bundle backup outside the tree, verified by `git bundle
verify` and a commit-count comparison (150 commits, all 15 tags present).
- Fetched the AGPL-3.0 text from `gnu.org` (not reconstructed from memory - a license must be
the authoritative text) and copied the CC-BY-4.0 text from the vendored `commonplace`
submodule, per the license each already carries.
- Added `LICENSE` (AGPL - deliberately the AGPL rather than a separate `LICENSE-CODE`, because
that is the file a forge reports for the repository, and under-noticing a copyleft obligation
harms a reader in a way over-noticing does not), `LICENSE-CONTENT` (CC-BY), `NOTICE` (the
license boundary and the `commonplace` attribution CC-BY requires).
- `dist_cmd.py`: added the three license files to `ROOT_FILES`, and a separate
`REQUIRED_ROOT_FILES` check that **fails the export** if they are missing - every other
`ROOT_FILES` entry is copied `if source.is_file()` and silently skipped otherwise, which is
wrong for a license (a distribution shipping AGPL code with no license text is a violation the
moment it is published).
- Added `find_leaks()`: a structural (not text-pattern) check of the finished export plan against
personalization files, `instructions/dev/`, `kb/` pages and `raw/` sources - rejected a
hostname/IP text-scan approach, because the project's own host legitimately appears in
`INSTALL.md` and `version.py`, so such a scan would either whitelist the string it's looking
for or false-positive on every export.
- Six new tests in `test_dist_cmd.py`; full suite green; version bumped `2.0.0 -> 2.1.0`.
## Turn 5 - The corpus purge
A workshop (`work/publish-cleanup`) was opened per `work/CONTRACT.md`, because ~103 planned
`wikitool rm` calls exceed a single iteration-budget unit.
Analysis found the plan's estimate wrong in a way worth recording: not ~35 pages would become
sourceless after deleting the obviously-private ones, but **75**. Splitting them: 28 were the
user's own infrastructure (unambiguous), and **40 carried generic technology titles but were
written entirely around the user's own cluster** (a storage page explained itself via one
specific storage class name, a Kubernetes page via the user's own network ranges) - not
reusable pages with a private example, but private documentation with a generic heading. The
remaining 7 were genuinely clean in body text but sourced from the user's personal
document-processing pipeline.
Presented to Torben as a three-way choice; he chose **"Alle 75 löschen"** over keeping the
clean 7 (via provenance reclassification) or rewriting the 40 as vendor-neutral pages. The
result: 152 pages plus 25 sources remained by design - the stack's own self-documentation
(gates, lint, versioning, search, the wiki pattern itself), which the earlier debate had argued
for without knowing this would be the actual outcome.
Execution: `wikitool rm --page <title> --yes` per page across three units (27 sources, 28
infra, 48 entangled), 90 raw files removed including the full cluster bootstrap tree and the
2.46 MB transcript. `wikitool rm` was found to de-link only mechanically (frontmatter refs and
whole-line link bullets) and to deliberately leave inline prose wikilinks and plain-text
mentions standing - roughly 20 pages needed manual follow-up to actually remove the remaining
references, which `lint` and a targeted `rg` scan surfaced.
Also reset: `kb/log.md` (116 private references, no regenerator - reset to the
`dist_templates/log.md` starting state, a deliberate one-time stack-dev operation, not a
hand-edit of a generated file), `USER.md`/`SOUL.md` rewritten as an explicit demo-operator
persona rather than Torben's real profile.
## Turn 6 - Squashing the history
Backup re-verified before the destructive step. An orphan root commit was built from the purged
working tree, `main` reset onto it, all 15 tags deleted (locally, then individually on the
remote - a batch refspec push failed silently), `git reflog expire --expire=now --all` and
`git gc --prune=now --aggressive`, then a `--force` push.
**Verified rather than trusted:** a fresh clone attempted `git fetch --depth=1 origin
<old-head-sha>` immediately afterward and succeeded - the objects were still reachable through
Gitea's own reflog on the bare repository, contradicting the earlier belief that force-pushing
was sufficient. The rejected shortcut here was accepting Gitea's own scheduled cleanup jobs as
proof; Torben ran them once, and the same fetch test still succeeded afterward. Only a direct
`reflog expire` + `gc --prune=now` run on the bare repository itself (which Torben ran, having
shell access the assistant did not) closed it - reverified by the same fetch test returning
`not our ref`.
A second leak was found by scanning **hidden directories** (`.gitea/`, `.github/`, `.vibe/`),
which the earlier `rg` sweeps had silently skipped without `--hidden` - two references to an
internal CI branch name in `.gitea/workflows/ci.yml`, fixed and amended into the squashed
commit before the first push.
## Turn 7 - Public switch, CI fixture bug, and verification
Torben switched the Gitea repository to public. Verified anonymously (no token, no SSH key):
repository API reports `private: false`, the release feed serves the latest tag, and a clean
`git clone` over HTTPS from an empty directory succeeds. A further leak scan of that anonymous
clone found one remaining hit: the 2.1.1 changelog entry (see below) had *listed* the private
fixture names it replaced, which put them back into the public history it was announcing the
removal from. Corrected in the same commit that introduced it.
Separately, the first CI run on the squashed history failed on a test unrelated to the corpus
purge in content but caused by it: `test_legacy_source_pages_flags_url_and_directory` checks
`(config.ROOT / legacy).is_dir()` against the **real** repository root rather than the test
fixture's own tree, and had only ever passed because this checkout happened to have a
`raw/documents/` directory - which the corpus purge had just emptied. Git does not track empty
directories, so the directory vanished from CI's checkout and stayed in the local one: green
here, red there. Reproduced locally by removing the directory and rerunning; fixed in the
`raw_dir` fixture (`conftest.py`) rather than the one test, matching the reasoning already
recorded for a prior, similar case (Gitea #8). Several other test fixtures still used the
user's real system names and were renamed to generic, unrelated placeholders
alongside. Published as 2.1.1 after Mass-Update Gate clearance from Torben.
## Outcome
- **Version:** 2.0.0 -> 2.1.1
- **Commits:** license/leak-canary work, corpus purge (multiple), history squashed to one root
commit, CI fixture fix
- **Tests:** 630 -> 752, all green
- **Issues:** none opened in this transcript's scope (see the other two transcripts for #27-#30)
- **CI:** green on the squashed history after the fixture fix; release `v2.1.1` built and
anonymously downloadable
@@ -0,0 +1,154 @@
# Conversation Transcript - Publish-Remote Gate and Issue Triage Session
> Source: Claude Code session (`claude-opus-5`), chemenu workspace
> Collected: 2026-09-01
> Participant: Torben
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's instructions are
> quoted verbatim; the assistant's design reasoning is condensed. Command outputs and test
> results shown are real. No credentials appeared in the session; where a private hostname
> could have been used as a code example, a generic placeholder is used instead, matching what
> was actually committed.
> Continues directly from "Public Release, Corpus Purge and History Squash Session" (same day).
> Two of three transcripts cut from this session; the third covers a bug found afterward in the
> procedure this one builds (issue #30).
Covers building the Publish-Remote Gate (a third code-enforced gate, alongside the Mass-Update
and rebase-review gates), writing `instructions/private-instance.md`, updating six open Gitea
issues for the rename and the new architecture, opening three new issues (#27, #28, #29), and
deleting the Gitea Actions run history at Torben's request. Resulted in version 2.2.0, then a
documentation-only 2.2.2.
---
## Turn 1 - "1. remote allowlist. 2. unterbreche und warte auf mich, wenn ich gitea scharf schalten soll... 3. setup a) meiner lokalen dev-umgebung"
Torben asked for three things in one message, plus: "parallel issuen anlgen und aktualisieren
nach eigenem ermessen, prüfe auch vorhandene, evtl. müssen wir hier auch noch tätig werden?"
**The gate.** Designed to pin the **resolved push URL**, not the remote name - a name-based
allowlist would pass a `publish` whose `origin` had been repointed, which is the exact failure
it exists to catch. `git remote get-url --push <remote>` is read at check time so a `pushurl`
override is respected. The file (`.wikitool-remotes.json`) is gitignored and per-checkout, for
the same reason `ENVIRONMENT.md` is: two clones push to two different places, and a committed
copy would tell a private clone the public upstream is a legitimate target for its own content.
Absence means unrestricted, matching the pattern of the other optional per-checkout files;
`doctor` reports the state and WARNs only when a checkout has more than one remote and no
allowlist.
**Deliberately no `--confirm` token**, unlike the other two gates. Their question ("is this
change right?") is answerable per changeset; this gate's question ("does this content belong in
that repository?") is a standing property of the checkout, so the only way past it is the user
editing the file themselves - an agent editing it to clear a refusal would be opening a gate on
its own initiative, which the repository's own rules forbid.
Implementation: `config.PUBLISH_REMOTES_FILENAME`, `read_allowed_push_urls()` /
`push_url_for()` / `publish_remote_refusal()` in `git_publish.py`, checked before the reconcile
step in `publish_command` (before any network contact, so a refused publish never even fetches
from the wrong place), `doctor.check_publish_remotes()`, twelve new tests covering the URL-vs-name
distinction, `pushurl` precedence, a broken/missing/empty allowlist, and that no flag exists to
bypass it. `instructions/gates.md` and `AGENTS.md` updated to describe a third gate. Version
bumped `2.1.1 -> 2.2.0`; the Mass-Update Gate itself fired at 10 files and Torben cleared it with
the printed token.
**`instructions/private-instance.md`** (new): the procedure for cloning with the public repo as
`upstream`, arming the gate *before* the first `publish` (not after - the assistant stressed this
ordering explicitly, since a gate added later leaves the earlier window open), taking the write
credential away from the private clone as a second, independent control, and where stack
development happens ("in the public repo, not here" - not a preference but a structural fact,
since `instructions/dev/` does not survive `dist export`). **This file's description of what a
`git merge upstream/main` actually does to the content stages was wrong as first written** - see
the third transcript for the correction.
**The Gitea admin cheat-sheet** (delivered as a reply, not committed): what to check before
flipping the repo public (`DISABLE_REGISTRATION`, `REQUIRE_SIGNIN_VIEW`, rate limits, the
Actions runner's network exposure), and the follow-up steps (`INSTALL.md`, anonymous release
check, a clone test). Also flagged that the open issues would go public with the repo, which is
what motivated the issue-triage pass below.
## Turn 2 - Issue triage
Read the labels (`prio/1..3`, `size/XS..L`) and the open issues. Several pre-dated the
`llm-wiki-test1` -> `chemenu` rename (issue #3) and still named the old package path
(`tools/wiki_tools/...`) or the old repository name in code examples:
- **#6** title corrected in place (`wiki_tools` -> `chemenu` path).
- **#7** (`dist upgrade`) commented: the "origin repo is private" fallback it describes no
longer applies once the repo is public, and its urgency for *this* instance specifically
dropped, because the private instance now takes updates via `git merge upstream/main` (real
three-way merge) rather than the tarball-copy path the issue was written against - it remains
the right design for any instance without shared git history.
- **#10** (coverage reporting) commented: step 1 is done (1.8.1 shipped `pytest-cov` without a
failure threshold), the test count referenced is stale (630 -> 752, and the gap is itself
evidence for the issue's own argument - the raw_dir fixture bug from the first transcript), and
one code example named a private CI branch and needs neutralizing before being read publicly.
- **#4, #5** flagged as needing the same path correction but not rewritten in this pass.
**Three new issues opened**, each traced to a decision made and then set aside earlier in the
day rather than invented fresh:
- **#27** - the shipped-manual idea the debate rejected (first transcript, Turn 2) needs a
decay/lint exemption for distributed pages before it becomes buildable at all; names the exact
blocker (`confidence_decay.py` has no exemption path) and the two things still undecided (how
a shipped page is recognized, what exactly is exempted).
- **#28** - the demo-vs-testbed tension the debate argued through (assistant recommended
testbed, C objected) is not resolved, only decided for now; proposes a curated fixture corpus
as the eventual answer and names why (`kb_dir`/`raw_dir` fixtures already cover the small case,
this is about the dense, interconnected one).
- **#29** - catalogs which open issues still carry pre-rename paths and a private hostname
(#10's CI example), separating "pointer, fix it" references from "citation of what was true
then, date it" references rather than blanket-editing everything.
## Turn 3 - Public verification and the actions-history request
After Torben confirmed the repository was public, verification ran anonymously: repo API
(`private: false`), release feed (latest tag served without auth), a clean HTTPS clone from an
empty directory (three commits, two tags, all three license files present, 170 pages, no leak
hits including in hidden files), and the full `INSTALL.md` release-tarball path end to end -
checksum verified, license files present in the unpacked tree, `kb/`/`raw/` empty as designed,
`instructions/dev/` absent.
Torben: "an der Stelle: wenn du per mcp die action runner historie löschen kannst, leere sie
bitte komplett, da finde ich keinen knopf für und dort dürften noch alte tarballs herumgeistern."
The assistant checked: the Gitea MCP server exposes `dispatch`/`cancel`/`rerun` for Actions runs
but no delete, and the delete route Gitea's own API defines (`DELETE
/api/v1/repos/{owner}/{repo}/actions/runs/{run}`) requires a token the assistant did not hold.
Findings reported instead of silently working around the missing capability: **zero artifacts**
existed already (confirmed via the anonymous artifacts API), but an anonymous SPA data endpoint
the run pages call was readable and returned old commit titles from the squashed-away history -
no hostnames or personal data among the six reachable runs, but development history the squash
was meant to remove. A `curl` loop using a write-scoped token was handed to Torben to run
himself, rather than asking for a token in the session.
Torben ran it and reported back ("die action-historie habe ich jetzt per api gelöscht") in the
same message as "korrigiere die install.md wie vorgeschlagen." Both handled: the anonymous SPA
endpoint was re-tested across all previously-reachable run numbers and returned nothing for any
of them, closing the loop; `INSTALL.md`'s "repo is currently private, you need a token" language
was removed from three places (the download command, the configuration table, a dedicated
paragraph - the paragraph rewritten to explain the token is still needed **for a private fork**,
not for this repository), "Weg C" was reworded from "Torben's personal wiki" to a description of
the testbed/demo nature of the corpus, and a new "Weg D" documented the private-instance path
with a pointer to `private-instance.md`. No version bump (prose only).
## Turn 4 - Wiring audit (from the third transcript's closing turn, included here for the gate/issue thread)
A later pass (opened by a different question, documented fully in the third transcript) checked
whether the gate work here was actually cross-referenced: `tools/CONTRACT.md` did not mention
the Publish-Remote Gate at all despite it being `publish`'s third exit-42 path - fixed in both
the command-table entry and the error-contract entry, since a tool's error contract is exactly
where a caller learns what a given exit code means and whether retrying is safe. `gates.md` did
not link to `private-instance.md`, the procedure it exists for - fixed. The project's own KB
page (`kb/entities/projects/Chemenu.md`) still described the instance as a personal wiki with no
mention of the license or its public, testbed-and-demo status - rewritten, keeping the
historical note about the pre-restructuring `AGENTS.md` but dating it explicitly rather than
stating it as a current fact. Published as 2.2.2.
## Outcome
- **Version:** 2.1.1 -> 2.2.0 -> 2.2.2
- **Commits:** Publish-Remote Gate + `private-instance.md` (2.2.0, Mass-Update Gate cleared),
`INSTALL.md` correction (unversioned prose), documentation wiring + project-page rewrite
(2.2.2)
- **Tests:** 752, all green throughout (12 new for the gate)
- **Issues:** #6 title fixed; #7, #10 commented; #27, #28, #29 opened
- **CI:** green on every push in this transcript's scope; Gitea Actions run history removed by
Torben via the API, verified anonymously empty afterward