# Changelog ↔ Commit Map

> Reference for maintaining the two changelog pages. Built 2026-07-17 from a full
> pass over the repo history (464 commits, 2026-02-23 → 2026-07-16).
>
> - **Game changelog page**: `app/p_changelog.cfm` (public, `i.cfm?p=changelog`)
> - **Admin changelog page**: `app/Admin/assets/views/changelog.js` ("What's New?" in the Admin panel sidebar)
> - Conventions and update procedure: `app/docs/changelog-system.md`

## Last processed commit

Everything up to and including this commit has been reviewed and is reflected
in the change logs. A generation pass (see
`app/docs/changelog-fireup-prompt.md`) scans `<hash>..HEAD`, generates the
entries, and then MUST move this marker to the branch tip in a final bump
commit.

**Two copies of this marker exist and must always match** (Amanda, 2026-07-31):
this one, and `changelogLastReviewedCommit` in `app/p_changelog.cfm` (the
in-app copy, at the very top of the file). Update BOTH in the same bump commit.

- **Last processed:** `79c836f` — 2026-10-05 "Display and Chat/Search Patch"

## Versioning baseline

- **Version 100** = the base game as imported in the first commit (`52be6d0`, 2026-02-23).
  Nothing before that commit is documented anywhere; the pre-repo history lives on
  `f_com_news_updates.cfm` ("Older Change Log", 2016–2023).
- Patches **#101 → #106** have manually written notes (posted to the Help Center).
  Those notes are reproduced on `p_changelog.cfm` essentially verbatim (downtime
  scheduling paragraphs trimmed).
