Skip to content

init-wiki --github silently overwrites Home.md when cloning a wiki that has pre-existing content #66

Description

@psaboia

Defect

wiki/init-wiki.sh:204-211 writes a redirect stub into Home.md:

# --- Write Home.md redirect (GitHub wiki landing page) ---
if [[ ! -f "$WIKI_DIR/Home.md" ]] || ! grep -qF "redirect" "$WIKI_DIR/Home.md" 2>/dev/null; then
cat > "$WIKI_DIR/Home.md" << REDIRECTEOF
<!-- redirect: this file exists for GitHub wiki compatibility -->
<!-- The real home page is ${HOME_NS}.md -->
See [${PROJECT_NAME}](${HOME_NS})
REDIRECTEOF
fi

The condition [[ ! -f Home.md ]] || ! grep -qF "redirect" Home.md is intended to be idempotent: leave the file alone on re-runs (where Home.md already has "redirect"), create it on first run (where the file is absent). But it has a third path that is silently destructive:

When init-wiki --github clones an existing GitHub wiki that has a substantive Home.md (no "redirect" marker in it), the script overwrites that file with the stub. No warning, no diff, no opportunity for the user to decline.

When this matters

adopt --apply --github-wiki against a project whose GitHub Wiki was used ad-hoc before adopting the llm-wiki pattern:

  • Team had been using GitHub Wiki as a regular wiki, authored Home.md as a real landing page (e.g. project summary, links to other pages).
  • They decide to adopt the llm-wiki pattern.
  • Run adopt --apply --github-wiki. Phase 2B clones the existing wiki, then init-wiki silently rewrites Home.md with the redirect stub.
  • Their original landing-page content is gone, both locally and on push to GitHub.

The pattern's other namespaced files (index_<repo>.md, log_<repo>.md, SCHEMA_<repo>.md) protect against this with the if [[ ! -f ... ]] guard alone (no grep -qF fallback path). Only Home.md has the second condition that triggers destruction.

How it surfaced

Discovered while explaining the GitHub Wiki "first page" UI step for the virgin-adopt quick start (issue #64's Quick start section). For the virgin case, the overwrite is the correct behaviour: the user wrote a placeholder ("test") to materialize <repo>.wiki.git on GitHub, and init-wiki replacing that placeholder with the redirect is what should happen. For the non-virgin case (real Home.md content), the same overwrite is silently destructive.

Bloco 2 manual test of PR #60 against a FUNSD scratch (wiki already materialized with three pre-existing pages) saw the Home.md on disk become 135 bytes after init-wiki ran — the redirect stub, not whatever FUNSD's prior Home.md content may have been. The three other pre-existing pages were preserved correctly; only Home.md was clobbered.

Fix sketches

Option A — preserve and rename. Detect Home.md exists, lacks "redirect", and was likely host-authored (e.g. has substantive content beyond a one-liner). Rename to Home-original.md (or Home.host-authored.md) and then write the redirect stub. Lossless. The host can move content into Home_<repo>.md (the real namespaced home) afterwards, or link to Home-original from there.

Option B — refuse loudly. If Home.md exists and lacks "redirect", lw_die with an explicit message: "Existing Home.md detected at $WIKI_DIR/Home.md. The llm-wiki pattern uses Home.md as a redirect to Home_.md. Either delete Home.md (its content will be lost) or move its content into Home_.md before continuing." Forces the user to make a deliberate choice. Less ergonomic but never destructive without consent.

Option C — diff and prompt (interactive). Show the diff between the existing Home.md and the redirect stub, prompt for [k]eep / [o]verwrite / [m]ove-to-Home_<repo>. Most flexible, but interactive mode is awkward inside adopt --apply which is meant to be scriptable.

Option D — skip if not empty. If Home.md exists with any content, leave it alone. Loses the redirect benefit (GitHub UI users land on the host's old Home.md, not the namespaced one), but never destructive.

Recommendation: Option A (preserve and rename) is the most lossless. It is also the most consistent with the rest of init-wiki's defensive posture (e.g. index_<repo>.md is "create-only-if-absent" — never overwrites). The cost is one extra file in the wiki sub-repo (the renamed original) that the host can clean up at leisure.

A hybrid is possible: Option A by default, with --force-overwrite-home (or similar) restoring the current overwrite behaviour for the case where the host really does want to discard the existing Home.md.

Acceptance

  • init-wiki --github against a wiki whose Home.md is substantive and lacks the "redirect" marker either:
    • (a) preserves the original (Option A: rename + write stub; user sees the rename in the adopt log), OR
    • (b) refuses with a loud error pointing at the exact file and the resolution path (Option B), OR
    • (c) some other non-destructive resolution.
  • The virgin case continues to work: a tiny placeholder Home.md (from a one-time UI step) is replaced by the redirect stub without ceremony.
  • Idempotency holds: re-running adopt or init-wiki against a wiki that already has the redirect Home.md is a no-op.
  • A test fixture under scripts/test/tests/integration/ or scripts/test/tests/smoke/ exercises both paths (virgin vs non-virgin Home.md) and asserts the appropriate outcome for each.

Context

Pre-existing defect, predates PR #60 and the manifest consolidation. Surfaced during the documentation pass for issue #64 (quick start for the virgin-adopt case) while explaining what the "first page in the UI" placeholder content becomes after adopt: it gets overwritten. That answer is correct for the virgin case but exposes the silent destruction for the non-virgin case.

Adopt-side flow that triggers this: adopt --apply --github-wiki against a host whose GitHub Wiki has already been used ad-hoc. The init-wiki --github invocation in adopt's Phase 2B is where the overwrite happens.

Refs: PR #60 (manifest introduction; the manual adoption test surfaced this), #64 (the quick start that documents the virgin-case overwrite as expected behaviour and needs to flag the non-virgin destruction once this is fixed), #63 (the Next steps block could include "your previous Home.md content was preserved at Home-original.md" if Option A is chosen).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions