Job: TypeScript
Runner: g1t, Linux X64 (Debian bookworm, Node 24, Python 3, Go, Rust)
##[group]G1T_TOKEN permissions
contents: read
metadata: read
##[endgroup]
Checking out flagon-io/g1t into /home/runner/work/repo
[command]git init --quiet
[command]git remote add origin https://g1t.sh/pulls/pr_01m4g1qbtme6dta91v67hqhgey.git
[command]git fetch --no-tags --prune --quiet --depth=1 origin HEAD
[command]git checkout --quiet --force --detach 026e42ef609250f990556013f34c68833e852e92
Checked out 026e42ef609250f990556013f34c68833e852e92
##[group]Install
npm ci --no-audit --no-fund
##[endgroup]
shell: bash -e /home/runner/_temp/18ddd540dd4797d8.sh

added 777 packages in 2m
npm warn install-scripts 2 packages have install scripts not yet covered by allowScripts:
npm warn install-scripts   esbuild@0.28.1 (postinstall: node install.js)
npm warn install-scripts   workerd@1.20261001.1 (postinstall: node install.js)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
##[group]Type checks
npm run typecheck
##[endgroup]
shell: bash -e /home/runner/_temp/18ded562552e9e7d.sh

> typecheck
> npm run typecheck --workspaces --if-present


> @g1t/status@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> typecheck
> wrangler types --include-env=false && react-router typegen && tsc -b --force


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> typecheck
> wrangler types --include-env=false && react-router typegen && tsc -b --force


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/agents@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/chat@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/context@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/deployments@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/docs-service@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/models@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/notify@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/og@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/pages@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/projects@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/runner@0.1.0 typecheck
> wrangler types --include-env=false && tsc -p tsconfig.json


 ⛅️ wrangler 4.146.0
────────────────────
Generating runtime types...

Runtime types generated.


✨ Types written to worker-configuration.d.ts

📖 Read about runtime types
https://developers.cloudflare.com/workers/languages/typescript/#generate-types
📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.


> @g1t/contracts@0.1.0 typecheck
> tsc -p tsconfig.json

##[group]Tests
npm test --workspaces --if-present
##[endgroup]
shell: bash -e /home/runner/_temp/18dfd5dc77346ea4.sh

> @g1t/status@0.1.0 test
> node --experimental-transform-types --no-warnings=ExperimentalWarning --test src/*.test.ts

✔ a draft at 4 bad of the last 5 checks, once (9.080553ms)
✔ N of M: a good check between does not hide trouble that keeps coming (2.825074ms)
✔ a blip is not an incident: three bad of five is under the line, and three good checks end the run (0.691941ms)
✔ slow then failing is one run, at its worst (0.515061ms)
✔ parts failing together share one draft (0.753301ms)
✔ with an incident already open on the part: a line on it, no draft; recovery is noted once the run ends (0.870721ms)
✔ a run that never crossed the line is not noted as a recovery (0.355271ms)
✔ parts under maintenance and unmonitored parts are left alone (0.512721ms)
✔ the draft says what failed (1.244972ms)
✔ a run that recovered is over: the next one starts fresh, with its own start (0.723801ms)
✔ a run slow for hours, raised long ago, still ends when the checks go healthy (1.365642ms)
✔ during a deploy, trouble is counted but not drafted; it is drafted once it outlasts the window (1.481623ms)
✔ during a deploy, an incident already open still hears about its parts (0.31637ms)
✔ the deploy window: running, finished plus grace, and a start that never finished (0.640041ms)
✔ deploys that overlap are one window, finished when the last one is (0.646141ms)
✔ a detected draft that recovers and stays healthy is dismissed; trouble in between starts the wait again (1.001282ms)
✔ a draft nobody acknowledges is raised again after 45 minutes, once, then every 6 hours (1.460502ms)
✔ slow and down are said apart, with the run's own start (0.859801ms)
✔ the 6 Oct draft: a slow run at 03:13 that recovered does not leak into the one at 07:25 (77.39384ms)
✔ a run kept before N of M (no checks, no recent) is read as all bad, and still ends (8.831163ms)
✔ a run is kept while it lasts, and only the parts still failing keep one (7.3363ms)
✔ the deploy window is kept between rounds (8.995083ms)
✔ every check is kept for 7 days, with where it ran from, and an incident's page reads its parts' checks (71.157861ms)
✔ a draft left waiting is raised again, with a line on its timeline, and forgotten once it is not waiting (9.574833ms)
✔ a detected draft that recovered is dismissed after ten healthy minutes; one staff picked up is left alone (11.351097ms)
✔ declaring: cleaned and checked; operational parts are left out (11.971517ms)
✔ declaring is refused without what it needs (1.742982ms)
✔ severities: SEV1 and SEV2 email subscribers by default (0.335341ms)
✔ an update needs words when it is public; a note can be just a change (0.448371ms)
✔ lifecycle: identified, then monitoring marks it mitigated, then resolved (1.215451ms)
✔ lifecycle: resolving straight away marks it mitigated too; reopening clears resolved (0.53992ms)
✔ lifecycle: a published incident's status changes only with public words (0.45358ms)
✔ lifecycle: severity and impact changes are written on the timeline (52.161705ms)
✔ lifecycle: drafts take notes but nothing public; dismissed takes nothing; the first touch acknowledges (2.058523ms)
✔ roles: each change is a line, and nobody is said plainly (0.943311ms)
✔ durations read plainly (0.59265ms)
✔ maintenance: a window in the future, under 72 hours, on known parts (1.572753ms)
✔ postmortems: published only with a summary and a cause; the draft is filled from the incident (2.350073ms)
✔ short ids are ten unambiguous characters (8.118492ms)
✔ classify: fast is up, slow is degraded, failed is down, none is unmonitored (5.417777ms)
✔ uptime rounds down, so one failure never reads as 100% (0.535621ms)
✔ a day's colour: a blip stays green, a bad hour is degraded, worse is down (0.347591ms)
✔ lastDays ends today, oldest first (0.659511ms)
✔ an incident is on every day it was open (0.473641ms)
✔ bars and 90-day uptime come from the daily tally (0.51397ms)
✔ a bar marks the days an incident on its part was open (4.841366ms)
✔ summarize: core down is a major outage, others partial, slow is degraded performance (1.314162ms)
✔ recent incidents: open ones and those resolved in 90 days, newest first (0.987442ms)
✔ buildPage: parts with no check are unmonitored and have no uptime; staleness is noticed (6.97592ms)
✔ components: an installation without a host leaves that part off (2.002523ms)
✔ a part's state: the worse of its check and open incidents; maintenance unless an incident says worse (0.521841ms)
✔ maintenance moves with its window, and cancelled or completed stays put (2.259423ms)
✔ buildPage: incident impacts and maintenance reach the parts and the banner (72.510594ms)
✔ git storage is listed only with the repos service, and degraded says why (0.532721ms)
✔ page loads say they are a browser, so the site streams them; the name stays on the end (120.035732ms)
✔ the data centre that answered is read from cf-ray (1.691843ms)
✔ a slow answer is asked again at once: one slow answer is not slow, two are (3.694275ms)
✔ a step works on 2xx, or on exactly the status it expects (3.996475ms)
✔ a step that cannot connect, or takes too long, fails with why (21.16223ms)
✔ a check's steps: all must work, and it takes as long as the slowest (1.069991ms)
✔ runCheck: billing without a binding, and a part with no check, are null (1.310122ms)
✔ git storage is judged by how its calls went, and quiet is up (2.563283ms)
✔ escape covers HTML's specials (3.262825ms)
✔ the page: banner, every part with its bar, and no incidents (83.158339ms)
✔ an outage and an open incident are said at the top, escaped (8.241492ms)
✔ a stale page says the checks stopped (5.195838ms)
✔ a day's detail names what happened (0.795481ms)
✔ the badge is an SVG coloured by state (0.590711ms)
✔ maintenance: upcoming, then in progress with its parts under maintenance (5.753188ms)
✔ an incident's page: every update, its parts' impact, and the postmortem once published (2.923934ms)
✔ prose: paragraphs and lists, escaped (1.367832ms)
✔ history: months newest first, empty ones said so (57.682532ms)
✔ subscribe pages: the form, its parts, and a confirm button rather than a link that acts (1.863383ms)
✔ addresses are trimmed, lowercased and checked (3.014424ms)
✔ confirmation tokens: random, and only their hash is kept (20.004069ms)
✔ unsubscribe links are signed, not stored, and refuse tampering (10.907886ms)
✔ per-part subscriptions (2.087303ms)
✔ letters: escaped HTML, plain text, and an unsubscribe link in every update (1.032392ms)
✔ senders: the binding when there is one, none otherwise (0.666901ms)
✔ feeds: every public update and maintenance notice, newest first, in Atom and JSON Feed (63.404971ms)
✔ the reader's zone: their cookie, else Cloudflare's guess, else UTC (101.488885ms)
✔ times carry their zone's abbreviation (5.921798ms)
✔ the status page says times in the reader's zone, with UTC in datetime and on hover (5.136497ms)
ℹ tests 83
ℹ suites 0
ℹ pass 83
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 9539.974307

> test
> node --test app/**/*.test.ts

✔ a valid token from staff is let in, by its email (206.964256ms)
✔ an audience given as a string is accepted too (8.218192ms)
✔ a token for another Access application is refused (9.248913ms)
✔ a token from another team is refused (61.675358ms)
✔ an expired token is refused (11.228886ms)
✔ a token without an expiry is refused (7.901011ms)
✔ a token not valid yet is refused (6.87966ms)
✔ a token signed by another key under a known key id is refused (5.859299ms)
✔ a token whose claims were changed after signing is refused (11.829867ms)
✔ a token signed by a key the team does not publish is refused (55.91397ms)
✔ alg none and HS256 are refused before any key is fetched (4.534367ms)
✔ a valid token whose email is not staff is refused (3.870676ms)
✔ a token with neither an email nor a client id is refused (4.494716ms)
✔ a listed service token is let in as its name at service.g1t.sh (5.044348ms)
✔ a service token not listed is refused (7.939651ms)
✔ a listed service token still needs a valid signature and audience (7.240081ms)
✔ an email wins over a client id on the same token (6.269229ms)
✔ service tokens are read as client id to name, dropping malformed entries (1.488122ms)
✔ staff emails match without regard to case (55.89206ms)
✔ a request without a token is refused (0.809722ms)
✔ garbage is refused (0.50594ms)
✔ the team's keys are fetched once and kept for a few minutes (16.590404ms)
✔ when the keys cannot be fetched, nothing is let in (3.575326ms)
✔ sudo is closed until every setting is given (2.533463ms)
✔ changes are only taken from sudo's own pages (1.301462ms)
✔ everyone at a staff domain is staff, and nobody at a lookalike (0.302261ms)
✔ an alias, its workspace and why are read as identity takes them (3.837695ms)
✔ a malformed alias or workspace, or no reason, is refused before identity is asked (0.403501ms)
✔ removing an alias needs a reason (0.32057ms)
✔ niceCeiling rounds up to 1, 2, 2.5 or 5 times a power of ten (2.743934ms)
✔ ticks run from zero to the top (1.869943ms)
✔ months are named (0.561931ms)
✔ margin and change (0.38008ms)
✔ monthBars scales both series to one axis from zero (1.232811ms)
✔ a tiny month still shows, and an empty chart has an axis (0.60699ms)
✔ negative figures draw nothing below the baseline (0.277481ms)
✔ barPath rounds the top and keeps the foot square (0.592501ms)
✔ axis labels are short (1.117132ms)
✔ shares are against the largest (0.681461ms)
✔ every day of the range is there, even an empty one (6.277109ms)
✔ all of g1t is money in against every cost; a product is its value against its cost (0.714661ms)
✔ margins read against the floor (0.451571ms)
✔ unit costs keep the places they need (0.395521ms)
✔ the range and product come from the address, within bounds (0.2193ms)
✔ the guardrails form is checked (167.23534ms)
✔ a mapping names Cloudflare's product and meter and one of g1t's products (1.181481ms)
✔ the spend bar shows only when a cap stops work (1.497722ms)
✔ what g1t paid this month adds every bucket, the free tier and subscriptions (1.215432ms)
✔ charged without real money is what it cost g1t, never its price (0.543771ms)
✔ margins are a share of the price: cost plus 20% is 16.7% (0.454901ms)
✔ who g1t paid is the statement's all-in cost, subscriptions included (0.623971ms)
✔ a rate g1t sets shows no cost, and a weight is no money (0.367721ms)
✔ a rise replaced before its date says so, rather than missing its date (0.3813ms)
✔ the pause banner names every paused level, and who paused it when it was not a person (1.106211ms)
✔ subscriptions over the range are billing's, day by day by the billing cycle (1.268972ms)
✔ test-mode charges are given away, never money in (0.377111ms)
✔ the billing cycle reads as Cloudflare's Billable usage page does (0.617171ms)
✔ the last read of the bill says when it may be incomplete (0.684661ms)
✔ the presets are $10, $20, $25, $50 and $100, each one step (3.937726ms)
✔ an expiry is never, 30, 90 or 365 days, or the end of a chosen day (1.254292ms)
✔ a small credit is one step; over $100 the slug is typed out (106.017661ms)
✔ a credit needs a kind and a note (0.52828ms)
✔ a refund says what it is for, never expires, and refunds a day that was (51.439913ms)
✔ a grant reads in a line, as the Billing page says it (7.622371ms)
✔ a month filter is a month (1.086681ms)
✔ what went reads as one line (1.933283ms)
✔ only a protected account is refused outright (0.404871ms)
✔ workspaces it owns alone go with it, said up front (0.897171ms)
✔ a protected workspace or billing that cannot settle stops it, naming which (0.32922ms)
✔ staff confirm with the username (0.431411ms)
✔ the form needs a reason, the username, and the box ticked when workspaces go too (0.383191ms)
✔ workspaces deleted with the account are matched to their deletions (1.547622ms)
✔ what went reads as one line (1.773653ms)
✔ days left round up, and none once it is due (0.419201ms)
✔ a purge is confirmed by the slug alone (50.638953ms)
✔ a 100% discount keeps its budget and an end date, and names who set it (173.332868ms)
✔ a discount is a preset or a custom whole percent (1.063362ms)
✔ no discount and no limit is standard, which clears the end date (0.528421ms)
✔ terms are refused without a note, with a bad discount, or ending in the past (0.657241ms)
✔ workspace lists take commas, spaces and lines, once each (0.795731ms)
✔ invoice emails are one address (0.627691ms)
✔ credits are positive and capped (0.919921ms)
✔ a sales record: a stage, an owner's email or nobody, a next step and its day (1.162582ms)
✔ a sales note is required, and not endless (1.006571ms)
✔ allowances: the plan without its price, pool shares, and staff's overrides (1.441382ms)
✔ a bank transfer: an amount, its reference, a note, and the slug typed out (0.613541ms)
✔ a decision: approve as asked or at another amount; decline needs a note (0.883951ms)
✔ goodwill: no amount is the one-click credit; a reason when one is needed; a day not in the future (0.835221ms)
✔ filters come from the address; unknown values are dropped (8.905093ms)
✔ tabs: open, drafts, and resolved (dismissed drafts included) (0.704321ms)
✔ maintenance: live first by start, then finished newest first (73.337445ms)
✔ phase chips: draft, dismissed, postmortem, else the status (3.758636ms)
✔ durations, medians and UTC times (21.22492ms)
✔ forms: impacts per part, notify by severity, next status, staff suggestions (164.707055ms)
✔ the status page's audit lines join the Audit log and link to their pages (0.795421ms)
✔ the postmortem preview reads text as the status page does (0.550211ms)
✔ the page opens on the waitlist, and each tab has an address (3.199114ms)
✔ a grant names who, how many and why (2.407163ms)
✔ a minted invite is for one address, or for anyone (0.924361ms)
✔ every outcome has words (0.368681ms)
✔ several requests are decided at once, each once (1.346712ms)
✔ an approval's note is optional and short (0.702901ms)
✔ the flash says how many were decided (0.31412ms)
✔ shared links have their own tab (1.091702ms)
✔ a shared link needs a label, 1 to 1000 uses, and a day within a year (3.311935ms)
✔ a shared link's domains are tidied, checked and capped (1.720552ms)
✔ a shared link reads as its state, its uses and its address (0.739321ms)
✔ the chart: answered checks as a line, broken by failures and gaps; slow ones dotted; the slow line drawn (60.810047ms)
✔ the chart's scale leaves room over the slow line when every check was fast (2.457874ms)
✔ the summary over the chart (0.874331ms)
✔ invoice filters are checked (2.237824ms)
✔ totals: void counts for nothing; open, overdue and failed are outstanding (1.893912ms)
✔ links keep only the filters that are set (0.712261ms)
✔ only https links are followed (0.37417ms)
✔ account ids link to their pages; anything else does not (0.817982ms)
✔ accounts are named by slug, or the enterprise's name when known (0.21261ms)
✔ actions read plainly, known or not (0.263361ms)
✔ an older page only when this one was full (0.36167ms)
✔ audit filters are checked (3.511665ms)
✔ prices per million are typed in dollars to a millionth (1.685802ms)
✔ approving a model takes its name, tier, prices and why (111.563519ms)
✔ a model purpose takes only an available, priced Claude (0.794121ms)
✔ a job takes a tier and an effort, or the harness's own (0.780722ms)
✔ a change shows what a typical run would cost before it is saved (0.706311ms)
✔ defaults and sizes read plainly (0.396721ms)
✔ dollars read to the cent, and small amounts keep their fractions (3.140664ms)
✔ typed amounts become micros exactly (0.965802ms)
✔ the sidebar: two top-level links, then sections that fold (3.257564ms)
✔ no section holds a single page, and every section has an icon (0.43714ms)
✔ the section holding the current page is the one drawn open (1.031012ms)
✔ every item has its own path, a label and a line about it (0.805311ms)
✔ the built pages are not marked soon (0.493871ms)
✔ every soon page says what it will do, why, and what it will have (0.553481ms)
✔ view as customer promises an audit and a time limit (0.461711ms)
✔ soonFor finds a placeholder by its path, and nothing else (2.576174ms)
✔ isCurrent: an item stays lit on the pages beneath it; / only on itself (1.172142ms)
✔ requests waiting show beside Invites, and on Customers while it is folded (0.945221ms)
✔ the request filter is open unless another status is named (2.410354ms)
✔ an answer is due one business day after the request (0.826781ms)
✔ how long a request has waited, and whether it is overdue (1.950543ms)
✔ a workspace's age in its largest whole unit (0.524981ms)
✔ goodwill: g1t absorbs only what is past its margin (0.531701ms)
✔ goodwill needs a reason past the one-click credit, or a second time in 12 months (0.696361ms)
✔ velocity: five times the usual hour is fast (0.336451ms)
✔ margin counts the plan's price and never what g1t gave (0.424581ms)
✔ given: labelled by source, totalled at price and at cost (4.290406ms)
✔ margin on what was sold leaves out the cost of what g1t gave (0.593671ms)
✔ most urgent first: by kind, then the larger figure, else as billing sent them (3.448305ms)
✔ sorting leaves the input alone (0.37042ms)
✔ filter by kind, and by whose they are (0.923202ms)
✔ counts by kind (0.3803ms)
✔ query values are checked (0.393281ms)
✔ links into the queue leave out the defaults (0.774282ms)
✔ names for kinds and stages, and for ones sudo does not know (0.42165ms)
✔ follow-ups due: today or earlier, open deals only, one per workspace, oldest first (65.112124ms)
✔ terms read as a discount; comped from before discounts is 100% (1.787252ms)
✔ the zone: the staff member's choice, else Cloudflare's guess, else UTC (154.082881ms)
✔ a time on a page: in the zone, with its abbreviation; UTC on hover (11.813547ms)
✔ form times are read and shown in the zone (11.029396ms)
✔ every workspace is listed, with or without billing (2.290363ms)
✔ a workspace on an enterprise shows the enterprise and only its own share (0.415231ms)
✔ a page lists only its own workspaces, not the rest of an enterprise (0.3714ms)
✔ pages stay within the list (0.46381ms)
✔ old account links go to the workspace or the enterprise (0.52139ms)
ℹ tests 164
ℹ suites 0
ℹ pass 164
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 12684.257105

> test
> node --test app/**/*.test.ts

✔ a session's status reads as its card in chat does (2.932964ms)
✔ kinds and places read in words (0.308481ms)
✔ spend against a cap warns at 75% and stops at 100% (0.547181ms)
✔ a tree of sessions puts each child under its parent, oldest first (62.715859ms)
✔ a schedule reads as a sentence (0.988151ms)
✔ a routine reads as its schedule, its events and its repositories (0.565791ms)
✔ the routine dialog's fields become a schedule and back (3.279025ms)
✔ repositories are typed as a list (1.029832ms)
✔ memories group by scope, pinned first (1.350312ms)
✔ a month's days run to today, with spend or 0 (1.283402ms)
✔ past five, the rest fold into one (0.817131ms)
✔ until reads short (0.351391ms)
✔ a version says what changed from the one before (1.387212ms)
✔ a license is named by its SPDX id, or not at all (1.726673ms)
✔ counts read as words (0.773961ms)
✔ small languages are gathered as Other (1.381192ms)
✔ weeks line up with the repository's (0.390981ms)
✔ pushes, tags, merges and renames are activity (0.843711ms)
✔ a token made for one workspace reads its reach, repositories and permissions (8.561832ms)
✔ a token reaches every workspace, or none, and may never expire (1.133041ms)
✔ a workspace's own token holds nothing about a person, and reaches all or selected repositories (0.630181ms)
✔ editing reads neither the expiry nor needs a name (0.327171ms)
✔ mistakes are named (1.028382ms)
✔ permissions are scopes read per resource (1.159402ms)
✔ lifetimes follow the rules of every workspace a token reaches (1.210302ms)
✔ lists read a token in a line (1.189031ms)
✔ old addresses of the token settings go to the current pages (2.016862ms)
✔ saving a token sends only what changed (2.265053ms)
✔ the dialog lists only what the account has (3.333195ms)
✔ owning a workspace alone stands in the way, and names it (0.492651ms)
✔ a protected account says so first (0.318591ms)
✔ only the username itself confirms (0.372361ms)
✔ every anchor of the old settings page lands on its own page (1.809293ms)
✔ a settings path names its page (0.597551ms)
✔ with no settings, the addresses are g1t.sh's (2.986885ms)
✔ settings replace the addresses, without trailing slashes (0.455611ms)
✔ files people supply are served from an origin of their own (0.639191ms)
✔ pages without root data use g1t.sh's addresses (0.329601ms)
✔ the defaults kept in meta and agent setup are g1t.sh's (0.20213ms)
✔ a clone address is under the site (0.276201ms)
✔ handles are cleaned as typed (2.057493ms)
✔ the agent form becomes what the service takes, in micro-dollars (111.065509ms)
✔ the agent form says what to fix (0.868881ms)
✔ dollars and micro-dollars (0.340231ms)
✔ a subagent's routing stays within its agent's (0.536671ms)
✔ a choice is remembered and read back (1.468052ms)
✔ no choice, an unknown one, or storage that throws falls back to the default (0.48633ms)
✔ every toggle on the page follows the last choice (0.938081ms)
✔ parseAgent accepts only known agents (0.23249ms)
✔ every snippet points at the MCP server (2.198613ms)
✔ the snippets can point at another MCP server (0.545631ms)
✔ a step that hands back a file says what was done, not where (2.323303ms)
✔ paths in the checkout read as the repository's own (0.676931ms)
✔ visitors from the EU, EEA, UK and Switzerland are asked first (1.701263ms)
✔ others are not, nor is a visitor whose country is unknown (0.33816ms)
✔ on the server nothing is chosen or required (0.251431ms)
✔ the front door is sent as it is (55.470619ms)
✔ names in other addresses are replaced, and g1t's own words kept (0.716651ms)
✔ a URL on the site keeps only campaign parameters; another site's is left alone (0.809692ms)
✔ a click inside the app goes without its text, link, attributes or title (2.742514ms)
✔ on the front door a click keeps its text (0.411001ms)
✔ recordings and error reports are never sent, and heatmaps only from the front door (0.601031ms)
✔ pages after signing in keep their address but not their text, which can show an email address (0.713661ms)
✔ iso projects the floor axes and lifts by z (2.709904ms)
✔ pts and isoPath round to one decimal place (0.43381ms)
✔ stagger spreads starts evenly inside the loop (0.603791ms)
✔ timing names the custom properties the stylesheet reads (0.35443ms)
✔ sizes read as KB, MB or GB (1.475412ms)
✔ expiry reads from now (0.668291ms)
✔ KV is asked for an old, finished run's artifacts only until they have expired (0.38619ms)
✔ overlaps for the same issue are alternatives; the rest are collisions (3.393565ms)
✔ the other attempts are the issue's other pull requests, newest first, a few at most (0.659111ms)
✔ shared paths are the files both change (0.645411ms)
✔ a review stands at each reviewer's latest verdict, changes asked for first (1.416662ms)
✔ an attempt's outcome says which was merged instead (0.384781ms)
✔ an agent's review is advisory: it neither approves nor asks for changes (0.538051ms)
✔ owners see everything, members their projects, others nothing (55.092639ms)
✔ filters are read from the address, and nonsense is dropped (1.828952ms)
✔ links keep the other filters (0.696151ms)
✔ an agent is shown with whom it acted for (0.49291ms)
✔ the CSV quotes what it must and keeps formulas as text (0.927481ms)
✔ the log reads back only as far as the plan keeps it (0.45981ms)
✔ an image is known by its bytes (2.366573ms)
✔ SVG and anything else is refused, whatever it is called (115.574845ms)
✔ more than a megabyte is refused (280.928932ms)
✔ an image is sent as base64 (0.872561ms)
✔ a missing file is asked for (0.794391ms)
✔ a badge says how the newest finished run went (1.880033ms)
✔ the badge is an SVG with its label and state, escaped (1.653212ms)
✔ its address and Markdown name the workflow file, and a branch or event when chosen (0.940421ms)
✔ a credit from g1t reads in a line, with what is left and when it expires (29.564692ms)
✔ the card fee shown before paying is the one billing charges, and prices exclude tax (0.489531ms)
✔ money reads as dollars (7.13709ms)
✔ a prepayment is $25 or more, by card up to $10,000, by bank transfer from $1,000 (2.211373ms)
✔ caps stay in range, and empty goes back to the default (1.726843ms)
✔ a limit request needs an amount, a reason and a monthly spend; an overage only a reason (0.55162ms)
✔ a spend limit is automatic, fixed, the full amount available, or the one-time raise (0.56198ms)
✔ the spend limit's range: up to the highest ceiling plus prepaid, then once to twice it, then ask (0.373741ms)
✔ the plan card says where the workspace stands (1.065072ms)
✔ the overview's Usage card reads the month by what pays (2.104523ms)
✔ a meter's share stays between 0 and 1 (0.36558ms)
✔ after a card check the owner reads whether the trial started (0.951742ms)
✔ alerts read as sentences (50.576862ms)
✔ a workspace needs attention when paused, on a spike, or at 90% (0.549781ms)
✔ a request says where it stands (1.752743ms)
✔ the plan shows every meter, with no quota beside any of them (0.856681ms)
✔ a free workspace sees only what it can use, and anything it used anyway (0.2361ms)
✔ storage reads in powers of ten (0.228351ms)
✔ kinds of work without words of their own are one Other, listed once and last (0.509781ms)
✔ AI credit is bought in whole dollars from $10 to $1,000 (0.762381ms)
✔ auto-reload's amounts are checked before billing sees them (1.393442ms)
✔ budget alerts keep the levels ticked, highest first (0.849191ms)
✔ invoice details read from the form, with the country in capitals (113.548063ms)
✔ branches with an open pull request are read first, the default branch never (2.974344ms)
✔ no default branch head, nothing to measure against (0.43891ms)
✔ each branch gets its measured commit and drift, newest first, by head hash (1.745362ms)
✔ when repos could not answer, the branches still show, without commits or counts (0.876042ms)
✔ repos' answer, as its JSON reads, keeps every count (flagon-io/hello's farewell) (0.887151ms)
✔ money reads as people type it (2.714564ms)
✔ what is not an amount is not one (0.596501ms)
✔ a money field starts with the suggestion, as an amount (0.39944ms)
✔ text is trimmed and empty text is nothing (0.23847ms)
✔ an input action sends its kind of value (0.555421ms)
✔ links open, the rest ask first, ask for a value, or run (0.354511ms)
✔ without an owner a card shows only its links (1.208661ms)
✔ a draft issue's chip says where it is (0.403751ms)
✔ a long body starts folded (0.948512ms)
✔ the update run for a request is the newest one since it was made (2.143653ms)
✔ it is done as soon as the pull request is no longer behind (0.40857ms)
✔ a run that ended while still behind failed (0.360691ms)
✔ it never waits forever (0.30082ms)
✔ the box says who is doing what (0.959171ms)
✔ the conversation cache keeps the most recently used, and no more (2.320983ms)
✔ messages from one author close together share a header; days get a rule (83.340279ms)
✔ merging keeps one copy of each message, and drops the pending one once saved (0.634241ms)
✔ an @ being typed suggests people and agents (0.766441ms)
✔ message text: mentions, references, links and code, never HTML (2.123663ms)
✔ message blocks: fenced code, lists, quotes and paragraphs (2.917944ms)
✔ the sidebar: sections, filters and the rail's count (2.572114ms)
✔ addresses, names, money and reconnecting (0.755201ms)
✔ a member shows by display name, else by their username as they wrote it (0.35956ms)
✔ mentions read as the names people know, found by the lowercased handle (1.451652ms)
✔ a new project has everything to do, in order (3.612525ms)
✔ each step is done from its own fact (0.383521ms)
✔ unknown facts count as not done (0.31903ms)
✔ each step links to where it is done (0.309881ms)
✔ instructions are AGENTS.md or CLAUDE.md at the root (52.125095ms)
✔ g1t counts as assigned from a run, a pull request or an issue (0.726311ms)
✔ dismissing is remembered per project, and storage that throws is ignored (0.829351ms)
✔ a library's checklist ships a release instead of deploying (0.994932ms)
✔ only what g1t deploys gets production's steps (1.596102ms)
✔ an app deployed elsewhere is never asked to deploy on g1t (3.486325ms)
✔ an app nobody has placed asks where it runs; docs and other ask for links (0.489021ms)
✔ someone signed in always gets the sidebar (2.064873ms)
✔ a visitor gets the sidebar on app pages (0.641511ms)
✔ a visitor gets the marketing frame on the front, pricing and sign-in pages (0.503801ms)
✔ a visitor reads profiles, Explore and Search in the public frame, with no sidebar (0.26411ms)
✔ a visitor reads the policies, security, support and status in the marketing frame (0.64721ms)
✔ a visitor's sidebar offers Explore and Search (1.176361ms)
✔ a project's menu hides member-only pages from everyone else (0.582761ms)
✔ the phone's project strip lights the page a path is under (1.032811ms)
✔ its author edits and deletes their own comment (2.702264ms)
✔ a maintainer edits and deletes anyone's (0.25769ms)
✔ a review is edited but never deleted, and a note is never changed (0.423421ms)
✔ an agent's comment is answered for by whoever it acted for; its review is never deleted (0.595281ms)
✔ the headline says the worst of a commit's checks (1.923693ms)
✔ the tally counts each kind, worst first (0.535291ms)
✔ a check run says how it went and how long it took (0.981522ms)
✔ details go to g1t's own page first, and elsewhere apart (1.987583ms)
✔ co-authors leave the body and keep only their names (2.504153ms)
✔ a message that is only trailers has no body (0.549221ms)
✔ a trailer shows its name, never an address (0.361341ms)
✔ prose that happens to contain a colon stays prose (0.29996ms)
✔ a confirmed address is the account, whatever name the commit carries (3.218165ms)
✔ an unconfirmed address matches nobody: the name on the commit, no link (0.596781ms)
✔ the noreply address is the account (0.25716ms)
✔ a deleted account's commits are ghost's, with no profile (0.26836ms)
✔ g1t's commits, now and as its agents and queue made them before, are g1t (0.371761ms)
✔ a commit sent to the page carries no address at all (1.097151ms)
✔ one question per page: every distinct address, g1t's left out (0.462241ms)
✔ co-authors are read from the trailers only (0.389611ms)
✔ contributors and commits show one person the same way (1.374012ms)
✔ the page a refusal names becomes a link, without its full stop (3.497275ms)
✔ text without a page, or with other slashes, stays text (0.512991ms)
✔ waiting is told apart from a refusal, as the gate words it (0.24494ms)
✔ a pending account is sent to confirm its address from every app page (2.228423ms)
✔ client navigations are gated as the page they load (0.579621ms)
✔ the pages confirming needs, and the public pages about g1t, stay open (0.472681ms)
✔ confirmed accounts, visitors and non-people are never gated (0.412771ms)
✔ what the page says once confirmed, and where it goes (0.471761ms)
✔ confirming an account whose invite names a workspace goes on to accept or decline it (0.20487ms)
✔ the code field is a one-time code typed with a number pad (0.890342ms)
✔ the two contexts list different connectors (2.227003ms)
✔ a category shows only its own connectors, sorted into connected, available and soon (2.776654ms)
✔ all shows everything once (3.458385ms)
✔ search finds by name, description, tag and keyword, across every category (2.357223ms)
✔ the navigation counts each category and leaves out empty ones (1.197781ms)
✔ an unknown category is all of them (0.351301ms)
✔ a tile has the connector's letters and a steady colour (1.215552ms)
✔ asking for a connector names it and who it is for (0.491151ms)
✔ a content key is a hash of every part, in order, and never of a join that could collide (21.933381ms)
✔ the isolate's memory keeps the most recently used within its weight (1.582882ms)
✔ lines weigh their characters (0.362271ms)
✔ an answer is computed once, then read from the isolate, then from the data centre (166.292098ms)
✔ a new version never reads what an old one kept (3.942226ms)
✔ nothing to keep is not kept, and a broken shared entry counts as missing (6.305539ms)
✔ without a data centre's cache the isolate still keeps answers (4.143556ms)
✔ publisher documents a browser would open are downloads (3.049674ms)
✔ data types stay inline (0.45553ms)
✔ every registry answer runs nothing and is never sniffed (118.113918ms)
✔ download names keep quotes and control characters out of the header (0.929621ms)
✔ the calendar is 53 weeks of seven days, ending with today's week (4.772187ms)
✔ each day is shaded in quarters of the busiest (5.338597ms)
✔ months are named over the week they start in (1.653402ms)
✔ a month that starts too close to the first column takes its place (0.968811ms)
✔ a year that starts early in a month keeps its first label (1.134162ms)
✔ a bad date draws nothing (0.23647ms)
✔ hints and the heading read as sentences (84.438791ms)
✔ a form becomes what to put the agent on (180.673678ms)
✔ only one of the viewer's projects can be chosen (0.745651ms)
✔ a started or queued agent goes on to the issue; one that did not start says why and where (0.763012ms)
✔ a next run is said as a time ahead (1.823782ms)
✔ an entry's status (1.507033ms)
✔ rules read as one line (0.678821ms)
✔ only live update pull requests are listed (0.41677ms)
✔ a commit that is gone is said plainly, naming the pull request (2.409474ms)
✔ a run of the same failure of one app is one row, counted, linking to the newest (2.093233ms)
✔ other apps' builds in between do not break a run; a different error does (0.994881ms)
✔ builds that did not fail are never folded (0.309711ms)
✔ environments list production first, then lasting ones, then previews, newest first in each (0.646181ms)
✔ production is the production environment that has had a deployment, named production first (0.311871ms)
✔ an environment is served at its own address, else its current deployment's (0.42923ms)
✔ the list's filter is read from the address, ignoring what it cannot be (2.479834ms)
✔ changing a filter keeps the others and starts again from the first page (1.255572ms)
✔ a filter's choices are each value once, sorted, keeping the chosen one (13.247849ms)
✔ words for states, sources, environments and pages (0.897801ms)
✔ a highlighted file's HTML, kept apart and given back, is the same highlighted file (793.348385ms)
✔ lines without HTML stay without it (0.346721ms)
✔ what a file's colours depend on: each line's side and text, not its numbers or path (0.569121ms)
✔ the tree orders each level and lifts pages whose parent is gone (3.216164ms)
✔ page addresses carry the id, read back from the end (0.709621ms)
✔ snippets mark their matches (0.728041ms)
✔ covers, colours, roles, reading time (2.422003ms)
✔ a citation links to its code, a glob to the folder it starts from (0.61846ms)
✔ a project's docs become folders under the space (0.757111ms)
✔ the primary cannot be removed, and only a confirmed address can become it (3.417465ms)
✔ the last confirmed address stays, even when it is not the primary (0.526581ms)
✔ the backup is a confirmed address other than the primary (0.511581ms)
✔ a change waiting on the password keeps its fields but never the password (109.639327ms)
✔ the emoji data is complete and small (5.376578ms)
✔ search finds by shortcode first, then name, then keyword (106.563303ms)
✔ the workspace's own emoji are found by name, ahead of standard ones as good (21.752111ms)
✔ skin tones apply where an emoji has them (1.176182ms)
✔ a new emoji's name: its shape, standard ones and taken ones (58.013233ms)
✔ a :name being typed is offered for completion, but not in links or times (0.818722ms)
✔ :name: becomes the workspace's emoji in text; anything else stays (4.092706ms)
✔ reacting shows at once, and taking it back undoes it (0.722531ms)
✔ the room's reaction events count others once, and the viewer's own never twice (2.238843ms)
✔ a message from the room keeps the viewer's own reactions marked (1.654092ms)
✔ who reacted reads as a sentence (0.680761ms)
✔ recent emoji: newest first, each once, a few (0.387401ms)
✔ an environment's name is lowercased, and anything else is refused (1.805813ms)
✔ a form's rules: reviewers in order without blanks or repeats, patterns only for selected branches (162.652733ms)
✔ a form past the limits says what is wrong (21.391631ms)
✔ an environment's rules in a few words (1.072472ms)
✔ a limit lets requests through until it is reached (2.502474ms)
✔ a missing or failing binding fails open (116.367916ms)
✔ secrets are keyed by a short hash, never as they are (73.226764ms)
✔ git without credentials is limited by address, with a message git shows (8.778912ms)
✔ git with credentials counts by a hash of them, apart from the address (4.680196ms)
✔ signed-out pages count by address, and costly ones against a tighter limit too (2.892965ms)
✔ signed-in requests count by session, and every request by address (3.929955ms)
✔ files the Worker serves itself are never limited (1.710623ms)
✔ costly pages are recognised (1.573713ms)
✔ the session cookie is read from among others (1.562112ms)
✔ every wrangler.jsonc declares the rate limits RATE_LIMITS lists, and only those (56.07068ms)
✔ repository files on the usercontent origin count per address; avatars do not (1.713453ms)
✔ token counts read short (1.723903ms)
✔ a request's tokens add up and are named by kind (71.149171ms)
✔ refusals for money or rate are warnings, other failures are errors (1.901312ms)
✔ durations read plainly (0.340681ms)
✔ a request says which format it came in and who served it (0.508211ms)
✔ a connection's AI Gateway models are typed as a list (0.409971ms)
✔ cache tokens read in words, hour-long writes named (0.34295ms)
✔ the state must come back exactly as it was given (14.12251ms)
✔ cookies are read by name, and odd values are ignored (0.672121ms)
✔ an installation returns to the workspace it was started for (0.51535ms)
✔ go get finds a repository's code from its address and any package in it (2.630783ms)
✔ only go-get requests for a repository's address are answered (0.997772ms)
✔ workflow-only domains are read one per line, and written back the same way (161.669981ms)
✔ an untouched form inherits everything (0.699231ms)
✔ choices of a level's own are kept (0.843511ms)
✔ nonsense is passed on for the service to refuse (0.433881ms)
✔ zero dollars means no cap (0.484541ms)
✔ helpers (0.27731ms)
✔ the card is the public profile, signed out too (2.309263ms)
✔ a private workspace is hidden from someone outside it (1.316242ms)
✔ commits to a repository show only to those who may read it (1.096662ms)
✔ the card carries the time zone a profile gives, and none when it gives none (0.509491ms)
✔ a failing service leaves its part out, not the card (0.697371ms)
✔ g1t has its own card; ghost and strangers have none (2.929954ms)
✔ workspaces past three are counted (0.368641ms)
✔ how recently, in the words the card uses (0.488691ms)
✔ the card's address and its repository (1.383442ms)
✔ tabs read from the address, and each shows one severity (1.680713ms)
✔ counts are what is unread under each tab (0.25717ms)
✔ the bell shows a number up to 99 (0.411631ms)
✔ times are said in a few characters (19.484258ms)
✔ a snooze is for later, by one of a few choices (0.870192ms)
✔ forms ask for one mark on one item, or read for every item (102.662507ms)
✔ what needs you puts a waiting agent before a failure, and leaves out the rest (1.770993ms)
✔ every tab says something when it is empty (0.780361ms)
✔ every reason has words, a filter and an email choice (0.954731ms)
✔ a thread says how much happened on it once more than one thing has (0.408451ms)
✔ watching is read from the menu, and a custom watch of nothing is the default (1.532582ms)
✔ the subscribe button says whether, and why (0.721281ms)
✔ email reasons are read from the settings form in rank order (1.322262ms)
✔ bold, italic, code and links read as marks (3.566885ms)
✔ what is not a mark stays as written (0.47505ms)
✔ the plain words, for a tooltip (0.32194ms)
✔ while invite-only, nobody is offered a plain sign-up (3.224634ms)
✔ asking for more invites goes to support with the [g1t Invites] subject (0.298921ms)
✔ an invite link is on g1t.sh unless told otherwise (0.35944ms)
✔ an invite email's proof is kept only when it looks like one, and goes along to the invite's page (0.358041ms)
✔ signing up from the invite email says the address is confirmed already; otherwise the code step applies (0.733161ms)
✔ a pasted link or code is tidied to the code (0.927002ms)
✔ each invite says where it stands and whom it is for (0.722421ms)
✔ what is left reads plainly (0.329951ms)
✔ bots that fill the hidden field or answer instantly are turned away (0.824011ms)
✔ a username is suggested from the invited address (0.678541ms)
✔ an invite lands in its workspace, else its repository (1.462013ms)
✔ the welcome is for one place, and ends (0.777241ms)
✔ a shared invite link names its group above the sign-up form (0.15826ms)
✔ a shared invite link is sign-up with its code filled in (0.479281ms)
✔ a shared link limited to domains says which, on the email field (0.25173ms)
✔ an invite to g1t can also invite its person to a workspace you own that can add people, never chosen for you (1.038522ms)
✔ an invite to g1t sends no workspace unless its box is ticked (0.33964ms)
✔ the invites form keeps the workspace behind an unticked box (0.619421ms)
✔ invites to g1t are made only while sign-up takes one; after that only the list stays (0.392651ms)
✔ the two invites say which they are (0.47086ms)
✔ an invite's page names the invite it is (0.28979ms)
✔ colors are six hex digits however they were written (1.598182ms)
✔ a chip is tinted with its label's color, and neutral without one (1.645083ms)
✔ labels are found by name or description (0.799771ms)
✔ a milestone's progress and due date read as words (0.522491ms)
✔ filters come from the address, and q wins (1.005201ms)
✔ changing one filter keeps the others (0.636011ms)
✔ the copyright year is computed, in UTC (1.275722ms)
✔ the legal line names the company and the year (0.31584ms)
✔ products are listed the way a sentence lists them (0.38855ms)
✔ policy dates read as words (0.296711ms)
✔ every policy has its own address (0.551651ms)
✔ security.txt has the fields RFC 9116 asks for, and expires within a year (0.835551ms)
✔ one line and a run of lines are read from the fragment (2.244034ms)
✔ a run written backwards is put in order (0.407351ms)
✔ anything else names no lines (0.44117ms)
✔ a run is held to the file's length (0.263951ms)
✔ a run is written back the way it is read (0.30166ms)
✔ a pick is one line; a shift-pick runs from the line already picked (0.322731ms)
✔ a line is in the run when it is between its ends (0.21937ms)
✔ a log reads as lines and folded groups, numbered past the group markers (53.146726ms)
✔ search finds lines in any case, inside folded groups too (0.777911ms)
✔ matches are marked where they fall (0.396441ms)
✔ a run's archive has each job whole and a file per step, named as the API names them (1.118612ms)
✔ @name links to the person or workspace (4.584286ms)
✔ @g1t is g1t's agent, never the workspace alias at /g1t (0.668251ms)
✔ @workspace/team links to the team (0.484661ms)
✔ issues and pull requests still link (0.632221ms)
✔ README.md: the kept tree renders exactly what react-markdown renders (902.999781ms)
✔ docs/PERFORMANCE.md: the kept tree renders exactly what react-markdown renders (811.433321ms)
✔ CONTRIBUTING.md: the kept tree renders exactly what react-markdown renders (91.661421ms)
✔ edge cases: the kept tree renders exactly what react-markdown renders (111.58556ms)
✔ empty: the kept tree renders exactly what react-markdown renders (5.525528ms)
✔ a fact remembered twice is shown once, the first kept (3.202205ms)
✔ near-duplicates collapse: a list that grew, a sentence cut short (0.958341ms)
✔ an @ that could become @g1t is offered (1.726402ms)
✔ anything else is not (0.28143ms)
✔ @g1t is offered with no teams, as before (1.356822ms)
✔ teams complete from the workspace or from their own name (0.572621ms)
✔ at most five, @g1t first, and nothing once one is typed in full (0.327551ms)
✔ a page gets its title, description, Open Graph and Twitter tags (2.695894ms)
✔ pages under a project describe the project, and their card follows its details (1.100752ms)
✔ a page's address and card come from the root loader's addresses (0.379991ms)
✔ without a card service, a page has no image tags (0.2799ms)
✔ with nothing particular to say, a page says what g1t is (0.553441ms)
✔ a card's version changes with what it shows (0.393671ms)
✔ every card address carries the render version, so a new design is a new address (0.604451ms)
✔ an excerpt is plain text from the start of the Markdown (54.328838ms)
✔ each kind of need gets its reason chip (6.239559ms)
✔ a stopped pull request's reason comes from the sentence g1t stopped with (1.086552ms)
✔ why a need needs a person is said for every reason (0.579301ms)
✔ what the agent knows lists only what is known (19.795878ms)
✔ the required checks are read from where the agent's pull request stands (1.078572ms)
✔ a change held for low confidence is its own reason, ahead of what it would read as (0.484911ms)
✔ what the agent knows gains its confidence, across the row (0.547861ms)
✔ test files are recognised by the names test runners use (0.40659ms)
✔ a push to the default branch counts a person's own commits, not merges or g1t's (1.202842ms)
✔ who pushed is the account that signed in, not the name on the commits (1.104181ms)
✔ a short read of the branch is enough when it reaches the oldest push (1.176732ms)
✔ a change landed without a person when g1t merged it (0.17573ms)
✔ the week is seven days, each split by who did the work, with the week before (60.268487ms)
✔ days follow the viewer's time zone (3.204004ms)
✔ the change from last week, and how it reads (0.282201ms)
✔ a repository's merged list reaches back when it is not full or its oldest is old enough (0.932691ms)
✔ landed today is the viewer's calendar day, newest first (1.007362ms)
✔ waiting on agents holds each pull request once, running ones first, and nothing that needs you (1.266202ms)
✔ tabs and sorting come from the address (0.44593ms)
✔ the summary says the week honestly (0.307691ms)
✔ a job waiting for a self-hosted runner says so, not that an agent went quiet (0.21576ms)
✔ each push to the default branch places the commits it brought, at its time, from one read of the history (0.368441ms)
✔ a first visit has nothing to count from and starts the clock (5.746209ms)
✔ views within a visit keep counting from the visit before (0.434131ms)
✔ a long gap starts a new visit, counting from the last view (0.26012ms)
✔ a cookie from the future is ignored (0.322451ms)
✔ cookies are read by name (0.661861ms)
✔ greetings follow the hour, in the viewer's zone (18.401146ms)
✔ the composer's first line is the title (1.045411ms)
✔ one agent's burst in one project reads as one line (0.964372ms)
✔ a burst breaks across projects and long gaps (0.868301ms)
✔ needs are ranked by urgency, then by how long they waited (52.819436ms)
✔ a running agent quiet for ten minutes is stuck (0.664381ms)
✔ the digest says what moved, the urgent parts toned (0.444931ms)
✔ daily buckets put each point on its day, oldest first (0.548991ms)
✔ median, pass rates and spans (0.56095ms)
✔ issue to merge pairs a merge with the issue it resolved (1.047741ms)
✔ agent hours count only agents, clipped to the window (0.364041ms)
✔ sparkline points span the box, zero on the floor (0.36959ms)
✔ a pull request's place in the pipeline (0.508741ms)
✔ open issues by age (0.334471ms)
✔ the feed names people, not account ids (0.24352ms)
✔ waits read in the largest whole unit (0.13335ms)
✔ the feed asks the log only for the kinds it shows, and pushes for one project (0.362831ms)
✔ a production deploy that finished is a line, linked to it on the current path (0.562091ms)
✔ a project's feed has its pushes to the default branch, but not the ones that only landed a pull request (0.657671ms)
✔ a path on g1t is kept, with its query and fragment (1.344982ms)
✔ anything that could leave g1t goes home instead (0.31297ms)
✔ sign in and sign up links carry where to come back to (0.27049ms)
✔ finds a title on an element, not on a component's own prop or inside an expression (2.990704ms)
✔ no native title hints in apps/web (180.863299ms)
✔ the kind a loader names wins over the address (1.926133ms)
✔ without one, the shape of the address decides (0.682651ms)
✔ signed out: nothing here, which may be private, and sign in if it is yours (0.379871ms)
✔ signed in: it does not exist or you cannot see it, and who you are (0.354551ms)
✔ a missing person is simply no one, signed in or not (0.29627ms)
✔ the page depends only on the kind and the viewer (1.442202ms)
✔ toasts: newest last, at most three, never twice (54.891109ms)
✔ a newer message in the same conversation replaces its toast (0.344811ms)
✔ no toast for the conversation on screen, by page or by channel; inbox items always (0.45225ms)
✔ quick replies post to the conversation, in its thread when there is one (0.47612ms)
✔ badges: chat only once the feed's counts are complete; the inbox whenever known (0.664141ms)
✔ reading a conversation here zeroes it at once (2.047233ms)
✔ the sidebar takes the feed's counts once they are complete, and spots conversations it does not list (0.59295ms)
✔ the tab title counts what needs you, once (0.618431ms)
✔ browser notifications are offered once, after a DM or mention, never after a no (0.721991ms)
✔ reconnecting waits a jittered, growing time, never past half a minute (0.38235ms)
✔ a stack taller than the screen folds its oldest toasts into a pill, never the newest (0.38621ms)
✔ a card's notification offers its actions and presses them as the card does (0.387951ms)
✔ recent notifications are kept newest first, once each (2.156113ms)
✔ the panel waits on the newest notification per card, for a day, until it is acted on (0.417621ms)
✔ the backoff starts over only after a connection held for a while (0.14416ms)
✔ a pull request g1t made shows g1t, requested by whoever asked (9.953205ms)
✔ anything else shows its author (0.508771ms)
✔ work g1t started itself names nobody as asking (0.43111ms)
✔ sizes read as registries show them (1.688052ms)
✔ digests shorten for lists (0.31143ms)
✔ an npm package is installed after .npmrc names its scope's registry, and a token for private ones (1.174232ms)
✔ a Composer package is required after its workspace's repository is added, with credentials for private ones (0.212981ms)
✔ a crate is added after .cargo/config.toml names its workspace's registry, with cargo login for private ones (0.547671ms)
✔ a Maven artifact is fetched from its workspace's repository, with a settings.xml server for private ones (0.39423ms)
✔ a NuGet package is added from its workspace's feed, named as a source with credentials for private ones (0.334911ms)
✔ a gem is added with Bundler from its workspace's registry, with credentials for private ones (0.30618ms)
✔ a container image is pulled by its address and tag (0.860472ms)
✔ packages are listed by the visibility and order asked for (12.040357ms)
✔ download counts read short (0.531311ms)
✔ a page runs only its own scripts and is never framed (9.738094ms)
✔ every answer gains nosniff and a referrer policy; pages are not framed (102.390797ms)
✔ nothing is pending while the page is idle (97.96321ms)
✔ a post is pending while it is sent and while the page reloads after it (0.584941ms)
✔ following a link, or a GET form, is not a pending write (0.355671ms)
✔ only the submission that matches is pending, so one row's button does not speak for another's (0.445861ms)
✔ people are searched by username or name, and an email address is never looked up (1.381232ms)
✔ the invite form names an address or a username (1.147222ms)
✔ an invitation says the role it joins with and how long it works (0.609471ms)
✔ bookmarks survive the cookie (3.292325ms)
✔ a malformed or foreign cookie entry is dropped (0.55009ms)
✔ the cookie is HttpOnly, short-lived and Secure over HTTPS (0.721451ms)
✔ what each call asks for (0.40351ms)
✔ only known reads are taken not to write (0.50715ms)
✔ a signed-out GET never sets the bookmark cookie, so public pages stay cacheable (0.275881ms)
✔ timings (1.116091ms)
✔ a phone is told by its client hint, else its user agent (53.175096ms)
✔ the project being looked at leads recent, once (2.612794ms)
✔ pinned projects are never also recent (0.36002ms)
✔ another workspace's project is not this one's recent (0.55543ms)
✔ recent holds a few (0.317621ms)
✔ a pin form says what to change (104.76189ms)
✔ a pin moves up or down within the list (0.651631ms)
✔ a seed always draws the same creature, symmetric and whole (3.839625ms)
✔ different seeds give different creatures (0.466551ms)
✔ clear after: minutes and hours from now, the end of today, the end of the week, or never (2.466544ms)
✔ a custom time is the viewer's own, and only one still ahead counts (0.53252ms)
✔ pausing notifications: half an hour, an hour, or until nine tomorrow morning (0.608021ms)
✔ every preset says something and clears sensibly (0.584791ms)
✔ how someone shows: offline, away, active, and Do Not Disturb over either (0.599201ms)
✔ a status past its time is gone, even before the feed says so (0.39433ms)
✔ when something ends, in a few words (70.566851ms)
✔ a tab is idle after ten minutes without input (0.26706ms)
✔ custom emoji are named; ordinary emoji are not (1.282722ms)
✔ people merge by id, and a later word wins (0.689881ms)
✔ a package reads as its registry, its name and its latest version (2.260103ms)
✔ what a library publishes comes before an image, released ones first (1.666232ms)
✔ each ecosystem links to how it publishes (0.33459ms)
✔ each choice sets a kind and where it runs, and reads back (0.372061ms)
✔ a project's badge says what it is and where it runs (0.601421ms)
✔ links show homepage, docs, then the rest, never twice (1.028271ms)
✔ an overview form changes only what it carries (103.134888ms)
✔ the latest release is the newest tag by its commit (11.870847ms)
✔ cards show production, else the homepage or docs (1.597452ms)
✔ custom links are read from a form's rows, blank rows left out (1.222312ms)
✔ an empty address is the default list (3.130285ms)
✔ what the address says is read, and nonsense is the default (0.651721ms)
✔ the address round-trips, and a change goes back to page one (0.641101ms)
✔ archived projects are left out unless asked for (62.42857ms)
✔ filters narrow by visibility, kind, language and deployments (0.858841ms)
✔ search matches every word, in the name, slug or description, names that start with it first (0.620471ms)
✔ each sort orders as it says, ties by name (0.878492ms)
✔ pages hold PAGE_SIZE, and a page past the end is the last (0.722741ms)
✔ facets count the whole workspace (3.620875ms)
✔ the keyboard moves through rows and stops at the ends (0.60202ms)
✔ code is not docs: a project never gets a Docs tab (1.924103ms)
✔ a project page names its repository (51.532234ms)
✔ pages that are not a repository's name none (0.372001ms)
✔ only a repository that is there and public is served from the cache (0.367871ms)
✔ a pull request's own snake_case fields are read into camelCase (2.583954ms)
✔ camelCase is taken as it is, and a missing review_pending is false (1.378652ms)
✔ getPull reads the work service's answer at the edge (100.110023ms)
✔ getPull passes a refusal through (1.260382ms)
✔ the container registry's paths go to the packages service (1.595313ms)
✔ the npm registry's paths go to the packages service (0.646811ms)
✔ the Composer registries go to the packages service (0.226851ms)
✔ the Cargo registries go to the packages service (0.2084ms)
✔ the Maven repositories go to the packages service (0.365811ms)
✔ the NuGet feeds go to the packages service (0.19026ms)
✔ the RubyGems registries go to the packages service (0.310251ms)
✔ git goes to repos, and everything else is the site's (0.19791ms)
✔ a registry request names its workspace, and can be moved to another (52.800726ms)
✔ the typed name confirms only the full name, in any case (1.359312ms)
✔ filters by visibility and archived (1.678763ms)
✔ search matches every word in name, description or topics (0.551711ms)
✔ counts each filter (0.4309ms)
✔ an unknown filter is all (0.23931ms)
✔ a bulk action is summed up, with each failure and why (0.369311ms)
✔ a renamed branch keeps the rest of the address (0.23552ms)
✔ days until a date, never negative (0.285831ms)
✔ dates read the same everywhere (71.851523ms)
✔ names are tidied, not judged (0.989672ms)
✔ a new ruleset protects the default branch, and a workspace's holds everywhere (2.976274ms)
✔ every rule type has a label, a group and its defaults (0.752291ms)
✔ an export imports back as it was (0.920722ms)
✔ an import fills in what it leaves out and refuses what is not a ruleset (0.987521ms)
✔ who may bypass, and whose changes a rule holds for, read plainly (0.303571ms)
✔ what a ruleset targets, in a few words (0.394911ms)
✔ columns go by the longest path of needs (2.721324ms)
✔ a need of a job not in the run is left out (0.483841ms)
✔ a cycle cannot loop the layout (2.277323ms)
✔ ordering a column by its needs takes out a crossing (1.066642ms)
✔ ordering keeps the order as listed when nothing crosses (0.572991ms)
✔ a matrix's jobs are one node, named without their combination (51.001943ms)
✔ an expanded matrix is taller, and its connectors still meet its first line (1.345032ms)
✔ a called workflow's jobs sit in a box under the job calling it (1.129322ms)
✔ a connector's colour follows the run: red from a failure, moving into a running job (1.102511ms)
✔ a deployment's address makes its node taller (0.875121ms)
✔ several jobs stand together as running, then as the worst ending (0.418531ms)
✔ connectors run straight on one row, and turn with rounded corners between rows (0.390781ms)
✔ an empty run lays out as nothing (1.254791ms)
✔ a matrix whose jobs deploy to one address shows it once (0.34676ms)
✔ quoted runs stay whole (2.514874ms)
✔ a qualifier is read, quotes and all (0.427011ms)
✔ a filter replaces its qualifier and keeps the rest (0.607481ms)
✔ is: values of one family replace each other (0.39306ms)
✔ addresses carry the query, the tab and the page (0.32078ms)
✔ counts stop at the cap (0.198151ms)
✔ the state parameter falls back to open (1.566022ms)
✔ ids say which tab and which role an alert takes (0.22869ms)
✔ alerts are counted by state (0.965282ms)
✔ likely test values are listed apart from real secrets (0.33997ms)
✔ packages group their alerts and take the worst severity (0.686301ms)
✔ versions compare number by number (0.299861ms)
✔ the newest security update wins (0.38495ms)
✔ a secret's activity starts with when it was found (10.088814ms)
✔ an older decision without a row is shown from the alert itself (1.628873ms)
✔ a dependency's activity links its pull request and issue (53.080006ms)
✔ secret filters are read from the address and narrow the list (2.986734ms)
✔ secret types are listed once each, custom patterns by name (12.039527ms)
✔ code filters and counts (51.215984ms)
✔ old Security links go to the sections that replaced their tabs (0.54012ms)
✔ the starter workflow scans each language it finds, then uploads SARIF for the right ref (1.187641ms)
✔ a trend is scaled to its tallest day (0.36261ms)
✔ a session card's state reads as what is happening (2.129223ms)
✔ every state has a chip, whatever its case; an unknown one is quiet (0.424271ms)
✔ a Mac shows the Command key, everything else Ctrl (1.438692ms)
✔ a client navigation that hits an older build reloads the page (2.142703ms)
✔ an address only the new build knows reloads, once it fell to the catch-all (0.38524ms)
✔ a document load, or any other error, shows the error page (51.786284ms)
✔ each stack is found by what is at the root (3.640605ms)
✔ a Node project's workflow runs the scripts it has (1.482782ms)
✔ an unreadable package.json runs the usual scripts only if present (0.388231ms)
✔ Rust, Go and an unknown project each get a workflow (0.677591ms)
✔ the workflow is well-formed: one job per stack, steps under each (0.858871ms)
✔ a branch name is found that is free (0.27271ms)
✔ the status page lives on its own host (1.168512ms)
✔ the short line is the report's title, else words for its state (0.34421ms)
✔ each state has its own dot (0.398531ms)
✔ team pages live under the workspace's teams (1.433612ms)
✔ teams are found by every word of the search (1.690223ms)
✔ your teams come first (0.56935ms)
✔ a team can go under any visible team but itself and those below it (0.649091ms)
✔ a new team reads its form (93.884944ms)
✔ settings change only what their form has (0.495061ms)
✔ review assignment is read within bounds (0.545201ms)
✔ counts leave out what is none (0.23459ms)
✔ who may create teams follows the workspace's setting (60.244606ms)
✔ a profile's local time is the time of day in its zone (22.457782ms)
✔ no zone, or one the runtime does not know, shows no time (0.675151ms)
✔ the zones to pick from are sorted, with UTC and a saved one always there (55.52025ms)
✔ zones read as places, with their offset (1.019431ms)
✔ every scope is on the checklist exactly once, admin ones under Dangerous (3.138035ms)
✔ ticked boxes store the highest level of each resource (0.998781ms)
✔ full access is null, and nothing ticked is refused (2.212573ms)
✔ a higher level ticks the lower ones of its resource only (0.22976ms)
✔ full access ticks the top level of everything (1.176192ms)
✔ presets are recognised however their scopes are written (1.170772ms)
✔ a token's access reads plainly (0.681981ms)
✔ an application asking for nothing usable gets the default set, never admin (0.37944ms)
✔ consent keeps only what was asked for (1.008532ms)
✔ expiry words (0.704781ms)
✔ token counts read short (1.448422ms)
✔ cache share is reads over every prompt token (0.278ms)
✔ the grid shades by quartile of the busiest day (0.225031ms)
✔ the best day, and none on an empty window (1.346022ms)
✔ the mix is in its checked order and adds up to one (0.555131ms)
✔ days are shown short, in UTC (63.322751ms)
✔ the accent is the logo's lavender, and mint means success (1.772592ms)
✔ merged reads apart from the accent (0.303491ms)
✔ text colours meet WCAG AA on every surface (1.206872ms)
✔ the dark base reads on an accent or success button (0.28789ms)
✔ focus borders in the dim accent stand out from the page (0.249521ms)
✔ the first frame is the pull request before its checks, the same on the server and the client (2.088593ms)
✔ the scenes come in the story's order: Code first (5.574237ms)
✔ checks pass before review, and the queue merges only after approval (0.20975ms)
✔ the cursor leaves the code only once it has merged (0.16553ms)
✔ Otto's work is done before the story opens (0.2256ms)
✔ the loop wraps (0.17389ms)
✔ pills start where their scene does, and progress runs 0 to 1 (0.445221ms)
✔ each still shows its step's point (0.17553ms)
✔ Izzy tells #support after g1t says it shipped (0.878631ms)
✔ an open trial says nothing (1.567353ms)
✔ a spent trial and a given-out month say so (68.770309ms)
✔ a workspace without a card check is told it needs one (0.253511ms)
✔ periods resolve to whole UTC days, both ends included (4.136896ms)
✔ columns cover every day, stack products, and add up when cumulative (71.470032ms)
✔ the money axis has clean ticks, never the same label twice (5.665608ms)
✔ money and quantities read in their units (0.877731ms)
✔ the receipt shows usage at price, then what paid, then what is charged (0.448501ms)
✔ grouping by project adds a project's meters together (0.492041ms)
✔ the CSV has a row per day and meter with anything on it (0.426891ms)
✔ test-mode hints are for g1t's own people (0.23414ms)
✔ money under a hundredth of a cent reads $0.00, never $0.0000 (1.178632ms)
✔ a raw file's path keeps a ref with slashes in one segment (1.954612ms)
✔ paths that are not a file, or climb out of the repository, are refused (0.303021ms)
✔ usercontent is its own host, or a path on the site (0.555641ms)
✔ a token is good for its file alone, until it ends (22.405692ms)
✔ files are served as data that cannot run (106.813923ms)
✔ a README's relative pictures are the repository's files at the same commit (1.269142ms)
✔ commits are full hashes (0.291841ms)
✔ the chosen workspace holds while you are a member, else the first (1.277062ms)
✔ a project in one of your workspaces is about that workspace (0.27483ms)
✔ a project somewhere you do not belong leaves the chosen workspace (0.307611ms)
✔ a workspace's own pages are about that workspace (0.19295ms)
✔ the cookie reads back what was remembered (0.552141ms)
✔ a deleted workspace you had chosen gives way to another, or to none (0.451461ms)
✔ what goes lists only what the workspace holds (2.086763ms)
✔ only billing or protection stands in the way (0.300921ms)
✔ the slug confirms in any case, and nothing else does (0.26128ms)
✔ someone with no workspace is sent to make one or answer an invitation, never to Mission control (1.475652ms)
✔ the pages someone without a workspace needs stay open (0.38639ms)
✔ nobody else is gated: a member, an unconfirmed account, a repository collaborator, someone held by a policy, a visitor (0.217191ms)
✔ a path is one of the workspace's pages, or none (2.071993ms)
✔ every page that once had a tab has a sidebar row (0.46654ms)
✔ one sidebar row is current wherever you are in the workspace (0.372511ms)
✔ old addresses go to where their pages are now (0.477031ms)
✔ ?tab= opens that page, keeping the rest of the query (0.38492ms)
✔ a click's data request is for the same page as a full load (0.289341ms)
✔ an alias or old name leads to the same page under the workspace (0.29586ms)
✔ a click's data request for an alias leads to the page, not its data (0.24639ms)
✔ the rail's mode follows the address (1.186032ms)
✔ a member without Code access is sent around Code's pages (0.555771ms)
✔ a thread's link is its conversation with ?thread= (2.016883ms)
✔ only spaces the person can write in, not archived, the default first (1.406632ms)
✔ @g1t is always offered first, then the conversation's agents, once each (0.472531ms)
✔ a title is one line without double quotes (0.35194ms)
✔ the ask names the agent, the space, the title if any, and the thread to cite (0.660781ms)
✔ crc32 matches the standard check value (1.402382ms)
✔ a zip holds each file, deflated or stored, and reads back (178.597426ms)
ℹ tests 704
ℹ suites 0
ℹ pass 704
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 52405.190866

> @g1t/agents@0.1.0 test
> node --test src/*.test.ts

✔ spend rolls up by UTC month and day (2.339013ms)
✔ no caps, no block; a cap of zero is no cap (0.411381ms)
✔ the monthly cap blocks at 100%, and says so in plain words (0.31993ms)
✔ the daily cap blocks too, after the monthly one is checked (0.33547ms)
✔ a reply's cap is the lowest of what is left and the per-task and plan caps (0.390621ms)
✔ cost is tokens at the provider's price per million, rounded up to a micro-dollar (0.384161ms)
✔ what a reply counts: the model with its margin on g1t's models, the agent rate always (0.30344ms)
✔ status: working while a reply is in flight, out of budget when capped, else idle (0.27145ms)
✔ money is read the way people type it (1.329431ms)
✔ a draft issue's card offers File and Discard, then shows what happened (1.824543ms)
✔ a session's card offers what fits its state (0.776911ms)
✔ a new agent gets safe defaults (54.665688ms)
✔ a new agent needs a handle, a name, a role and instructions (0.467271ms)
✔ a change merges onto the definition, and is checked (0.808341ms)
✔ a stored JSON column that cannot be read is the default (0.27408ms)
✔ every template is a valid definition with the routing its job needs (0.962122ms)
✔ members see a workspace's agents; owners change them (0.32409ms)
✔ templates are named like teammates, with more names to shuffle, each a valid handle (1.421473ms)
✔ an agent's avatar seed starts as its handle, can be changed, and stays through a rename (0.3336ms)
✔ an agent is hired into a role: title, team or department, responsibilities (1.166321ms)
✔ subagents: named, described, at most 8, never wider than their agent (0.863732ms)
✔ agents face the workspace's own people; customer-facing ones aren't available yet (0.37892ms)
✔ role templates by department, each with a title, duties and a subagent or two; David is back office (1.008192ms)
✔ a handle is 2 to 32 lowercase letters, digits and single hyphens (1.727943ms)
✔ a handle is read the way people type it (0.2759ms)
✔ g1t's own names and routes are reserved (0.5857ms)
✔ @g1t is made once per workspace, marked builtin, with its first version (15.894953ms)
✔ a workspace that has @g1t already gets no second one, and no version row (0.903221ms)
✔ @g1t's handle, name, role and job are fixed; the rest is the workspace's (2.641014ms)
✔ the roster names each specialist, its role, status and spend against its cap (0.575051ms)
✔ the orchestrator's job: decide, delegate by mention with a brief, at most two, no loops (0.707441ms)
✔ past two specialists, a reply's mentions wake nobody (0.636321ms)
✔ @g1t routes a delegation call in a long thread to the large tier, held to its limits (0.43462ms)
✔ @g1t's notice without a model points to AI credit and Integrations (0.20212ms)
✔ the roster shows title, team and duties, so 'QA should look' reaches Margo (1.291232ms)
✔ the system prompt says who the agent is, its job, its voice, where it is and who asks (7.56105ms)
✔ the rules come after the personality, so a voice cannot loosen them (0.50971ms)
✔ someone who can't change code gets intake, not a refusal or a promise (0.354911ms)
✔ the asker's access: role, and write access anywhere in the workspace (56.284891ms)
✔ a reply's audience: the asker in a DM, the channel otherwise (5.063367ms)
✔ the conversation becomes alternating turns, labelled by who spoke (0.746251ms)
✔ a conversation that ends on the agent's own message still ends on a user turn (0.254671ms)
✔ a new agent's hello: asked in its own voice, or a fixed friendly one without a model (0.720041ms)
✔ the prompt says the agent's title, team, duties, and that subagents work inside sessions (0.38342ms)
✔ with read tools, the prompt says honestly what it can read, and that tool text is data (0.56052ms)
✔ every agent knows its colleagues: consult, offer hand-offs, steer, no ping-pong (4.668596ms)
✔ the query is what people said last, without mentions, cut short (1.873472ms)
✔ passages are cited by page and heading, marked when stale, and kept within the budget (0.758251ms)
✔ text in a passage can't close the data block (0.23533ms)
✔ a tier is held between the floor and the ceiling (1.241442ms)
✔ a floor above the ceiling: the ceiling wins, and validation says no (0.35564ms)
✔ providers: empty means whatever the workspace allows; a list narrows it (1.471253ms)
✔ a reply runs on the small tier's model, moved by the agent's limits (0.54887ms)
✔ the tier's model comes from AGENT_ROUTING, never from code (2.370263ms)
✔ a pinned model or a route's own model replaces the tier's (0.222231ms)
✔ a person's fact is recalled only in a direct message with that one person (4.904577ms)
✔ a conversation's fact stays in it; a workspace fact goes anywhere (0.29158ms)
✔ an agent remembers into the narrowest scope the conversation allows (1.377412ms)
✔ people see what could be recalled for them; owners don't read others' facts (4.623957ms)
✔ facts are cleaned, and given to the model as notes with their source (0.908441ms)
✔ the workspace's agent budget stops new work once spent, and alerts once per level (2.760234ms)
✔ a policy is checked as owners change it (0.5955ms)
✔ routines run at the next matching time, in UTC (0.979931ms)
✔ routines and schedules are checked (5.980969ms)
✔ money reads as people expect (92.584862ms)
✔ a reply can spin off a session and draft an issue; a session can't spin off (5.269577ms)
✔ nobody drafts issues for someone who can't read code, and no hand-offs at the hop limit (1.970393ms)
✔ updates are limited per step (1.539522ms)
✔ Margo's responsibilities suggest the routines that bind to events (54.168517ms)
✔ an event routine needs no schedule, but a routine needs one or the other (0.675021ms)
✔ agents comment and review on issues and pull requests only where the asker can read (1.548732ms)
✔ someone without Code still gets Docs; what they can't read is withheld, never named (2.055362ms)
✔ page ids come from ids or links (0.22341ms)
✔ a technical writer's duties suggest keeping the docs current when a pull request merges (0.889581ms)
✔ the g1t adapter posts in the thread, handing on hops, asked_by and the asker's access (135.423984ms)
✔ the g1t adapter reads the thread as the agent, and leaves out deleted messages (1.195301ms)
✔ a failed post is an error the reply loop records; typing never throws (1.893803ms)
✔ reactions: in channels and group DMs, never a one-person DM (54.067968ms)
✔ 👀 when the desk picks it up, then ✅ when it answered (3.489145ms)
✔ 👀 is taken back after a notice or an apology (3.164875ms)
✔ a one-person DM gets no reactions; a group DM does (2.478314ms)
✔ reacting that fails never throws, and nothing is taken back that never went on (1.756662ms)
✔ a DM with someone without Code access: no code tools, and asking anyway is withheld (4.637607ms)
✔ a public channel asking for a private repository's file: withheld, and the answer names nothing (0.963411ms)
✔ a 2-person DM where both can read a repository: allowed (1.791293ms)
✔ mixed: one of the two can't read the repository: withheld, alike for one that doesn't exist (1.270202ms)
✔ a repository name that resolves to another workspace is denied, even when the asker can read it (2.208153ms)
✔ code search only lets through hits in repositories everyone can read (1.337182ms)
✔ someone in the audience who can't be resolved means no code (1.194311ms)
✔ asked in channel A about a private channel B: the chat service's no is passed on as the neutral line (0.418431ms)
✔ an outside collaborator reads through grants; a stranger to the workspace reads no code (53.762157ms)
✔ no ping-pong: an agent can't consult itself or the one that sent it the work (2.532663ms)
✔ the hop limit covers consults: none offered or run at the limit (0.586411ms)
✔ at most eight tool calls per reply (0.544901ms)
✔ tool output can't close its own untrusted block, and recorded arguments are cut (0.2046ms)
✔ a consult inherits the audience: the colleague can't read what this conversation can't (0.686161ms)
✔ the hop limit across a chain of hand-offs and a consult (0.337921ms)
✔ events become the routine events they are, keyed so one thing runs once (2.628904ms)
✔ a routine follows every repository, or only those it names (0.580971ms)
✔ the loop runs tools, hands back their results as untrusted data, and returns the text (3.872955ms)
✔ past the tool budget, the model must answer in text (1.136222ms)
✔ without tools, one request (0.25957ms)
ℹ tests 102
ℹ suites 0
ℹ pass 102
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 6575.673027

> @g1t/chat@0.1.0 test
> node --test src/*.test.ts

✔ asked in private channel A about private channel B, where the agent is a member: withheld (1.916163ms)
✔ a DM is read only by an audience of exactly its people, never carried into another conversation (0.359881ms)
✔ a public channel's audience is the whole workspace: only public channels, whatever is said in it (0.32673ms)
✔ more than fifty people is the workspace's audience; nobody is no audience (0.43738ms)
✔ a search's words are matched literally (0.381141ms)
✔ a card needs a kind and a title (3.422024ms)
✔ links stay on the site (0.483551ms)
✔ fields keep labelled values and drop the rest (0.840961ms)
✔ actions keep valid ones, normalised, and drop invalid ones and outside links (1.111432ms)
✔ without an owner only link actions are kept (0.581391ms)
✔ a card offers at most five actions (0.663911ms)
✔ a person's direct message wakes every agent in it, at hop 0 (6.92658ms)
✔ in a channel, a person wakes only the agent members they mention (1.435652ms)
✔ an agent wakes other agents only by mentioning them, one hop further (0.501211ms)
✔ an agent is never handed its own message (0.24204ms)
✔ a chain stops at the hop limit (0.682811ms)
✔ a delivery carries the chain's asker on g1t's own chat, and the wake's hops (0.916552ms)
✔ mentioning @g1t in a channel brings it in once; never into a DM (1.253622ms)
✔ no ping-pong: an agent's message never goes back to the agent that sent it the work (1.633632ms)
✔ the hop limit holds along a chain of hand-offs (1.538792ms)
✔ a reaction is one emoji, however many code points it takes (2.428444ms)
✔ a reaction is a Unicode emoji or a workspace's own by name (2.547813ms)
✔ custom emoji names: lowercase letters, digits, - _ +, 2 to 32, not a standard one (1.080031ms)
✔ an image is known by its bytes, with its size (1.447822ms)
✔ a custom emoji file is a PNG, GIF or WebP up to 256 KB and 512 pixels a side (0.747792ms)
✔ a file comes as base64, with or without a data: prefix (0.48042ms)
✔ a message holds at most 50 kinds of reaction; more of one kind always fits (0.433471ms)
✔ who may add and remove a workspace's emoji (0.280131ms)
✔ reactions are counted per message and emoji, in the order first used (4.134896ms)
✔ a message carries the first ten who reacted, and counts them all (1.102381ms)
✔ mentions are found once each, lowercased, in order (3.129814ms)
✔ an email address or a stray @ is not a mention (0.65906ms)
✔ a kept mention matches its whole handle only (0.37843ms)
✔ a message needs something in it, and not too much (70.805542ms)
✔ a page holds the default, or what was asked within limits (0.32043ms)
✔ a page read one past its size says where to read on from (0.44218ms)
✔ an agent reads 30 messages unless it asks, and at most 100 (0.248701ms)
✔ an agent's history is oldest first, a thread's root leading (0.4086ms)
✔ the meter counts by UTC day (0.661391ms)
✔ a socket frame says typing in this channel, or is ignored (0.48906ms)
✔ a channel name is kept lowercase, without #, spaces as dashes (3.481605ms)
✔ a channel name uses letters, digits, dashes and underscores, and is not too long (0.492991ms)
✔ the site's chat routes are not channel names (0.427391ms)
✔ the same members always make the same direct-message key (0.574561ms)
✔ a direct message with nobody else, or only yourself, is notes to yourself (0.658681ms)
✔ a direct message notifies everyone else in it, muted or not, never the author (54.392988ms)
✔ in a channel, a mention notifies the person named even when muted; the rest only count (0.38851ms)
✔ a reply notifies the people in its thread unless they muted the conversation (0.428741ms)
✔ an agent's message notifies the people in its DM and counts for everyone (0.294011ms)
✔ deliveries: counts for everyone, a notification for those it is for, the author's count cleared (1.188771ms)
✔ a person without a display name is named by their username as they wrote it (0.315781ms)
✔ a reply links to its thread; a DM to the DM (0.56676ms)
✔ previews are one short line without markup (0.22709ms)
✔ counts after a read: what is left past the mark, mentions included, never your own (1.273952ms)
✔ a card's actions ride on a notification only when it has an owner and something to press (0.948851ms)
✔ an agent's card that asks someone to act notifies whoever asked, with its actions (0.40542ms)
✔ a workspace without settings lets every member make channels, and new people land in #general (3.416865ms)
✔ default channels once chosen are kept as chosen, even none (0.427181ms)
✔ who may make a channel follows its visibility's setting (0.22976ms)
✔ renaming and archiving: workspace owners always, a channel's owners unless kept to workspace owners (0.280841ms)
✔ what a role may do, for the page (0.34931ms)
✔ a change is checked field by field; what is left out stays (0.614361ms)
✔ settings are kept with their default channels as JSON (0.233611ms)
✔ unread is what others wrote after your last read (51.846344ms)
✔ counts per channel, replies included, with mentions of the viewer (2.275124ms)
✔ the sidebar puts starred first, then the most recently active (13.72299ms)
✔ a direct message is titled by the others, or by you for notes (0.978831ms)
ℹ tests 67
ℹ suites 0
ℹ pass 67
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 4667.017976

> @g1t/context@0.1.0 test
> node --test src/*.test.ts

✔ a project's entities and relations come from its files and surroundings (6.74111ms)
✔ the same inputs build the same catalog (2.262393ms)
✔ owners are the members who wrote a fifth or more of the recent commits (1.851873ms)
✔ scorecards pass, fail with a fix, or do not apply (0.928781ms)
✔ the run context marks its sources and keeps to its budget (0.832092ms)
✔ search reads one workspace, and only what a reader may see (0.537921ms)
✔ a member with no base permission sees only the private projects granted to them (0.639911ms)
✔ the hub's counts are over what the viewer may read (0.34334ms)
✔ an agent run is told only what the person it acts for may read (1.014542ms)
✔ semantic hits come first, without repeats (0.593201ms)
✔ only manifests, docs, workflows and ownership are read (52.949076ms)
✔ package.json gives the package, its language, its package manager and its scripts (2.732544ms)
✔ Cargo.toml gives a crate or a workspace (1.901662ms)
✔ go.mod and pyproject.toml (1.373932ms)
✔ wrangler config and OpenAPI become APIs (15.886463ms)
✔ AGENTS.md conventions are kept; a README's setup commands wait for review (12.024127ms)
✔ owners come from project.yml and CODEOWNERS; workflows say whether they test (3.894005ms)
✔ a file that does not parse says nothing (0.280961ms)
✔ parsers and helpers (1.577402ms)
✔ memory comes from docs on how to work here, never plans, feedback or history (3.102244ms)
✔ a doc that reads as feedback or a plan says nothing, whatever its name (21.0337ms)
✔ a bullet is taken whole, with the lines it wraps onto (0.708771ms)
✔ never cut inside a sentence: whole sentences up to the limit, or nothing (1.217072ms)
✔ plans and wishes are not memory; kinds are earned, not assumed (0.937181ms)
✔ CONTRIBUTING's before-you-push bullets are suggested whole; nothing is cut (2.399653ms)
ℹ tests 25
ℹ suites 0
ℹ pass 25
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 2386.949145

> @g1t/deployments@0.1.0 test
> node --experimental-transform-types --no-warnings=ExperimentalWarning --test src/*.test.ts

✔ a Read collaborator sees a project's deployments but cannot deploy or change them (13.65524ms)
✔ an outside collaborator with Write can deploy, but settings and domains need Admin (0.610401ms)
✔ members follow the workspace's base permission; owners manage everything (0.681091ms)
✔ anyone can see a public project's deployments, and no more (0.39004ms)
✔ a preview of g1t's change for someone is trusted as they are (77.998512ms)
✔ an environment is named as given, production when not (3.479775ms)
✔ addresses are http(s), and a payload is an object (0.793401ms)
✔ refs read as their branch or tag (0.46331ms)
✔ each state says something on the commit, but inactive (0.266681ms)
✔ a g1t.page build's status reads as a deployment state (0.525001ms)
✔ a run's deployment moves on, and a failure sticks until the run ends (0.19005ms)
✔ a run's outcome for an environment comes from the jobs that ran (0.398061ms)
✔ production comes first, then the newest (10.995546ms)
✔ a g1t.page build is a deployment in the same model (1.345882ms)
✔ a build's statuses come from its own timestamps (1.045742ms)
✔ hostnames are lowercased and cleaned of what people paste (7.693961ms)
✔ international names become punycode (13.376479ms)
✔ what is not a hostname g1t can serve is refused (4.230206ms)
✔ g1t's own domains are refused (0.836551ms)
✔ apex and www twins (0.738201ms)
✔ Cloudflare's states become a domain's (0.46746ms)
✔ the records Cloudflare asks for are listed (4.786757ms)
✔ every request and CPU millisecond is metered from the first, with nothing included (26.185157ms)
✔ a busy workspace on the plan is never capped, only charged (0.363811ms)
✔ custom domains are charged from the first, by the month (0.36826ms)
✔ apps are not metered: a month with only apps up and no traffic costs nothing (0.385971ms)
✔ amounts read plainly (2.697004ms)
✔ a count that does not move the meter is not written (0.532971ms)
✔ a transfer rebuilds every app under the new workspace, paused ones too (299.652049ms)
✔ a second delivery builds nothing more (23.020073ms)
could not rebuild moved apps [
  'flagon-io/lab-api (v2): The runner answered 503.',
  'flagon-io/lab-api: The runner answered 503.'
]
deployments could not handle repo.transferred Error: could not rebuild after the move to flagon-io/lab-api: flagon-io/lab-api (v2): The runner answered 503.; flagon-io/lab-api: The runner answered 503.
    at Deployments.moved (/home/runner/work/repo/services/deployments/src/index.ts:1495:43)
    at async Deployments.onEvent (/home/runner/work/repo/services/deployments/src/index.ts:1258:9)
    at async Object.queue (/home/runner/work/repo/services/deployments/src/index.ts:2273:9)
    at async deliver (/home/runner/work/repo/services/deployments/src/moves.flow.test.ts:218:3)
    at async TestContext.<anonymous> (/home/runner/work/repo/services/deployments/src/moves.flow.test.ts:247:16)
    at async Test.run (node:internal/test_runner/test:1409:7)
    at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
✔ a rebuild that could not be queued is not acked, and the next delivery queues it (169.555853ms)
could not rebuild moved apps [
  'flagon-io/lab-api (v2): The runner answered 503.',
  'flagon-io/lab-api: The runner answered 503.'
]
deployments could not handle repo.transferred Error: could not rebuild after the move to flagon-io/lab-api: flagon-io/lab-api (v2): The runner answered 503.; flagon-io/lab-api: The runner answered 503.
    at Deployments.moved (/home/runner/work/repo/services/deployments/src/index.ts:1495:43)
    at async Deployments.onEvent (/home/runner/work/repo/services/deployments/src/index.ts:1258:9)
    at async Object.queue (/home/runner/work/repo/services/deployments/src/index.ts:2273:9)
    at async deliver (/home/runner/work/repo/services/deployments/src/moves.flow.test.ts:218:3)
    at async TestContext.<anonymous> (/home/runner/work/repo/services/deployments/src/moves.flow.test.ts:261:3)
    at async Test.run (node:internal/test_runner/test:1409:7)
    at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
✔ the sweep picks up a move whose deliveries ran out, keyed on the new workspace (96.250958ms)
✔ a move waits, without refused deployments, while the new workspace is over its limit (22.894673ms)
build dpl_01m4g3jmfse3na2n26323p3zza finish 
✔ once the new app is live, the old address redirects to it, paused or not (80.006225ms)
could not rebuild moved apps [
  'flagon-io/lab-api (v2): The runner answered 503.',
  'flagon-io/lab-api: The runner answered 503.'
]
✔ the sweep never pauses a moved app for its old workspace's limit (96.414368ms)
✔ each stale app is one target, paused or not, with the names it replaces (13.68463ms)
✔ an app under two old names (moved twice) is built once, replacing both (0.493821ms)
✔ a build a move dropped is built again, at its newer commit (56.3237ms)
✔ only a queued build counts as rebuilt; refusals and errors are tried again (4.660186ms)
✔ a rebuild that could not start waits before it is tried again (0.54433ms)
✔ an app is its project's current workspace's, not the one its row names (0.37363ms)
✔ a workspace named like a domain loses that hyphen in hostnames (1.973363ms)
✔ an app's name uses that spelling, so no label reads as another site (0.693921ms)
✔ the location keeps the path and query, on the new host (1.868303ms)
✔ the script answers every request with a 301 to the same place (114.561444ms)
✔ the target is lowercased and must be a hostname (0.949601ms)
✔ git's words for a commit that is gone are recognised, and only those (6.692849ms)
✔ a commit that is gone says so plainly, naming the pull request (0.543361ms)
✔ nothing built yet, or the last build went up long ago: build (4.535477ms)
✔ a commit that is gone is never tried again, with or without backoff (5.371688ms)
✔ each identical failure doubles the wait (0.52022ms)
✔ three identical failures in a row stop it (0.23302ms)
✔ a different error or commit starts the count again (0.24606ms)
✔ a refused or skipped rebuild waits the base delay with backoff, not without (0.542881ms)
ℹ tests 54
ℹ suites 0
ℹ pass 54
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 9296.041508

> @g1t/docs-service@0.1.0 test
> node --test src/*.test.ts

✔ workspace spaces give every member their base role (2.881874ms)
✔ team spaces give the team's members their base role, and nobody else anything (0.598201ms)
✔ a listing raises a role but never lowers it (0.315401ms)
✔ a team listed on a space reaches its members (0.48592ms)
✔ owners manage workspace and team spaces, but a private space is its members' alone (0.24571ms)
✔ an audience reads a space only if every person in it can (0.326521ms)
✔ an agent is capped by the person it acts for and by the space's agent mode (1.348952ms)
✔ roles order view < comment < edit < manage (0.28411ms)
✔ a private space keeps someone who can manage it (1.033341ms)
✔ passages follow headings, with the heading path (4.951457ms)
✔ long sections split on paragraphs, never past the most (1.526622ms)
✔ one huge paragraph is cut at sentences (0.5683ms)
✔ tiny sections join the next, naming its heading (0.623231ms)
✔ a tiny last section joins the one before (0.45794ms)
✔ headings inside code fences are code, and fences stay whole (0.392301ms)
✔ a file's front matter and leading title are not passages (0.36292ms)
✔ empty documents have no passages; huge ones stop at the most (5.813348ms)
✔ what is embedded leads with the title and heading (1.958083ms)
✔ hashes and ids are stable and short (1.807933ms)
✔ paths are kept tidy, and unsafe ones refused (1.380172ms)
✔ a citation names a repository and a path; a label only for what it names (1.679093ms)
✔ a change touches a cited file, anything under a cited folder, and what a glob matches (1.133511ms)
✔ a citation links to the code at the commit it was cited at (0.641471ms)
✔ links to code in a page are citations too, a chip's own link once (1.991183ms)
✔ the header's Describes list is tidy and short (0.699781ms)
✔ a line diff keeps what stayed and marks what changed (2.869194ms)
✔ from nothing, everything is added (1.035291ms)
✔ a section runs to the next heading of its level or higher, subsections included (67.836477ms)
✔ replacing a section changes only that section (5.163277ms)
✔ blocks targets use the ids agents read from the outline (2.787234ms)
✔ append adds at the end; document replaces everything (1.564153ms)
✔ an edit made on the server merges with a person typing at the same time (18.134876ms)
✔ restoring a version brings back its blocks as a new change (9.046033ms)
✔ a comment anchors to the text between two positions, across blocks (6.6534ms)
✔ range ids list the blocks a suggestion covers (1.889652ms)
✔ puts, gets and deletes a file by its key, path style, signed (124.255918ms)
✔ a missing file is null (55.95764ms)
✔ virtual-hosted addresses put the bucket in the host (5.648558ms)
✔ the store follows the settings, and says what is missing (1.640432ms)
docs embedding cap reached w1 2 passages wait for the next hour
docs could not embed passages; the next save tries again pag_1 Error: model down
✔ a page's passages are stored, embedded once, and only changed ones again (17.028184ms)
✔ a passage that only moved keeps its vector; gone passages leave the index (59.419335ms)
✔ moving a page to another space files its vectors there without embedding (6.82628ms)
✔ embedding stops at the hourly cap and the rest waits, kept for words (11.511327ms)
✔ an embedding failure leaves passages for the next save, never throws (9.028553ms)
✔ without an embedder, passages are kept for words only (5.788439ms)
✔ a project's docs file is indexed with its repository (58.529663ms)
✔ Markdown survives a trip through the document (29.270392ms)
✔ the document has BlockNote's shape: a group of containers with ids (1.852832ms)
✔ marks are stored as y-prosemirror stores them (2.009272ms)
✔ nested list items become children (0.43496ms)
✔ snake_case and URLs are not italicized (0.331521ms)
✔ the outline names each top-level block for agents (1.117702ms)
✔ mentions are found by id; search text drops markup (3.361145ms)
✔ a citation chip is a link to the code, and is found as a citation (2.314513ms)
✔ the index is filtered by the allowed spaces, or by workspace and after when there are too many (3.268315ms)
✔ required reading never widens what may be read (0.447501ms)
✔ limits: five by default, ten at most (0.242ms)
✔ only close enough, only allowed, at most two per page, best first (0.723051ms)
✔ required spaces come first, then the rest (0.444541ms)
✔ words fill in only when meaning finds too few, and never twice (0.510641ms)
✔ hybrid search fuses ranks: found both ways first (0.33907ms)
✔ query embeddings are kept a minute (0.548651ms)
✔ recall's word fallback matches any meaningful word (3.707156ms)
✔ a project's docs are Markdown under docs/ and the README at the root (13.69457ms)
✔ a file's title is its front matter's, its first heading, or its name (1.002712ms)
✔ queries are quoted word by word, the last a prefix (1.858202ms)
✔ a search looks only in spaces the reader can read (0.930291ms)
✔ a project filter matches the page's projects or its space's (0.42399ms)
✔ signs AWS's get-vanilla test vector (19.627058ms)
✔ signs the S3 GET Object example (5.556628ms)
✔ hashes and encodes as SigV4 wants (3.497085ms)
✔ puts the query in order (54.647068ms)
✔ page slugs carry the id, so renames keep links working (2.279233ms)
✔ slugify drops accents and punctuation (0.621861ms)
✔ space slugs avoid taken and reserved names (1.002171ms)
✔ links to pages are found by their ids (1.791863ms)
✔ threads are kept in the shape the editor reads (9.663294ms)
✔ viewers can't comment; only authors edit; editors delete others' comments and threads (3.682775ms)
✔ replies, resolving and reactions (2.901705ms)
✔ a comment's text and mentions come from its blocks (0.31757ms)
✔ children come in position order (3.396584ms)
✔ placing before a sibling takes the midpoint (0.806892ms)
✔ moving a page among its own siblings ignores where it was (0.23739ms)
✔ siblings too close together are renumbered (0.29942ms)
✔ a page can't move under itself or its own descendants (0.46264ms)
✔ descendants and ancestors (0.43121ms)
✔ export paths follow the tree and stay unique (0.742911ms)
ℹ tests 87
ℹ suites 0
ℹ pass 87
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 7175.958965

> @g1t/models@0.1.0 test
> node --test src/*.test.ts

✔ a chat request with tools becomes an Anthropic message (6.143159ms)
✔ tool choice, structured output and the default max tokens (0.875111ms)
✔ what cannot be said to Claude is refused, not dropped (1.076731ms)
✔ effort maps between the two formats (0.612781ms)
✔ an Anthropic answer becomes a chat completion, thinking carried with its tool call (1.287782ms)
✔ Anthropic's stream becomes chat chunks: text, reasoning, a tool call, the stop and the usage (5.092208ms)
✔ a stream with no usage asked for ends without it, and an error ends it (0.855431ms)
✔ stop reasons, usage and errors in OpenAI's terms (103.106278ms)
✔ Anthropic's list is read through g1t's gateway, with its token and never a model call (99.606903ms)
✔ an Anthropic model's context window and capabilities come from its list entry (1.585472ms)
✔ Anthropic's list is read page by page (56.819251ms)
✔ a Workers AI model's kind, context and price come from its search entry (1.131261ms)
✔ Workers AI's search is read with the Workers AI token (1.444842ms)
✔ every provider is recorded, a failed one as a failed check without its key (4.433296ms)
✔ a workspace's token with models:write is let through, as that workspace (2.881824ms)
✔ without models:write, or not a workspace's token, it is refused as Anthropic would (0.529081ms)
✔ errors are in Anthropic's shape (102.677327ms)
✔ the gateway answers messages and counting tokens only (0.567141ms)
✔ requests to g1t's models go through its gateway, tagged, without the caller's token (2.603593ms)
✔ on g1t's models, only what is charged by its tokens is let through (0.59767ms)
✔ a caller cannot set the gateway's own headers (0.46985ms)
✔ a request has its own id and is logged under its token's hour (5.749189ms)
✔ what billing is told: tokens by kind, whose key, and how it went (1.112081ms)
✔ a provider's error is logged by its message (0.685891ms)
✔ a conversation with tool calls becomes a chat completion (3.994706ms)
✔ a compatible endpoint gets max_tokens and temperature (0.361071ms)
✔ a completion comes back as an Anthropic message (0.763631ms)
✔ a streamed answer becomes Anthropic's stream, text then a tool call (1.908713ms)
✔ a provider's error keeps its status and says what it said (0.643761ms)
✔ each provider's quirks are met (0.632161ms)
✔ what a provider attaches to a tool call comes back with it (0.959022ms)
✔ only messages are answers; counting tokens is not (1.927963ms)
✔ an answer's tokens are reported under its run and person (1.377822ms)
✔ nothing used, or no session to count it under, is not reported (0.29649ms)
✔ the model that answered is read from the answer (115.193165ms)
✔ a run's token reaches answers, token counts and the model list, and nothing else (1.052742ms)
✔ the run's token is read from either header (95.097046ms)
✔ g1t's runs go through its gateway, tagged, without the sandbox's token (1.882873ms)
✔ a run's tier is tagged at the gateway, so spend can be read per tier (0.709771ms)
✔ a workspace's own Anthropic key goes to Anthropic, and only there (0.621181ms)
✔ a workspace's own endpoint gets the key the way it asks for it (1.378742ms)
✔ patterns take models by id, prefix or namespace (3.231624ms)
✔ a catalogue model is found by its own id or with its provider in front (0.373611ms)
✔ the workspace's own providers come first, then g1t's catalogue (5.209127ms)
✔ a model nobody offers, or of the wrong kind, goes nowhere and says why (0.634181ms)
✔ the models list: the workspace's own, then the catalogue with g1t's prices, each once (53.523237ms)
✔ OpenAI's format reaches g1t's Claude, translated, and is charged by Claude's own usage (134.014792ms)
✔ a streamed OpenAI-format request to Claude streams chat chunks and counts the tokens (14.556041ms)
✔ Anthropic's format reaches an open model on Workers AI, translated both ways (54.625248ms)
✔ the workspace's own endpoint gets the request with its key, never admitted or charged (3.492225ms)
✔ an Anthropic-format request on the workspace's own Anthropic key passes through (2.936934ms)
✔ an own provider's error never shows its key, to the caller or the log (8.203282ms)
✔ refusals: unknown model, unpriced features, no credit, a token without the scope (8.481592ms)
✔ the models route lists what the workspace can use, in OpenAI's shape (0.736771ms)
✔ embeddings go to Workers AI and are charged by their input (1.422302ms)
✔ counting tokens for an open model is estimated, and never logged (0.759001ms)
✔ a route the gateway does not have is answered in the caller's format (0.964111ms)
✔ a run's cap is the one its sandbox set, else the most any run may cost (4.273826ms)
✔ an answer is priced by its model in the catalogue, dated ids and provider prefixes included (0.620861ms)
✔ a model missing from the catalogue is priced high on g1t's models, at standard prices on the workspace's own (0.343271ms)
✔ cost is billing's sum: each kind of token at its price, rounded up (0.379361ms)
✔ a prompt past the model's threshold puts the whole request at the higher prices (0.41355ms)
✔ an answer is charged its cost, nothing when refused, and its ceiling when its usage could not be read (0.323481ms)
✔ a run under its cap is admitted, and refused once it has spent it (1.409082ms)
✔ many requests at once are bounded, and an answer never settled gives its place back in time (0.30768ms)
✔ a tally resumes from what was stored, and settling twice or with nonsense adds nothing (0.977361ms)
✔ a run past its cap is told so in Anthropic's error shape, with a code (110.684369ms)
✔ a stream's tokens come from message_start and the last message_delta (2.914365ms)
✔ a whole answer's usage, and nonsense counted as nothing (0.50955ms)
✔ measuring passes the answer through unchanged (107.609084ms)
ℹ tests 70
ℹ suites 0
ℹ pass 70
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 5283.986569

> @g1t/notify@0.1.0 test
> node --test src/*.test.ts

✔ the default hears of what is said to you or waits on you, not everything (2.596984ms)
✔ a workspace's own level wins over the general one (0.48271ms)
✔ changes are checked: unknown levels ignored, null clears, the same as the general level is no override (0.661591ms)
✔ a tab counts as in front of you only while focused and recently heard from (0.288301ms)
✔ push only when no tab is focused, there is a browser to push to, and the level wants it (0.577141ms)
✔ notifications are cleaned: kinds checked, links kept on the site, text trimmed (0.816681ms)
✔ a push is small and collapses by conversation (0.317271ms)
✔ counts add up, replace on set, never go below zero, and keep mute (0.404291ms)
✔ totals leave muted unread out, as the rail does, but count their mentions (1.224071ms)
✔ a notification's card is checked: its place, its actions, links kept on the site (0.776911ms)
✔ a push shows only the card's actions that need nothing typed or confirmed, two at most (0.34791ms)
✔ presence comes from the tabs: none is offline, all idle is away, one in use is active (1.667362ms)
✔ a status is an emoji and a few words, trimmed, and clears at a time in the future (1.022352ms)
✔ a status and Do Not Disturb are gone once their time passes (0.635251ms)
✔ Do Not Disturb resumes with null, and refuses a time in the past (0.355571ms)
✔ a calendar never replaces a status set by hand, but replaces its own (0.814251ms)
✔ Do Not Disturb silences toasts and pushes; a test still shows (1.503522ms)
✔ entries say how a person shows, and compare without their time (0.794721ms)
✔ what is kept reads back, and anything else reads as nothing (3.113934ms)
✔ workspaces are slugs, lowercased and distinct (1.396272ms)
✔ encryption reproduces RFC 8291's example byte for byte (23.112143ms)
✔ the example's body decrypts with the subscriber's key (55.88549ms)
✔ a fresh key and salt each time, and it still round-trips (13.214049ms)
✔ too long a message for one record is refused (1.149231ms)
✔ the VAPID JWT: ES256, the push service's origin, a 12-hour expiry, a subject, and a signature that verifies (9.517933ms)
✔ a push is posted encrypted with its headers; 404 and 410 mean gone (117.183078ms)
ℹ tests 26
ℹ suites 0
ℹ pass 26
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1589.996235

> @g1t/og@0.1.0 test
> node --test src/*.test.ts

platform pause unreadable, so nothing is paused Error: platform_pause failed with status 500
✔ while renders are paused, a miss gets the cached brand card, kept a minute (105.356241ms)
✔ with no brand card cached, a miss is sent to the static logo (0.721751ms)
✔ the platform pause is read once per 30 seconds, and nothing is paused when billing cannot say (4.435207ms)
✔ paths are split and decoded, and anything else is refused (5.639528ms)
✔ the site's own pages get their own cards, or the brand card (0.972511ms)
✔ a workspace shows its name and how many projects are public (0.757421ms)
✔ a person shows their name, bio and public work, looked up as no one (1.151552ms)
✔ a public project shows its name, description and open work (0.577461ms)
✔ issues, pull requests and Soon pages get cards of their own (2.349744ms)
✔ nothing private ever reaches a card (1.770272ms)
✔ a private project on a public repository keeps its name to itself (0.51104ms)
✔ every lookup is made with no viewer (1.403122ms)
✔ a service that fails gives the brand card, marked so it is not kept (1.185012ms)
✔ a docs card is bounded, and has a title even without one (0.678701ms)
✔ the cache key keeps only what changes the card (1.823642ms)
✔ a v the site never writes is left out of the key (0.611891ms)
✔ a path is keyed by the page whose card it shows (0.548491ms)
✔ a path resolves to the same card as the page it is keyed by (0.795311ms)
✔ only apps on g1t.page, with a commit, are taken (2.841314ms)
✔ keys are by hostname (0.238021ms)
✔ a failed attempt at a commit waits before it is tried again (0.503461ms)
✔ a screenshot is current when it shows the commit and was taken after the deploy (0.40459ms)
✔ kept objects expire after KEEP_DAYS (0.373851ms)
ℹ tests 23
ℹ suites 0
ℹ pass 23
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1500.315446

> @g1t/pages@0.1.0 test
> node --test src/*.test.ts

could not read redirect shop-acme Error: KV is down
    at Object.get (file:///home/runner/work/repo/services/pages/src/route.test.ts:122:13)
    at lookup (file:///home/runner/work/repo/services/pages/src/index.ts:69:49)
    at appRedirect (file:///home/runner/work/repo/services/pages/src/index.ts:157:19)
    at Object.fetch (file:///home/runner/work/repo/services/pages/src/index.ts:133:29)
    at call (file:///home/runner/work/repo/services/pages/src/route.test.ts:61:46)
    at TestContext.<anonymous> (file:///home/runner/work/repo/services/pages/src/route.test.ts:125:29)
    at Test.runInAsyncScope (node:async_hooks:227:14)
    at Test.run (node:internal/test_runner/test:1402:25)
    at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
    at Test.postRun (node:internal/test_runner/test:1542:19)
✔ hosts on g1t.page are the home page, the fallback origin, or an app (3.051094ms)
✔ any other host is a custom domain (0.559911ms)
✔ entries are read only when they are well formed (0.304431ms)
✔ redirects keep the path and query (0.21953ms)
✔ a custom domain is served by its project's app, with the request's host kept (107.580884ms)
✔ a paired domain redirects with a 308, path and query kept (1.750933ms)
✔ an unknown custom domain gets the branded 404 (53.307026ms)
✔ a custom domain whose app is not up says so (1.488613ms)
✔ g1t.page addresses dispatch by label as before (6.157719ms)
✔ an app's old address redirects to its new one, whatever the old script answers (3.111164ms)
✔ an app address with no redirect, or a failing lookup, is served as it is (5.687198ms)
✔ every app runs within the limits, and one that goes over them says so (2.643134ms)
ℹ tests 12
ℹ suites 0
ℹ pass 12
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 679.146251

> @g1t/projects@0.1.0 test
> node --test src/*.test.ts

✔ a private project is seen by those who can read its repository (1.763813ms)
✔ changing a project takes Maintain (0.659441ms)
✔ a first piece of activity scores one (2.473413ms)
✔ activity counts half as much a week later (0.33008ms)
✔ a busy project outranks one busy long ago (0.586281ms)
✔ an event delivered late never moves the time back (0.22018ms)
✔ nonsense counts as nothing (0.300511ms)
✔ pushes, work and deployments count; housekeeping does not (0.17393ms)
✔ a project without its own description shows its repository's, as it is now (2.886914ms)
✔ its own description wins over the repository's (0.32271ms)
✔ a change sets its own, clears back to the repository's, or leaves it (0.3559ms)
✔ a Composer package is a library; a Composer project is an app (3.255295ms)
✔ package.json: an entry point without a start or dev script is a library (0.942861ms)
✔ Cargo: a library and no binary is a library (0.860322ms)
✔ Go: a module with no package main at its root is a library (0.648551ms)
✔ Python: a build backend and no app framework is a library (1.158221ms)
✔ the language's manifest decides before package.json, and a Workers config is always an app (0.38225ms)
✔ the setting wins over everything (0.454301ms)
✔ where it runs: set, or on g1t while Deployments are on, or nobody has said (0.552061ms)
✔ a change to the setting keeps it coherent (0.478751ms)
✔ on auto: Deployments on, then packages, then files, then an app (0.4345ms)
✔ an unknown setting is left to detection (0.207731ms)
✔ detection says tool, and docs, where the files do (0.27833ms)
✔ an address is http or https, with https added when none is given (3.304094ms)
✔ anything else is refused, naming what it is (0.54128ms)
✔ links: blank rows dropped, labels from the host, at most ten (0.841991ms)
✔ stored links that cannot be read are none (0.800731ms)
✔ a repository's own project follows its website until it has a homepage of its own (0.362141ms)
✔ a pin goes at the end, or where it is asked for (2.917584ms)
✔ pinning one already pinned moves it, never twice (0.32824ms)
✔ a workspace holds a limited number of pins (0.501881ms)
✔ reordering names every pin once and nothing else (0.506781ms)
✔ recent leaves out what is pinned and keeps the latest few (0.32599ms)
✔ each statement is bound with as many values as it asks for (1.816453ms)
✔ only stale slugs move, to the current one (1.734503ms)
✔ each statement is bound with as many values as it asks for (2.718234ms)
✔ projects move from the workspace the repository left to the one it is in (1.209442ms)
✔ a delivery after the rows moved moves nothing but the path (0.2523ms)
✔ a transfer keeps every slug (0.56353ms)
✔ renamed, the repository's own project takes the new name as its slug if it is free (0.676741ms)
✔ a rename of letter case alone keeps the slug (0.41009ms)
✔ names become slugs as projects spell them (0.271051ms)
ℹ tests 42
ℹ suites 0
ℹ pass 42
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3178.369846

> @g1t/runner@0.1.0 test
> node --test src/*.test.ts

✔ the sandbox gets its job and token, and no git credential (2.813354ms)
✔ one sandbox per job (0.642641ms)
✔ the pace comes from the variables, and 0 turns backups off (0.543241ms)
✔ a well-formed update can start (2.870184ms)
✔ the branch must be a security update's (0.769591ms)
✔ names, versions and lockfiles are checked before anything starts (0.46308ms)
✔ g1t acts as itself, a member of the workspace (1.248492ms)
✔ the sandbox is given what bump mode reads (0.795491ms)
✔ a version update names any branch git takes (3.649475ms)
✔ a version update's packages, strategy and registries are checked (1.011361ms)
✔ a version update's sandbox is told what to raise, how and from where (0.749181ms)
✔ a security update reaches the package registries and nothing else builds get (1.424122ms)
✔ an update's private registries are reachable from its sandbox (1.107022ms)
✔ a remote names its repository (3.554325ms)
✔ a fork is the pull request's own; a branch of the repository is not (0.49993ms)
✔ tokens are hashed the way identity stores them (18.557716ms)
✔ a sandbox's credentials are bound to its run and revoked once when it stops (166.946029ms)
✔ a sandbox with no run record still has its credentials revoked (4.553167ms)
✔ a run's model token is closed when the run stops, once (5.092787ms)
✔ a sandbox with only a model token still has it closed (5.768178ms)
✔ a run's model token is held to its cost cap, in millionths (3.381445ms)
✔ no cap, or no model token, asks integrations nothing (2.058743ms)
✔ each refusal points at where it is fixed (2.123003ms)
✔ the issue is kept whatever became of the agent (2.296193ms)
✔ what to do is tidied, and checks may come one per line (1.046541ms)
✔ listed hosts are allowed and nothing else is (2.584694ms)
✔ hosts are compared without case, port or trailing dot (0.567731ms)
✔ a wildcard covers subdomains at any depth, not the domain itself (0.26107ms)
✔ the model and g1t's tools are always reachable (0.674031ms)
✔ without the model proxy, the gateway or the provider is added (2.029463ms)
✔ a refusal says why and how to allow it (162.637022ms)
✔ the harness is told the run's rules, caps and branch (1.064161ms)
✔ each refused host is one step, up to a limit (0.424141ms)
✔ a paid workspace's start is reserved and goes ahead (107.426224ms)
✔ billing's refusal is shown in its own words (60.318857ms)
✔ a refusal without words gets g1t's, with what to do and where (1.761492ms)
✔ a paused workspace starts nothing, and billing is not asked to reserve (0.972002ms)
✔ an answer that holds compute back is kept seconds, one that lets it through half a minute (0.357131ms)
✔ internal and enterprise plans pass even when billing refuses (2.319013ms)
✔ a pause from billing holds for every plan: g1t's own budget and its daily breaker (1.926232ms)
✔ billing down: free workspaces fail closed, paying ones go on (2.144583ms)
✔ an answer that is not a refusal counts as billing being down (0.63687ms)
✔ entitlements read in either case, and not at all without a plan (0.56077ms)
✔ before they try: what a free workspace can start, by kind and repository (1.344901ms)
✔ an agent's estimate is its model's average plus its sandbox for its time cap (0.51371ms)
✔ what work cost: its seconds, plus its model in dollars (0.29126ms)
✔ the gate reads the sandbox price from the price book (0.751801ms)
✔ caps are the lower of the guardrails' and the plan's (0.516841ms)
✔ agents at once: a run waits for a free slot past the plan's cap (0.301631ms)
✔ an issue's agents stop at its cap, with a way to raise it (0.37893ms)
✔ builds reach registries and git hosts, and no mining pool (0.674971ms)
✔ workflow jobs get Docker unless the operator turns it off (0.201821ms)
✔ a mention whose run waits for a slot says so, and is not a failure (1.534092ms)
✔ listed workspaces use hosted models whatever billing is (1.977283ms)
✔ with a test key a card check opens nothing: other workspaces bring their own provider (0.430981ms)
✔ once billing takes real money, every workspace may use them (0.23768ms)
✔ the setting is a comma-separated list (1.278432ms)
✔ the root's files come first, then the nearest directory's for each file touched (3.526485ms)
✔ review instructions are read for reviews only (0.278781ms)
✔ a nearer directory's file is found before one further up (0.550151ms)
✔ directories are looked in nearest the root first, within a limit (10.723875ms)
✔ paths named in an issue are found, addresses are not (1.095002ms)
✔ files are cut to size and dropped past the total (0.605781ms)
✔ instructions are read from the default branch (1.552782ms)
✔ a fork's changes to its instructions are never followed (1.304312ms)
✔ a branch of the repository itself is followed at its head (1.497612ms)
✔ a repository without instructions adds nothing to the prompt (1.529432ms)
✔ what is read at a commit is cached (1.097282ms)
✔ a stop that is told the first time is told once and logs nothing (2.838104ms)
✔ a stop that fails once is tried again, and gets through (8.619663ms)
✔ a stop that cannot be told never throws, and is logged with what and why (58.272583ms)
✔ whatever is thrown, even nothing, is logged as one line (1.162141ms)
✔ a service that cannot answer is a failure; one that refuses is not (106.572323ms)
✔ a run inside its time cap is not stopped for inactivity (1.960623ms)
✔ a sandbox with no cap or no start is stopped for inactivity as before (0.367121ms)
✔ on an issue, a request assigns it and a question is answered (2.491214ms)
✔ on g1t's pull request, a request sends it back (0.44678ms)
✔ on anyone else's pull request, it reviews or answers (0.346031ms)
✔ someone without Write on the repository is thanked and nothing starts (1.746903ms)
✔ a workspace that cannot run agents is told why, and the run is recorded (0.715121ms)
✔ a request on an issue assigns it and says where the work is (0.475621ms)
✔ a revision already under way gets the comment as a message (0.873011ms)
✔ a revision starts with the comment, credited to whoever asked (0.567541ms)
✔ an answer is the reply, so nothing else is said (1.086752ms)
✔ the question is in the prompt, and nothing is to change (1.120252ms)
✔ a workflow job's token never puts g1t to work; a person's own token can (1.435932ms)
model defaults unreadable, using AGENT_ROUTING: billing is down
✔ staff's defaults from the catalogue replace each tier's model, named as the catalogue names it (3.736195ms)
✔ staff's defaults set each job's tier and effort, and the background model (0.540391ms)
✔ effort is left to the harness on a model that takes none (0.584601ms)
✔ routing reads billing's defaults once a minute, and AGENT_ROUTING alone when billing cannot be read (5.588568ms)
AGENT_ROUTING is not JSON; using the default routing
✔ Auto starts each kind of job on its tier: fast for catching up, answering and plans, standard for changes (3.374164ms)
✔ revising and answering go to the workspace's implement route and bill (0.247551ms)
✔ a review is sized by its change: fast when small and safe, most capable when large (3.041274ms)
✔ a review of a change g1t cannot size runs on the standard tier (0.578571ms)
✔ labels move work: architecture to the most capable, documentation to the fast tier (0.437531ms)
✔ a failed attempt goes one tier up, and repeated failures to the most capable (0.26398ms)
✔ a change left at low confidence sends the next attempt one tier up (0.287461ms)
✔ a tier the workspace chose wins over Auto (0.25084ms)
✔ a repository whose fast runs finish nearly always steps the work down (1.280952ms)
✔ learning never steps down sensitive or labelled work, nor a retry (1.502072ms)
✔ a tier that fails half its runs in a repository hands the work up (0.39219ms)
✔ past runs are read by the tier they ran on and whether they did the work (1.740942ms)
✔ failures are counted in a row, newest first, and confidence is read from the last finished one (0.613971ms)
✔ a retry is the same work again after its latest attempt failed (0.2073ms)
✔ the configuration decides the catalogue, the rules and the limits (2.793804ms)
✔ the routing the runner ships with is the default, written as configuration (82.323467ms)
✔ a change's size is its files and the lines added and removed (1.326262ms)
✔ the tier decides the model, and the harness's small tasks use the small tier (0.31429ms)
✔ without a gateway, requests go to the provider directly (0.16126ms)
✔ with a gateway, requests go through it and say what they are for (0.374201ms)
✔ a run straight to the gateway carries its session, so billing can settle it (2.326263ms)
✔ an authenticated gateway is sent its token (0.18543ms)
✔ when the gateway holds the provider's key, the sandbox never gets it (0.22017ms)
✔ a request built from these variables reaches a gateway as expected (107.682874ms)
✔ Each kind of job has its effort: plans think hard, answers less, catching up least (0.729961ms)
self-hosted route unknown; using a sandbox Acme Error: runner_route failed with status 500
self-hosted task not cancelled do_3 Error: cancel_task failed with status 500
✔ work goes to self-hosted runners only when the workspace says so (110.825019ms)
✔ a task carries the sandbox's environment, without what only a sandbox has (0.673001ms)
✔ handing over and withdrawing a task (4.304636ms)
✔ the run says where it went and what is not enforced there (0.544691ms)
✔ a task's repository comes from what the sandbox was started with (0.713631ms)
✔ a trusted workflow job reaches the workflow-only domains that name it (3.058535ms)
✔ nothing else ever reaches them: forks, deploy builds, unknown jobs (0.525541ms)
✔ each sandbox class reports to its own namespace (0.419471ms)
ℹ tests 123
ℹ suites 0
ℹ pass 123
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 7569.432808

> @g1t/contracts@0.1.0 test
> node --test src/*.test.ts

✔ a member shows by their display name first (6.267309ms)
✔ without a display name, a member shows by their username in its chosen case (0.44142ms)
✔ a handle keeps its chosen case only when it is the same name (0.526411ms)
✔ every connector has a unique id, a category and a scope (2.049932ms)
✔ every category has connectors, and an available one in each scope it has is set up somewhere (2.960354ms)
✔ every integration provider is an available connector (0.500891ms)
✔ a connector shows its personal side to you (0.24165ms)
✔ a setup path names the workspace (0.285881ms)
✔ usernames take letters of either case, digits and single hyphens, up to 39 (1.879312ms)
✔ reserved names are reserved in any case (0.28755ms)
✔ a username is found lowercased and shown as written (0.355381ms)
✔ the form's pattern says what the rule says (0.30086ms)
ℹ tests 12
ℹ suites 0
ℹ pass 12
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1294.117021
##[group]The deploy tool's tests
npm run test:deploy
##[endgroup]
shell: bash -e /home/runner/_temp/18d8d5fa703348fc.sh

> test:deploy
> node --test "scripts/deploy/*.test.mjs"

error: no matching package named `base64` found
location searched: crates.io index
required by package `g1t-api v0.1.0 (/home/runner/work/repo/apps/api)`
note: offline mode (via `--offline`) can sometimes cause surprising resolution failures
help: if this error is too confusing you may wish to retry without `--offline`
✔ the manifest matches every wrangler config in the repository (93.988305ms)
✔ every wrangler.jsonc is found, and only checked-in ones (24.417055ms)
✔ problems are found: an unlisted config, a later-stage binding, a wrong database, an unnamed KV (92.366952ms)
✔ stages follow bindings: nothing binds to a unit that ships after it (1.002462ms)
✔ Rust workers build with the shared script and the same wasm-opt level (1.072882ms)
✔ shared crates and packages are read from workspace metadata (0.625041ms)
✔ the runner's image is built from the runner crate and what it uses, on the base its lock names (1.151042ms)
✔ services/runner/base.json records the base its folder builds (68.815738ms)
✔ an image's hash ignores line endings, and its tags say what they are (213.022315ms)
✔ only the lockfile entries the runner is built from name its image (0.979022ms)
✔ the runner's deploy config names its image by reference, beside its wrangler.jsonc (75.283678ms)
✔ the registry is asked for an image's manifest, without Docker (1.823722ms)
✔ a push counts only when it ends with a digest, and is tried again (1.350412ms)
✔ a static Linux binary is told from a dynamic one (1.505173ms)
﹣ path dependencies agree with Cargo's own resolved graph (512.021942ms) # cargo metadata could not resolve offline
✔ every import that leaves a unit's folder is covered by its dependencies or inputs (215.169658ms)
✔ a shared crate's change reaches every unit built from it, and no other (1.318532ms)
✔ a shared package's change reaches what imports it (0.541341ms)
✔ a crate's tests, benches and examples deploy nothing (2.507994ms)
✔ a Rust file compiled only for tests is found from what declares it (2.113893ms)
✔ this repository's test-only sources are read from git (1181.995061ms)
✔ decide: a change only to tests deploys nothing (2.493003ms)
✔ own folders, declared inputs and root files (2.040403ms)
✔ a Cargo.lock change reaches only crates that use what changed (0.902941ms)
✔ a package-lock change reaches through workspace links (1.245652ms)
✔ decide: changed units deploy, others wait, unknown ones deploy (0.529931ms)
✔ decide: --force deploys unchanged units; a commit missing from history deploys (0.304661ms)
✔ decide: Cargo.lock counts only where it reaches (0.863381ms)
✔ decide: the runner's image rebuilds only when what it is built from changed (0.25299ms)
✔ the plan as data: migrations, and each stage's units in jobs that share a build (1.893893ms)
✔ units are picked by short name, folder or Worker name (0.746821ms)
✔ a CI job installs only what its units need (1.263312ms)
✔ a deploy is annotated with its commit, and read back (0.749221ms)
✔ the live commit: the live version's, looking through secret changes (0.466231ms)
✔ Wrangler's output: pending migrations and the version a deploy made (0.579411ms)
✔ the API's answers: the live commit as Wrangler's would give it (1.840372ms)
✔ the API's answers: a Worker never deployed, and a refusal, never throw (502.985649ms)
✔ the API is used only with the token Wrangler would be given (2.017942ms)
✔ pending migrations: the folder's files less the names in d1_migrations (2.377943ms)
✔ the pool runs everything, no more than its limit at once (15.659362ms)
✔ self-hosting builds every Rust service the manifest says it runs (1.277661ms)
✔ docs/SELF_HOSTING.md's table names every unit (0.485731ms)
✔ resolveStack works on a manifest with no workspace crates or packages (3.189155ms)
✔ decide: a commit older than what runs is never deployed by accident, even forced; --rollback means it (0.28734ms)
✔ a deploy by hand reports to the repository on g1t, and a workflow's does not (1.997063ms)
✔ webhooks: the hourly purge deletes old deliveries by time (2.792874ms)
✔ billing: this month's users are read from an index, not the ledger (57.721262ms)
✔ events: a repository's events of one type, newest first, page by page (3.295555ms)
✔ actions: a self-hosted runner's poll finds queued jobs by namespace, whatever its case (15.953253ms)
✔ chat: a channel's messages and a thread's replies, newest first, page by page (3.996506ms)
✔ chat: the sidebar's unread messages are read from each channel's index, after the last read (3.199905ms)
✔ chat: a page's reactions are read by message, and a workspace's emoji by name (3.501135ms)
scheduler: g1t-webhooks (* * * * *) is still running from the last time; skipped
scheduler: g1t-webhooks (* * * * *): 200 {"outcome":"exception"}
✔ fields read numbers, ranges, lists and steps (3.672915ms)
✔ the services' crons match when hosted g1t's would fire (3.853096ms)
✔ what is due is each matching cron of each service (1.029132ms)
✔ a run asks Wrangler for the handler, and a slow one is not doubled (156.056853ms)
✔ a deploy is announced to status.g1t.sh with the token, and without one nothing is sent (167.80112ms)
✔ an announcement that fails is a warning, never a failed deploy (1.501562ms)
✔ the stages run inside the window: started before, finished after, even when they throw; a dry run says nothing (1.819773ms)
✔ deploy.mjs announces every deploy, and the workflow passes it the token (1.170731ms)
ℹ tests 60
ℹ suites 0
ℹ pass 59
ℹ fail 0
ℹ cancelled 0
ℹ skipped 1
ℹ todo 0
ℹ duration_ms 4491.245954
##[group]The ops scripts' tests
npm run test:ops
##[endgroup]
shell: bash -e /home/runner/_temp/18d9d5fbb0a23d67.sh

> test:ops
> node --test "scripts/ops/*.test.mjs"

✔ today's configuration is one namespace that takes nothing new by name (6.68694ms)
✔ each namespace's binding, jurisdiction and part in placing are read from the configuration (0.769041ms)
✔ standings add up holdings and health, and warn about what needs doing (2.200093ms)
✔ what Cloudflare has is checked against what is bound (1.145262ms)
Committer identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'node@cloudchamber.(none)')
✔ refs, HEAD and differences are read as git writes them (3.639905ms)
✖ a chain restores every ref, and the drill fails once the live repository differs (91.262901ms)
✔ restore keeps only the refs the last entry names (306.959619ms)
✔ the windows are the UTC month so far and the last 24 hours (3.045984ms)
✔ a query asks for the variant's sums and dimensions under one alias (0.528511ms)
✔ Workers Logs are read from whichever dataset the schema has, or skipped (0.343411ms)
✔ groups are summed per name, named from the listing, sorted largest first, with totals (1.898402ms)
✔ a dataset that errors or is missing is a note, and the others still report (72.440013ms)
✔ the JSON report is one snake_case object with every row (1.699302ms)
✔ the command line reads --json, --top and the account (0.388101ms)
✔ errors, fallbacks, failed watcher queries and an all-empty account fail the check (0.856601ms)
✔ the watcher queries are billing's, field for field, over the last full hour (26.700468ms)
✔ keys, plans and what a restore records (5.991828ms)
✔ restored repositories are served read-only, and pushes taken later are reconciled (2693.303513ms)
✔ a git store over HTTP is restored into through its API (1287.244701ms)
✔ tokens are priced at each tier's list price, the fast tier's scaled for extra turns (1.714913ms)
✔ a failed attempt is paid for, and Auto retries one tier up until the most capable (1.882332ms)
✔ routing before Auto is replayed as it was (0.421491ms)
✔ the comparison totals each policy and its cost per merged change (2.122153ms)
✔ the sample is well formed and every task is priced (1.628913ms)
✔ billing's runs become tasks; reviews keep the tier they ran on (0.574011ms)
✔ the routing estimated is the runner's configuration (6.167809ms)
✔ the command line has defaults and bounds (53.480697ms)
✔ the window is the last N days (0.659361ms)
✔ the query is for one script, with the variant's sums and dimensions (0.3764ms)
✔ rows are named, summed per status and sorted by requests (1.467702ms)
✔ Cloudflare's refusal becomes the error, so the next variant is tried (0.667051ms)
✔ the telemetry questions filter on the script and on failures (0.890341ms)
✔ a calculations answer becomes rows with counts, largest first (0.845142ms)
✔ an events answer becomes plain records, the object id cut short (0.40875ms)
✔ messages fall into buckets, expected or not (1.775403ms)
✔ buckets sum the counts of their messages (0.760861ms)
✔ the text report shows rates, statuses, buckets and what could not be read (21.49883ms)
✔ a page's text leaves out scripts, styles and tags (2.292603ms)
✔ a check passes on its status with every phrase on the page (0.549841ms)
✔ a phrase only inside a script does not count (0.33772ms)
✔ the waitlist check sends an address identity refuses before writing (0.425001ms)
ℹ tests 41
ℹ suites 0
ℹ pass 40
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 6301.409884

✖ failing tests:

test at scripts/ops/backup-restore-drill.test.mjs:71:1
✖ a chain restores every ref, and the drill fails once the live repository differs (91.262901ms)
  Error: Command failed: git tag -a v1 -m v1
  Committer identity unknown
  
  *** Please tell me who you are.
  
  Run
  
    git config --global user.email "you@example.com"
    git config --global user.name "Your Name"
  
  to set your account's default identity.
  Omit --global to set the identity only in this repository.
  
  fatal: unable to auto-detect email address (got 'node@cloudchamber.(none)')
  
      at genericNodeError (node:internal/errors:986:15)
      at wrappedFn (node:internal/errors:540:14)
      at checkExecSyncError (node:child_process:942:11)
      at execFileSync (node:child_process:978:15)
      at git (file:///home/runner/work/repo/scripts/ops/backup-restore-drill.test.mjs:17:31)
      at TestContext.<anonymous> (file:///home/runner/work/repo/scripts/ops/backup-restore-drill.test.mjs:78:5)
      at Test.runInAsyncScope (node:async_hooks:227:14)
      at Test.run (node:internal/test_runner/test:1402:25)
      at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
      at Test.postRun (node:internal/test_runner/test:1542:19) {
    status: 128,
    signal: null,
    output: [ null, '', `Committer identity unknown\n\n*** Please tell me who you are.\n\nRun\n\n  git config --global user.email "you@example.com"\n  git config --global user.name "Your Name"\n\nto set your account's default identity.\nOmit --global to set the identity only in this repository.\n\nfatal: unable to auto-detect email address (got 'node@cloudchamber.(none)')\n` ],
    pid: 3772,
    stdout: '',
    stderr: `Committer identity unknown\n\n*** Please tell me who you are.\n\nRun\n\n  git config --global user.email "you@example.com"\n  git config --global user.name "Your Name"\n\nto set your account's default identity.\nOmit --global to set the identity only in this repository.\n\nfatal: unable to auto-detect email address (got 'node@cloudchamber.(none)')\n`
  }
##[error]Process completed with exit code 1.
