Skip to content

fix(gateway-test): preserve real SIGTERM coverage on Windows - #89

Merged
sayed710 merged 2 commits into
mainfrom
codex/windows-sigterm-harness
Oct 3, 2026
Merged

sayed710 merged 2 commits into
mainfrom
codex/windows-sigterm-harness

Conversation

@edwardnewgate710

Copy link
Copy Markdown
Collaborator

Windows child.kill('SIGTERM') force-terminates the trust worker without delivering its JavaScript signal handler, so the existing integration test fails with null !== 0. Gateway npm test now routes the same complete suite through Linux Docker on Windows and runs it directly on POSIX hosts and Ubuntu CI. The signal test remains a single discovered copy and requires the handler's structured log, exit code 0 and no terminating signal.

The test image follows the existing gateway dependency/build order. The topology guard verifies runtime discovery, Linux CI execution and change-filter coverage. Eight faulty alternatives are rejected by routing/source/discovery guards; five real Linux runtime mutants also fail, including forced kill and missing handler execution. Production shutdown behavior is unchanged.

Validation (sequential, zero unexpected skips):

  • Unchanged Windows RED: 1 failed, null !== 0, no shutdown-handler log.
  • Full build/lint, standalone gateway build/lint, all eight check:* guards.
  • 3,915 hermetic tests across 19 workspaces; 315 script tests; 2 PostgreSQL script integration tests.
  • Focused real Linux SIGTERM: 1 passed before and after mutations; Windows-routed and native Linux full gateway gates: 86 passed each.
  • Topology: 476 files across 21 suites; all eight required falsifications rejected; five runtime mutants killed and emitted files restored byte-identically.

Separate prerequisite from the frozen Arena work. Append-only Increment 87 and running/test architecture documentation included. Owner performs the manual merge; this PR must remain open until the exact-head CI, Qodo, Greptile and review-thread gates are satisfied.

@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6f703d78-a894-4868-bd2f-dd25a733b8f3
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Preserve real gateway SIGTERM test coverage on Windows

🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Route Windows gateway tests through Linux Docker while POSIX hosts run the same complete suite
 directly.
• Require the trust-worker test to prove real SIGTERM handler execution and a clean exit.
• Guard test discovery and CI routing; document the required services and platform behavior.
Diagram

graph TD
  A["Gateway npm test"] --> B["Platform router"] --> C{"Windows host?"}
  C -- "Yes" --> D["Linux Docker image"] --> E["Runtime suite"] --> F["SIGTERM contract"]
  C -- "No" --> E
  G["Ubuntu CI"] --> A
  H["Postgres Redis"] --> E
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Run the suite under WSL2 on Windows
  • ➕ Avoids rebuilding a test image for each Windows run.
  • ➖ Requires a separately provisioned Linux environment and dependency setup.
  • ➖ Makes the local test path less reproducible than the lockfile-based image.
2. Test SIGTERM only in Linux CI
  • ➕ Avoids Docker as a prerequisite for Windows gateway tests.
  • ➖ Windows developers cannot run the complete gateway gate locally.
  • ➖ A local passing result would not establish the shutdown contract.

Recommendation: Keep the PR's single-suite Docker route: it preserves local Windows coverage without weakening the signal assertion, while native POSIX and CI runs remain direct. WSL2 adds environment-specific setup, and CI-only coverage would leave Windows local results incomplete.

Files changed (10) +225 / -17

Bug fix (1) +51 / -0
run-gateway-tests.mjsRoute Windows gateway tests through Linux Docker +51/-0

Route Windows gateway tests through Linux Docker

• Runs test:runtime directly on POSIX hosts or builds and runs a unique Linux test image on Windows. Requires service URLs, maps loopback addresses for Docker Desktop, propagates failures and removes the temporary image.

scripts/run-gateway-tests.mjs

Tests (3) +123 / -8
check-test-topology.mjsGuard gateway signal-test discovery and execution routes +44/-3

