From ff2f6628bfbc2ec9506edffa41cf79dda64964da Mon Sep 17 00:00:00 2001 From: Gabriel Mongefranco <42566461+gabrielmongefranco@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:01:51 -0400 Subject: [PATCH 1/4] Mark the issues implementation plan complete The storage dialog merged on 2026-09-29 and its issue is closed, so phase 4 is now marked done. The plan's introduction, summary, and conclusion now say the plan is complete, and that phase 5, Markdown in chats, stays deferred. --- docs/issues-implementation-plan.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/issues-implementation-plan.md b/docs/issues-implementation-plan.md index a7c4a38..0acf517 100644 --- a/docs/issues-implementation-plan.md +++ b/docs/issues-implementation-plan.md @@ -3,8 +3,8 @@ This file is part of Field Station AI. docs/issues-implementation-plan.md: Ordered plan and status tracker for the open GitHub issues, in Markdown format. Author(s): Gabriel Mongefranco. Created: 2026-09-22 -Last Modified: 2026-09-29 -Summary: Lists the open GitHub issues in the order they will be worked, the branch and scope for each, and the rules every phase follows. +Last Modified: 2026-10-07 +Summary: The completed plan for the GitHub issues open in September 2026: the order they were worked, the branch and scope for each, and the rules every phase followed. Notes: See README file for documentation and full license information. Copyright © 2026 The Regents of the University of Michigan @@ -20,7 +20,7 @@ See . See README for full license inf [Back to project README](../README.md) -This page is the working plan for the open [GitHub issues](https://github.com/DepressionCenter/FieldStationAI/issues). It says which issue comes next, what branch it lives on, what is in and out of scope, and how we know it is done. Everything on this page is planned work, not a description of what the app does today. The other pages in this folder describe current behavior, and they get updated as each phase lands. +This plan is complete. It was the working plan for the open [GitHub issues](https://github.com/DepressionCenter/FieldStationAI/issues) in September 2026. It says which issue came next, what branch it lives on, what is in and out of scope, and how we know it is done. Everything on this page is planned work, not a description of what the app does today. The other pages in this folder describe current behavior, and they get updated as each phase lands. ### How to use this page @@ -47,10 +47,10 @@ Status values are **Not started**, **Planning**, **In progress**, **In review**, | 1 | [#1](https://github.com/DepressionCenter/FieldStationAI/issues/1) | Crisis notice for prompts that may signal a mental health emergency | `feature/crisis-notice` | Done | | 2 | [#6](https://github.com/DepressionCenter/FieldStationAI/issues/6) | "Paste text" input for the four text classifier skills | `feature/skill-paste-text` | Done | | 3 | [#7](https://github.com/DepressionCenter/FieldStationAI/issues/7) | Direct chat-to-skill flow for text-only skills | `feature/chat-to-skill` | Done | -| 4 | [#4](https://github.com/DepressionCenter/FieldStationAI/issues/4) | Storage management dialog in the menu | `feature/storage-manager` | In review | +| 4 | [#4](https://github.com/DepressionCenter/FieldStationAI/issues/4) | Storage management dialog in the menu | `feature/storage-manager` | Done | | 5 | [#2](https://github.com/DepressionCenter/FieldStationAI/issues/2) | Full Markdown support in chats | `feature/chat-markdown` | Not started (do much later) | -Issues [#3](https://github.com/DepressionCenter/FieldStationAI/issues/3), [#5](https://github.com/DepressionCenter/FieldStationAI/issues/5), [#12](https://github.com/DepressionCenter/FieldStationAI/issues/12), and [#21](https://github.com/DepressionCenter/FieldStationAI/issues/21) stay open but are not scheduled. See [Issues not scheduled](#issues-not-scheduled). +Issues [#3](https://github.com/DepressionCenter/FieldStationAI/issues/3), [#5](https://github.com/DepressionCenter/FieldStationAI/issues/5), and [#21](https://github.com/DepressionCenter/FieldStationAI/issues/21) stay open but are not scheduled. Issue [#12](https://github.com/DepressionCenter/FieldStationAI/issues/12) was done outside the phases. See [Issues not scheduled](#issues-not-scheduled). ### Phase 1: Crisis notice (issue #1) @@ -272,7 +272,7 @@ Found while testing and not changed in this phase: with the app's 4-bit embeddin ### Phase 4: Storage management dialog (issue #4) -**Status:** In review +**Status:** Done. Merged on 2026-09-29, and the issue is closed. **Branch:** `feature/storage-manager`, from `main`. @@ -399,12 +399,12 @@ Model output is untrusted, so rendered Markdown must be encoded before it reache - [#3](https://github.com/DepressionCenter/FieldStationAI/issues/3), zip and progressive XML ingestion, is groundwork for a wearable-data skill that does not exist yet. It stays open until that skill is planned. - [#5](https://github.com/DepressionCenter/FieldStationAI/issues/5), service worker and cache bucket, changes the deployment story and adds a network allowlist. It needs an explicit design decision first, recorded in `docs/design-change-record.md`. -- [#12](https://github.com/DepressionCenter/FieldStationAI/issues/12), pinning the WebLLM import, is a small dependency change that needs its own release-note and advisory check. Do it in its own branch when convenient. +- [#12](https://github.com/DepressionCenter/FieldStationAI/issues/12), pinning the WebLLM import, was done on its own branch, `fix/pin-webllm-version`, with a release-note and advisory check. See [WebLLM Pinned to an Exact Version](design-change-record.md#webllm-pinned-to-an-exact-version). - [#21](https://github.com/DepressionCenter/FieldStationAI/issues/21), extracting pain location, qualities, and timeframe from text, follows the rework of Estimate pain level on `feature/pain-intensity-interference`. It needs a decision on whether it is a new skill or a mode of the existing one, and on which model extracts the wording. See [Estimate Pain Level](field-kit.md#estimate-pain-level) for what exists today. ### Conclusion -Phases 1, 2, and 3 are done and phase 4 is in review. Move down the table as each pull request merges: create the next branch from `main`, write the detailed plan under the phase heading, and set the status to Planning. +This plan is complete. Phases 1 through 4 are done and their issues are closed, except for the parts of issue #7 described under phase 3. Phase 5 stays deferred, and issue #2 stays open until it is scheduled. ### Additional resources From 123e0dbda6aa776a30ccff306866c1e2d27852e8 Mon Sep 17 00:00:00 2001 From: Gabriel Mongefranco <42566461+gabrielmongefranco@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:01:52 -0400 Subject: [PATCH 2/4] Pin WebLLM to version 0.2.85 The app loaded WebLLM from esm.run with no version, so every new WebLLM release reached users the day it shipped, with no change in this repository. WebLLM now loads from a single constant, WEBLLM_URL, pinned to 0.2.85 on jsDelivr. That is the version the unpinned address served, so behavior does not change. esm.run only redirected to jsDelivr, so the app now uses one less host. Before pinning, I read the 0.2.85 release notes, which list fixes only, and found no advisories for the package in the GitHub advisory database. All 11 chat models the app offers are in that version's prebuilt model list. A new test fails on any CDN address in index.html that lacks an exact version. The runtime page lists each library's version, and the developer guide gives the steps for raising one. Closes #12. --- docs/design-change-record.md | 12 +++++++- docs/developer-guide.md | 17 +++++++++-- docs/models-and-runtime.md | 23 ++++++++------- index.html | 11 ++++++-- skills/project-preferences/SKILL.md | 7 +++-- tests/index-html.test.mjs | 44 +++++++++++++++++++++++++++-- 6 files changed, 93 insertions(+), 21 deletions(-) diff --git a/docs/design-change-record.md b/docs/design-change-record.md index dd34efa..4437cca 100644 --- a/docs/design-change-record.md +++ b/docs/design-change-record.md @@ -3,7 +3,7 @@ This file is part of Field Station AI. design-change-record.md: Summary of recent major design changes in Field Station AI, in Markdown format. Author(s): Gabriel Mongefranco. Created: 2026-07-26 -Last Modified: 2026-09-30 +Last Modified: 2026-10-07 Summary: Field Station AI is a private, in-browser AI workspace for health and behavioral researchers. Notes: See README file for documentation and full license information. @@ -302,6 +302,16 @@ Decision: - The results table is built element by element, because item names come from a person's spreadsheet or file names. The table sits in a region that scrolls sideways on a narrow screen. - The tone bars showed white text with a dark halo over a pale track, which fails the contrast check on the unfilled part. The fill is now a tint and the text is dark, on every tool that uses the bars. +## WebLLM Pinned to an Exact Version + +The app loaded WebLLM from `esm.run` with no version, while every other library carried one. So each new WebLLM release reached every user the day it shipped, with no change in this repository, and a bad release would have broken chat for everyone at once. + +Decision: + +- WebLLM loads from one constant, `WEBLLM_URL`, pinned to 0.2.85. That was the version the unversioned address served when it was pinned, so the app's behavior did not change. Its release notes list fixes only, and the GitHub advisory database had no advisories for the package. All 11 chat models are in its prebuilt model list. +- The address points at jsDelivr directly. `esm.run` only redirects there, so this removes one host and one redirect from every first load. +- A test fails on any CDN address in `index.html` that lacks an exact version. Raising a version is a deliberate change, made with the steps in the developer guide. + ## Documentation Rule When these areas change, update this file and the relevant user or developer doc: diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 9efebab..0b75687 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -3,7 +3,7 @@ This file is part of Field Station AI. developer-guide.md: Guide for developers working on Field Station AI, in Markdown format. Author(s): Gabriel Mongefranco. Created: 2026-07-26 -Last Modified: 2026-09-30 +Last Modified: 2026-10-07 Summary: Field Station AI is a private, in-browser AI workspace for health and behavioral researchers. Notes: See README file for documentation and full license information. @@ -268,6 +268,19 @@ try { } ``` +## Update a Pinned Library + +Every library the app loads from a CDN is pinned to an exact version. [Models and Runtime](models-and-runtime.md#runtime-sources) lists them. A test in `tests/index-html.test.mjs` fails if any CDN address lacks an exact version, so `@latest`, `@4`, or a bare package name will not pass. + +To move a library to a new version: + +1. Read the release notes for every version between the current one and the new one. +2. Check the GitHub advisory database for the package, and note what you found in the pull request. +3. Change the version in `index.html`. WebLLM's address is the `WEBLLM_URL` constant, and Pyodide's is `PYODIDE_VERSION`. +4. For WebLLM, confirm that every model in `MODEL_CTX` is still in the new version's prebuilt model list. The list is in the package's `lib/index.js`, as `model_id` entries. +5. Update the table in [Models and Runtime](models-and-runtime.md#runtime-sources). +6. Run the tests, then load each changed library's paths in a browser. For WebLLM, load a cached model and a new one, and send a prompt. + ## Python / Pyodide Changes For browser-based Python workflows: @@ -322,7 +335,7 @@ The tests live under `tests/` and use Node's own test runner, so nothing is inst node --test tests/ ``` -That checks every documentation page (links, license comment, heading structure), the file header, single-script rule, reranker wiring, **Paste text** tab wiring, skill offer wiring, and pain estimate wiring in `index.html`, the crisis check's phrase tier against the prompt fixture, the reply and citation text helpers, the Field Kit paste text helpers, the skill offer's helpers and lists, the pain estimate's helpers and its fixture's stated scores, the emotions tool's helpers, the CSV cell writer, and the storage dialog's helpers and wiring. The model-backed tests skip themselves unless their dependency is installed. +That checks every documentation page (links, license comment, heading structure), the file header, single-script rule, exact versions on every CDN address, reranker wiring, **Paste text** tab wiring, skill offer wiring, and pain estimate wiring in `index.html`, the crisis check's phrase tier against the prompt fixture, the reply and citation text helpers, the Field Kit paste text helpers, the skill offer's helpers and lists, the pain estimate's helpers and its fixture's stated scores, the emotions tool's helpers, the CSV cell writer, and the storage dialog's helpers and wiring. The model-backed tests skip themselves unless their dependency is installed. Pure helpers the tests need are fenced in `index.html` by a pair of comments, `### (start) ###` and `### (end) ###`. There are ten such blocks: the router's intent data, the skill offer's data and helpers, the crisis check's data, the citation tag helpers, the reply and citation text helpers, the Field Kit paste text helpers, the emotions tool's data and helpers, the pain estimate's data and helpers, the CSV cell writer, and the storage dialog's helpers. `tests/helpers/marked-block.mjs` evaluates a block on its own, so keep each block free of DOM access and of constants from outside it. diff --git a/docs/models-and-runtime.md b/docs/models-and-runtime.md index 348932b..9eeb967 100644 --- a/docs/models-and-runtime.md +++ b/docs/models-and-runtime.md @@ -3,7 +3,7 @@ This file is part of Field Station AI. models-and-runtime.md: Documentation for models and runtime behavior in Field Station AI, in Markdown format. Author(s): Gabriel Mongefranco. Created: 2026-07-26 -Last Modified: 2026-09-28 +Last Modified: 2026-10-07 Summary: Field Station AI is a private, in-browser AI workspace for health and behavioral researchers. Notes: See README file for documentation and full license information. @@ -19,17 +19,20 @@ See . See README for full license inf ## Runtime Sources -Field Station AI™ uses browser model runtimes and helper libraries. Runtime downloads may occur on first use. The exact pinned URLs and versions should be checked in `index.html` before release. +Field Station AI™ uses browser model runtimes and helper libraries. Each one downloads from a public content delivery network (CDN) the first time the app needs it. Every library is pinned to an exact version, so a new release upstream cannot change the app until someone updates `index.html` on purpose. -Known runtime/library areas documented in the current repository context: +| Library | Version | Used for | +| --- | --- | --- | +| Transformers.js | 4.2.0 | Helper models: embeddings, reranking, the router, classification, transcription, and vision | +| WebLLM | 0.2.85 | Main chat models on WebGPU | +| Pyodide | 0.26.4 | Python data-cleaning code in the browser | +| PapaParse | 5.4.1 | CSV files | +| SheetJS | 0.18.5 | Excel files | +| PDF.js | 4.7.76 | PDF files | -- Transformers.js. -- WebLLM where configured for main chat models. -- Pyodide for browser-based Python workflows. -- PapaParse for CSV parsing. -- SheetJS for Excel files. -- PDF.js for PDF behavior. -- Optional Ollama for local backend generation. +Ollama is optional. When you turn it on, the app talks to an Ollama server on your own computer for larger models. It is not loaded from a CDN. + +The automated tests fail if any CDN address in `index.html` lacks an exact version. To change a version, follow [Update a Pinned Library](developer-guide.md#update-a-pinned-library) in the developer guide. ## Main Chat Models diff --git a/index.html b/index.html index f2e8886..1de23ae 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ index.html: Main HTML file for the Field Station AI application. Author(s): Gabriel Mongefranco. Created: 2026-07-18 -Last Modified: 2026-09-30 +Last Modified: 2026-10-07 Summary: Field Station AI is a private, in-browser AI workspace for health and behavioral researchers. This is the main HTML file for the Field Station AI application. Notes: See README file for documentation and full license information. @@ -2780,7 +2780,12 @@

Compe // Transformers.js - WebLLM ships no equivalents for those. When the // browser has no WebGPU, webllm: picks fall back to a small // Transformers.js model on WASM CPU so the app still runs. - let webllmModule = null; // lazy import of @mlc-ai/web-llm (esm.run CDN) + // Pinned so a WebLLM release cannot change model loading or generation + // without a change here. Before raising the version, read its release + // notes, check it for advisories, and confirm every id in MODEL_CTX is + // in its prebuilt model list. jsDelivr is the host esm.run redirects to. + const WEBLLM_URL = 'https://cdn.jsdelivr.net/npm/@mlc-ai/web-llm@0.2.85/+esm'; + let webllmModule = null; // lazy import of WEBLLM_URL let webllmEngine = null; // active MLCEngine, or null let hasWebGPU = null; // null until detected; then boolean let runningOnCpu = false; // true when the active chat model executes on CPU (WASM fallback) @@ -5408,7 +5413,7 @@

Compe try { if (!webllmModule) { showProgress('Preparing the fast AI engine...'); - webllmModule = await import('https://esm.run/@mlc-ai/web-llm'); + webllmModule = await import(WEBLLM_URL); if (stale()) return; } const cachedW = isCached(targetId); diff --git a/skills/project-preferences/SKILL.md b/skills/project-preferences/SKILL.md index 26a2a59..57b8ab7 100644 --- a/skills/project-preferences/SKILL.md +++ b/skills/project-preferences/SKILL.md @@ -88,9 +88,10 @@ run without one, so check that a change still works on modest hardware before ca `index.html` to a web server and be done. Do not split the app into modules, add a build step, or introduce a framework. - **Third-party libraries load from public CDNs at runtime**, currently Transformers.js, - PapaParse, SheetJS, PDF.js, and Pyodide, all pinned to explicit versions. Keep versions - pinned. Before changing one, check the release notes and any known CVEs, and say what - you checked. + WebLLM, PapaParse, SheetJS, PDF.js, and Pyodide, all pinned to explicit versions. Keep + versions pinned; `tests/index-html.test.mjs` fails on a CDN address without an exact + version. Before changing one, check the release notes and any known CVEs, and say what + you checked. The developer guide's "Update a Pinned Library" section has the steps. - **Treat every model output as untrusted input.** Model text, retrieved compendium passages, and parsed file content are data, never instructions. Never let them reach `innerHTML`, `eval`, a generated URL, or the Pyodide sandbox without validation. diff --git a/tests/index-html.test.mjs b/tests/index-html.test.mjs index 0c228d7..58eb29f 100644 --- a/tests/index-html.test.mjs +++ b/tests/index-html.test.mjs @@ -2,10 +2,11 @@ // tests/index-html.test.mjs // Author(s): Gabriel Mongefranco. // Created: 2026-09-23 -// Last Modified: 2026-09-30 +// Last Modified: 2026-10-07 // Summary: Static checks on index.html, the whole application: the file // header carries the project and license notice, the app is still one -// module script, the crisis notice constants point at the 988 Lifeline, +// module script, every library loaded from a CDN names an exact version, +// the crisis notice constants point at the 988 Lifeline, // the excerpt reranker is wired the way that yields real scores, the // Field Kit text skills offer a "Paste text" tab whose text is never // parsed as markup or stored, the chat's skill offer hands text to a @@ -77,6 +78,45 @@ test('index.html is one module script', () => { assert.equal(modules.length, 1, 'the app must stay a single module script'); }); +// ### Pinned Libraries ### + +// Hosts that serve the app's third-party code at runtime. Every address on +// one of them must name an exact version, so that a new release upstream +// cannot change or break the app without a change to index.html. +const CDN_HOSTS = ['cdn.jsdelivr.net', 'cdnjs.cloudflare.com', 'esm.run', 'esm.sh', 'unpkg.com', 'cdn.skypack.dev']; + +// An exact version is three numbers, optionally with a pre-release tag, +// written after "@" or as a whole path segment with an optional "v". +// "@latest", "@4", "@^4.2.0", and a bare package name all fail. +const EXACT_VERSION = /(?:@|\/v?)\d+\.\d+\.\d+(?:-[0-9A-Za-z.]+)?(?=\/|$)/; + +// Returns every CDN address in index.html, comments included. An address +// written as a string followed by "+ SOME_VERSION" is read with that +// constant's value appended, which is how the Pyodide address is built. +function cdnAddresses() { + const hosts = CDN_HOSTS.map(host => host.replace(/\./g, '\\.')).join('|'); + const pattern = new RegExp('https?://(?:' + hosts + ')[^\'"`\\s)<>]*(?:[\'"`]\\s*\\+\\s*([A-Z][A-Z0-9_]*_VERSION)\\b)?', 'g'); + return [...html.matchAll(pattern)].map(match => { + const address = match[0].replace(/['"`]\s*\+\s*[A-Z0-9_]+$/, ''); + return match[1] ? address + stringConstant(match[1]) : address; + }); +} + +test('every library loaded from a CDN names an exact version', () => { + const addresses = cdnAddresses(); + for (const library of ['@huggingface/transformers', '@mlc-ai/web-llm', 'PapaParse', 'xlsx', 'pdfjs-dist', 'pyodide']) { + assert.ok(addresses.some(address => address.includes(library)), `the scan finds the ${library} address`); + } + const unpinned = addresses.filter(address => !EXACT_VERSION.test(address)); + assert.deepEqual(unpinned, [], 'every CDN address carries an exact version'); +}); + +test('WebLLM loads from its one pinned address', () => { + assert.match(stringConstant('WEBLLM_URL'), /@mlc-ai\/web-llm@\d+\.\d+\.\d+\//, 'WEBLLM_URL names an exact version'); + assert.ok(html.includes('await import(WEBLLM_URL)'), 'the engine is imported from WEBLLM_URL'); + assert.equal((html.match(/@mlc-ai\/web-llm@/g) || []).length, 1, 'no second WebLLM address can drift from the first'); +}); + // ### Crisis Notice ### test('the crisis notice points at the 988 Lifeline', () => { From bf65f69e9fee8d5490f38af27a94b2bfbf11503e Mon Sep 17 00:00:00 2001 From: Gabriel Mongefranco <42566461+gabrielmongefranco@users.noreply.github.com> Date: Thu, 8 Oct 2026 00:58:57 -0400 Subject: [PATCH 3/4] Move the test workflow's actions to their Node 24 versions The workflow pinned actions/checkout v4.4.0 and actions/setup-node v4.4.0, which both run on Node 20. GitHub is retiring Node 20 for actions, so they now pin checkout v7.0.1 and setup-node v7.0.0, both on Node 24, by commit hash as before. The release notes between those versions list no change that affects this workflow: it uses no npm token and no fork-triggered events, and it sets its cache options explicitly. setup-node v7.1.0 was left out because it was released the same day. The workflow has never run because GitHub Actions is turned off for this repository by the organization. The developer guide now says so, and says what to do when a pull request shows no checks. --- .github/workflows/tests.yml | 10 +++++----- docs/developer-guide.md | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 43c1a57..d24ed33 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,7 @@ # .github/workflows/tests.yml # Author(s): Gabriel Mongefranco. # Created: 2026-09-23 -# Last Modified: 2026-09-28 +# Last Modified: 2026-10-08 # Summary: Runs the test suite on every pull request and on every push to # main. The static job installs nothing: it checks the documentation, the # single-file app, and the crisis check's regex tier with Node's own test @@ -47,10 +47,10 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Check out the repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Node - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" @@ -65,10 +65,10 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Check out the repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Node - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" cache: npm diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 0b75687..e41bd1d 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -3,7 +3,7 @@ This file is part of Field Station AI. developer-guide.md: Guide for developers working on Field Station AI, in Markdown format. Author(s): Gabriel Mongefranco. Created: 2026-07-26 -Last Modified: 2026-10-07 +Last Modified: 2026-10-08 Summary: Field Station AI is a private, in-browser AI workspace for health and behavioral researchers. Notes: See README file for documentation and full license information. @@ -350,7 +350,7 @@ The first run downloads about 300 MB of model files into `tests/.cache/`, which The pain estimate has its own model test, `tests/pain-estimate-models.test.mjs`. It is off unless `FSAI_PAIN_MODEL_TEST=1` is set, because its model is another 440 MB. See [Change the Pain Estimate](#change-the-pain-estimate). -The GitHub Actions workflow in `.github/workflows/tests.yml` runs both on every pull request and on every push to `main`. Browser testing of the app is still manual: record the browser, the models, and the steps in the pull request. +The GitHub Actions workflow in `.github/workflows/tests.yml` runs both on every pull request and on every push to `main`. It runs only while GitHub Actions is turned on for the repository, which an organization owner controls. If a pull request shows no checks at all, Actions is off: run both commands above yourself and paste the results into the pull request. Browser testing of the app is still manual: record the browser, the models, and the steps in the pull request. ## Security Checklist From f64fb3dde7f6fef54bb832b989a5d692b012c827 Mon Sep 17 00:00:00 2001 From: Gabriel Mongefranco <42566461+gabrielmongefranco@users.noreply.github.com> Date: Thu, 8 Oct 2026 01:04:30 -0400 Subject: [PATCH 4/4] Run the fast test suite with a file pattern that Node 22 accepts The workflow's first run failed in the static job because Node 22's test runner does not accept a folder name: "node --test tests/" stopped with "Cannot find module". Newer Node versions accept it, which is why the suite passed locally on Node 26. The workflow and the documented commands now use the quoted pattern "tests/*.test.mjs", which runs the same 405 tests on Node 22 and Node 26. The developer guide says why the quotes matter. --- .github/workflows/tests.yml | 2 +- docs/developer-guide.md | 4 +++- docs/issues-implementation-plan.md | 4 ++-- skills/project-preferences/SKILL.md | 2 +- tests/docs.test.mjs | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d24ed33..ced63b7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,7 +56,7 @@ jobs: # The model-backed test skips itself here; the models job runs it. - name: Run the fast suite - run: node --test tests/ + run: node --test "tests/*.test.mjs" env: FSAI_SKIP_MODEL_TESTS: "1" diff --git a/docs/developer-guide.md b/docs/developer-guide.md index e41bd1d..2098095 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -332,9 +332,11 @@ Rules for changes: The tests live under `tests/` and use Node's own test runner, so nothing is installed for the fast suite. You need Node 22 or newer. ```text -node --test tests/ +node --test "tests/*.test.mjs" ``` +Keep the quotes, so that Node expands the pattern the same way in every shell. Node 22 does not accept a folder name such as `tests/` here; newer versions do. + That checks every documentation page (links, license comment, heading structure), the file header, single-script rule, exact versions on every CDN address, reranker wiring, **Paste text** tab wiring, skill offer wiring, and pain estimate wiring in `index.html`, the crisis check's phrase tier against the prompt fixture, the reply and citation text helpers, the Field Kit paste text helpers, the skill offer's helpers and lists, the pain estimate's helpers and its fixture's stated scores, the emotions tool's helpers, the CSV cell writer, and the storage dialog's helpers and wiring. The model-backed tests skip themselves unless their dependency is installed. Pure helpers the tests need are fenced in `index.html` by a pair of comments, `### (start) ###` and `### (end) ###`. There are ten such blocks: the router's intent data, the skill offer's data and helpers, the crisis check's data, the citation tag helpers, the reply and citation text helpers, the Field Kit paste text helpers, the emotions tool's data and helpers, the pain estimate's data and helpers, the CSV cell writer, and the storage dialog's helpers. `tests/helpers/marked-block.mjs` evaluates a block on its own, so keep each block free of DOM access and of constants from outside it. diff --git a/docs/issues-implementation-plan.md b/docs/issues-implementation-plan.md index 0acf517..c58c082 100644 --- a/docs/issues-implementation-plan.md +++ b/docs/issues-implementation-plan.md @@ -3,7 +3,7 @@ This file is part of Field Station AI. docs/issues-implementation-plan.md: Ordered plan and status tracker for the open GitHub issues, in Markdown format. Author(s): Gabriel Mongefranco. Created: 2026-09-22 -Last Modified: 2026-10-07 +Last Modified: 2026-10-08 Summary: The completed plan for the GitHub issues open in September 2026: the order they were worked, the branch and scope for each, and the rules every phase followed. Notes: See README file for documentation and full license information. @@ -36,7 +36,7 @@ Status values are **Not started**, **Planning**, **In progress**, **In review**, 4. Treat every prompt, file, model output, and compendium passage as untrusted input. Nothing user-controlled reaches `innerHTML` without encoding. 5. Every new control needs a keyboard path, a visible focus state, and a label. Status changes must not rely on color alone. 6. Update the documentation pages named in the phase in the same branch. Stale documentation is a defect. -7. Run `node --test tests/` before opening a pull request, and the model-backed test when the phase touches the crisis check (see the [developer guide](developer-guide.md)). The suite covers the documentation and the crisis check, not the app's behavior in a browser, so also test in a real browser before calling the phase done, and record the browser, the models, and the exact steps in the pull request. Say plainly what was not tested. +7. Run `node --test "tests/*.test.mjs"` before opening a pull request, and the model-backed test when the phase touches the crisis check (see the [developer guide](developer-guide.md)). The suite covers the documentation and the crisis check, not the app's behavior in a browser, so also test in a real browser before calling the phase done, and record the browser, the models, and the exact steps in the pull request. Say plainly what was not tested. 8. Commit only when the work is tested, then open a pull request against `main`. Commit messages and pull request text are plain English, describe what changed and why, and carry no co-author trailer, robot signature, or tool or model name. 9. Close the GitHub issue when the pull request merges, and update this page. diff --git a/skills/project-preferences/SKILL.md b/skills/project-preferences/SKILL.md index 57b8ab7..5b7695a 100644 --- a/skills/project-preferences/SKILL.md +++ b/skills/project-preferences/SKILL.md @@ -75,7 +75,7 @@ browsers block model downloads for `file://` pages. The automated suite under `tests/` covers the documentation, the single-file rule, the crisis check, the excerpt reranker, the reply text helpers, the Field Kit paste text -helpers, the chat's skill offer, the pain estimate's helpers, the emotions tool's helpers, the CSV cell writer, and the storage dialog; run `node --test tests/` before opening a pull request. The app itself is +helpers, the chat's skill offer, the pain estimate's helpers, the emotions tool's helpers, the CSV cell writer, and the storage dialog; run `node --test "tests/*.test.mjs"` before opening a pull request. The app itself is verified manually in a browser. Say exactly which browser and which models you used, and say plainly when you could not test something. Never report a result you did not observe. diff --git a/tests/docs.test.mjs b/tests/docs.test.mjs index 9e82caf..662690f 100644 --- a/tests/docs.test.mjs +++ b/tests/docs.test.mjs @@ -2,13 +2,13 @@ // tests/docs.test.mjs // Author(s): Gabriel Mongefranco. // Created: 2026-09-23 -// Last Modified: 2026-09-23 +// Last Modified: 2026-10-08 // Summary: Checks that the written documentation agrees with the repository. // Every relative link under docs/, skills/, the README, and SKILLS.md // resolves to a file; every page opens with the license comment; and every // page under docs/ has one H1, no skipped heading level, and a link back to // the project README. Runs with Node's built-in test runner and no -// dependencies: node --test tests/ +// dependencies: node --test "tests/*.test.mjs" // Notes: See README file for documentation and full license information. // // Copyright © 2026 The Regents of the University of Michigan