Week of June 15, 2026. This is an archive page; back to the current week.
2026-06-21 · 84 items
Headlines
- Stood up the real login server on a live account backend, replacing the stand-in with genuine bcrypt auth, entitlements, and character slots.
- Replaced the entire legacy patcher stack with a from-scratch rsync-style block-delta patcher, signed manifests and all, live on the patch host.
- Built a login-gated account-admin web app to create, edit, reset, and delete test accounts, fronted through the portal.
- Mapped the ~20-CCU Photon ceiling and deployed the multi-instance scaling fix that breaks past it.
- Embedded the wiki assistant as a site-wide widget that answers with citations.
- Documented the full Store & Commerce suite and the entire Crown Store toolset.
Login server & accounts
- Stood up the live ***** + privapi account backend on a host LAMP stack as the real UserService login server, replacing the ***** stand-in.
- Wired the Photon game server to the real backend so auth uses real bcrypt passwords plus access-flags, character slots, and heraldry from real entitlements.
- Validated on the production bare-metal host: credentialed Master login authenticates end-to-end (Result=Ok), wrong passwords are rejected, and the no-cred bot baseline still exits clean.
- Added
setup-login-server.shto provision the login-server host. - Added
fk_strip.pyto strip old-MySQL foreign keys the migrations assume. - Added
base-tables.sqlto reconstruct the auth-path store base tables a clean build misses. - Added
seed-account.shfor creating test accounts andwire-vm.ps1for a reversible VM switch onto the real login server. - Added
bot-login-test.ps1plus a tools/login-server README documenting the new scripts. - Confirmed the in-VM "Group timeout" was a loopback NAT-hairpin artifact, not a login defect.
- Documented that PublicIPAddressReader resolves the advertised Scene/Group/Game address once at startup to the public IP (*****), which a loopback client cannot hairpin to.
- Verified an off-box BotClient login with seeded creds completes the full Master + Game + character flow with a clean exit.
- Documented the off-box test, the resolver mechanism, the optional hairpin masquerade, and the WaitingOnPreviousGame stuck-session gotcha.
- Built a login-gated Flask account-admin web app on the login-server host to list, create, edit-flags, reset-password, grant/revoke game access, and delete test accounts.
- Reused the proven account path: wp-cli for bcrypt and the register hook, with entitlements and flags applied via SQL on *****.
- Made account deletion use direct SQL to avoid the inactive XenForo forum-sync plugin fatal, since the forum is not deployed.
- Deployed the admin app on the login-server host as systemd
sota-accounts(waitress @*****) behind an Apache ***** reverse proxy on :*****. - Added login, CSRF protection, and a session-fixation guard, and verified TLS login, the auth gate, and create/edit/delete end-to-end.
- Fronted the account-admin tool through the dev portal so it sits behind a single door with a trusted cert.
- Taught the Flask app to honor X-Forwarded-Prefix via ProxyFix so it serves correctly under the /accounts sub-path.
- Firewalled the admin endpoint :***** to the portal host only so the admin app is no longer internet-facing.
- Configured the portal nginx /accounts/ location to bypass the ***** basic-auth so the app's own login is the single gate, and verified login/list/create/delete through the portal URL.
- Fixed the real-client login failure that returned an error after a correct password, traced to a Master InternalServerError over a mismatched accountId.
- Identified the root cause: accounts carried a Mongo game-account from the ***** stand-in (gameAccountId = *****) while the real server handed out a different random id, which the Master refuses to change.
- Made the admin tool and
seed-account.shstamp every new account with a deterministic ***** id at creation so it can't collide with stand-in-era Mongo data. - Documented the symptom, cause, and fix (align ***** or drop the stale Mongo account) in the login-server-mirror troubleshooting section, cross-linked from the account-admin-tool doc.
Patcher / Launcher
- Replaced the legacy UnityPatcher delivery stack (BitTorrent + xdelta per-version deltas + recursive-SQL PHP version service) with an rsync-style block-delta patcher.
- Designed the new model around version-numbered static build folders plus a small channel pointer for the "current version".
- Built a client that transfers only the changed bytes of changed files via rolling-checksum block delta, converging to latest from any prior version with no patch chain and no pre-generated deltas.
- Created the Patcher.Core .NET 8 library with RollingChecksum and BlockMap for the rolling-checksum block matching.
- Implemented ManagedBlockDeltaFileSync as the managed IFileSync that reconstructs files from local blocks plus fetched changed blocks.
- Added an HTTP range fetcher (IContentFetcher) that pulls only the needed byte ranges of changed files.
- Implemented an Ed25519-signed Manifest plus ChannelPointer, with per-file SHA-256 verification.
- Built TreeUpdater to skip unchanged files, delete stale files with user-data excludes, and self-heal via a
.repairmarker. - Added an ExternalZsyncFileSync wrapper as the production zsync option alongside the managed sync.
- Added Hashing, Signing, Channel, and Publisher helpers to round out Patcher.Core.
- Built the Patcher.Publish CLI with keygen, publish, and update commands.
- Added 13 tests including an end-to-end "only changed bytes transfer" proof over HTTP, backed by a TinyHttpServer test harness with range support.
- Added
infra/provision/80-patch-host.shto provision an nginx static vhost on 443 (immutable builds, no-cache channels) with Let's Encrypt. - Deployed the patch host live behind its own TLS cert.
- Added
tools/patch-publish.ps1as the CI publish wrapper that runs publish, rsync push, and the channel flip. - Validated end-to-end against the live host: a 1.5 MB file with ~100 changed bytes updated by fetching one 16 KB block, with signed-manifest verify and HTTP 206 ranges confirmed.
- Wrote
docs/components/patcher-v2.mddocumenting the new engine and addeddocs/migration/patcher-replacement-plan.md. - Added a banner to the legacy
docs/components/patcher.mdand updated the infra README to point at the new patch host.
Photon server & scaling
- Documented the ~20 CCU per game-server ceiling as the Photon Bootstrap (free, unlicensed) limit of 20 concurrent connections per PhotonSocketServer process, shared across all apps in the all-in-one Primary.
- Explained that an in-world client holds ~4 connections (Game + Scene + Group + Logging), so one all-in-one instance tops out around 5-6 players.
- Wrote
docs/operations/scaling-game-servers.mdcovering the bottleneck and the multi-instance fix where each per-player app runs in its own process for its own Bootstrap-20 while the Master load-balances Game/Scene/Group. - Captured measured per-type resource costs and the two topologies (in-VM instances vs separate VMs).
- Documented 100-CCU sizing, noting Logging is an unscalable single endpoint, plus the 20-CCU split now deployed on the Chaos box and verified live.
- Added
Server/deploy/apply-20ccu-split.ps1, an idempotent script that re-applies the split. - Made the script trim the Primary to Master/Social/CounterPublisher and stand up dedicated Game/Scene/Group/Logging instances on standard ports plus a 2nd Game/Scene/Group for headroom to ~20 CCU.
- Documented that a deploy overwrites PhotonServer.config and the extra app dirs, so the script should run as the last deploy step to restore them.
Wiki & assistant
- Fixed the /assistant page rendering as a standalone, unstyled "blank white page" by rendering it inside BookStack's own layout.
- Made page() return a Blade view: assistant-full (full wiki chrome) or, with ?panel=1, assistant-panel (chrome-less), with the shared chat UI in
_assistant-body.blade.php. - Switched colors to BookStack's accent custom-props plus a dark-aware palette so light and dark match the wiki automatically.
- Registered the
urpgtheme::view namespace in functions.php via View::addNamespace. - Wrapped the render in try/catch, falling back to the now dark-aware self-contained template so /assistant can never blank or 500 on the live wiki.
- Added
custom-head.htmlas the version-controlled source for the app-custom-head setting, with a floating launcher and slide-out panel that embeds /assistant?panel=1 in a same-origin iframe, gated to logged-in users. - Documented the embed/widget design and the new
view:cleardeploy step in the theme README. - Deployed and verified on the wiki: full page plus widget in light and dark, end-to-end ask with citations, ESC-close, and no console/CSP errors.
- Added the login-server-mirror and account-admin-tool pages to the BookStack manifest.
- Published the store-suite plan record to the BookStack manifest as a page under Migration > Design Plans.
- Published the Store & Commerce suite (hub plus the two how-to guides) to the BookStack manifest under the Game Systems (Client) chapter.
Dev portal & infra
- Added an "Accounts" card to the dev-portal landing page (infra/landing/index.html) linking to /accounts/.
- Wired one-click SSO: the portal /accounts/ location inherits the portal ***** basic-auth and passes a ***** header.
- Made the Flask app trust that header in before_request and auto-sign-in, so clicking the card lands straight in the manager with no second login.
- Kept the app's admin/password login as a fallback for the IP-blocked direct path, and verified no-creds returns 401 while a portal login shows the account list.
Documentation
- Updated docs/README.md and docs/repo-tour.md to link the new patcher-v2 doc and the patcher-replacement-plan.
- Wrote the login-server-mirror runbook and linked it from docs/README.md and docs/repo-tour.md.
- Wrote the account-admin-tool doc and linked it from the docs index, with the admin login and URL kept in .secrets and uncommitted.
- Updated the account-admin-tool runbook with the portal nginx block and the :***** lockdown.
- Rewrote the in-game-store how-to around the real Unity editor tooling under SotA > Crown Store instead of a bare menu-item list.
- Documented the Crown Store toolset map (create menu, Shelf Item Maker, custom inspector, Store Manager, Tag/Image brushes, Tag inspector, bake/export menus).
- Described the fast path (Shelf Item Maker drag-and-drop batches) versus the precise path.
- Documented the StoreShelfItem 3-tab custom inspector (Edit / Web Data / Default) field by field, including the live Categories/Item-Sets panels and the IsPremium / CanApplyToShelfItems warnings.
- Documented the Store Manager's 7 tabs (Item Explorer, Categories, Availability, Sale Rules, Vault Rules, Logging, Charity Ids) and the tag-expression mini-language.
- Documented the Tag Brush and Image Brush bulk painters.
- Documented the publish pipeline (Update Metadata bake → Server StoreShelfItems db export → deploy) with a start-to-finish walkthrough and menu reference.
Tooling & bridge
- In progress: drafting
docs/migration/photon-replacement-plan.md, a new migration plan for replacing the Photon server. - In progress: adding
tools/bookstack/deploy-wiki-index.ps1, a new script to deploy the wiki index. - In progress: refining the docs/wiki sync tooling.
- In progress: updating docs/README.md, docs/repo-tour.md, docs/wiki-publishing.md, and docs/operations/issue-tracking.md.
- In progress: revising
docs/systems/photon-api-surface.md(Photon API surface notes). - In progress: further edits to the BookStack theme README and
assistant.php. - In progress: updating .gitignore and adding the
tabula-rasa-fixed.pngasset.
2026-06-20 · 94 items
Headlines
- Got a 100% local Photon server fully playable: a Unity client connects, authenticates offline, creates a character, and spawns into the world.
- Squashed the top live client crash in chat input.
- Ran a codebase-wide documentation accuracy audit, 198 corrections across 131 files and 1,797 checked claims.
- Wrote an exhaustive housing and decorations suite, design, data model, code, and generated catalogs down to ~14k world lots.
- Built the offline UserService stand-in and the run-local-server tooling behind the local-server milestone.
- Shipped the Store & Commerce docs suite and a repeatable bot-test harness.
Login server & accounts
- Added a dev-only offline UserService stand-in (tools/local-userservice.ps1): a raw loopback TcpListener that answers the auth endpoint with an ErrorCode.Ok success response so a local server can authenticate without reaching the live website UserService.
- Made the stand-in derive a stable 24-hex gameAccountId *****, so each name maps to a persistent Mongo account across runs.
- Had the stand-in return access flags "Player, Dev" so CheckUserAccess is always-ok for local logins.
- Reverse-engineered the auth contract from Server's UserService.cs to build the stand-in response.
- Added -LocalAuth (+ -LocalAuthPort) to run-local-server.ps1 to repoint UserServiceURIFormat at the stand-in, re-applied each run since deploy.bat restores the apidev URL.
- Verified end-to-end: BotClient login makes the Master log AuthResponse ResultCode=Ok and persist a non-bot User (access=Player|Dev) keyed on the deterministic gameAccountId.
Photon server & scaling
- Added a verified end-to-end "running a local server" runbook for standing up the Photon backend on one box (assemble deploy layout, single-node MongoDB rs0, start the Default instance, prove it with an offline BotClient login).
- Documented that Photon runs on the free Bootstrap license (20 CCU) on localhost, so no license file is needed.
- Documented that a missing CounterPublisher app is FATAL (host aborts), not harmless, and must be provisioned from the Photon SDK tree.
- Documented that the Master needs bin/ServerAdmin/CharNameBlacklist.config at a hardcoded path.
- Documented that game-data reports (RollingServerReport.xml, StartingSkills/Decks/Hotbar) are absent from this mirror, so the server boots and authenticates but character creation fails with InternalServerError, plus how to source them from Perforce.
- Documented using MongoDB ***** to match the vendored ***** .NET driver.
- Assessed platform support: Photon Server (native Windows host) plus .NET Framework ***** make the server Windows-only; only the MongoDB tier can be Linux.
- Added tools/run-local-server.ps1 to assemble the layout, provision CounterPublisher + ServerAdmin, deploy a localhost Mongo.config, and start the instance, plus a committed Mongo.local.config template.
- Added a 'Primary' Photon instance to run-local-server.ps1 (deploy layout plus the Logging app on UDP *****) for connecting a Unity client; 'Default' stays for the BotClient.
- Verified live that the Primary instance binds UDP ***** + TCP ***** and the Logging app starts serving DefaultServerMessages.json, the connection the client login gate needs.
- Made run-local-server.ps1 -LocalAuth also blank LoginRewardDescription and SubscriberRewardDescription in the runtime config, so the monthly login/subscriber reward grant no longer crashes first login (ArgumentNullException in OnAuthenticateComplete).
- Documented the verified game-data procedure: build Server/Tools/ReportCombiner and run it over the Perforce workspace ServerReports to produce the ~119 MB RollingServerReport.xml into the deploy bin.
- Verified that with reports generated, rewards disabled, and the auth stand-in, a credential login completes end-to-end to the character-select stage (Master logs LoginSuccess then HandleAddAuthenticatedPeer, Access=Player|Dev).
- Reconciled the local-server runbook to the full working flow: a Unity client connects, authenticates offline, creates a character, and spawns into the world on a 100%-local server.
- Rewrote the runbook status banner + TL;DR around two paths (BotClient smoke test vs. full Unity offline login) and the verified Unity-into-world result.
- Updated the runbook architecture diagram to show the Primary instance, the Logging app (UDP *****), and the auth stand-in.
- Corrected the runbook's game-data note: the starting loadout comes from StartingContextDb in RollingServerReport.xml, so a separate StartingSkills/Decks/Hotbar file is NOT required; character creation verified working.
- Added a single "Connect a Unity client end-to-end (offline)" recipe tying together game-data, the stand-in, the Primary instance, -LocalAuth, and the Localhost button.
- Added troubleshooting rows for WebServerError, the reward-payout crash, and NoLoggingConnection.
Gameplay & server fixes
- Fixed the top client-side crash in chat input, the most frequent exception in the live logs, by hardening how the chat field tracks item links so drifted state degrades to plain text instead of crashing.
- Hardened a chat slash-command handler that could crash on a length mismatch.
- Made the GM-client "Localhost" server option fully work: it previously only set the game host (NetworkHost) and hard-blocked at login on NoLoggingConnection because the logging host was never set.
- Added a loopback-address constant in LoginManager (GMCLIENT) so the Localhost button uses it instead of the bare "localhost" string.
- Updated LoginUI.OnConfirmServerAddressButtonClicked so a loopback target also sets LoggingHost to the same host, while remote targets (Dev/QA/Live) clear the override so default/redirect logging is unchanged.
Wiki & assistant
- Registered systems/console-and-chat-commands.md in the BookStack manifest as a Game Systems (Client) page.
- Registered systems/quest-system.md in the BookStack manifest, mapped to the architecture book (gs-client chapter) after NPC Conversation & Dialogue.
- Added the new guilds deep-dive to the BookStack manifest (gss-guilds).
- Added 16 previously-unmapped docs to the BookStack manifest: running-a-local-server, hosting-on-linux-kvm, logging-and-kibana, the consumables-mechanics crafting reference, a new Housing (Deep Dive) chapter, and the 5 Migration design-plan docs.
- Simplified the regex-replace in tools/wiki/publish-docs-to-wiki.ps1 by removing the unnecessary Singleline option.
Documentation
- Added a Store & Commerce docs suite (docs/systems/store/) documenting both stores and how to add an item to each.
- Wrote the store README hub: the unified real-money funnel (web/Steam/reseller into *****), the web→game offer-fulfillment chain and its three brittle no-FK joins, the instant Crown path, currencies, the metadata-only Crown↔web linkage, idempotency, and a source-of-truth map.
- Wrote add-item-to-web-store.md: the ***** catalog row + flags bitmask, the ***** SQL (the step with no UI), the game-side OfferBundle dependency, verification, and traps.
- Wrote add-item-to-in-game-store.md: StoreShelfItem asset → bake (Portalarium ▸ Store ▸ Update Metadata) → export (Server StoreShelfItems db → StoreShelfItemsDb.xml) → deploy.
- Corrected the in-game store how-to to remove the non-existent "Export StoreShelfItems.xml" menu in favor of the real Reports ▸ Server StoreShelfItems db pipeline.
- Cross-linked the store suite from economy-vendors-store.md and components/website.md and indexed it from README and repo-tour.
- Added a Guilds deep-dive (docs/systems/guilds.md) covering creation/charter flow, the role & permission model, membership management, leadership succession & auto-disband, MOTD/chat, the client/server protocol, SocialServer architecture, the three Mongo collections, and the audit log.
- Cross-linked guild-war internals to server-economy-and-guilds.md and added a Guild glossary entry.
- Added a console & chat commands reference documenting the chat/slash commands (ChatUI.ProcessSlashCommand, 92 cases) and the GM-only /~ developer console (DeveloperConsole.cs, ~184 aliases) with grouped arg/effect/example tables drawn from in-code format strings.
- Documented the three-layer command gating model (#if GMCLIENT → runtime GM-power check → server UserAccountFlags) plus a maintainer source map.
- Added a quest-system deep dive: quests as knowledge flags + journal entries + conversation actions (no monolithic Quest object), FlagsExpression evaluation, QuestData NPC markers and quest AI, server-side reward/anti-farm validation and quest reset, and an authoring walkthrough.
- Corrected the quest-visual description: QuestVisuals maps QuestStatus to designer-assigned SkinnedMeshRenderer/GameObject sets and there is no hardcoded !/? glyph in code; added a gotcha noting the absence of a default icon.
- Added an exhaustive housing & decorations suite (docs/systems/housing/) covering the system from design, data, and code angles plus generated catalog data.
- Wrote housing/design.md: lot tiers, the deed/tax economy, decoration limits/categories, permissions & roles, basements/dungeons, magic mover, Player-Owned-Towns, devotionals, and guild/PVP lots.
- Wrote housing/data-model.md: the 10 Mongo collections (fields/indexes/TTLs), 18 enums, the DecorationSettings/PlacedItemParameter key map, TaxRules, and the PlotStateParameter/TownStateParameter bags plus the sotamap SQL schema.
- Wrote housing/code.md: migrated and expanded from the old housing-and-plots.md, adding the GameServer economy side (GameImpl.cs) and SceneServer validation (SceneImpl.cs) the old doc under-covered, the op/event interface catalog, and end-to-end traces.
- Generated housing catalog tables with real numbers: tax/rent, per-shape decoration limits for standard/basement/dungeon/POT, the 199 homes, and ~14k world lots.
- Turned the old systems/housing-and-plots.md into a redirect stub to keep inbound links working, and repointed README.md + repo-tour.md indexes at the suite hub.
- Added a hosting-on-linux-kvm runbook for hosting the Photon server on a bare-metal Linux box: a single Windows VM under KVM with ZFS-mirror storage for instant snapshot/rollback.
- Covered ZFS pool setup, the KVM/libvirt/OVMF stack, the ufw + NAT security posture (sensitive services kept private), the unattended Windows guest, near-native single-level-KVM tuning, the SotA deploy, and the snapshot-before-migrate + rollback workflow.
- Brought the KVM runbook from "deploy in progress" to completed/validated and folded in the host bring-up specifics.
- Documented autounattend gotchas: virt-install --noautoconsole power-off-between-phases, Shell-Setup element order, the 259-char CommandLine cap (split first-logon commands), and reading Panther\UnattendGC\setuperr.log via an ntfs-3g ro mount of the guest disk.
- Documented the concrete deploy steps: ship the deploy/ tree, the VC++ redist (mongod 0xC0000135), the MongoDB ***** service + explicit-loopback rs.initiate, running Photon as a service (not Start-Process /debug, which dies on SSH disconnect), the auth stand-in as a scheduled task, and a bot smoke test.
- Documented exposing the server to clients: public-IP advertisement, host port-forwarding for the game client ports (sensitive services kept private), and the VM Windows Firewall openings (loopback bot exempt, external clients not).
- Documented the live Kibana/ELK logging stack, verifying it is still live: debug/all logs at ***** and economy/item at *****; an older debug VM is dead.
- Added docs/operations/logging-and-kibana.md covering topology, the log4net→syslog→Logstash ingest path, index/field schemas, and copy-paste ES query recipes for scanning errors/exceptions.
- Cross-linked the logging doc from README, the repo tour, ports-and-environments, and the log4net appenders table in the config reference.
- Documented the GM-client one-click Local option and the logging-server requirement in client-editor-server-targeting.md (a Unity client needs a Logging-enabled instance).
- Added plan records for the chat-input crash fix, the housing docs suite, and the store docs suite.
Documentation: accuracy audit (198 fixes)
- Ran a codebase-wide doc accuracy audit (131 files, 1,797 claims checked) and applied 198 corrections (22 P0, 52 P1, ~124 P2); 5 findings were re-verified as false positives and left unchanged.
- Removed an invented "LoadBalancing" Photon instance from ports-and-environments.md (the LoadBalancer.config path is just a load-shedding weights file).
- Fixed skills/magic/sun.md: 5 spells wrongly marked "Reagents: None" (SolarFlare, SummonPhoenix, ElysianIllumination, RevealHidden, DazzlingRays) now list their actual reagents and consume chances.
- Corrected the ShadowForm lock time in skills/magic/lunar.md to 6 − skillLevel/20 (it was inverted to 1 + skillLevel/20).
- Corrected combat/hit-outcomes.md and damage-and-resistance.md: rooted targets skip the dodge roll entirely rather than having dodge halved.
- Corrected systems/pvp-and-flagging.md: open-world PVP attackability is enforced via collision-layer switching (CharactersPVP), not a both-flagged OpenPVP check in CombatEffect.
- Corrected skills/crafting/catalog/patterns.md: patterns are consumed on use (Eternal variants returned on salvage), not "learned once, never consumed".
- Corrected components/server-ops-and-tools.md: sota-stream is a donation/goal tracker; the Twitch chat feed is designed (config.yml.example + custom.js) but not implemented server-side.
- Corrected combat/status-effects.md: using a combat rune or unsheathing sets LastSpawnTimeTicks=0 but does not remove the SpawnProtectionCharacterEffect; only fall damage ends it early.
- Corrected hosting-on-linux-kvm.md to drop an internal S2S port (*****) from the public-forward list; the client TCP port set is ***** only.
- Corrected systems/ui-framework-ngui.md: SimpleJSON is not used by MoveableWindow/UIPersist (those use JSONPropertyBag); SimpleJSON is only in TranslationAPI and CharacterAppearance.
- Corrected skills/magic/earth.md SummonEarthElemental combo requirement to the actual runes referenced (Juxtapose and SummonAirElemental).
- Corrected the data-model class count to 75 [ShroudStorage] document classes (was ~60) and fixed the Portalarium.SotABackend.dll.config filename (was "Portalinium").
- Corrected the photon-api-surface.md ApplicationBase list to 6 server applications (removed the non-existent LiteApplication; Lite.dll is an SDK dependency).
- Corrected glossary.md auction class names to PlayerAuctionItem / PlayerPurchaseOrder, and updated the CharacterStat channel count to ~556.
- Corrected skills/strategy/taming.md: the TameFrenzy -20 aggro effect targets the pet, not the handler, and fixed the TameCombatTraining tree parentage (TameObedience, not TameCollarRecovery).
- Corrected skills/magic/air.md: ChainLightning chains up to 4 hops (not 2) and Blink consumes Black Pearl + Mandrake Root + Sulfurous Ash (not just Black Pearl).
- Corrected the skill-school count to 37 schools (was 32) in repo-tour.md and README.md, and the crafting pattern count to 1,657.
- Corrected combat/formulas.md to cite CombatFormula.cs at 3,389 lines (was 2,092) and infra-sizing.md to ~440k tracked files (was 350-400k).
- Corrected the unity6-upgrade-plan.md NGUI framing to match the linked assessment (NGUI is actively maintained and likely Unity 6-compatible after a version bump).
- Added docs/_audit/2026-06-20-doc-accuracy-audit.md with the full findings.
Tooling & bridge
- Added tools/run-bot-tests.ps1: a harness that drives SotABotClient across many /t modes, continues past failures, and writes a per-mode PASS/FAIL report under .test-results/ (gitignored); can bring the local stack up/down with -StartStack.
- Added a new '/t whisper' BotClient mode (WhisperTest + GroupConnectionForWhisperTest): a minimal multi-user reference test where bot A whispers bot B and bot B asserts the received event.
- Documented the bot-test harness and whisper test in running-a-local-server.md and systems/server-testing-and-botclient.md.
- Added an export-housing-catalogs.ps1 exporter (deterministic, marker-injected, regenerable after a Perforce sync) plus a tools/housing/README.
- Gitignored local-server runtime artifacts (deploy/SotABackend, deploy/CounterPublisher, deploy/log, deploy/itemlog, deploy/bin_win64/log, and a root log/) so local runs leave a clean working tree.
2026-06-19 · 95 items
Headlines
- Closed two XP-award exploits where combat bonuses were paid without genuine risk or to the wrong players; both now validate server-side.
- Migrated the entire wiki to BookStack and layered a citing Wiki Assistant on top of it.
- Stood up self-hosted Gitea Issues as the team's task and bug tracker.
- Landed a massive documentation push: a full combat engine reference plus all 32 skill schools across 33 new docs.
- Documented the entire crafting content layer, every recipe, item, effect, and pattern across 15 schools.
- Fixed GM invisibility still broadcasting "is now online" to friends and guild.
Gameplay & server fixes
- Fixed GM invisibility still broadcasting an "is now online" notification to friends and guild in some cases.
- Fixed the GM invisibility toggle not fully restoring normal presence when switched back off.
- Closed two XP-award exploits: one paid a group/PVP combat bonus in instances that carried no genuine risk, and one paid the bonus to the wrong players. Both now validate authoritatively on the server, with regression coverage. Mechanics withheld.
Photon server & scaling
- Enabled local server builds with
tools/setup-server-build-deps.ps1, which junctions the four out-of-tree sibling trees (PortalariumLibrary, InstallTools, Photon, MongoDb) from the Perforce workspace. - Stopped committing server codegen output, since GenCode.exe rewrites
Server/src-server/**/Generated/*.cswith a timestamp header on every build, causing endless churn. - Gitignored and untracked the server
Generated/code; verified a clean build recreates all of it (deleted 67, rebuilt, 67 restored, exit 0). - Kept the Unity client
Generated/copies tracked, since the Unity build does not run GenCode. - Noted to keep the untrack Git-only until cutover so the outbound bridge doesn't replay it as a Perforce delete.
- Documented every Photon API called on server and client (method signatures, behavior contracts, custom serialization types) plus a replacement-library evaluation matrix for replacement planning.
Wiki & assistant
- Migrated the wiki from Docmost/Wiki.js to BookStack, deployed via
70-bookstack.sh(BookStack + MariaDB on *****, internal-only) with cutover/rollback and a daily backup cron. - Added
tools/bookstack/: a token-REST publisher (docs/ to Shelf/Book/Chapter/Page with a two-pass link rewrite) plus a manifest and awiki-sync-status.ps1drift detector. - Added the
sync-wikiskill to reconcile docs/ and BookStack both ways, deprecating the old Docmost/Wiki.js provisioning scripts. - Added a Wiki Assistant at
/assistantvia a BookStack logical theme: a search-and-answer helper over the wiki that returns cited, permission-aware results. - Stored the assistant's API key server-side only, never committed.
- Added a doc map (precomputed per-page summaries + section headings for all ~45 pages) so the assistant can pick relevant pages, with keyword search as a fallback.
- Added
tools/bookstack/build-wiki-index.ps1to generate the deterministicwiki-index.jsondoc map from docs/ + .bookmap, with no extra search index or database required. - Made the assistant permission-filter the doc map via
Page::visiblebefore it uses it. - Added unanswered-question logging: a
report_gaptool plus alooksUnansweredheuristic and truncated-run fallback so misses are caught. - Made the assistant append gap records as JSON to
assistant-gaps.jsonland tell the user the question was logged. - Added an admin-only
GET /assistant/gapsendpoint to review the research backlog, with?format=jsonfor raw export. - Fixed the BookStack publisher creating duplicate pages/chapters on every publish, since this BookStack version derives slugs from the name and ignores the requested slug; fell back to name-based matching.
- Applied the same name-fallback match to shelves, stopping re-publish from creating duplicate shelves (5 had accumulated).
- Applied the same name-fallback match to books, closing the duplicate "Combat & Skills Reference" book on republish.
- Registered all new crafting, combat, and skill pages plus new chapters in the BookStack manifest and corrected the Combat & Skills book slug to
combat-skills-reference.
Documentation
- Added
docs/skills/crafting/consumables.md, a code-verified dive into how the 533 consumables work at runtime, with every claim cited to file:line. - Documented the consumable item+rune model and the consumption flow.
- Documented the cooldown system, including that an inventory double-click is not cooldown-gated while a locked combat-deck card is.
- Documented the Consumable Power Bonus / "potion sickness" mechanic.
- Documented the 6-slot food/drink buff channel, elixirs, and per-category behavior (potions, food/drink, poisons, transformations, mounts, scrolls, cosmetics).
- Documented the entire crafting content layer: every recipe (3,257), item/material/tool (2,960), item-instance effect (781), and pattern (1,658), across all 15 crafting schools.
- Added three crafting data-model reference docs (recipe/item/effect asset schemas, enums, and the magnitude formula
1 + Prof/125 + 0.05·(Tier−1)). - Added a Crafting System hub README tying the skill docs, references, catalogs, and runtime pipeline together.
- Generated 21 content catalogs under
catalog/(recipes per school, materials, components, reagents/fuels/ingredients, tools, masterwork/enchant/other effects, consumables, craftable equipment, patterns) with exact ingredients-to-outputs. - Folded the Smelting alloy recipes (Bronze, Constantan, White Iron, Meteoric Iron) surfaced by the catalog into
refining.md. - Recorded the key data-model finding that consumable buffs are an
m_runereference to a Rune asset, not an Item-Instance-Effect. - Recorded that
CharacterStatis a plain sequential enum with 574 members and thatGemType's element is encoded in the effect name rather than the field. - Added
docs/skills/rune-asset-reference.mddocumenting every serialized field of a skill asset (Rune ScriptableObject + CombatEffect/MasterCombatEffect), grouped by inspector divider. - Documented the runtime formulas that combine rune fields (focus cost, cooldown, fizzle, weighted effect selection) and the supporting enums.
- Fixed two stale
../../../systems/links (one../too many) inheavy-armor.mdandrefining.md. - Added an exhaustive combat system reference plus a 32-school skill reference across 33 new markdown docs.
- Documented the CombatFormula RPN evaluator (147 token types), all 50+ EffectType handlers, the DamageType/resistance pipeline, 28 CharacterEffect subclasses, and HitType roll order with Crit/Glancing/Dodge/Parry/Block mechanics.
- Added a master skill index, data model + InnateReward scaling, and progression/XP curves, then one doc per school (7 Combat, 9 Magic, 5 Strategy, 3 Crafting).
- Documented the PVP flagging system (self/group/scene), how a party overrides attackability, and the server-authoritative PVP XP bonus award flow with the client/server authority split.
- Added
building-the-server.mdcovering the four out-of-tree dependencies + junction setup, .NET ***** / MSBuild prerequisites, the GenCode generator, the build command, and why generated code is no longer committed. - Updated
migration/status.md(local build works; codegen + bridge notes) andonboarding.mdwith server build steps. - Added
docs/operations/mongodb.md, an operational and developer guide covering replica-set topology, connection/config, adding a collection, the data-migration process, backup/restore, security findings (P0-P2), and a modernization roadmap. - Cross-linked the MongoDB doc from data-model, server, server-ops-and-tools, ports-and-environments, and server-config-reference.
- Added a Windows-fleet SSH remote-management plan comparing SSH vs WinRM/Ansible/PsExec, with a per-box bootstrap runbook and security rules.
- Started a persistent
docs/critical-tasks.mdbacklog, seeded with the SSH rollout and a fleet inventory/assessment, and later added MongoDB task #4. - Added comprehensive AdminTool documentation covering setup, authentication, command set, repository layout, and security notes for internal use.
- Added
client-editor-server-targeting.mdexplaining how to retarget the editor to Dev, QA, or Live servers via scripting defines and GM client options. - Established
docs/plans/as the per-task history of why a change was made, with date-prefixed kebab-slug plan records. - Linked all new docs from
docs/README.mdanddocs/repo-tour.mdacross the crafting, combat, skills, PVP, MongoDB, AdminTool, and remote-management additions.
Dev portal & infra
- Stood up self-hosted Gitea Issues on cspears/urpg as the team's free, self-hosted task & bug tracker, driven over its REST API.
- Wired scoped API access to the tracker for the team, with the token supplied via an environment variable.
- Added
docs/operations/issue-tracking.mdcovering scoped labels, milestones/scheduling, the kanban board, a REST cookbook, and the agent loop. - Added idempotent Gitea setup scripts under
tools/gitea/to mint a bot account + issue-scoped token and to create labels, the seed milestone, and seed issues. - Pinned issue time-tracking in
app.iniviainfra/provision/20-gitea.sh. - Provisioned 20 scoped labels, an "Infra hardening (P0)" milestone, and 4 seed issues from
docs/critical-tasks.md.
Tooling & bridge
- Added
tools/crafting/export-crafting-catalogs.ps1, which parses the Unity crafting.assetfiles, builds a GUID-to-path index, resolves references to display names, and injects markdown tables into the catalog docs. - Made the exporter derive
CharacterStatnames from source, build produced-by/used-in cross-refs, and stay deterministic and idempotent for re-running after a Perforce sync. - Extended the exporter to resolve each consumable's
m_runeto its cooldown, food-slot weight, and power-bonus gate. - Regenerated the consumables catalog with new Cooldown (all 533 items) and Food slots columns.
- Found via the exporter that every rune-bearing consumable has a cooldown, while the 94 no-rune items (dyes, repair/engraving kits, mugs, ammo, treasure-map pieces) have none.
- Added the standard "generated, do not edit by hand" note line to the other catalog blocks on regeneration.
- Added
tools/win-ssh/bootstrap-sshd-win81.ps1, a per-box OpenSSH bootstrap template for the legacy Windows 8.1 fleet. - Removed stale Playwright console and page-log artifacts and gitignored them.
- Recorded the team preference in CLAUDE.md to work directly on main and only branch when explicitly asked.
- Updated CLAUDE.md guidelines to record successful discoveries in docs and to link new findings from README and repo-tour.