Guard gateway signal-test discovery and execution routes

• Points gateway suite discovery at test:runtime and adds checks for the platform router, Linux CI job and triggers, test image, and real-signal assertions. Reports routing violations as topology-check failures.

scripts/check-test-topology.mjs

gateway-signal-route.test.mjsTest platform routing and reject weakened signal coverage +63/-0

Test platform routing and reject weakened signal coverage

• Tests the Docker and direct execution plans, service URL mapping, missing prerequisites and failed commands. Checks test reachability and verifies that faulty changes to the signal contract or CI routing are rejected.

scripts/test/gateway-signal-route.test.mjs

trust-worker-entrypoint.integration.test.tsRequire observable, clean trust-worker SIGTERM handling +16/-5

Require observable, clean trust-worker SIGTERM handling

• Fails direct Windows execution and missing database configuration instead of skipping the contract. Waits for child output to close, then requires successful SIGTERM delivery, exit code 0, no terminating signal and the structured shutdown-handler log.

services/gateway/test/trust-worker-entrypoint.integration.test.ts

Documentation (3) +37 / -7
PROJECT_STATE.mdRecord Increment 87 and its validation boundary +13/-1

Record Increment 87 and its validation boundary

• Documents the Windows SIGTERM failure, Linux routing approach, contract checks and reported validation. Separates this prerequisite from Arena work and notes that final review and CI gates remain outstanding.

docs/PROJECT_STATE.md

RUNNING.mdExplain gateway test prerequisites and platform routing +23/-6

Explain gateway test prerequisites and platform routing

• Adds the gateway production build to setup instructions and describes required PostgreSQL and Redis URLs. Explains direct POSIX execution, Windows Docker routing, and why forced Windows termination cannot satisfy the SIGTERM contract.

docs/RUNNING.md

0142-zero-test-skip-ci-architecture.mdDocument the gateway's single zero-skip runtime suite +1/-0

Document the gateway's single zero-skip runtime suite

• Clarifies that Windows and POSIX routes discover the same tests, with real handler execution required for SIGTERM coverage and topology checks guarding CI reachability.

docs/adr/0142-zero-test-skip-ci-architecture.md

Other (3) +14 / -2
ci.ymlTrigger gateway CI for signal-routing changes +1/-1

Trigger gateway CI for signal-routing changes

• Extends the gateway change filter to include the test image, platform router, topology guard and its test so changes to these files run the Linux gateway gate.

.github/workflows/ci.yml

Dockerfile.gateway-testBuild a Linux gateway test image +11/-0

Build a Linux gateway test image

• Adds a Node 22 image that installs both dependency trees, builds server packages and the gateway entrypoint, and runs the complete gateway runtime suite.

Dockerfile.gateway-test

package.jsonSeparate gateway test routing from suite execution +2/-1

Separate gateway test routing from suite execution

• Makes npm test invoke the platform router and moves the unchanged compile-and-zero-skip command into test:runtime, giving both platforms one suite to execute.

services/gateway/package.json

@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[High risk] Gateway test infrastructure now routes Windows through Docker.

The PR appears safe to merge based on the reviewed changes.

Summary

The PR routes the complete gateway test suite through Linux Docker on Windows while retaining direct execution on POSIX hosts.

  • The latest changes move dependency installation into a manifest-only image layer and build server packages before copying gateway source.
  • Database and Redis URLs now pass through the Docker child environment rather than appearing in Docker arguments.

Reviews (2) · Last reviewed commit: "fix(gateway-test): protect credentials a..."

Comment thread scripts/run-gateway-tests.mjs Outdated
@qodo-code-review

qodo-code-review Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Test credentials appear in process lists ✓ Resolved
Description
gatewayTestPlan places the full DATABASE_URL and REDIS_URL values in the arguments to `docker
run`, including any passwords embedded in those URLs. On Windows, the Docker command remains running
for the test suite, exposing those credentials in its command line to users or tools that can
inspect local processes.
Code

