Releases: ImmersiveFusion/deepcube-docs
Releases · ImmersiveFusion/deepcube-docs
Release list
Docs hardening.
The Steam notes served a directory listing, not a page (#120)
* fix(routing): the Steam notes served a directory listing, not a page
All eleven of them, and every one is in the sitemap.
https://docs.deepcube.ai/DC/3D/steam/1.9.0 returned 200 with the title "Files
within public/DC/3D/steam/1.9.0/". A file index, not a release note. The same
was true of every version page.
CAUSE, reproduced locally against the real server with the real artifact. serve
resolves a path segment containing dots as a filename: path.extname("1.9.0") is
".0", so it never looks for index.html inside the directory and renders a
listing instead. cleanUrls then 301s /1.9.0/index.html back to /1.9.0/, so the
two rules chase each other and the page is unreachable by any URL.
MkDocs was building all eleven correctly. This was purely the serving layer.
FIX. Renamed the notes to dotless -- 1.9.0.md becomes 1-9-0.md -- which serves
correctly; verified both forms side by side against serve before committing.
Redirects added in both maps so the published URLs keep resolving, and the
IAPM-era redirects are retargeted straight to the new paths rather than chained
through the old ones, which would have made them two hops.
Also turned off directoryListing. A docs site has nothing to gain from serving
a file index, and this failure is exactly why: a listing returns 200, so
anything checking only status codes sees a healthy page.
The routing suite already knew that shape. Its comment says a directory listing
returns 200 "which is how cleanUrls:false shipped past a suite that only
asserted status codes. Check the TITLE." It had no case on these paths, so the
same failure shipped again somewhere it was not looking. Added two, one dotted-
version page and the newest note.
Verified: strict build clean, redirect parity clean, meta descriptions clean,
routing suite green, and by hand -- /DC/3D/steam/1.9.0/ now 301s to
/DC/3D/steam/1-9-0/ which serves the page, and /IAPM/3D/steam/1.9.0/ reaches it
in one hop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* ci: fetch full history so the revision-date plugin can date renamed pages
The Steam rename failed CI. Not the routing change itself: mkdocs build
--strict aborted on eleven warnings from git-revision-date-localized, one per
renamed page.
actions/checkout defaults to a depth-1 clone. A file renamed in the commit under
test has no history at that depth, so the plugin cannot date it and warns, and
--strict turns a warning into a failed build. The plugin's own message names the
fix: "Try setting fetch-depth: 0 in your GitHub Action."
It passed locally because a developer clone has full history, which is exactly
the class of failure that only appears in CI.
Worth noting beyond this PR: the warning is about dates being WRONG, not only
missing. Every page carries a "last updated" stamp from this plugin, and on a
shallow clone that stamp is only as good as the history fetched. This makes
those dates correct rather than incidental.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Pricing updates.
Take the prices off the Plans page and point at the storefront (#118) * docs(plans): take the prices off the page and point at the storefront Closes #105. The page carried live commercial terms in a repository that accepts outside pull requests: per-node prices, node minimums, a volume-discount table with thresholds and savings percentages, a worked forty-node calculation, and the annual prepayment discount. A docs PR should not be able to change what the product costs. It also duplicated a surface the repo already treats as canonical. Four retired pages -- Toolkit, the ROI calculator, Offers and Discounts -- already redirect to immersivefusion.com/pricing. Plans was simply never swept with them, and a second copy of a price list is a copy that drifts. Removed with them, per Friday on bus #2337: the Uptime SLA row and the matching per-plan bullets. The figures did match the finance model, unlike the retired SLA page's, but an uptime commitment on a public page is a contractual instrument and nothing establishes it has been approved for publication. Same reasoning that retired Resources/Legal/sla.md in #104. Also from #2337: "Enterprise SLA, 50+ nodes" in the plan-choosing table became "Largest deployments, 50+ nodes". Enterprise is not one of our tiers, and this is the adjectival use that most likely manufactured the Starter/Professional/ Enterprise set in the first place. What stays is what a docs page should answer: what each plan does. Throughput, retention, AI budget, support channels, infrastructure, and which capabilities each tier includes. Retitled from "Plans & Pricing" to "Plans", since it no longer carries pricing, and the inbound link from the OpenTelemetry page is updated to match. Not verified, and left as found rather than re-asserted: the throughput, retention and AI query figures. They come from the same finance model as the uptime numbers and I have no confirmation they are approved for publication. Flagged rather than silently blessed by touching the page around them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(plans): put the uptime figures back I removed them against an explicit instruction. Friday's ruling on bus #2337 says, in the WHAT TO DO block: "Plans page: rename Free to Start (free). Uptime figures already match canon; leave them." The same reply also said "I would not publish the canon numbers either", and marked that sentence, in capitals, A FLAG NOT A RULING. It was written about the legal SLA page in the context of PR #104 retiring it, not about this table. I promoted the advisory aside over the instruction and removed rows Friday had told me to keep. The figures match docs/finance/pricing.md line 48 and belong on a plan comparison: uptime by tier is one of the first things a buyer compares, and Fuse at 99.99% is a selling point rather than a liability. Restored: the Uptime SLA row and the three per-plan bullets. The pricing removals in this PR stand, since those rest on their own reasoning -- commercial terms in a repository that accepts outside pull requests, duplicating a storefront the repo already treats as canonical. Friday's flag is still worth answering, and is worth answering properly rather than by my unilateral deletion: whether an uptime commitment sourced from a finance model has been approved for publication is a legal question. Raising it separately. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(plans): say that changing tiers costs money The Changing Plans section walked a user through four steps to switch tiers and never mentioned a fee. The storefront states a one-time charge for a tier change, with same-tier node adjustments free. Someone following this page would follow the steps and be charged without warning. Found while checking whether dropping the volume-discount tables from this PR was safe. It was: the storefront carries the per-node prices, the discount above minimum, the node minimums and the annual prepayment discount, and carries them more completely than this page did -- it also has Tessa seat pricing and this fee, neither of which was ever here. The docs copy was a stale subset, which is the argument for pointing at one surface rather than maintaining two. The amount is deliberately not repeated here. Naming a figure recreates exactly the drift this PR removes; saying a fee exists and linking to where it is stated does not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Docs and preferences.
Rewrite Preferences from the Unity source (#112) * docs(3D): rewrite Preferences from the Unity source The page described a settings dialog that does not exist. It listed audio volumes, mouse sensitivity, invert-Y, sprint multiplier, VR comfort options, locomotion type, connection timeouts and a server-region picker. None of those are in the client, in any form. Twenty of roughly twenty-five rows were marked "coming soon" or "not yet configurable", which read as a roadmap but described settings with no counterpart in the code. Rewritten against PreferencesConfigurationDescriptors on the Unity branch that introduces them, which declares every preference with a key, label, description, category, section, control kind, value type and bounds. All twenty-three are documented here with the labels and descriptions the UI itself uses, so the page and the dialog say the same words. The real categories are World, Display, Effects, Assistant and Advanced. Most of what a user actually tunes is grid behaviour, not engine settings: which blocks are drawn, whether errored and lost blocks age out, phantom-node detection. Three things the old page did not say and should have: Tessa can change twelve of these herself. The descriptors mark them AgentWritable, and it is deliberately a short list -- redaction, sign-in and the frame budget are excluded. Marked with an icon and explained once. Demo mode redacts hosts, URLs and database names. It was not mentioned at all, and it is the setting to reach for before screen-sharing. Blocks per frame is the first thing to lower when the client struggles on a busy grid. Removed with the rest, and worth naming: "Server Region - Preferred data center region". That is the same claim retired from the Data Security page in #109. There is one region, and no user-facing picker exists. Corrected the reset paths. The product folder is DC, not "Immersive APM" -- ProjectSettings has companyName "Immersive Fusion" and productName "DC" -- which resolves the SP-074 TODO that was waiting for the shipped app to create it. The Linux path is dropped rather than guessed: Unity's persistentDataPath on Linux is not the path that was published, and I could not verify the correct one. The F10 access line is dropped rather than restated. The dialog is opened from the scene, not from code, so nothing in source confirms it and I could not verify it either way. Not documented: the Graphics, Audio and Comfort categories exist in the PreferenceCategory enum with no descriptors yet. Those are where volume and comfort settings will land. Tracked separately rather than pre-announced here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(3D): preferences open on F9, and restore the access line Founder-confirmed: F9 opens preferences, not F10. The Navigation controls table said F10 and the Preferences page said "F10 -> Main Menu -> Preferences". The Preferences rewrite dropped the access line rather than restate a path it could not verify from source, since the dialog is wired in the scene. It is back, as the single key it actually is. Not touched, and worth recording why. The Navigation table also lists "Console | F12 | Open the developer console". SP-067 finds the McMaster console unreachable and retires it, which looked like a second stale row -- but F2 of the same spike says the QFSW Quantum Console is a different system and stays. Two consoles, one being removed and one remaining, so the F12 row may well be correct and is left alone rather than removed on a misreading. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(3D): document the function keys, and where they do not work Founder-confirmed, filling gaps the controls table never had. The help dialog defines ten key containers; the docs covered six of them and had one wrong. F1 Help was undocumented F6 Copy was undocumented F9 Preferences was documented as F10 F10 Main menu was undocumented as itself F12 Console already correct That explains the old "F10 -> Main Menu -> Preferences" phrasing: F10 does open the main menu, and preferences used to be reached through it. F9 opens preferences directly. Also recorded, and not derivable from the source: F1 and F9 are grid-only. The lobby and the login screen do not have them and neither dialog opens there. A reader following the controls table from the login screen would otherwise conclude the app was broken. Still undocumented: the help dialog also defines KEY_P, and what it does is not established. Left out rather than guessed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(3D): drop the UI panel keys that are not a thing Founder-confirmed: C, L and T are not implemented and are not planned in the form the table described. They claimed to toggle the AI assistant panel, the log panel and trace details. None appears in the help dialog's key set, and the client has no such bindings. Removed with them: "Toggle Metrics", which had no key at all and a not-yet- configurable marker. A row with no key, no implementation and no date is not documentation. That leaves the UI & Panels table with the two camera-view keys that are real, M and N. On KEY_P, which the help dialog defines and which prompted this: the only first-party reference is PlayerControlsControl.cs line 12, and it is commented out -- //public KeyCode ToggleKey = KeyCode.P; -- so P does nothing in the client while the help dialog still advertises it. That is a product defect rather than a documentation gap, and it stays out of the docs until the key does something. The Avatar input map does bind <Keyboard>/p, but to SecondaryPointerButtonPress in the XR simulator, which is not a user-facing shortcut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(3D): mark Grid map and Avatar as unfinished Both descriptors carry ComingSoon = true, which the descriptor documents as a setting that is present but not finished -- "a dropdown with no options is normally a defect worth an error; on a setting nobody has finished, it is just the truth." The rewrite listed them as working settings with a default. A reader would open the dialog, find an empty dropdown, and reasonably conclude the client was broken. Found while verifying a different claim. The page says Tessa can change twelve of these, which I had taken from AgentWritable without checking that anything consumes it. It does: AssistantBootstrapper registers GetPreferencesTool and SetPreferenceTool as tools, and PreferenceToolGateway enforces AgentWritable on write and rejects unknown keys. The claim holds. What the same check turned up is that the gateway computes writability as "AgentWritable && !ComingSoon", which is what surfaced these two. Neither is agent-writable, so the robot markers are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Region and redundancy clarifications.
Correct two unsupportable claims on the Data Security page (#109) * docs(legal): correct two unsupportable claims on the Data Security page Both were live on a legal page, which is where a buyer's counsel reads them. DATA RESIDENCY. The table listed "European Union | Available (Enterprise)". There is no EU infrastructure: a region inventory across IF.GitOps, services.json and the architecture docs finds East US carrying effectively everything, East US 2 carrying only the Azure OpenAI deployment, West US appearing solely as a worked example in README and RUNBOOK under "Adding a region", and zero references to any EU region token. The claim was not fabricated so much as mis-tensed. We can provision in additional regions where the required services and capacity exist; no customer has asked, so none is deployed. "Available" said it was ready today. Rewritten to state what is true now (stored and processed in the United States, AI-assisted features in a separate US region) and to put other regions where they belong: on request, subject to availability and capacity. The tier gating is gone too; "Enterprise" is not one of our tiers. MULTI-REGION DR. Removed "Multi-region deployment for redundancy and disaster recovery" from Infrastructure Security. One region is deployed. Having a documented procedure for adding a second is not operating across two, and unlike the residency row this one is not rescued by being able to provision on request: it is a present-tense claim about the running architecture. Verified before pushing: mkdocs build --strict succeeds, redirect parity and meta-description checks pass, and the built page shows the new wording with a resolving contact link and no remaining instance of the removed claims. Not changed: Data-Security/.pages keeps hide: true. Unhiding is craft and mine, but not in the same change that corrects the claims on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(legal): restore multi-region as a capability rather than deleting it The previous commit removed the multi-region bullet outright. That was inconsistent with how the same commit handled the residency row: both were present-tense claims about a state we are not in, and the residency one was re-tensed to a capability while this one was deleted. Same defect, two treatments. The capability is real. What was not true is the tense: under a list headed "DeepCube is hosted on enterprise-grade cloud infrastructure with:", the original wording reads as describing the running deployment, so a reader concludes failover exists today. It does not. Restored as "Multi-region capable - additional regions can be provisioned for redundancy or data residency, subject to service availability and capacity." That claims what we can do without asserting what we currently run, and it matches the residency wording in the same file. Deleting it undersold a genuine capability, which is its own kind of inaccuracy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Release notes.
docs(release-notes): 1.18.8 ships, and Steam catches up on eight tags 1.18.0 was the last Steam post, so the Steam note rolls up 1.18.1 through 1.18.8: Tessa drives the Shoebox sandbox end to end, the chat window becomes a window you can select from, resize, zoom and reopen, and phantoms and error nodes now say what they are through motion rather than color alone. Web and Studio get roll-up entries too. Web 3.177.5 is the honest-charts release: all 32 Insights charts rebuilt against the current telemetry after the old queries were found rendering plausible but wrong numbers, plus a node metering fix that had been under-counting multi-grid accounts. Studio 1.4.3 is the rename and nothing else user-facing. What is deliberately absent: - Replay and time travel. The reference docs still say time travel is disabled while replay is reworked, and a lot of this range is SP-061 replay work. Announcing it would contradict a page we publish. - Direct3D 12. It did not ship; the switch is parked as PR 3695 because it did not move the frame rate and broke the build gate. whats-new.md also gains June and July, which were never recorded, and retires its oldest highlight block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Page descriptions and CI work.
feat(seo): derive a description for every page from its own opening Closes the defect Dobri reported: every page on the site served the same meta description, so a Slack unfurl of an installation guide and of the release notes were indistinguishable. 11 pages were fixed by hand on 2026-08-30. This covers the other 108. NOT BY HAND, AND THAT IS THE POINT. The Writing Standard (canon, 2026-07-31) already requires the first ~50 words of a page to stand alone as a summary. Where a page complies, its opening paragraph IS its description; the text existed and simply was not reaching the meta tag. Sampling eight untouched pages, seven opened with a usable summary sentence. So the hook derives rather than invents, and hand-authoring drops from 108 to 3. hooks/meta_descriptions.py runs on_page_markdown and fills the gap only. Explicit front matter always wins. It SKIPS rather than guesses when it cannot produce something honest: an include directive, an admonition, a list item, anything under 40 characters. A page falling back to a correct generic string beats one carrying a derived sentence that misleads. Trademark per Friday's ruling (#2223, clarified #2270): the mark once, on first appearance, never on every appearance, because "DeepCube Web" and "DeepCube Studio" are distinct product names and marking the family name inside them asserts a claim that has not been filed. Written ™ to match the © already in mkdocs.yml. TWO BUGS FOUND AND FIXED BEFORE WIRING IT UP, both caught by reading the generated output rather than trusting it: 1. Multi-line HTML comments were not tracked across lines, only skipped at the opener. Uninstallation/Windows and macOS open with an SP-074 note, so the hook would have published "Per R-DOCS-005, docs that quote a shipping string stay on the old" as those pages' descriptions. An internal rule ID and a rename instruction, to Google. Comment state is now tracked like fence state. 2. The character budget measured the SOURCE string. `™` is 7 source characters and 1 glyph, so a 159-character source is 153 to a reader. The ~155 budget belongs to the rendered snippet, not the markup producing it. Now measured with html.unescape, marking happens before truncation, and truncation never severs an entity. THE CHECK NOW ASSERTS THE REAL INVARIANT. The compare pass only inspected pages that DECLARE a description, so it could not see a page that has none and silently inherits. That is precisely what shipped. A third pass now fails any page serving site_description. Of 309 rendered pages, 0 inherit. The allow-list is two entries and both are named. The homepage legitimately carries the descriptor. Data-Residency is an EMPTY PAGE: 16 bytes, a heading and nothing else, published under the legal section, linked from nowhere, and returning 200 with only site chrome. It has no description because it has no content, and writing one would describe a page that says nothing. Tracked as DOC-SP-079, with the CI comment saying to delete the line when the page gets content or is unpublished. That is a tracked defect, not an exemption. Verified: mkdocs --strict green, 41 front-matter blocks parse, 14 compared and 0 mismatched, 309 checked for silent fallback and 0 inheriting, no &trade; leaking as literal text, no internal markers in any rendered description. The hook produces __pycache__ at build time; .gitignore already covered it at line 7, so nothing was needed there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restamps and clean up.
1.28.10 docs(seo): apply Friday's meta-description rulings, and fix a descrip…
Studio instructions
Studio ships on macOS, and the install page says it does not The page opened with "Alpha channel, Windows only" and told readers that only Windows builds are available and that macOS would follow. The macOS half is false. Verified against the artifacts rather than taken on report: 200 release/alpha/DCS.latest.msi 200 release/alpha/DCS.latest.dmg <- ships today 404 beta, both platforms 404 stable, both platforms So Studio is alpha-only, which the warning got right, and it is alpha on BOTH platforms, which it got wrong. The download section offered only the .msi, so a Mac reader landed on our own install page, read that their platform was not supported, and left. The build was one link away the whole time. The warning now says alpha-only across both platforms, the dmg has a download button, and there is a macOS section. The macOS steps are sourced, not adapted from the 3D page on the assumption that the two are alike. The bundle name is DCS.app, read off the dmg pipeline (IF.APM.App.Avalonia/pipelines/cd-dmg.yml, sourceAppBundleName, with its own comment recording that Dotnet.Bundle produces it from CFBundleName). The quarantine removal is the same step 3D's macOS page documents, because it is a property of unsigned bundles rather than of that product. Deliberately not copied from 3D: its ring language. 3D is macOS alpha only with Windows on all three rings, Studio is alpha only on both, and both are correct for their own product (Friday, bus #2183, founder-confirmed). Nothing here implies Studio will follow 3D's shape. Raised by Friday on bus #2182 as the one part of that ask that was not low priority. The structure mirror in the rest of it is not in this change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Site title.
Read site_name from mkdocs.yml in the routing tests The rename broke the routing suite, which is the suite working correctly: it asserts page TITLES rather than status codes, precisely because a directory listing also returns 200 and that is how cleanUrls:false once shipped past a status-only suite. It caught the change. What it should not have done is need a hand edit. The three title cases pinned the literal string Immersive Fusion Docs, so the brand lived in a test file as well as in mkdocs.yml, and a rename had to remember to visit both. It did not. Renaming the site broke CI before it broke anything a reader could see, which is the good version of this failure, but the next one might not be. Now read from mkdocs.yml at import. The assertion still does its real job, which is proving the response is a rendered page and not a directory listing, and a directory listing will not carry the site name whatever it is called. This is the rule check-redirect-parity.py already states for the redirect maps, that there is exactly one reader of mkdocs.yml because a second one that normalizes differently is how they drift apart. Same reason here. Verified: the module imports, SITE_NAME reads back as DeepCube Docs, and the three cases resolve to it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Forward fixes.
1.28.7 Agree the two redirect maps, and fill the block that was waiting on a…