Files
sow-tools/docs/superpowers/plans/2026-05-21-generated-wiki-stale-purge.md
T

25 KiB

Generated Wiki Stale Purge Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add an opt-in purge stale policy that permanently removes only manifest-tracked generated NodeBB wiki topics that no longer exist in current generator output.

Architecture: Keep stale ownership and candidate selection inside the existing deploy-wiki manifest planner. Extend the deploy result/plan model with purge counts and purge actions, add a thin NodeBB topic purge client call, remove successfully purged entries from the next manifest, and surface the policy through existing toolkit validation and module release/docs paths.

Tech Stack: Go toolkit code and httptest deploy tests, YAML-backed toolkit project config validation, POSIX shell module release wrapper, Markdown docs.


File Map

Toolkit files:

  • Modify internal/project/project.go: validate purge as a supported stale policy and remove the unsupported unpublish config assumption.
  • Modify internal/project/project_test.go: prove project config accepts purge and rejects unsupported stale policies.
  • Modify internal/topdata/wiki_deploy.go: add purge deploy state, stale purge planning, manifest removal, and NodeBB topic purge requests.
  • Modify internal/topdata/wiki_deploy_test.go: cover dry-run/live purge and missing-topic-id refusal without changing archive/report behavior.
  • Modify internal/app/app.go: expose purge in deploy CLI help and print purged deploy counts.
  • Modify internal/app/app_test.go: cover CLI output/help parsing for the new count and policy text.
  • Modify README.md: document the destructive generated-manifest-scoped purge mode in the toolkit CLI docs.

Module files:

  • Modify ../module/scripts/release-all.sh: allow SOW_MODULE_WIKI_DEPLOY_STALE_POLICY=purge.
  • Modify ../module/README.md: document release usage and the destructive boundary.
  • Modify ../module/topdata/README.md: document deploy-wiki --stale-policy purge.
  • Modify ../module/tests/release-all-cache-cleanup.sh: prove release automation forwards purge into both wiki deploy phases.

Task 1: Align Stale Policy Validation

Files:

  • Modify: internal/project/project.go

  • Modify: internal/project/project_test.go

  • Step 1: Write the failing project-config test

Add a project validation case in internal/project/project_test.go that loads stale policy config with purge and expects validation to pass:

func TestProjectValidationAcceptsWikiStalePurgePolicy(t *testing.T) {
	root := t.TempDir()
	writeProjectFile(t, filepath.Join(root, ConfigFile), `
module:
  name: Test Module
  resref: testmod
topdata:
  wiki:
    stale_pages:
      default: report
      live_cleanup: purge
`)

	proj, err := Load(root)
	if err != nil {
		t.Fatalf("load project: %v", err)
	}
	if err := proj.ValidateLayout(); err != nil {
		t.Fatalf("validate purge stale policy: %v", err)
	}
}
  • Step 2: Run the focused test to verify it fails

Run:

go test ./internal/project -run TestProjectValidationAcceptsWikiStalePurgePolicy -count=1

Expected: FAIL because topdata.wiki.stale_pages.live_cleanup "purge" is not supported.

  • Step 3: Replace unsupported project validation vocabulary

In internal/project/project.go, update the stale-policy switch from:

switch policy {
case "report", "archive", "unpublish":
default:
	failures = append(failures, fmt.Errorf("%s %q is not supported", key, policy))
}

to:

switch policy {
case "report", "archive", "purge":
default:
	failures = append(failures, fmt.Errorf("%s %q is not supported", key, policy))
}

This removes the config-only unpublish value that the deploy command cannot execute.

  • Step 4: Add the unsupported-policy regression

Add or extend a project validation test so unpublish and an arbitrary bad value fail:

func TestProjectValidationRejectsUnsupportedWikiStalePolicies(t *testing.T) {
	for _, policy := range []string{"unpublish", "remove-everything"} {
		t.Run(policy, func(t *testing.T) {
			root := t.TempDir()
			writeProjectFile(t, filepath.Join(root, ConfigFile), fmt.Sprintf(`
module:
  name: Test Module
  resref: testmod
topdata:
  wiki:
    stale_pages:
      live_cleanup: %s
`, policy))

			proj, err := Load(root)
			if err != nil {
				t.Fatalf("load project: %v", err)
			}
			err = proj.ValidateLayout()
			if err == nil || !strings.Contains(err.Error(), policy) {
				t.Fatalf("expected %q stale policy validation failure, got %v", policy, err)
			}
		})
	}
}