scripts/run-gateway-tests.mjs[R25-27]

+    { command: 'docker', args: ['run', '--rm', '--platform=linux/amd64',
+      '-e', `DATABASE_URL=${dockerServiceUrl(env.DATABASE_URL)}`,
+      '-e', `REDIS_URL=${dockerServiceUrl(env.REDIS_URL)}`, image] },
Relevance

●●● Strong

Credentials in persistent Docker command arguments create a concrete local exposure risk; security
findings are typically fixed.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The runner constructs docker run arguments containing both complete service URLs, then passes
those arguments to spawnSync. The route test demonstrates that a database URL can contain a
username and password.

scripts/run-gateway-tests.mjs[23-27]
scripts/run-gateway-tests.mjs[37-38]
scripts/test/gateway-signal-route.test.mjs[7-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Windows Docker command embeds database and Redis credentials in command-line arguments for the duration of the test run.
## Fix Focus Areas
- scripts/run-gateway-tests.mjs[23-27]
- scripts/run-gateway-tests.mjs[37-40]
## Recommended Fix
Rewrite the service URLs into the spawned Docker process's environment and use Docker's `-e DATABASE_URL -e REDIS_URL` form, which forwards those values without putting them in command-line arguments. Preserve the existing loopback mapping and test coverage.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Every Windows gateway test run reinstalls all dependencies ✓ Resolved
Description
Dockerfile.gateway-test copies all of packages/, services/ and scripts/ before the single
RUN npm ci && npm run build:server && npm ci --prefix services/gateway && npm run build ... layer.
Because of that order, any source edit invalidates the Docker cache for both npm ci installs and
the full build. So every npm test on Windows after a code change reinstalls both dependency trees
from scratch and rebuilds every server package.
Code

Dockerfile.gateway-test[R5-9]

+COPY package.json package-lock.json ./
+COPY packages/ ./packages/
+COPY services/ ./services/
+COPY scripts/ ./scripts/
+RUN npm ci && npm run build:server && npm ci --prefix services/gateway && npm run build --prefix services/gateway
Relevance

●●● Strong

Accepted history favors self-contained, efficient test workflows; dependency layers should precede
source copies.

PR-#57

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Docker caches each layer based on the inputs of the layers before it. The COPY lines for whole
source trees come before the install, so any file change under them forces the install to run again.
run-gateway-tests.mjs runs docker build on every invocation, so the slow path applies to each
local Windows test run.

Dockerfile.gateway-test[5-9]
scripts/run-gateway-tests.mjs[23-28]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Windows gateway test image reinstalls all npm dependencies on every source change, because the source trees are copied before `npm ci`.

## Fix Focus Areas
- Dockerfile.gateway-test[5-9]

## Recommended Fix
First copy only `package.json`, `package-lock.json`, every `packages/*/package.json`, and `services/gateway/package.json` and `services/gateway/package-lock.json`. Then run `npm ci` and `npm ci --prefix services/gateway`. After that, copy the full `packages/`, `services/` and `scripts/` trees and run `npm run build:server && npm run build --prefix services/gateway`. Keep the `check-test-topology` string check for `npm run build --prefix services/gateway` passing.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Loopback rewrite breaks on Docker without Desktop ✓ Resolved
Description
dockerServiceUrl rewrites loopback hosts to host.docker.internal, but the docker run step does
not add --add-host=host.docker.internal:host-gateway. That name resolves automatically only on
Docker Desktop. With a Docker Engine running directly inside WSL, or other non-Desktop engines, the
container cannot resolve the host, and DATABASE_URL and REDIS_URL connections fail.
Code

scripts/run-gateway-tests.mjs[R25-27]

+    { command: 'docker', args: ['run', '--rm', '--platform=linux/amd64',
+      '-e', `DATABASE_URL=${dockerServiceUrl(env.DATABASE_URL)}`,
+      '-e', `REDIS_URL=${dockerServiceUrl(env.REDIS_URL)}`, image] },
Relevance

●● Moderate

Potentially valid for non-Desktop engines, but documentation intentionally limits support to Docker
Desktop and lacks decisive precedent.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The URL rewrite always targets host.docker.internal, and the run arguments include no host
mapping. RUNNING.md admits the Docker Desktop assumption only in passing. Adding
--add-host=host.docker.internal:host-gateway also works on Docker Desktop, so the rewrite would
work on any engine.

scripts/run-gateway-tests.mjs[10-15]
scripts/run-gateway-tests.mjs[25-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Windows Docker route rewrites loopback service URLs to `host.docker.internal`, but that name resolves only on Docker Desktop.

## Fix Focus Areas
- scripts/run-gateway-tests.mjs[25-27]
- scripts/test/gateway-signal-route.test.mjs[16-16]

## Recommended Fix
Add `'--add-host=host.docker.internal:host-gateway'` to the `docker run` args before the `-e` flags, and update the expected args in the plan test.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: 🧠 Deep: This is a behavior-changing, cross-platform test/CI harness spanning routing, Docker builds, signal semantics, topology guards, and integration tests, with many independent paths where subtle defects could be missed in one pass.

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread scripts/run-gateway-tests.mjs Outdated
Comment thread Dockerfile.gateway-test Outdated
Comment thread scripts/run-gateway-tests.mjs Outdated
@edwardnewgate710

Copy link
Copy Markdown
Collaborator Author

@greptileai Please review the complete current PR head 907590c. The previous credential finding is fixed: service URLs now travel only through the child environment, while Docker arguments contain variable names. Please verify the final diff and report any remaining actionable findings.

@sayed710
sayed710 merged commit abab2bc into main Oct 3, 2026
12 checks passed
@sayed710
sayed710 deleted the codex/windows-sigterm-harness branch October 3, 2026 22:03
edwardnewgate710 pushed a commit that referenced this pull request Oct 3, 2026
Resolves docs/PROJECT_STATE.md only: #89's M15 Increment 87 entry and header lines are kept exactly; this PR's entry and its own header lines are renumbered to M15 Increment 88.
sayed710 added a commit that referenced this pull request Oct 4, 2026
* fix(web): enforce player ownership on board interaction

BoardInteraction fell back to the side to move when no player colour was
given, and the game route mounted its board without one and enabled input
whenever the game was not over. Spectators could select, drag and premove;
the board was interactive before the joined role arrived; an off-turn
player could pick up the opponent's pieces and queue premoves with them;
and a finished-game join briefly enabled input.

- Ownership is explicit: a colour, null (nobody) or 'side-to-move' (boards
  without players only). setPlayerColor drops the selection, a pending
  promotion and queued premoves on a real change; drop() re-checks the
  origin's owner. Legality stays oracle-driven for every variant.
- BoardView.setPlayerColor closes an open promotion chooser and abandons a
  drag; focus, keyboard navigation and flip are untouched. mountBoard
  exposes it with the same churn guard as setInputEnabled.
- The game route mounts fail-closed and derives owner and input from one
  GameSync snapshot from both onColor and onActionState, so callback order
  cannot open a window; a finished game latches.

Tests: core, view and route suites plus a backend Playwright spec with a
real two-player game and a spectator (click, keyboard and drag). The
finished-board step of illegal-move-feedback.spec.ts relied on the old
fallback and now tries White's own premove.

* docs: record M15 Increment 87 player board ownership

* fix(web): drop the trailing click of a gesture cut short by an owner change

Qodo on 6068e0b: BoardView.setPlayerColor cancelled an in-progress
pointer gesture, which removed its pointer-up handler, so the gesture's
trailing click reached tap() and could select the new owner's piece
(e.g. a swipe begun before `joined` landed). An owner change during a
gesture now suppresses that click, and every pointerdown resets the
suppression so an abandoned gesture cannot swallow the next real click.

* docs: record the Increment 87 review correction and its validation

* fix(web): clear click suppression when the release that set it makes no click

Greptile on a623b11: a gesture cut short by an owner change and released
off the board left suppressClick set, so the next click with no pointer
events (assistive technology, programmatic activation) was swallowed. An
ordinary drag dropped off the board leaked the same way.

Suppression now covers only the click the release itself produces: it
clears on the next tick, since the browser dispatches that click straight
after pointer-up. An owner change waits for the cut-short gesture's
release (or pointercancel) instead of setting a sticky flag; the wait ends
at that release, at the next pointerdown, or on destroy.

* docs: record the Greptile correction and Linux backend validation for Increment 87

* docs: correct Increment 87 over-claims and record the exact-head review

* fix(web): tie click suppression to the pointer that produced the click

Qodo and Greptile on 38e1bdd: clearing suppression on a next-tick timer
assumed a release's click arrives in the same task, which touch does not
guarantee, so a late touch click from a completed drag or from a gesture
an owner change cut short could still act. Qodo also found that the
cut-short wait ended on any pointer's release, so a second finger lifting
first let the original finger's click through.

Suppression now names the pointer whose next click must be swallowed and
matches the click's own pointerId whenever it arrives. A click with no
pointer behind it (pointerType '', e.g. assistive technology) is never
swallowed. The wait ends only on that pointer's release or cancel, a new
press by the same pointer, or destroy; a new press by the same pointer also
clears a stale entry from a release that made no click. Engines whose
clicks carry no pointer fields keep suppressing the release's own click.

* docs: record the pointer-matched suppression fix and its Linux validation

* fix(web): bound the no-pointer-id click fallback and ignore other pointers' drag releases

Independent exact-head review of 79686a5:
- On an engine whose click carries no pointerId, a stale suppression
  (e.g. a touch drag released off the board, which makes no click) matched
  the next tap's click and swallowed it once. In that fallback a click now
  counts as the release's own only if no press came after the release
  (a press counter, not a timer). Engines with pointer ids are unchanged.
- The drag's pointerup listener accepted any pointer, so another finger's
  release could drop the carried piece at its own coordinates. It now
  ignores releases from other pointers.

* docs: record the bounded click fallback and its Linux validation

* fix(web): end a drag on its own pointercancel and on a new press

Independent exact-head review of 066f046: drags never listened for
pointercancel, so a touch drag the browser took over (a pan, a system
gesture) stayed live with its floating piece; after the drag's pointerup
started ignoring other pointers, no later event recovered it. A new press
during a live drag also dropped the old drag's listeners without removing
its floating piece.

A drag now cancels on its own pointer's pointercancel, like a drop off the
board (selection cleared, floating piece removed). A press that never
became a drag keeps an existing selection. A new press calls cancelDrag()
before starting, so no floating piece is left behind.

* docs: record the drag cancellation fix and its Linux validation

* fix(web): a new press abandons another pointer's gesture without acting on it

Independent exact-head review of dd52355: a press during another pointer's
live drag only detached that drag's listeners. Its selection stayed, its
release went unwatched, and its trailing click reached tap() with the
piece still selected, so an abandoned drag could submit a move.

Owner changes and new presses now share abandonGesture(): wait for the
abandoned pointer's release and swallow its click, and undo a drag it
started (selection cleared, re-rendered). A re-press by the same pointer
(its release was lost) only resets, so its own click still works.

* docs: record the abandoned-gesture fix and its Linux validation

* fix(web): track abandoned-gesture waits and click suppressions per pointer

Independent exact-head review of b1441a4: a single wait slot and a single
suppression slot meant a third simultaneous pointer could defeat them
(abandoning A replaced the pending wait on C, so C's click still tapped),
and setInputEnabled(false) still only cancelled a drag.

Waits are now a set of awaited pointer ids served by one window listener
pair (attached while any is awaited), and suppressions a map of pointer id
to the press count at its release. Each pointer's release, click,
re-press and the legacy no-pointer-id fallback work as before, per pointer.
setInputEnabled(false) now abandons the gesture like an owner change.

The PR #87 test that asserted no pointerup listener after a game ends now
asserts the new contract: drag listeners go at once, and only the wait for
the abandoned release remains until that release.

* docs: record per-pointer gesture tracking and its Linux validation

* fix(web): tie a pointer-less click to the last released pointer

Greptile on 3bd6965: on an engine whose clicks carry no pointerId, the
fallback matched clicks with a press count shared by all fingers. If
finger A was abandoned after finger B pressed and A released without a
click, A's suppression was recorded at B's press count and B's genuine
tap was swallowed.

A click without a pointer id is now taken to be the last released
pointer's (a browser dispatches a click straight after its own pointer's
release) and is swallowed only if that pointer is suppressed; the shared
press counter is gone. An awaited pointer's pointercancel now ends its
wait without recording a suppression, since a cancelled pointer never
clicks (the optional LOW from the independent review of 3bd6965).
Engines with pointer ids are unchanged.

* docs: record the last-release click fallback and its Linux validation

* fix(web): bound click records and put abandoned clicks first on engines without pointer ids

Qodo on 8314d11: off-board drops (and, earlier, cancelled pointers)
recorded click suppressions that no click could ever consume, and touch
pointer ids are never reused, so records grew for the life of the board.
Releases off the board now record nothing, and pending records are capped
(oldest evicted), which also bounds on-board touch drags that make no click.

Greptile on 8314d11: on an engine whose clicks carry no pointerId, finger
A's abandoned gesture could produce a delayed click after finger B's
release, and the last-released rule attributed it to B, so it acted.
Without a pointer id a click cannot be attributed, so a choice is
unavoidable: safety first. While an abandoned gesture's click is pending,
a pointer-less click is taken to be that one (an abandoned gesture never
acts; at worst one genuine tap is swallowed and repeated). Drag-release
suppressions keep the last-released rule. Engines with pointer ids are
unchanged.

Tests now create stale entries with on-board no-click releases so every
protection stays reachable; a redundant re-add line and a dead write are
removed.

* docs: record bounded click records and the safety-first pointer-less click rule

* fix(web): only recent releases can claim a pointer-less click

Independent exact-head review of 39c2f9d: on an engine whose clicks carry
no pointerId (reportedly including Safari/iOS, unverified), an abandoned
touch that never produced a click left an abandoned record with no
expiry, so each later genuine tap was swallowed against one stale record,
up to the cap: dead taps spread over any amount of time.

Records now carry their release's time, and on the pointer-less path
records older than CLICK_WINDOW_MS (1 s: a release's click comes within
milliseconds, or ~300 ms when touch holds it for double-tap detection)
are dropped before matching. Times come from the events' own timeStamp.
Engines with pointer ids are unchanged.

* docs: record time-bounded pointer-less click matching and its Linux validation

* test(web): pin the pointer-less click window from both sides

Independent exact-head review of 242ad1c: only one test used explicit event times, so shrinking CLICK_WINDOW_MS (e.g. to 50 ms) or flipping its comparison went unnoticed. An abandoned release's click 300 ms later must still be swallowed, and a click just past the window must act.

* docs: record the pinned click-window tests and their Linux validation

* docs: record the merge with #89 and its Linux validation

* fix(web): an abandoned release swallows every pointer-less click in its window

On engines whose clicks carry no pointer id, a newer finger's click could
use up an abandoned finger's record before that finger's delayed click
arrived, letting the abandoned click act. The record now stays until its
window closes, so both ambiguous clicks are swallowed in either order.

* docs(web): say when a suppressed click keeps its record

* docs: record the abandoned-click fix and its Linux validation

* docs: keep one current Increment 88 line in the project-state header

---------

Co-authored-by: Hussein Mohamed <americanopbr@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants