The lws output wedge addressed in the previous commit was incompletely understood: under genuine backpressure (peer slow or paused, kernel send buffer full) a connection still froze permanently. Root cause, established by tracing the writeable-request plumbing end to end: lws_send_pipe_choked() is true not only when lws holds a truncated send (lws re-arms the writeable callback itself then) but also when a zero-timeout poll(POLLOUT) reports the socket simply full -- and in that case every lws_write() has fully succeeded, lws has nothing pending, and nobody re-arms anything. Fix, per lws README.coding.md: whenever the drain loop exits with data still queued in pss->buffer, request the next writeable callback. Queued data always has a callback requested, so no exit path can strand output. Also: - LWS_CALLBACK_CLOSED frees the session evbuffer unconditionally: on driver-initiated closes (e.g. the mudlib destructing the interactive) close_user_websocket() nulls pss->user first, and the old early return leaked the buffer every time. - src/www/README.md + src/www/AGENTS.md: architecture doc and agent checklist for the web terminal pages (xterm.js/telnet.js layering, vendor policy, packaging, testing, the wedge mechanism). - tools/ws-smoke.js, wired into CI on the Clang Debug matrix entries (with and without sanitizers): a dependency-free node websocket client that boots the real driver and exercises the http mount, telnet + ascii subprotocols through the shared src/www/telnet.js, SGA char-mode switching, live TUI streaming, TLS, and -- the actual regression gate -- forced-backpressure bursts (paused socket, ~4.8MB) on the plain and TLS ports plus a destruct-while-choked teardown check. All three backpressure checks fail on the unfixed driver; neither GTest nor the LPC suite exercises any websocket client traffic. - Fix stale src/www/wasm/vendor/ path references left from the vendor directory move (src/wasm/README.md, docs/build-wasm.md, release.yml). Validated on the ASan Debug build: forced-backpressure repros recover the full burst on both subprotocols, destruct-while-choked clean under ASan, ws-smoke 17/17, GTest 312/312, LPC testsuite clean. |
||
|---|---|---|
| .. | ||
| apply | ||
| archive | ||
| cli | ||
| concepts/general | ||
| driver | ||
| efun | ||
| i18n/zh-CN | ||
| lpc | ||
| src/css | ||
| static | ||
| stdlib | ||
| .gitignore | ||
| add_missing_efuns.py | ||
| bug.md | ||
| build-wasm.md | ||
| build.mdx | ||
| build_v2017.md | ||
| CLAUDE.md | ||
| docusaurus.config.ts | ||
| gen_config_docs.py | ||
| gen_sidebar.py | ||
| index.mdx | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| sidebar_meta.json | ||
| sidebars.generated.json | ||
| sidebars.ts | ||
FluffOS Documentation
This directory contains the source for the FluffOS documentation site, published at https://www.fluffos.info.
The site is built with Docusaurus 3 (@docusaurus/preset-classic).
Markdown files live directly in this directory (the docs plugin is configured with
path: '.' and routeBasePath: '/'), so docs/efun/strings/explode.md becomes
/efun/strings/explode on the site.
This README is for contributors and is excluded from the published site (see
excludeindocusaurus.config.ts).
Local Development
Requires Node.js 18+ (Node 22 recommended).
cd docs
npm install
npm run dev # dev server on http://localhost:3000
Other scripts:
npm run build # production build → docs/build/
npm run preview # serve the production build locally
npm run clear # clear the Docusaurus cache
Search
Full-text search is provided by
@easyops-cn/docusaurus-search-local,
an offline/local search theme — the index is generated at build time and shipped with the
site, so no external search service (e.g. Algolia) is needed.
Notes:
- The search index is only generated by
npm run build. In the dev server (npm run dev) the search bar shows a hint instead of results; usenpm run build && npm run previewto test search locally. - Both English and Chinese pages are indexed (
language: ['en', 'zh']). - Search options live in the
themessection ofdocusaurus.config.ts.
Chinese docs (i18n)
The Chinese corpus lives under i18n/zh-CN/docusaurus-plugin-content-docs/current/,
mirroring the English tree layout (a translation of docs/efun/arrays/allocate.md
goes at i18n/zh-CN/docusaurus-plugin-content-docs/current/efun/arrays/allocate.md).
The site serves it at /zh-CN/ with a locale dropdown in the navbar; untranslated
pages automatically fall back to the English content.
- Sidebar/navbar/footer label translations:
i18n/zh-CN/docusaurus-plugin-content-docs/current.jsonandi18n/zh-CN/docusaurus-theme-classic/*.json. Rescaffold new keys withnpx docusaurus write-translations --locale zh-CNafter sidebar changes, then translate them. - The dev server runs one locale at a time:
npm run dev -- --locale zh-CN. npm run buildbuilds both locales.
Layout
| Path | Contents |
|---|---|
docusaurus.config.ts |
Site config: navbar, footer, docs plugin, search theme |
sidebars.ts |
Sidebar skeleton; splices in the generated reference trees |
sidebars.generated.json |
Generated sidebar trees for the reference docs (do not hand-edit) |
sidebar_meta.json |
Curated sidebar labels, descriptions and ordering for the generated trees |
src/css/custom.css |
Infima CSS variable overrides |
static/ |
Files copied verbatim to the site root (CNAME, Google site verification) |
apply/ |
Driver-to-LPC callback (apply) reference |
efun/ |
Built-in function (efun) reference, by category |
stdlib/ |
LPC standard-library reference |
driver/ |
Driver internals & configuration |
lpc/ |
LPC language reference |
concepts/ |
High-level LPC / MUD concepts |
cli/ |
Command-line tool docs |
i18n/zh-CN/ |
Chinese translations (Docusaurus i18n; mirrors the English tree layout) |
archive/ |
Historical MudOS-era documents (not published) |
Maintenance scripts
| Script | Purpose |
|---|---|
gen_sidebar.py |
Regenerates sidebars.generated.json from the reference doc trees + sidebar_meta.json (--check verifies freshness, used by CI) |
gen_config_docs.py |
Regenerates driver/config.md from src/base/internal/rc.cc |
add_missing_efuns.py |
Creates stub pages under efun/general/ for undocumented efuns (needs a keywords.json from the generate_keywords tool) |
Conventions & Gotchas
driver/config.mdis auto-generated fromsrc/base/internal/rc.cc— never edit it by hand. Regenerate withpython3 docs/gen_config_docs.py; CI fails if it is stale..mdfiles are treated as standard CommonMark (markdown.format: 'detect'), but bare{...}in prose is still parsed as a JSX expression and breaks the build — escape it as\{...\}outside fenced code blocks.- Sidebar entries in
sidebars.tsuse doc IDs (relative path without extension), not URLs. - The reference trees (efun/apply/stdlib/cli/concepts/driver) have no
index.mdfiles: their sidebar trees live insidebars.generated.jsonand their landing pages are Docusaurusgenerated-indexcard pages. After adding, removing, or moving a page in those trees, run./gen_sidebar.pyand commit the result — CI fails if it is stale. Category labels/descriptions/ordering are curated insidebar_meta.json.lpc/index.mdis hand-written and its sidebar is hand-authored insidebars.ts. - The sidebar is shared by both locales; Chinese category labels come from
i18n/zh-CN/docusaurus-plugin-content-docs/current.json, not fromsidebar_meta.json. onBrokenLinksis set to'throw': a broken internal link fails the build (and the Pages deploy) instead of shipping a 404.
See CLAUDE.md for detailed documentation templates (applies, efuns, CLI
tools) and the full contribution workflow.