Add fmt to the existing internal/project/project_test.go imports for the Sprintf YAML fixture.

  • Step 5: Run project tests

Run:

go test ./internal/project -count=1

Expected: PASS.

  • Step 6: Commit the validation change
git add internal/project/project.go internal/project/project_test.go
git commit -m "feat: validate wiki stale purge policy"

Task 2: Plan Manifest-Scoped Purge Actions

Files:

  • Modify: internal/topdata/wiki_deploy.go

  • Modify: internal/topdata/wiki_deploy_test.go

  • Step 1: Write failing deploy tests for dry-run purge planning

In internal/topdata/wiki_deploy_test.go, add:

func TestDeployWikiDryRunPlansTrackedStalePagePurge(t *testing.T) {
	root := t.TempDir()
	sourceDir := filepath.Join(root, "pages")
	if err := os.MkdirAll(filepath.Join(sourceDir, "skills"), 0755); err != nil {
		t.Fatalf("create source dir: %v", err)
	}
	manifestPath := filepath.Join(root, "deploy-manifest.json")
	if err := saveDeployManifest(manifestPath, wikiDeployManifest{
		Version: "nodebb-v1",
		Pages: map[string]wikiDeployManifestPage{
			"skills:retired": {Hash: "old-hash", Title: "Retired Skill", Namespace: "skills", TID: 7, PID: 42, CID: 3},
		},
	}); err != nil {
		t.Fatalf("write deploy manifest: %v", err)
	}
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Fatalf("dry-run purge must not call NodeBB, got %s %s", r.Method, r.URL.Path)
	}))
	defer server.Close()

	result, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{
		SourceDir:    sourceDir,
		Endpoint:     server.URL,
		Token:        "nodebb-token",
		ManifestPath: manifestPath,
		DryRun:       true,
		StalePolicy:  "purge",
	}, nil)
	if err != nil {
		t.Fatalf("DeployWikiWithOptions stale purge dry run failed: %v", err)
	}
	if result.Stale != 1 || result.Purged != 1 {
		t.Fatalf("expected one planned stale purge, got %#v", result)
	}
	if _, ok := loadDeployManifest(manifestPath).Pages["skills:retired"]; !ok {
		t.Fatalf("dry-run purge must not change the deploy manifest")
	}
}
  • Step 2: Write the failing missing-topic-id test

Add:

func TestDeployWikiPurgeRefusesStaleManifestEntryWithoutTopicID(t *testing.T) {
	root := t.TempDir()
	sourceDir := filepath.Join(root, "pages")
	if err := os.MkdirAll(filepath.Join(sourceDir, "skills"), 0755); err != nil {
		t.Fatalf("create source dir: %v", err)
	}
	manifestPath := filepath.Join(root, "deploy-manifest.json")
	if err := saveDeployManifest(manifestPath, wikiDeployManifest{
		Version: "nodebb-v1",
		Pages: map[string]wikiDeployManifestPage{
			"skills:retired": {Hash: "old-hash", Title: "Retired Skill", Namespace: "skills", PID: 42, CID: 3},
		},
	}); err != nil {
		t.Fatalf("write deploy manifest: %v", err)
	}
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Fatalf("missing-topic-id purge must not call NodeBB, got %s %s", r.Method, r.URL.Path)
	}))
	defer server.Close()

	_, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{
		SourceDir:    sourceDir,
		Endpoint:     server.URL,
		Token:        "nodebb-token",
		ManifestPath: manifestPath,
		DryRun:       true,
		StalePolicy:  "purge",
	}, nil)
	if err == nil || !strings.Contains(err.Error(), "topic id") {
		t.Fatalf("expected stale purge to require tracked topic id, got %v", err)
	}
}
  • Step 3: Run the focused tests to verify they fail

Run:

go test ./internal/topdata -run 'TestDeployWiki.*Purge' -count=1

Expected: FAIL because purge is not yet accepted and deployResult has no Purged field.

  • Step 4: Add purge plan/result model fields

In internal/topdata/wiki_deploy.go, extend deployResult:

type deployResult struct {
	LocalPages int
	Created    int
	Updated    int
	Stale      int
	Archived   int
	Purged     int
	Skipped    int
	Drifted    int
	Renamed    int
	Manifest   string
}

Allow purge during deploy option validation:

if opts.StalePolicy != "" &&
	opts.StalePolicy != "report" &&
	opts.StalePolicy != "archive" &&
	opts.StalePolicy != "purge" {
	return deployResult{}, fmt.Errorf("wiki stale policy %q is not supported", opts.StalePolicy)
}

Add the purge count to the deploy plan progress line so dry-run logs show the destructive action explicitly:

progress(fmt.Sprintf("NodeBB wiki plan: create %d, update %d, rename %d, skip %d, stale %d, archive %d, purge %d, drift %d",
	result.Created,
	result.Updated,
	result.Renamed,
	result.Skipped,
	result.Stale,
	result.Archived,
	result.Purged,
	result.Drifted,
))
  • Step 5: Add stale purge planning

In the stale manifest loop inside planNodeBBDeploy, keep the current report/archive branches and add the purge branch:

case "purge":
	if entry.TID == 0 {
		return nil, result, next, fmt.Errorf("stale generated wiki page %q cannot be purged without tracked NodeBB topic id", pageID)
	}
	result.Purged++
	delete(next.Pages, pageID)
	plans = append(plans, wikiDeployPlan{
		Page:   wikiDeployPage{PageID: pageID, Title: entry.Title, Namespace: entry.Namespace},
		Entry:  entry,
		Action: "purge",
	})

Use a switch policy or equivalent structure so report, archive, and purge remain explicit. Do not add namespace search or title matching to find purge targets.

  • Step 6: Run the focused purge planning tests

Run:

go test ./internal/topdata -run 'TestDeployWiki.*Purge' -count=1

Expected: the dry-run and missing-topic-id purge tests pass once they compile.

  • Step 7: Commit purge planning
git add internal/topdata/wiki_deploy.go internal/topdata/wiki_deploy_test.go
git commit -m "feat: plan stale generated wiki purges"

Task 3: Execute NodeBB Topic Purges

Files:

  • Modify: internal/topdata/wiki_deploy.go

  • Modify: internal/topdata/wiki_deploy_test.go

  • Step 1: Write the failing live purge test

Add a live stale purge test in internal/topdata/wiki_deploy_test.go:

func TestDeployWikiPurgesTrackedStaleGeneratedTopic(t *testing.T) {
	root := t.TempDir()
	sourceDir := filepath.Join(root, "pages")
	if err := os.MkdirAll(filepath.Join(sourceDir, "skills"), 0755); err != nil {
		t.Fatalf("create source dir: %v", err)
	}
	manifestPath := filepath.Join(root, "deploy-manifest.json")
	if err := saveDeployManifest(manifestPath, wikiDeployManifest{
		Version: "nodebb-v1",
		Pages: map[string]wikiDeployManifestPage{
			"skills:retired": {Hash: "old-hash", Title: "Retired Skill", Namespace: "skills", TID: 7, PID: 42, CID: 3},
		},
	}); err != nil {
		t.Fatalf("write deploy manifest: %v", err)
	}
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodDelete || r.URL.Path != "/api/v3/topics/7" {
			t.Fatalf("unexpected request %s %s", r.Method, r.URL.Path)
		}
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(map[string]any{"status": map[string]any{"code": "ok"}})
	}))
	defer server.Close()

	result, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{
		SourceDir:    sourceDir,
		Endpoint:     server.URL,
		Token:        "nodebb-token",
		ManifestPath: manifestPath,
		StalePolicy:  "purge",
	}, nil)
	if err != nil {
		t.Fatalf("DeployWikiWithOptions stale purge failed: %v", err)
	}
	if result.Stale != 1 || result.Purged != 1 {
		t.Fatalf("expected one stale purge, got %#v", result)
	}
	if _, ok := loadDeployManifest(manifestPath).Pages["skills:retired"]; ok {
		t.Fatalf("expected purged stale manifest entry to be removed")
	}
}

This route is the NodeBB core purge route. DELETE /api/v3/topics/:tid/state is the separate soft-delete route and must not be used here.

  • Step 2: Run the live purge test to verify it fails

Run:

go test ./internal/topdata -run 'TestDeployWiki.*Live.*Purge|TestDeployWiki.*Purges.*Stale' -count=1

Expected: FAIL because purge plans are not yet executed by the NodeBB client.

  • Step 3: Add the NodeBB purge client method

Place a thin method near updatePost and renameWikiPage in internal/topdata/wiki_deploy.go:

func (c *nodeBBClient) purgeTopic(tid int) error {
	if tid == 0 {
		return fmt.Errorf("NodeBB topic purge requires topic id")
	}
	return c.request(http.MethodDelete, fmt.Sprintf("/api/v3/topics/%d", tid), nil, nil)
}
  • Step 4: Execute purge plans

In the live plan execution switch, add:

case "purge":
	if err := client.purgeTopic(plan.Entry.TID); err != nil {
		return result, fmt.Errorf("deploy wiki page %q: purge NodeBB topic %d: %w", plan.Page.PageID, plan.Entry.TID, err)
	}

Do not acquire wiki edit locks for purge: the NodeBB topic purge endpoint owns its own privilege checks.

  • Step 5: Keep current generated pages out of purge coverage

Add this test so a current generated page with the same manifest page id is skipped instead of purged:

func TestDeployWikiPurgeDoesNotTargetCurrentGeneratedPages(t *testing.T) {
	root := t.TempDir()
	sourceDir := filepath.Join(root, "pages")
	if err := os.MkdirAll(filepath.Join(sourceDir, "skills"), 0755); err != nil {
		t.Fatalf("create source dir: %v", err)
	}
	generated := "[//]: # (sow-topdata-wiki:managed:start)\n# Athletics\n\nGenerated athletics page\n[//]: # (sow-topdata-wiki:managed:end)\n"
	if err := os.WriteFile(filepath.Join(sourceDir, "skills", "athletics.md"), []byte(generated), 0644); err != nil {
		t.Fatalf("write source page: %v", err)
	}
	manifestPath := filepath.Join(root, "deploy-manifest.json")
	if err := saveDeployManifest(manifestPath, wikiDeployManifest{
		Version: "nodebb-v1",
		Pages: map[string]wikiDeployManifestPage{
			"skills:athletics": {
				Hash:      computeManagedHash(generated),
				Title:     "Athletics",
				Namespace: "skills",
				TID:       7,
				PID:       42,
				CID:       3,
			},
		},
	}); err != nil {
		t.Fatalf("write deploy manifest: %v", err)
	}
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Fatalf("current generated page must not call NodeBB during matching-hash deploy, got %s %s", r.Method, r.URL.Path)
	}))
	defer server.Close()

	result, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{
		SourceDir:    sourceDir,
		Endpoint:     server.URL,
		Token:        "nodebb-token",
		ManifestPath: manifestPath,
		StalePolicy:  "purge",
	}, nil)
	if err != nil {
		t.Fatalf("DeployWikiWithOptions current page purge deploy failed: %v", err)
	}
	if result.Stale != 0 || result.Purged != 0 || result.Skipped != 1 {
		t.Fatalf("expected current generated page to skip purge, got %#v", result)
	}
	if _, ok := loadDeployManifest(manifestPath).Pages["skills:athletics"]; !ok {
		t.Fatalf("expected current generated page to remain in deploy manifest")
	}
}
  • Step 6: Run deploy tests

Run:

go test ./internal/topdata -run 'TestDeployWiki' -count=1

Expected: PASS.

  • Step 7: Commit purge execution
git add internal/topdata/wiki_deploy.go internal/topdata/wiki_deploy_test.go
git commit -m "feat: purge stale generated wiki topics"

Task 4: Surface Purge In Toolkit CLI And Docs

Files:

  • Modify: internal/app/app.go

  • Modify: internal/app/app_test.go

  • Modify: README.md

  • Step 1: Write failing CLI-output coverage

In internal/app/app_test.go, extend TestTopdataConsoleDebugProgressAndRelativePaths so the sample progress and emit call include a purge count:

console.progress("NodeBB wiki plan: create 1, update 2, skip 3, stale 4, archive 5, purge 6, drift 0")
console.emitWikiDeployResult(10, 1, 2, 3, 4, 5, 6, 0, "/workspace/project/build/wiki/deploy-manifest.json")

Assert:

if !strings.Contains(output, "purged: 6") {
	t.Fatalf("expected purged deploy count, got %q", output)
}

Update the debug progress expectation to include purge 6.

  • Step 2: Run focused app tests to verify failure

Run:

go test ./internal/app -run TestTopdataConsoleDebugProgressAndRelativePaths -count=1

Expected: FAIL because emitWikiDeployResult does not yet take a purge count.

  • Step 3: Print purge counts

Update the emit signature and output in internal/app/app.go:

func (c *topdataConsole) emitWikiDeployResult(localPages, created, updated, skipped, stale, archived, purged, drifted int, manifest string) {
	spin.linebreak()
	fmt.Fprintln(c.stdout, "Deploy Wiki ----------")
	fmt.Fprintf(c.stdout, "project: %s\n", c.projectName)
	fmt.Fprintf(c.stdout, "local pages: %d\n", localPages)
	fmt.Fprintf(c.stdout, "created: %d\n", created)
	fmt.Fprintf(c.stdout, "updated: %d\n", updated)
	fmt.Fprintf(c.stdout, "skipped: %d\n", skipped)
	fmt.Fprintf(c.stdout, "stale: %d\n", stale)
	fmt.Fprintf(c.stdout, "archived: %d\n", archived)
	fmt.Fprintf(c.stdout, "purged: %d\n", purged)
	fmt.Fprintf(c.stdout, "drifted: %d\n", drifted)
	fmt.Fprintf(c.stdout, "manifest: %s\n", c.relPath(manifest))
}

Pass result.Purged from the deploy command call site.

  • Step 4: Update CLI usage text

Change deploy-wiki help text in internal/app/app.go from:

[--stale-policy <report|archive>]

to:

[--stale-policy <report|archive|purge>]

Add this focused help assertion in internal/app/app_test.go:

func TestParseDeployWikiHelpListsPurgeStalePolicy(t *testing.T) {
	_, err := parseDeployWikiArgs("deploy-wiki", []string{"--help"})
	if err == nil || !strings.Contains(err.Error(), "--stale-policy <report|archive|purge>") {
		t.Fatalf("expected deploy-wiki help to list purge stale policy, got %v", err)
	}
}
  • Step 5: Update toolkit README

In README.md, update the deploy-wiki usage and stale-page explanation so it states:

`--stale-policy purge` permanently removes only stale generated topics already
tracked in the wiki deploy manifest. Dry-run that policy before the live run;
it never discovers manual wiki pages from NodeBB for purge.

Keep report as the documented default and archive as the nondestructive cleanup option.

  • Step 6: Run app tests

Run:

go test ./internal/app -count=1

Expected: PASS.

  • Step 7: Commit toolkit CLI/docs
git add internal/app/app.go internal/app/app_test.go README.md
git commit -m "docs: expose wiki stale purge policy"

Task 5: Expose Purge Through Module Release Workflow

Files:

  • Modify: ../module/scripts/release-all.sh

  • Modify: ../module/README.md

  • Modify: ../module/topdata/README.md

  • Modify: ../module/tests/release-all-cache-cleanup.sh

  • Step 1: Write failing release wrapper coverage

In ../module/tests/release-all-cache-cleanup.sh, set the stale policy in the existing release invocation:

SOW_MODULE_WIKI_DEPLOY_STALE_POLICY="purge" \
TAG_NAME="v-test" \
	"${CHECKOUT}/scripts/release-all.sh" >"${TEST_TMP}/stdout.log" 2>"${TEST_TMP}/stderr.log"

Update the wiki log expectations from:

grep -Fxq "deploy-wiki --dry-run --create" "${TEST_TMP}/wiki.log" \
	|| fail "wiki dry run was not invoked"
grep -Fxq "deploy-wiki --create" "${TEST_TMP}/wiki.log" \
	|| fail "wiki deploy was not invoked"

to:

grep -Fxq "deploy-wiki --dry-run --create --stale-policy purge" "${TEST_TMP}/wiki.log" \
	|| fail "wiki stale purge dry run was not invoked"
grep -Fxq "deploy-wiki --create --stale-policy purge" "${TEST_TMP}/wiki.log" \
	|| fail "wiki stale purge deploy was not invoked"

Update the API ordering assertion to match the new dry-run log line:

$0 == "WIKI deploy-wiki --dry-run --create --stale-policy purge" { wiki_dry_run = NR }
  • Step 2: Run the release wrapper test to verify it fails

Run from ../module:

./tests/release-all-cache-cleanup.sh

Expected: FAIL because scripts/release-all.sh rejects SOW_MODULE_WIKI_DEPLOY_STALE_POLICY=purge.

  • Step 3: Update release wrapper validation

In ../module/scripts/release-all.sh, change:

if [[ "${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}" != "report" && "${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}" != "archive" ]]; then
	echo "Unsupported SOW_MODULE_WIKI_DEPLOY_STALE_POLICY=${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}; expected report or archive" >&2
	return 1
fi

to:

if [[ "${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}" != "report" && "${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}" != "archive" && "${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}" != "purge" ]]; then
	echo "Unsupported SOW_MODULE_WIKI_DEPLOY_STALE_POLICY=${SOW_MODULE_WIKI_DEPLOY_STALE_POLICY}; expected report, archive, or purge" >&2
	return 1
fi

The existing dry-run/live deploy argument plumbing already forwards every non-report stale policy through --stale-policy.

  • Step 4: Run the release wrapper test

Run from ../module:

./tests/release-all-cache-cleanup.sh

Expected: PASS and both release wiki deploy phases include --stale-policy purge.

  • Step 5: Document release controls

In ../module/README.md, revise the environment variable bullet to name both destructive modes explicitly:

- `SOW_MODULE_WIKI_DEPLOY_STALE_POLICY` (defaults to `report`; use `archive`
  after a controlled dry run to retire stale generated pages in place, or
  `purge` after a controlled dry run to permanently remove stale generated
  topics already tracked in the wiki deploy manifest)

In the wiki deployment paragraph, replace the archive-only sentence with a sentence that keeps these boundaries:

  • report is default

  • archive rewrites stale generated pages in place

  • purge permanently removes only manifest-tracked stale generated topics

  • manual NodeBB wiki pages are not purge candidates

  • Step 6: Document local deploy controls

In ../module/topdata/README.md, replace:

reports stale manifest entries by default and can archive them in place with `--stale-policy archive`; it does not delete topics

with:

reports stale manifest entries by default, can archive them in place with
`--stale-policy archive`, and can permanently purge only manifest-tracked stale
generated topics with `--stale-policy purge` after a dry run
  • Step 7: Check module diffs

Run:

git -C ../module diff --check
git -C ../module diff -- scripts/release-all.sh tests/release-all-cache-cleanup.sh README.md topdata/README.md

Expected: no whitespace failures; diff shows only wrapper policy vocabulary, wrapper coverage, and docs.

  • Step 8: Commit module wrapper/docs

Run from ../module:

git add scripts/release-all.sh tests/release-all-cache-cleanup.sh README.md topdata/README.md
git commit -m "docs: allow generated wiki stale purges"

Task 6: Full Verification And Operator Notes

Files:

  • Verify: toolkit and module working trees

  • Step 1: Format Go changes

Run from toolkit:

gofmt -w internal/project/project.go internal/project/project_test.go internal/topdata/wiki_deploy.go internal/topdata/wiki_deploy_test.go internal/app/app.go internal/app/app_test.go

Expected: command exits 0.

  • Step 2: Run toolkit verification

Run from toolkit:

go test ./internal/project ./internal/topdata ./internal/app
go test ./...
git diff --check

Expected: all tests pass and diff check emits no whitespace errors.

  • Step 3: Build the toolkit development binary

Run from toolkit:

./build-tool.sh

Expected: tools/sow-toolkit is rebuilt successfully for module wrapper verification.

  • Step 4: Run module verification with the development binary

Run from module:

SOW_TOOLS_DEV_BINARY=../toolkit/tools/sow-toolkit ./validate-topdata.sh
SOW_TOOLS_DEV_BINARY=../toolkit/tools/sow-toolkit ./build-wiki.sh --force
git diff --check

Expected: topdata validation and wiki build pass; module diff check emits no whitespace errors.

  • Step 5: Record the cleanup command in the final handoff

The final implementation response must state that destructive cleanup is opt-in and show the operator sequence:

./deploy-wiki.sh --dry-run --stale-policy purge
./deploy-wiki.sh --stale-policy purge

For tag-triggered module release automation, state the equivalent variable:

SOW_MODULE_WIKI_DEPLOY_STALE_POLICY=purge

The handoff must mention that purge targets only stale generated pages already tracked in the deploy manifest and permanently removes their NodeBB topics/posts.