- Entries marked **(filled in retroactively)** on the page were compiled from commit
  history by Claude on 2026-07-17 — Amanda has not reviewed the numbering
  (#104.1 / #105.1 / #106.1 / #106.2 / #107 are extrapolated, not official).

## Classification rules (from Amanda, 2026-07-17)

1. **Admin-related files anywhere in the tree go ONLY in the admin changelog** —
   that includes `app/Admin/` and admin hooks living in game files
   (force-relog flag in `s_loadvar.cfm`/`i_f_800.cfm`, `z_admin_reset_notice.cfm`,
   lastaccess tracking added for the panel's live-players view, etc.).
2. **Legacy edmin (`app/edmin/`) is defunct and is NOT documented in any log,
   anywhere.** Its commits are mapped below only so future passes know they were
   deliberately excluded, not missed.
3. **Backend/internal details players don't need are excluded from both** — e.g. the
   per-user CF22/UIP overrides in `p_login.cfm`, CI/workflow fixes, cache-busting,
   debug toggles, SQL-injection refactors, IP-conversion plumbing, `ihasrunflag`
   guards, Z_Get API debugging.
4. Player-facing *effects* of backend work can be documented generically
   ("fixed page lag on Summary") without implementation detail.
5. **Undisclosed mechanics are never documented** — hidden formulas/thresholds
   players are meant to discover (e.g. the Gordo cluster-conversion land
   threshold change in `ac0e084`, 15,000 → 20,000, was cut from the #106.2
   entry for this reason). Staff-written posts set the disclosure line.
6. Describe features by the screen the player sees, not the file name —
   `s_com_market_use.cfm` is the *artifact use* screen, not a market page.
7. **The account obfuscator is a BLACK SITE — it appears in no changelog,
   ever** (Amanda, 2026-08-06, reaffirmed 2026-08-12). This covers the whole
   feature and everything that touches it, for all time: the original build,
   fixes, follow-ups, ACL changes, and the removal of its audit logging.
   Applies to the admin What's New as much as the public page — the panel
   changelog is read by staff the feature is meant to hide accounts from.
   Files: `Admin/api/components/Obfuscation.cfc`, `Admin/assets/views/
   obfuscation.js`, `Admin/sql/admin_obfuscation*.sql`, and the obfuscation
   hooks inside `Base.cfc` / `Users.cfc` / `AntiCheat.cfc`. If a commit's only
   substance is obfuscator work, the pass produces no entries at all — just
   record it below and move the marker.
8. **Verify a changed file is actually reachable in the UI before documenting
   it** (Amanda, 2026-07-26). Dead/orphaned pages get edited during sweeping
   refactors; their changes are documented nowhere. Check with
   `grep -rn "f=<pagename>" --include="*.cfm"` — if nothing but the file itself
   (and defunct edmin) links to it, it is dead. Known dead:
   `f_com_changelogs.cfm`.

## Reading industry modifiers out of the DB

`gcc.planet_type.industry` stores a multiplier where **100 = no modifier**, so
the percentage shown on the change log is simply **`industry - 100`**
(Amanda, 2026-08-11). Verified against live values: Infected C3 stores `110`
and the #106 table shows `+10%`; Infected C0 stores `80` → `-20%`.

```
SELECT id, name, pop, industry, agriculture, mining FROM planet_type ORDER BY id;
```

Present them with the `clog-mods` grouped-panel component (see the #106 and
#109 entries) — group by race/family, preserve in-group order, colour-code.

## Patch ↔ date ↔ commit mapping

| Entry | Date | Status | Key commits (non-merge) |
|---|---|---|---|
| v100 base | 2026-02-23 | baseline | `52be6d0` |
| #101 | 2026-04-15 | official notes | `b5d7124` (initial updates), `2a14e2f` (Argon2 + SQLi fixes), `0b9d25e`, `3050c00`/`4214900` (public rework), `551c6cc`, `e6c4662` (forum/HC), `2e1aeea` (signup email), `f4aa738` |
| #102 | 2026-04-23 | official notes | `d235802`/`e7b6400` (UI prep), `e0d83c0`/`fb67ebb` (new Events), `f5886e3`, `b368c71`, `2173372` (game part), `9686515` (market sum), `be6a631`, `90eeba6`, `12da089`, `aa8081e`; builder work `eb2a812`/`6426fc8` (5/6) |
| #102.1 | 2026-05-09 | official notes | `d3b7419` ("Patch 103 Various Fixes" branch — released as 102.1), `0397992`, `fcbbcfc` (DSR), `529cc74`…`827953f` (small-fixes churn) |
| #102.2 | 2026-05-14 | official notes | `e28a4c3`, `b386a5d`, `e1a12ac`, `7db1a39` |
| May additions | 2026-05-14/15 | **filled in** | `08cc5c3` (24h uniques + users-online popup), `d1a003d`+`58cc92e` (Server Activity page `f_com_activity.cfm`), `0e9d79d` |
| Race Explore | 2026-05-15 | official notes | `8e446aa` |
| #103.1 | 2026-05-16 | official notes | `dfb9275`, `41e096d` (plunder formula), `6cc6a7b` (#103.12), `8238c34` (#103.13) |
| #104 | ~2026-05-22 (approx) | official notes | `a821353` (Act 0 tutorial), `263cf34` (M1), `531ac7c`, `f2de26b`; PW min length `d798a05`/`6fc79c4`; later act0/restart bits `3bec92a` (6/4) |
| #104.1 | 2026-05-27→30 | **filled in** | `dbd1f34` (TrueRank), `db5a8e5`/`3dce5a8` (plunder credit calc), `1558e3a` (mineral ceil), `e5adb9a`/`0c1f34c` (market bidmin/minprice) |
| #105 | ~2026-06-07 (approx) | official notes | `fc693da` (game part), `845cc67`/`5515711`/`799a5d7` (colony + market styles), `2e1052f`, `300c896`/`5f2db7f`/`5f5f0fc` (market expiry+refresh), `3c54c9a` (Firefox chat), `824d7eb`+`b64b8fa`/`7919c76`/`9d02176`/`37fa3b4` (mineral income accuracy), `9cd381c` (6-5 fixes), `6253cf0` (attack req rewrite — backend), `638cc06` (validation — backend) |
| #105.1 | 2026-06-11→24 | **filled in** | `1dce281` (Turnstile captcha), `825a02e` (Act 0 reward), `4b5cb5e`/`01fd600` (Act 1 M9 colony levels), `3278e32`/`7c05331`/`58bf204`/`6c45ac0`/`67e4495` (capture + Corruption-era code), `9ed3712` (attack misc), `1cce1a0` (mineral cap in turn use), `baa1ced`/`dedc5f1`/`ce80c19`/`de303f8` (infect/assim + converted colonies) |
| #106 | 2026-06-26 | official notes | Fracture: `9287579`, `7e7f8b0` (loyalty), `9912635`, `a5c1425`, `ca74569`, `d29b818`, `492f7fd`, `f403181`, `38a405a`, `9a1bd11`/`f0164e5` (caps/thresholds), `f33b3bb`/`23a96df` (random market buys), `4e19988` (industry mods), `7088120`, `f43b71d` (industry RM), `a8dbe33` (post caps) |
| #106.1 | 2026-06-26→30 | **filled in** | `9ebae5b` (market withdraw), `f82f458` (caplab), `af95a4a` (mobile gordos), `204139f` (activity 5yr), `86957d6`/`c177680` (Temple daily), `c0a302f` (rank styling), `56d9be2` (summary lag), `91c36ea` (artifact-use goods update) |
| #106.2 | 2026-07-03→10 | **filled in** | `ac0e084` (UnRe cooldown; its cluster-threshold 15k→20k change is EXCLUDED per rule 5), `8ec7cd1`, `c513edb`/`c80da93` (VM excluded), `0d03a03` (NPCs excluded), `723845c` (events display), `c3463ba` (fed member UI), `453da9d` (summary), `ca17e2e` (COY filter), `3159ab1` (premium counter counts on rank) |
| #107 | 2026-07-15→16 | **filled in** | `ddf3c76` (Net Worth List), `32ad78e`/`dd04baa`/`ef1e656`/`7e63632` (builder end-turn + total cost msg), `929f85b` (old caps on market/ship), `2384472` (modern refresh page) |
| Staff chat posts | 2026-09-26 | `979ec3d` (no commit body; read from the docs it updated, checked against the code). **Admin log only** — Amanda: the game-side parts are admin-related, including the staff name styling players see and the player API's `badge: "admin"` (`api/components/Chat.cfc` `splitBadge`). New `Chat.post` endpoint + ACL `chat.post` (default 5); always game `1`, channel 1, server 4; name `^[A-Za-z0-9 _.\-]{1,20}$`, text capped at 150 (as `i_chatb.cfm`), stored value rejected over 255. Staff name is a `<span class="gc-chat-staff" data-admin="<id>">` stored in `chat.name`; `Functions.cfm` `gcChatStaffName()` / `gcChatName()` match it on the RAW value (player names are entity-encoded, so none can forge it). `Base.staffPostAuthor()` resolves the author from `data-admin`, falling back to the `chat.post` audit entry for older posts. `chatResolve` refuses warn/silence on a staff post; No action only, audited against the admin account. Audit screen takes `#/audit?username=`. **Migration `Admin/sql/chat_name_expand.sql` widens `chat.name` and `chat_abuse.name` to `varchar(80)` — required before deploy** (strict mode makes an over-long name an error). Applied on the local DB. |
| Moderation: PM log, Dismissed, Resolution card | 2026-09-26 | `7e6d6ff` (no commit body; read from the docs it updated, then checked against the code). **Admin log only.** `moderation.chatActions` now UNIONs PM outcomes (`PM_ACTION_SQL`) only when `canSection("moderation.pm")` — audit `target_id` records `1`/`0`; ACL `moderation.chatlog` relabelled "Recent moderation actions (chat + PM)". New `moderation.dismissed` endpoint + ACL (default 3; `kind=pm` also needs `moderation.pm`), readflag 255 duplicates excluded. `resolveAudit()` supplies who/when/reason/shared-with for the Resolution card and Dismissed rows, and shifts `admin_audit_log.created_at` (DB clock) onto the game clock by the measured offset, rounded to the quarter hour; the Audit screen still shows raw times. `pmDetail` now starts from `user_pm_abuse` and LEFT JOINs `user_pm`, so a complaint whose message was deleted still opens; deep link `?pid=`. Deleted-message counts (1,350 of 1,373 resolved, locally) dropped from both the entry and `CHAT-MODERATION.md` as not the point; both now say "most". |
| PM reporting + verdict reasons | 2026-09-26 | `3cd3735`. **Admin log only** (Amanda: PM reporting from the game counts as admin-side). Panel: `Moderation.chatResolve` / `pmResolve` take `showreason`; routed to the verdict's message recipient — offender on warn/silence, complainer on No action, nobody on Suspend/Blacklist, never both; `Base.reasonForPlayer()` shared wording capped at 200 chars to match the audit entry; audit records who was actually told. Game: `f_pm_r.cfm` rebuilt (`gc-pmr-*` in theme.css) — shows the message, reason box, rules link, confirm + move to Trash; refuses not-your-mailbox / system / not-recipient. Double-submit guarded by a single check-and-insert statement. `user_pm_abuse.datetime` defaults to NULL and the old insert set only `(id, name)`, so game-filed reports were undated — 808 of 81,271 local rows have no date. **Not in the entry (rule 3):** the old page built its `update` / `insert` from raw `url.id` and `form` values; now parameterised. The PM complaint queue itself (`pmResolve`) already existed. Amanda had not committed the work; committed here at her request, then documented. |
| Colony mineral editable | 2026-09-21 | `bcdbe61`. **Admin log only** — the feature is panel-side; nothing a player sees changed, and the API touched is the ADMIN API (`Admin/docs/API-REFERENCE.md`), not the player API under `app/api/`. `Base.mineralGoods()` reads `good WHERE type = 1` (cached) rather than hardcoding the six, so a seventh mineral would appear on its own; `mineralName()` backs the name-not-number change log ("Mineral Terran Metal → Rutile"). `Users.cfc` validates `col.goodid` against that list — an artifact id would leave the colony mining something the turn engine never pays out for. Note the validation `continue`s, i.e. drops the field silently rather than returning an error. No new ACL: `players.colony.view` / `.edit` already gate it. Entry written by a different session; audited here (JS parses, newest-first, no duplicate, claims check out) and the missing commit-map row + marker bump added. |
| #109.10 | 2026-10-05 | **filled in** (thread + auto Discord, @everyone; Amanda-approved bullet wording) | `79c836f`: global Search box (`i_gsearch.cfm`, `JS/gc-search.js`, `Z_Search_Empire.cfm`, `s_loadbar.cfm`, `_shell_mobile.cfm`), inline chat posting (`i_chat_compose.cfm`, `i_chat_feed.cfm`, `JS/gc-chat.js`, `s_chat_post.cfm`, `Z_Chat_Post.cfm`; Post New popup removed from `f_com_msgsector.cfm` / `pop_msgsector.cfm`), side chat button restyle (`i_f_800.cfm`), Inactive Accounts + Forgot Password restyle (`p_login_old.cfm`, `p_login_password.cfm`, `login-modern.css`), Viral/Collective U-class planet types (60-69) recognised for Gordo conversion (`s_com_market_use.cfm`, `f_com_col_calc.cfm`) — described by effect only, no land/planet-count thresholds (rule 5), Summary/Intel spacing (`f_com_empire.cfm`). `6100eff`: Intel explored/plundered rows moved into the combat grid (`f_com_intel.cfm`), reset-password page fix. **Excluded:** the game half of `3cd3735` (rebuilt PM Report Offensive Message page) — per the standing ruling in the "PM reporting + verdict reasons" row it is admin log only, so it was dropped from the public draft; `18d87b4` (Server-Timing, backend), `d182934` (Forum form-action refactor, backend), `7e6d6ff` / `979ec3d` (admin), marker commits. |
| #109.9 | 2026-10-02 | **filled in** (thread + auto Discord, @everyone; Amanda-approved bullet wording) | `f703846`: Empire Intel / Summary redesign (`f_com_intel.cfm`, `f_com_empire.cfm`, `theme.css`), Last Activity (`user.last_active`, `s_total_users_online.cfm`, `p_logout.cfm`), animated GIF fed flags (`s_fed_flag_*`, `fed.flaganim`), Medals (`medal`/`user_medal`, Convergence 2026 awarded; winners deliberately not named), copy-as-row (`JS/Mods.js`) worded as a copy/paste formatting fix. Presence-bucket thresholds undisclosed (rule 5). The old Intel page's Trade Partner row, Global Rank row and slave-empire actions (tribute/punish/free) vanished in the redesign; per Amanda NOT mentioned in the notes. **Excluded:** `18d87b4` (Server-Timing, backend), `b3a7c9b` (marker), admin flag-API/SQL changes in `Federations.cfc`. |
| #109.8 | 2026-09-24 | **filled in** (quiet — no thread, no Discord; Amanda: minor patch, simple blurb) | `b5c915b` (Excavation Dig, `f_com_col_find.cfm`, rebuilt on the modern dig-panel layout; the theme.css diffstat is mostly line-ending churn) and `4b5108b` (a **Luck** panel on the dig page: dropdown lists only the luck artifacts the player holds — Minor/Major Suerte, Minor/Major Afortunado — and uses them through `s_com_market_use.cfm` without leaving the page; preselects the one just used while any remain). No odds or effect sizes documented. **Scanned, not in the entry:** `63a2c06` (Command Center / hub layout and media-query tuning, `f_com.cfm` + `app-shell.css`) and `cbd7e6e` (commented-out unused code in `f_com.cfm`) — Amanda scoped the entry to the dig page. **H.Man-O-war mineral cost change added to #109.8 (2026-09-24, Amanda).** Red Crystal 100 → 10, White Crystal 100 → 10, Rutile 200 → 20, Composite 200 → 20 — most of the way back from the #109.3 increase (1/1/2/2 → 100/100/200/200). **DB-only, applied on live; NOT in the local instance and in no commit**, so these values come from Amanda and could not be checked against `ship_type` here. Displayed in the #109.3 cost-table style (Collective table, six mineral columns, `--pos` for decreases). **D.Ray mineral cost change added to #109.8 (2026-09-24, Amanda), also live-only and in no commit:** Terran Metal 75 → 40, Red Crystal 25 → 10, Strafez Organism 25 → 10. **Discrepancy, unresolved:** #109.3 recorded D.Ray's third cost as *Composite* 0 → 25 with Strafez Organism unchanged, so on this page's own record Strafez Organism was never 25. Written as Amanda stated (Strafez Organism) and flagged to her. Either the live value moved off-record, or it is Composite; if the latter, this row's 25 → 10 belongs in the Composite column and Strafez Organism goes back to a dot. |
| #109.7 | 2026-09-21 | **filled in** (quiet — no thread, no Discord; not requested, small set) | `f31f120` (`Admin/sql/forum_section_events.sql` — new Forum section **Events**, `he_type` id **106** + `forum_section` placement in The Galaxy below Federation, `access 0` / `publicflag 1` / postable. Id must stay in 100–199: legacy `f_he.cfm` lists the Forum as `type>=100 and type<=199`, so a section outside it becomes unreachable there the way type 1 was for two decades. Needs an app restart — `he_type` is cached by `s_loadsystem.cfm`). `cf02b69` (**no player replies**: `forum_thread_staff_only.sql` adds `staff_only_at` / `staff_only_by` to `forum_thread_meta`, timestamp-as-flag beside the existing lock pair; `Base.canReplyTo()` is the single gate for the reply box, the reply action and the thread view; UI reads "Staff replies only" with a No player replies / Allow player replies toggle; new Forum ACL `post.events`, default 3, for who may START an Events thread — players may still reply). `234820e` (mobile drawer gains Options + Event Rewards, `f=option` / `f=com_eventrewards`). **Admin log** gets its own `game-side` entry for the moderator control and the new section/ACL. **Not an entry:** `7e118a7` — it only adds the already-written Event Points row to the admin changelog. |
| #109.6 | 2026-09-16→18 | **filled in** (thread + auto Discord, @everyone; Amanda chose 109.6 over 110, 2026-09-19) | **Event Rewards** — `3f571b4`: new `f_com_eventrewards.cfm` (reward catalogue in-file: artifact stacks, `infra` levels, `gc` credits, plus `Auto = 0` admin-applied rewards behind a Help Center ticket), linked from `f_option.cfm` and both Options menus in `s_loadbar.cfm`, schema `Admin/sql/event_points.sql` (`user.eventpoints`, `user_eventpoint_log`). A bullet on refused rewards (rarity cap, infrastructure total) was written and then CUT by Amanda on review (2026-09-19) — the reward caps are not documented at all, which is the safer side of rule 5. The per-rarity artifact caps (`EventGoodCap`) and the 260 infrastructure total are named nowhere. The admin half (Event Points tab, grant/deduct, two new ACL sections) was written into `Admin/assets/views/changelog.js` by the same commit, so this pass added no admin entry for it. **Convergence End** — `e9df0fb`: `f_com_faction.cfm` reduced to a `cflocation` to `i.cfm?p=info&file=event` (old links are all over the forum and Discord), boss/unrestricted-target handling stripped from `s_com_attack_req.cfm`, `f_com_attack3.cfm` and `f_com_intel.cfm`, event banner removed from `f_com_empire.cfm`, new `text/info_event.cfm` reading the frozen `faction_event_archive*` tables (`Admin/sql/convergence_archive.sql`, `convergence_removals.sql`). Amanda cut the sentences about old event-hub links redirecting and about attacking returning to the ordinary rules (2026-09-19) — the entry states only that the event ended and where the record lives. The winner is NOT named in the entry — the page reads it from the archive at runtime and this pass did not query prod. **Market** — `67a3379`: `f_com_market_w.cfm` + `s_/s_attack_refresh.cfm` credit only what fits under the real cap and leave the remainder listed (previously the overflow was destroyed and the listing deleted), `f_com_income.cfm` mineral trim 2B → 10B. The withdrawal bullet prints no cap figures; the income bullet DOES name the old 2 billion limit, because Amanda rewrote it that way on review (2026-09-19) and reframed it as a DISPLAY fault on the Income page rather than lost production — staff wording sets the disclosure line. **Forms broken by #109.5's htmx swap** — `bf500d0`, `6d6fd2d` (`f_com_attack.cfm`, `attack2`, `colupgrade`, `fed_detail`, `option_race`), `c45f7af` (`f_com_project2.cfm`), `50a84e6` (55 mission files, all races/acts: `<form>` moved out of the `<tr>`). `40a1cb8`: `TurnUse = session.TurnUse = …` left `TurnUse` undefined once sessions moved to DB storage, so the end-of-turn summary vanished. **Chat** — `c45f7af` + `a0402c0`: `f_com_msgsector2.cfm` rebuilt (per-post Report button, working form, Cancel, empty-reason check, paging; the 5/day limit counted from `chat_abuse` over 24h instead of a session counter that relogging reset), `.gc-chatnav` buttons in `main.css`/`theme.css`, `help/rule.htm` + `rule_cheat.htm` refreshed (spacefed → Wolfren Games, "minerals" → "resources", Game: Ethics section dropped). **Fed display** — `c45f7af`: new `gcName()`/`gcNameAttr()`/`gcDecodeEntities()` in `Functions.cfm` (nics and fed names are stored HTML-encoded, so `encodeForHTML` on the raw value printed the entity), fed_apply counts in `f_fed.cfm`/`f_com_empire.cfm` now join `user` so applicants who joined elsewhere drop out; `dabd5cb`: fed list/roster columns sized to content, Forum "Back to the Game" → `i.cfm?f=com_empire&cm=3`. **Sessions** — `4522afc` (30m → 1h30m), `d7e86b1`/`499a2d5`/`35a7655` (Lucee DB session storage so a restart no longer logs everyone out), `92e8e2b` (`sessionCookie` SameSite cleared — Firefox for Android was dropping players on Session expired after a phone lock). Effect only, per rule 3: no cookie/storage mechanism, no session-loss diagnostics (`gcSessionTrack`/`gcSessionLossLog`). **Cache rebuild** — `daf0c3c`, `3cf8d08`, `28ae347`, `3547955`, `88add4d`, `50a84e6` (`i_f_800.cfm` rebuilds research/infrastructure/goods/tick/upkeep application-scope values when they are missing) — one effect-only bullet. **Forum section default** — `8140bd5`: `views/section.cfm` archive default 1 → 0, and visited-link colour dropped in `forum.css`. **Excluded:** `ee8163c`/`8f04678` (marker + map meta), the Forum ACL screen and ticket-queue Dismiss in `8140bd5` (admin entry instead), all session/diagnostic internals. |
| #109.5 | 2026-09-16 | **filled in** (quiet — no thread, no Discord; Amanda: minor backend/performance update) | `6d36909` (htmx: `hx-boost` on the `i_f_800.cfm` frame body, `JS/gc-htmx.js`; forms on `RESUBMIT_PAGES` — `com_ship`, `com_ship2`, `com_market2`, `com_market3`, `com_market_use` (the ARTIFACT USE screen, not the market), `com_disband`, `com_attack2`, `com_attack3`, `com_col`, plus Capsule Lab `com_project2&id=3` — still submit natively so F5 offers a resend; `option_screen` full-submits because a swap never replaces `<body data-theme>`; store/popups/public/Forum not swapped). `fe94272`: `Admin/sql/gcc_event_artifact_type.sql` gives self artifact uses `event.type = 5` (was 2, excluded by a `name NOT LIKE` on longtext) — the Events-indicator lookup was 53% of DB time, up to 65ms/page, now <0.7ms; `gcc_event_attack_indexes.sql` (battle log `source`/`target` UNION, up to 13,784 rows read → 12, 29ms → 0.06ms); `forum_lastpost_indexes.sql` (Latest Activity 6.5ms → 0.1ms); `Application.cfc` clientStorage `gcc` → `cookie` (accidental since the 2026-05-07 folder move: 5.3M `cf_client_data` rows / 15.6 GB, ~65k/day, a read+write every page) + `gcc_drop_lucee_storage_tables.sql`; column-existence cache in `Functions.cfm`; `p_timeout.cfm` restyled to the `.gc-public-status` card. **Not detailed publicly:** table names, row/GB counts, the storage-flag cause — effect only, per rule 3. Client-scope values (chat auto-refresh interval, timezone, first-visit flag) were not migrated, so they fall back to defaults once; judged too minor to announce. **Excluded:** `efbdf85` (form/control linking on attack + artifact use pages under htmx) — same-day fix to `6d36909`, never broken on live. |
| #109.4 | 2026-09-16 | **filled in** (thread + auto Discord, @everyone) | **Forum / Help Center rebuild** — `7d664e1` (search, section view, settings, thread display), `67b2dfe` (source param, HC navigation, staff directory + ticket queue), `eeee916` (avatar upload hardening), `5698371` (**The Archive** rename + `Admin/sql/forum_archive_rename.sql`), `92f7394` + `a21850e` (newest-first replies, thread and ticket queue), `15fc880` (staff roles read by `Forum/components/People.staffDirectory`). New `app/Forum/` runs on the EXISTING `he`/`hef`/`he2`/`hef2` tables — no import, no migration; legacy `hef.cfm` untouched and still live. Player-facing detail drawn from `Forum/docs/HISTORY.md` §2: 1,341 `type=1` threads (2006–2023, 1,236 still open) that no listing query could reach, now section **The Archive** (`postable = 0`); moderation no longer appends "thread closed by…" into the author's `nlong`, moving to `forum_thread_meta` + `forum_modlog`; POST-Redirect-GET so refresh no longer re-posts. **Deliberately NOT detailed publicly:** the stored-XSS history (§2.2 — live rows from 2009/2010 that rewrite `document.stepform`, plus iframes and a tracking pixel) and the permission-model rewrite (§2.3). The entry describes only the visible effect — old posts that broke the page are cleaned at display time — with no mechanism, per rule 3. **Federation pass** — `293d702`, `2b51975`, `0b0e314`, `965ad5d`: Federation HQ (`f_fed.cfm`, +406) with hero stats and notice/discussion panels, Diplomatic Center (`f_fed_war.cfm`), elections (`f_fed_elect.cfm`), discussion board (`f_fed_forum.cfm`), activity (`f_fed_prev.cfm`), member/join pages. **Battle logs** rebuilt for Nebula/Daylight (`s_com_attack_prev.cfm` +281 — note this is the battle LOG, not a preview). **Research message fix** (`f_com_rtree.cfm`): flash and turn-use message were mutually exclusive, now both render. |
| #109.3 | 2026-08-26 | **filled in from J's notes** (thread def added, `createFlag = FALSE` until live) | **No commits** — a pure `ship_type` / `Z_Upkeep_Calc.cfm` data change, planned to go live the evening of 2026-08-26. Written from J's Discord notes (2026-08-23), with every "before" value verified against the live `gcc.ship_type` table before writing. Covers races 0–6 only (player ships); the race 8/9 duplicate rows for V.Triton, T.Kalieum, D.Hammerhead etc. are NPC ships and are not documented. **Build rate** is the multiplier on `ship_type.power`: J's second figure is `BR × power`, matching the legacy `f_com_news_updates.cfm` wording "Build rate: 20 → 16 (34,176 per turn)". **Upkeep mod** is the per-race fleet multiplier in `Z_Upkeep_Calc.cfm` `RaceMod[]` (Miners 10.1→10.5, Collective 3.3→3.5, Terran 8→8.2, Viral 7→6.8) — not a per-ship value. Damage slots `weapon1..4` = Energy / Kinetic / Missile / Chemical; shield slots `shield1..4` = Energy / **Absorption** / Missile / Chemical (slot 2 differs between the two — see `f_com_ship2.cfm`). Goods `g1..g6` = Terran Metal / Red Crystal / White Crystal / Rutile / Composite / Strafez Organism (`gcc.good`). New CSS: `.clog-ptable-label` for the left-aligned stat-name column. The ship tables read at the **same scale as the #109.1 cluster panels** (`--text-sm` cells, 0.85rem headers) — an earlier pass bumped them to `--text-base`/`--text-lg` and Amanda called it too big (2026-08-26). Legibility on a fifty-row table comes from contrast and dividing rules, not point size; size and padding stay on the shared `.clog-ptable` rules. **Federation flags shipped in the same patch** and are documented in the same entry (`dddec7d`, merged from `Fed-Flags/Tags`): leader upload at `f_fed_flag.cfm` + `s_fed_flag_save.cfm`/`s_fed_flag_util.cfm`, display on `f_rank*.cfm`, `f_fed*.cfm` and `f_com_intel.cfm`, storage under `app/i/fed/`, schema `Admin/sql/fed_flag.sql` (`fed.flagver` / `flagby` / `flagdate`). Both branches independently claimed #109.3; they were folded into one entry rather than split (Amanda, 2026-08-26). The Admin-side flag queue in that commit is an admin What's New entry, not a game one. |
| #109.2 | 2026-08-25 | **filled in** (thread + auto Discord, @everyone) | `531d6de` + `869ad5d`. **Public player API** — new `app/api/` (Application.cfc, index.cfm, `components/*`, 16 endpoints in `Registry.cfc`, only `dsr.battles` gated on `project:5`, 120 req/min in `Base.RATE_LIMIT_PER_MIN`), player key page `f_option_api.cfm` + link from `f_option.cfm`, schema `Admin/sql/05_api.sql` (`user.api_key`). **Research** consolidated on Nebula/Daylight via new `s_com_research_data.cfm` + `s_com_research_view.cfm`, included by `f_com_research`/`research2`/`rtree`. **System messages**: unread System PM (userfrom 0) flags the Messages button in `i_f_800.cfm`/`_shell_mobile.cfm`, highlighted in `f_pm.cfm`, Help Center thread link in `f_pm_d.cfm`, backed by `Admin/sql/he_type_system_messages.sql`. **Colony production fix** — new `s_col_production.cfm`/`s_col_production_init.cfm` wired into `s_show_colony.cfm` (only 18 real lines there; the 1258-line diff is line-ending churn), restoring the industry modifier, commerce goods and commerce/agriculture interaction so the Consumption tab agrees with `f_com_income.cfm`. Vacation 50% fleet-loss warning (`f_option_vacation.cfm`), Nebula un-WIP'd (`f_option_screen.cfm`), inbox index (`Admin/sql/user_pm_userto_index.sql` — the unread check was full-scanning ~99k rows per page load). Renamed `z_admin_reset_notice.cfm` → `p_relog.cfm`. |
| #109.1 | 2026-08-14 | **filled in** (thread + auto Discord, @everyone) | `5781724` (cluster conversion thresholds in `s_loadvar.cfm` `GordoTypeConvertAt` — normal 5/25/50 → 2/6/30, viral 4/16/32 → 2/18/24, collective 4/16/32/128 → 2/18/24/96; plus Gordo config added for types 60-69, which had none, so T./A. U Class could not be gordoed at all). **DB-side alongside it, not visible in any diff**: `planet_type.agriculture` T.Fertile 190 → 125 (+90% → +25%) and A.Fertile 215 → 135 (+115% → +35%) — verified by querying the DB. Balance-badge patches use `clog-badge--balance`, matching the Help Center's own Change/Bugfix/Improve/**Balance** prefixes. The #109 table now carries a pointer to this entry so its superseded Fertile values are not read as current. |
| #109 | 2026-08-11 | **filled in** (thread + auto Discord, @everyone) | `f462bf8` (captured U Class types 60-69 + artwork, multi infect/assimilate `f_com_change2.cfm`, Builder unbuildable-ship list `Modules/Ships/Builder.cfm`+`f_com_ship.cfm`, disband clipboard override `JS/Mods.js`), `ecc52a4` (adds the new A. types 65-69 to the Collective doubled-housing range in `s_endturn_gc_col.cfm`), `0c420c9` (password `trim()` on change, chat Refresh, Back to Shop href, Raw Materials on Income), `21b5441` (market shorthand `u_abbrev.cfm` `gcParseAbbrev()` + JS mirror, black-market cap unification), `ad23d81` (Collective race 4 max-pop ×2 — a **DISPLAY fix, not a balance change** (Amanda, 2026-08-11): the ×2 housing was already applied during turn processing in `s_endturn_gc_col.cfm`; `s_getvalue_maxpop.cfm` never applied it, so Manage Colonies showed half the real cap and population stayed white instead of green once past the figure shown). NOTE: all four of `pop`/`industry`/`agriculture`/`mining` are 100-based modifiers, and the game renders a -100 as "No Support" (`pop_planettype.cfm`) — new colony types must list the full set, not just industry. |
| #108.1 | 2026-08-04 | **filled in** (quiet — no thread) | `f2c4bbe` (Builder switched from the `<cf_s_getvalue_turn>` custom tag to a new in-app module `Modules/Ships/s_getvalue_turn2.cfm`). ROOT CAUSE worth remembering: `<cf_*>` custom tags resolve from a **customtags folder on the server**, not from `app/`, and that copy had gone stale — it lacked the `floor()` in `tempturnmin = floor(turnmin * 0.85)`, so with `server4_turnmin = 6` the Builder accrued turns at **5.1s** while the rest of the game used **5s**, counting players one turn short. Same symptom as the #102.1 Builder fix; this addresses the actual cause. |
| #108 | 2026-07-31 | **filled in** (thread + auto Discord, @everyone) | `bed9393` + `806cf65` (Smart Disband: builder-parity +/- controls, live preview of surviving ships/upkeep/power, Power Removed + New PR totals, live re-sort, drop-below-next-stack button — `f_com_disband.cfm`/`JS/Mods.js`/`theme.css`/`Z_Upkeep_Calc.cfm`), `5a0abf3` (copy-event backtick→apostrophe normalisation `f_com_empire.cfm`; fed discussion post separation `theme.css`; fed war unclosed `<div>` fix `f_fed_war.cfm`) |
| #107.3 | 2026-07-26 | **filled in** (thread + auto Discord) | `bfad152` (self-use artifacts no longer flash the Events alert — `i_f_800.cfm`), `679807b` (artifact screen grouped by rarity `f_com_market_use.cfm`+`theme.css`; shield rename ECM→Missile Shield / Ionized Hull→Chemical Shield in `f_com_ship2.cfm`/`help/ship_shield.htm`/`text/manual_faq.cfm`; rankings filter restyle `f_rank_s.cfm`+`main.css`; tighter/cleaner panel display for Empire Summary, Empire Intel, Exploration and Battle Logs — `theme.css` `.gc-intel-page`/`.gc-battle-prev-*` + `f_com_explore.cfm`/`f_com_attack_prev.cfm`. NOTE: `f_com_attack_prev.cfm` is the **battle log**, not a "battle preview" — legacy filename, per rule 6) |
| #107.2 | 2026-07-26 | **filled in** (quiet — no thread) | `6aff24f` (self-use artifact events logged as event type 0 → 2, so they file under Artifacts not Misc) |
| #107.1 | 2026-07-22 | **filled in** (quiet — no thread) | `6871914` (game part: `.removed` styling in `i_chatt.cfm`), `63bd611` (game part: side-chat author divider `i_f_800.cfm`/`theme.css`). Kept to one line per Amanda; no forum thread, Discord text handed over manually (no @everyone). |

## Admin changelog mapping

| Entry | Date | Key commits |
|---|---|---|
| Modern panel v1 | 2026-07-12 | `57f9bfd` |
| Modern panel v2 | 2026-07-13 | `a4837ff`, `a3de342` |
| Panel iteration day 1 | 2026-07-15 | `4dfb011`, `a9a124b`, `c0e2635`, `c51a2d7`, `456fd51`, `faadb0f`, `71ddc37` (game-side lastaccess), `7d00569`, `91c6ee5`, `8984252`, `4e6564d`, `b023c5e`, `43c65c2`, `7b9ee87`, `b1eb848`, `e8c8db9` |
| Panel iteration day 2 | 2026-07-16 | `f59425a`, `32ebcae`, `374ad59`, `52e0226`, `0ae7f63`, `9e0c1c0`, `d4b3807`, `d96c344`, `d56c4dc`, `be1d28b`, `6200237`, `7cd8275`, `05c2c3d`, `16876ec`/`74b24fa`/`22e8425`/`037ee80`/`5f1da45` (force relog + logout notice), `dfec827`, `7e484f6`, `2384472` (refresh page is game-side; panel triggered) |
| Chat moderation suite + polish | 2026-07-18/19 | `fda2c09` (chat moderation), `3259f71` (GC/UC mapping), `59148b2` (feed render), `02acead` (battle-report + lock actioned posts), `c2957c6`/`6df59b5` (polish), `10e9fd2` (complaint deep link), `d8102ff`/`d62a988`/`019bdb9`/`7845f9e`/`367b1c6`/`6cb9225` (remove-post flow), `a7740d8` (hash-escape fix), `14a37af` (Suspect→User), `ed7c793` (profile click-to-edit + anti-cheat search), `6efe85a` (dedupe + IP decode + hardening), `ba41759` (orphaned grant code) |
| View auditing + fed gating + search fix | 2026-07-22 | `44a8b37` (view audit logging, faction ACLs + change reasons, search box), `01b93b3` (overview view audit), `6f9e82e` (What's New ACL on direct navigation) |
| Market, Turn Logs, custom sidebar | 2026-08-25 | `869ad5d` + `21b7a7e` (Anti-Cheat Turns Used tab: dropped a client-side hard-coded `level >= 9` that sat on top of the `anticheat` section gate, hiding the tab from admins with anticheat access below 9 with no ACL entry to explain it; `anticheat.turnTop` never required more than the section, so the check protected nothing) (new `Market.cfc`/`market.js` order book, `TurnLogs.cfc`/`turnlogs.js` reading `Detailed_Turns` instead of `Stat_Turns` whose DATE column made "last 24h" mean 24–48h, `Nav.cfc`/`navsetup.js` + `admin_pref.sql` per-admin sidebar, `UserActions.sendMessage` + `he_type_system_messages.sql`, `AntiCheat.ipLookup`, Economy market listings, Events battle filters + keyset paging, roster power/planets with real name off the wire, new ACL sections market/turnlogs/ip.lookup/players.donation.view/players.action.sysmessage) |
| Staff To-Do board | 2026-07-31 | `a752b52` (kanban To-Do board: `Todo.cfc`, `views/todo.js`, `sql/admin_todo.sql`, `todo` ACL section at def 0, route + nav). **The feature commit shipped its own What's New entry** — verified accurate against the code rather than rewritten. |
| Chat removed-post styling + wider column | 2026-07-22 | `6871914` (admin part: `.removed` span in chat feed, Chat.cfc wrapper), `63bd611` (admin part: widen `chat.post` 150→255 `chat_post_expand.sql`, drop stored `<br/>`) |
| In-game staff list (Guide/Mod/Admin) | 2026-09-14 | `ab07fc4`. Clean port of `edmin/f_admin_guide.cfm` (the `gcc.user_guide` editor — NOT the in-game `f_com_guide.cfm`, which is entirely commented out and renders nothing). New `Admins.guideList` / `guideSave` / `guideRemove` (+ `this.endpoints`), new ACL section `admins.guidelist` def 6 (legacy page was `adminflag GTE 5`), second tab on `views/admins.js` at `#/admins/staff` with a new `/^\/admins\/(\w+)$/` route. **No migration needed** — `user_guide.modflag` already exists in the schema; the legacy page simply never exposed it. What the flags drive: `guideflag`/`adminflag` feed `application.s_list_guide`/`s_list_admin` in `s_loadsystem.cfm`, printed by `f_he_main.cfm` (reachable via `hef.cfm`) as the Help Center's "Guides :" / "Admins :" lines; `modflag` is written by this screen and read by nothing yet — flagged to Amanda, not wired unilaterally, since it would change what players see. Any flag also lands the player in `s_list_gma`. `guideSave` validates the empire exists (legacy did not — 6 of 27 rows point at deleted accounts, now surfaced as `exists:false`). Writes legacy `log_admin` type 5 with CFML `now()` for the same TZ reason as the announcement banner. Cache note: those lists are built at application start, so edits land on the next runtime refresh — stated in the UI rather than triggering a full bootstrap per tickbox. |
| Refresh Tech/Ship: preserve paid projects | 2026-09-14 | `ab07fc4`. `UserActions.PAID_RESEARCH = "256,257,258,259,260"` (hand-maintained; nothing in the schema marks a restree row as purchasable) and a paid branch in `refreshTech`'s pool rebuild. Reproduced before fixing: user 511696 had `257` in `r_research` and it was gone after a refresh. Cause is that paid rows fail the rebuild twice — `r1`-`r6` are all `0` and `req1 = 253` *Special*, whose own `req1` is `253`, so it can never be satisfied. Preserved only when the id is already in the player's `r_research` or `r_researched`, matching `f_option_race.cfm`'s restart carry-over, so a refresh can neither remove nor grant one. `255` UnReverse Engineer stays out of the list — it carries `r5 = 1`, so the race rules already handle it correctly. Completed paid projects were never at risk (step 1 keeps any valid restree id) and needed no change; `paidKept` added to the audit detail. Verified across 7 users incl. 3 with no paid projects (gained none). Note `restree` has no rows depending on 255-260 today, and no `ship_type.treeid` in that range, so there is no downstream unlock to carry. |
| Server Settings — announcement banner | 2026-09-14 | `ab07fc4`. New `server.announcement` / `server.announcementSave` on `ServerOps.cfc` (+ `this.endpoints`), new ACL section `server.settings` def 6, new screen `views/serversettings.js` + route + nav item (`sliders` icon added to `icons.js`), `.annbar*` / `.annbox` in `admin.css`, `sanitizeEvent` exported from `app.js` for the live preview. Ports the yellow announcement off edmin's Server Management page, minus the UC column (dead datasource) and the expiry field — the banner is driven entirely through that stamp — `announcementSave` takes a `show` flag and writes `2099-12-31` to put it up or `2000-01-01` to take it down, keeping `list1` either way so the wording survives a take-down. This also makes the expired-branch fix below load-bearing rather than incidental. Storage is unchanged: `gcc.cluster_cache` id 6, `list1` text + `datetime` expiry, with the legacy `log_admin` type 4 "last updated by" row still written (CFML `now()`, **not** SQL `NOW()` — the db container runs UTC and the app runs America/New_York, so SQL `NOW()` lands four hours ahead of everything else in the schema). Game-side: the banner cache resolve moved out of `s_loadbar.cfm` into new `s_yellowmsg.cfm`, and `i.cfm` includes it directly for a session-less `?yellowmsg=1`. Both were necessary — `s_loadbar.cfm` only runs via `i_f_800.cfm`, which is gated on `url.f` **and** `session.userid`, so the panel's call fell through to `i_p.cfm` and never touched the cache; requesting `s_loadbar.cfm` directly answers 200 and still does nothing. No `cfabort` in that `i.cfm` branch: `Application.cfc`'s `onAbort` dumps unconditionally and would staple Lucee debug output onto a public URL. Also fixes a long-standing bug carried over in the move — the expired branch set `yellowmsg` to the stored text regardless, so an expired banner rendered for whichever player happened to trigger the refresh. |
| Dialog X close + show-reason-to-player + game-data log fix | 2026-09-05 | `45a0dca`. (1) `modalHead(title, onClose)` added to `assets/app.js` and used by all four overlay sites (`modal()`, `views/gamedata.js` openViewer, `views/admins.js` login history, `views/playerDetail.js` colony editor); every `.modal-backdrop` onclick removed; `.modal__head` made `position:sticky` with an opaque background and `.modal__x` styled in `admin.css`. (2) `reasonFields()` / `showReasonToggle()` in `app.js`, wired through all player editors; `showreason` read centrally by `Base.reasonShownToPlayer()` inside `logChange()`, appended to the PM by `notifyPlayerOfChange()`; audit gains `reasonShown` **only when a PM was actually sent**, so silent edits do not claim to have shared anything. (3) **Bug fix, not a regression from this work** — `Content.gdLogVal()` ran every value through `logNum()`/`numberFormat()`, which rounds, so `shieldPct` 0.55 logged as `1` and 0.35 as `0`. Present since `7e484f6` (2026-07-22). It now takes the column descriptor and mirrors `displayValue()` in `views/gamedata.js`: `shieldPct`, `pctFromOne`, `capturePct`, `raceEnable`, `noDefense`, `noRetal`, `enum`, `resolve`. Note `numberFormat()` masks reject `#`, so `gdPct()` uses `decimalFormat()` + regex trim. |
| Recent chat actions log | 2026-09-02 | `c65c2f4`. New `Moderation.chatActions` (+ `this.endpoints`), new ACL section `moderation.chatlog` def 3, new "Recent actions" tab in `views/moderation.js`. Reads the `ref:` marker rows on `user_pm_abuse` — the same source as `Chat.history()` — because `chat_abuse` has no admin column and sharing the source keeps the global log and a player's own history in agreement. The prefix → label mapping moved into `Base.chatActionType()` and `Chat.history()` now calls it, so it lives in one place. Pages on `user_pm_abuse.rowid` via `before`. `LEFT JOIN user` so records of deleted accounts still list. Gated at 3 rather than reusing `moderation.chat` (2) to avoid widening access to data the per-player Chat History already restricts at 3. |
| Silent resource edits | 2026-09-02 | `9e24bba`. `Users.resourcesSave` takes `silent` (1/0, default 0); `Base.logChange` gains a trailing `notifyPlayer` argument defaulting to `true`, so the "no scope can silently skip the player PM" guarantee still holds for every caller that does not opt out. Silent runs skip `notifyPlayerOfChange()` and `forcePlayerRelog()` but still write `auditLog` (detail marked `silent`) and `gamePmAbuse`. UI is a `type:"checkbox"` field with `value:false` on the existing save modal in `views/playerDetail.js` — `modal()` ticks checkboxes unless told otherwise. Gated by the existing `players.resources.edit`; deliberately **no new ACL section**. Skipping the re-log is sound only because `i_f_800.cfm` re-reads `credit`/`food`/`power` into the session on every game page load — verified, not assumed; documented in `Skills/admin-game-integration`. |
| Event Points (grant/deduct tab) | 2026-09-18 | `3f571b4`. Written by the shipping commit itself, not by a changelog pass — `Admin/api/components/Users.cfc` (balance, history, adjust), `assets/views/playerDetail.js` Event Points tab, `Base.aclRegistry()` gains `players.eventpoints.view` (def 2) and `players.eventpoints.edit` (def 6), schema `Admin/sql/event_points.sql`. The player half is game changelog #109.6. |
| Forum access control + ticket Dismiss | 2026-09-17 | `8140bd5`. `Forum/views/acl.cfm` + `Base.aclRegistry()`/`aclOverrides()`/`aclCap()`/`aclRows()` and `Mod.aclSet()` (deletes the row when a level is set back to its default), schema `Admin/sql/forum_acl.sql` (`gcc.forum_acl`, deliberately NOT shared with `gcc_admin.admin_acl`), route + nav item in `Forum/index.cfm`, `ACL_ADMIN_LEVEL = 10` so the screen cannot be configured from inside itself; `Avatar.canModerateAvatars()` now reads `aclCap("avatars")`. Ticket queue `dismiss` action (archive + return to the same queue page) in `index.cfm`/`views/queue.cfm`, plus a `table.tbl td.mid/th.mid` specificity fix in `forum.css`. Tagged `game-side` — it lives in `app/Forum/`, not `app/Admin/`. The player-visible half of the same commit (section lists defaulting to live threads, visited-link colour) is game changelog #109.6. |

## Excluded: legacy edmin (defunct — never document, per Amanda 2026-07-17)

`2173372` (edmin part: global events + runtime refresh tools), `2e868d3` (detailed
turn logs), `7fd4f49` (edmin part: admin login hashing), `08cc5c3` (edmin part:
activity history view), `d1a003d` (edmin part: `s_admin_action.cfm` project
removal), `fc693da`/`866858a` (user detail + artifact editor), `6aba9b3`
(marketspawn), `51d9e1a` (edmin part: IPv6 views), `9a8dc81` (global events),
`3a0cd81`/`3c1f859` (colony view for cluster types), `45dfec5`/`f05dc91`
(request logging).

## Excluded as backend/internal (never document)

- `p_login.cfm` per-user CF22/UIP override block (the `checkuser.id == …` lines).
- Login-Adjustment branch churn 2026-05-17 (`dcb0815` → `43b6b3e`) — session/cookie plumbing.
- IP-numeric conversion work 2026-06-16 (`502601b` → `6f7456a`) except the IPv6 admin-display effect.
- Z_Get API output debugging 2026-06-19/20 (`cb22756` → `28398eb`, `46b384f`/`4ecbc13`).
- SQL-injection / evaluate() / array-syntax refactors (`638cc06`, `323b76e`, `f53dc5b`, `3a6ffe6`, `67dda42`).
- Workflow/deploy/cache commits (`e4ffd30`, `8847220`, `bf8ac06`, `f313d59`, `5c83a40`, `ad37af2`, `6e4b87b`, `189c0be`, `bf90878`, `6faf1e1`, `d798a05`/`6fc79c4` internals).
- Whitespace/line-ending churn (`0397992`, `866858a` reformat portions, `799a5d7` reformat portions).
- Reverts and same-day release churn ("Maybe?", "Sigh", "hate.", "Oops" commits) unless the final state shipped a change already captured above.
- 2026-07-18/19 pass: `a6d5a53`/`46c6256`/`97eff1c` (p_login CF22/UIP override
  updates — the canonical never-document backend), `05283f4`/`1503bce` (parity
  churn), `f7f69b9` (dev/.env local test hook — infra).
- 2026-07-26 pass: `bfa8dc0` (theme.css cache-bust + `USE gcc;` added to the
  chat_post_expand migration file — cache-busting/infra housekeeping).
- 2026-08-12: `8ba6549` (removed the obfuscator's audit logging — the audit log
  is readable at level 5, below the obfuscation section, so `obfuscation.list`
  / `.save` / `.remove` entries told moderators which accounts were obfuscated
  and when; plus `sql/admin_obfuscation_audit_purge.sql` to clear the history).
  Black site, rule 7 — not an entry anywhere.
- 2026-08-06: `085c676` + `0f7eae7` (owner-account obfuscation feature and its
  null-handling follow-up — `Obfuscation.cfc`, `views/obfuscation.js`, related
  `Base.cfc`/`Users.cfc`/`AntiCheat.cfc` hooks). **Never document, in any log**
  (Amanda, 2026-08-06) — a feature that hides accounts is defeated by
  announcing it. This exclusion covers all future work on the feature too.
- 2026-08-04: `d1a75a4` — **decided: not documented** (Amanda, 2026-08-06).
  `s_endturn.cfm` (the shared guard for every turn-spending action, which still
  uses the stale `<cf_s_getvalue_turn>` tag — see #108.1) loosened from
  `endturn GT turn` to `endturn GT turn && turn == 0`, so "Can't perform task!
  No turns left!" now only fires at genuinely zero turns. Raised as a possible
  addition to #108.1; Amanda's call was no changelog entry. Do not re-raise.
- 2026-08-04: `63a20d2` + `8bb4210` (IP address handling in login flood control)
  — backend security plumbing, rule 3; Amanda confirmed no log needed.
- 2026-07-31: `8c72080` (`.gc-disband-controls` inline instead of inline-flex +
  `user-select:none` — Chrome's selection serialiser was breaking the -/+ glyphs
  onto their own lines when copying a disband row; now matches Firefox).
  Browser-specific polish finishing off ##108, excluded at Amanda's call.
- 2026-07-31: `71a005f` (extends the `s_assetver.cfm` cache-bust key to the JS
  bundles — it previously only covered CSS; `f_com_cart*.cfm`, `i_f_800.cfm`,
  `i_p.cfm`, `i_popup.cfm`). Cache-busting infrastructure, rule 3 — scanned and
  deliberately not documented, marker advanced past it.
- 2026-07-31 (#108) pass: `786b213` (Admin developer documentation set +
  Claude task skills under `app/Admin/docs/` and `app/Admin/Skills/`, plus a
  `USE gcc;` line in `admin_reset.sql`) — dev tooling with no panel-visible
  behaviour, so it is not an admin What's New entry. Same treatment our own
  docs/skills get.
- 2026-07-26 (#107.3) pass, parts of `679807b` excluded: `s_assetver.cfm` + the
  shell rewiring in `i_p.cfm`/`i_popup.cfm`/`s_loadbar.cfm` (shared asset
  cache-bust key — infra); `edmin/f_admin_ship*.cfm` (defunct panel, rule 2);
  **`f_com_changelogs.cfm`** — a DEAD page: nothing in the live app links to
  `f=com_changelogs` (only its own form action and a legacy edmin turn-log
  label map), so its shield-rename edits are not documented. Verify
  reachability before documenting any unfamiliar file.
- 2026-08-25: `c897b5b` (power handling switched to ROUND in SQL instead of
  `int()` coercion in CFML — `Admin/api/components/Economy.cfc`,
  `Federations.cfc`, `Users.cfc`; large power values overflowed the int cast).
  **Not documented** (Amanda, 2026-08-25) — "a bug nobody saw", so there is
  nothing for an admin to be told changed.
- 2026-08-26: `7f1a9bb` (Turn Logs was not honouring the `global_paid` server
  setting — `Admin/api/components/TurnLogs.cfc`, `views/turnlogs.js`). With
  global paid on, every account generates at the premium rate whatever its own
  `p_type` says; the screen sized generation at the standard rate instead, so
  "spent vs generated" read far too high. The per-player line now also says
  "premium — global paid" so the rate does not look like a panel bug.
  **Not documented** — a same-week correction to the Turn Logs screen that
  shipped in the 2026-08-25 entry; nothing an admin was told about has changed.
- 2026-09-16: `f1bec22` (every forum link retargeted from `hef.cfm` to
  `/Forum/index.cfm`, with `f=he&ch=0` -> `b=he&p=tickets` and `f=he_new` ->
  `b=he&p=compose&s=1`) and `edf25a5` (Forum accessibility: scalable text
  sizes). **Not documented** (Amanda, 2026-09-16) — iterated past without a
  changelog entry.


## Deferred — game-side, scanned but NOT yet documented (Amanda, 2026-09-14)

These are **not exclusions**. The marker has been advanced past them so the
admin log could be brought up to date; the player-facing write-up is still owed
and must be picked up when the work ships. Do not treat a marker past them as
"already documented".

- **Convergence Event** (`1b28990` first test, `eccb134`, `a42591d`, `f219f50`,
  `dd2f2d8`, `221bf7c`, `006c14f` staff event log, `10cd1a3`, `a825166` CT rate,
  `9622354` + `3b087c2` + `6344aae` phase 2 war fleets, `976ecc1` future event).
  Amanda: iterate past the event for now — it is still being built. Admin-side
  SQL (`Admin/sql/convergence_event.sql`, `convergence_phase2*.sql`) is event
  infrastructure, not a panel feature, so it is not an admin entry either.
- **Game balance / display** (`13ca3ca` race modifiers, `b8b2553` planet racial
  mod fix, `12ae82d` mineral fix, `9906f3d` multi handover col, `424f6fb` +
  `f40a66b` race upkeep multipliers, `af9b3fe` hide manual NPC ships,
  `090a052` playable-race restriction on the API ships endpoint, `4fc895b`
  attitude dropdown, `ed6ff38` leader init fix, `e329d1d`, `31b4311`).
- **Daylight / VM display** (`697a864`, `5fce5ec`, `9bc2646`, `4853052`).

## Known date uncertainties

- #104 and #105 release dates are approximations from commit clusters; the Help
  Center posts (linked in `i_f_800.cfm` News/Updates box) have the authoritative
  dates — correct the page if they differ.
- #106 notes say "Friday July 26th" in one place and June 26th elsewhere; commits
  confirm **June 26** is right.
