archvillainette 87feaf96b7
build-binaries / build-binaries (push) Successful in 2m27s
fix(wiki): purge through the plugin page actions and count reset deletions (#101)
Closes #99. Closes #100.

## #99 — purge used the core topic API

`deploy-wiki --stale-policy purge` deleted pages with `DELETE /api/v3/topics/{tid}`. On a NodeBB running `nodebb-plugin-westgate-wiki` that is refused for topics in wiki categories — revision history is plugin-owned — so every purge failed with HTTP 400 and the deploy exited 1.

Purge now goes through the plugin's own page actions:

1. `PUT /api/v3/plugins/westgate-wiki/page/tombstone`
2. `DELETE /api/v3/plugins/westgate-wiki/page/hard-purge`

in that order, because a page must be tombstoned before it can be purged. A page that is already gone answers 404 on the tombstone and is treated as a completed purge, as before.

**Archive was audited and needs no change.** It rewrites the page through `updatePost`, which is an ordinary post edit the plugin allows; only delete, restore, and purge are reserved to the page actions.

**The wiki home topic.** A namespace reset enumerates every topic in the category, including the home page, which the plugin excludes from tombstone, restore, and purge alike. Those are now skipped instead of aborting the reset. NodeBB answers 403 for that and for a token without purge privileges alike, and the response body cannot tell the two apart — what can is scope. A category where nothing at all could be deleted is a privilege problem, so the run still fails there rather than writing a manifest that claims a fresh start over pages that are all still present.

**The fakes.** Every fake NodeBB in `wiki_deploy_test.go` now goes through one constructor that refuses native topic mutation exactly the way the plugin does. The old fakes answered the core API, which is how a purge path that has never worked in production stayed green in CI.

## #100 — `stale: 0` above `purged: 1213`

The reset purge never went through stale computation, so the preview reported zero deletions on a run that would delete every topic in the managed categories.

Reset deletions are now counted in `stale`, which is the number callers word their destructive-policy warning around, and the summary gains a line naming the reset and how many of its targets the manifest has no record of writing:

```
stale:       1213
purged:      1213
namespace reset: 1213 (unrecognized: 13)
  unrecognized pages were not written by this deployer; recreating them is not possible
```

The unrecognized subset is the number worth surfacing, since those are the deletions a re-seed cannot undo. The `--reset-managed-namespaces` help text now says plainly that the flag deletes every page in the managed categories, not only the ones this deployer wrote.

`DeployResult` is exported so the console reads named fields instead of eleven positional ints.

## Verification

`go vet ./...` and `go test ./...` pass. New tests cover the plugin purge order, the already-missing page, the skipped undeletable topic, the per-category privilege failure, and the reset counts.Reviewed-on: #101

Co-authored-by: vickydotbat <vickydotbat@tutamail.com>
2026-08-05 16:01:51 +00:00
2026-06-18 07:29:09 +00:00
2026-06-25 09:29:39 +00:00
2026-07-12 12:06:40 +00:00
2026-06-20 15:41:33 +00:00
2026-06-12 10:14:38 +02:00

sow-tools — Crucible

Crucible is the Shadows Over Westgate build/conversion/sync toolchain: one Go module producing several small binaries plus a crucible dispatcher (D11). It is the only repo that owns builder logic; the artifact repos (sow-module, sow-topdata, sow-assets-manifest) invoke Crucible through wrapper scripts and never embed a toolkit.

Repos produce artifacts.  sow-platform deploys artifacts.
Crucible is how the artifact repos turn source into artifacts.

Binaries

Binary Dispatcher form Owns
crucible dispatcher: crucible <builder> [args]
crucible-depot crucible depot content-addressed depot blob verify/move
crucible-hak crucible hak ERF/HAK pack/unpack + hak manifests
crucible-module crucible module build/extract/validate/compare the .mod
crucible-nwsync crucible nwsync NWSync blob emit + manifest assemble + verify
crucible-topdata crucible topdata compile 2da/tlk topdata + packages
crucible-wiki crucible wiki render + deploy mechanical wiki pages

The dispatcher and the standalone shims share one registry (internal/dispatch); the shims exist so consumer wrapper scripts can resolve a single-token command. The full legacy nwn-tool command surface and where each command lands is mapped in docs/command-surface.md.

Status (cutover performed)

The internal app/pipeline/project/erf/gff/topdata/changelog/ validator packages from gitea/sow-tools have been migrated into this tree, and the module, topdata, hak, and wiki builders now delegate to the migrated nwn-tool command surface (mapped in docs/command-surface.md). config and changelog are global commands on the dispatcher. depot has no migrated logic yet, so it keeps the fail-closed path: exit 70, never a faked artifact.

See docs/migration-from-nwn-tool.md for what was done and what remains (the consumer --manifest/--source/--out flag contract is the open Phase-6 item).

Quick start (no Nix)

Teammates without Nix don't build anything — they run the bootstrap wrapper, which downloads the latest released crucible for your OS and runs it:

./crucible            # interactive menu (pick a command)
./crucible module build
./crucible topdata validate

Windows (PowerShell):

.\crucible.ps1 module build

The binary is cached under ~/.cache/crucible/<version>/ (%LOCALAPPDATA%\crucible on Windows); --repo-local caches inside the repo instead. Private releases: set CRUCIBLE_TOKEN or write the token to ~/.config/crucible/token.

Develop

Self-contained (D8) — a host with only Nix can run everything:

nix develop            # Go + shellcheck + yamllint + make
make check             # go vet + go test + shellcheck + yamllint
make build             # build every cmd/* into ./bin (gitignored)
make smoke             # build + assert the fail-closed contract

Binaries are never committed — they are CI artifacts (D19). This retires the old habit of checking in nwn-tool / sow-toolkit.

CI

PR-first (D7): checks run once on pull requests; the only publish event is a v* tag (see runbooks/ci-trigger-standard.md in sow-docs, https://git.westgate.pw/ShadowsOverWestgate/sow-docs).

  • ci.yml — vet, test, shellcheck, yamllint, binary smoke, and cross-build all targets once per pull request.
  • build-binaries.yml — on a v* tag, cross-build and upload the binaries, SHA256SUMS, and the wrappers to the Gitea release, then delete the assets of every release except the newest two — Gitea keeps them forever otherwise, and every binary is reproducible from its tag.
  • sync-wrappers.yml — on a main push that touches wrappers/, auto-PR the canonical wrappers to the consumer repos in wrappers/consumers.txt. Consumer drift checks run after those PRs merge to main, not on the PRs themselves, to avoid recursive cross-repo checks.

Consumers

How the artifact repos resolve a Crucible binary is documented in docs/consumer-contract.md.

S
Description
Contains Crucible, our toolkit for processing NWN data and assets into its final form.
Readme GPL-3.0
60 MiB
v0.3.40
Latest
2026-08-05 16:02:36 +00:00
Languages
Go 98.8%
Shell 0.9%
PowerShell 0.2%
Nix 0.1%