Team mode makes promises: a station cannot read another station's mail, a Complete by the wrong role is refused on every device, and so on. This page shows how each promise is checked, how to run the checks yourself, and what is still a stated limit. It is for developers and reviewers; people using team mode only need the Team guide.
Each promise is a term. A term is ENFORCED only when a test (a witness) passes and every one of its broken controls is found in the test's output. A broken control is the same test aimed at a deliberately broken case, so it shows the test can fail. A term that is stated but not tested is OPEN and is never shown as met. A test that judged nothing prints INCONCLUSIVE, never PASS.
Current record: 13 enforced, 0 open (run of 2026-10-31). It is published as Project quality objectives (tested properties and stated limits, not a warranty; see GOVERNANCE.md) and as the Terms button in the Team panel. The raw record is team_terms.json (schema terms-v1).
The checker can say no. Removing one broken control from a test's output turns that term UNCONTROLLED and the whole run FAIL; this was tried for the newest term (sealing). Many tests also run mutants: the product code is edited on purpose (one exact line, which must be found exactly once), and the test must go red. A mutant that crashes the test does not count as caught.
The checks run in Node on your own machine. Two public repositories are needed: BIMCompiler (the terms runner and the comm-engine tests) and bim-ootb (this app, its browser tests).
git clone https://github.com/red1oon/BIMCompiler.git git clone https://github.com/red1oon/bim-ootb.git cd BIMCompiler && npm install node scripts/dev_env_fetch.js --root-bim-ootb ../bim-ootb # files git does not carry, from public storage, hash-checked cd ../bim-ootb/tests && npm install # the bim-ootb tests need it (sql.js), with or without the browser layer npx playwright install chromium # only for the browser layer (the real page in headless Chromium) cd ../../BIMCompiler node scripts/witness_terms.js --ootb ../bim-ootb
The last line it prints is the verdict, for example §TERMS_VERDICT PASS enforced=13 open=0 witness_failed=0 uncontrolled=0 browser=judged 5/skipped 0. Every test's log is written under build/scriptor/terms_run/.
| Option | What it does |
|---|---|
--browser 0 | Skip the browser layer (no Playwright needed). The verdict then says browser=judged 0/skipped 5, so a skipped layer is never read as a pass. |
--only id,id | Judge only some terms (ids as in team_terms.json). |
--fresh 1 | Run every test again, ignoring the cache below. Published records are made this way. |
--json file | Write the record (terms-v1) that the Terms button and the objectives page are generated from. |
--logs dir | Where the logs go. |
build/erp/ad_full.db (45 MB, the public iDempiere demo data). Each such file is listed in dev_env/manifest.json with its sha256 and kept on public storage; dev_env_fetch.js downloads it and refuses it if the hash differs. The runner finds these files by itself: it records every file each test reads and names any that git does not have (§UNTRACKED), then prints how many terms a fresh copy can check (§TERMS_PORTABLE, today 13 of 13). npm install (in BIMCompiler, 199 s), then node scripts/dev_env_fetch.js --root-bim-ootb ../bim-ootb (4 s, it fetched the 45 MB dictionary and checked its hash), then node scripts/witness_terms.js --browser 0 --ootb ../bim-ootb. Clones took 184 s. The first attempt gave 12 of 13 terms: the runner still demanded exactly 9 mutants killed in the sealing test, and the current bim-ootb runs 10. A script bug, not a missing file, and it fixed itself once the runner accepted any all-killed count (BIMCompiler pull request 286, not yet merged when this was written). With that change in the fresh copy the runner gave 13 enforced, 0 open, 13 of 13 portable. No other file, install step or path was missing. On a busy machine a slow test can pass its 10-minute limit; WITNESS_TIMEOUT_MS raises it.A full run takes minutes, and most of it repeats tests whose inputs have not changed. The runner therefore keeps each passing test's result together with a fingerprint of every file the test actually read. The files are recorded while the test runs, not taken from a hand-written list. If none of those files changed, the stored result is replayed, marked §CACHED with its fingerprint; nothing runs.
require, files read by name, files the test serves to headless Chromium through its own small web server, folders it lists, files it checks for (a file that was missing and now exists counts as a change), and files read by any Node program the test starts. The arguments and the settings the runner gives the test count too.import( (Node loads those modules without going through the recorded file calls); and a run that starts any program other than Node (git, a database client, a shell), because that program's reads cannot be recorded. Playwright's own browser is the exception: it reads only what the test's recorded server sends it. These always run again and say why (§CACHE_SKIP). better-sqlite3 is read by native code, not by Node's file calls; it is recorded separately, so a changed database re-runs the test. This was missing at first: the check for files git does not carry exposed it, before a stale result was ever published (2026-11-01). --fresh 1 when one of those changed.import( rule). One browser test (the Publish screen) read 348 files and went from 158 s to 0 s with the same result.~/.cache/bim-witness/; deleting it is always safe.Stated limits: the relay still sees who sent how much and when (sender, box, counts, sizes); someone who holds a pair key can pass it on outside the system; an older app in a new POS team does not read mailboxes and silently misses that mail (the version floor is the lever); the first-ever download of a new device still contains the whole member list; in a mailbox team a checkpoint (a compacted history) carries no state at all, so a light client that would have adopted a checkpoint reads the history instead, which costs it more to download.
Design, test specifications and results, each with its log: TEAMWORK_FRAMEWORK.md in BIMCompiler — §48 the terms and their wording, §45.10 mailboxes, §45.11 sealing and the per-mailbox number, §51 the cost of keeping the checks honest and the cache. The tests themselves: scripts/witness_terms.js, scripts/witness_witness_cache.js (BIMCompiler); common/tests/witness_f1_mailbox.js, common/tests/witness_read_scope.js, erp/tests/witness_team_*.js (bim-ootb).