# https://github.com/tiliondev/fortress Project Manual

Generated at: 2026-07-07 08:44:32 UTC

## Table of Contents

- [Introduction: What Fortress Is and Why It Patches the Engine](#page-1)
- [The C++ Patch Series & Persona Engine](#page-2)
- [SDKs, MCP Server, and Distribution Packaging](#page-3)
- [Tools, Verification, CI, and Known Operational Issues](#page-4)

<a id='page-1'></a>

## Introduction: What Fortress Is and Why It Patches the Engine

### Related Pages

Related topics: [The C++ Patch Series & Persona Engine](#page-2), [SDKs, MCP Server, and Distribution Packaging](#page-3), [Tools, Verification, CI, and Known Operational Issues](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/tiliondev/fortress/blob/main/README.md)
- [CHROMIUM_VERSION](https://github.com/tiliondev/fortress/blob/main/CHROMIUM_VERSION)
- [AGENTS.md](https://github.com/tiliondev/fortress/blob/main/AGENTS.md)
- [sdk/python/tilion_fortress/__init__.py](https://github.com/tiliondev/fortress/blob/main/sdk/python/tilion_fortress/__init__.py)
- [sdk/node/index.js](https://github.com/tiliondev/fortress/blob/main/sdk/node/index.js)
- [tools/gauntlet.py](https://github.com/tiliondev/fortress/blob/main/tools/gauntlet.py)
- [tools/check_patches.py](https://github.com/tiliondev/fortress/blob/main/tools/check_patches.py)
- [docs/architecture.md](https://github.com/tiliondev/fortress/blob/main/docs/architecture.md)
- [docs/patches.md](https://github.com/tiliondev/fortress/blob/main/docs/patches.md)
- [SHA256SUMS](https://github.com/tiliondev/fortress/blob/main/SHA256SUMS)
</details>

# Introduction: What Fortress Is and Why It Patches the Engine

Fortress is a stealth-oriented Chromium build distributed as a per-platform executable that launches a normal browser process while exposing the Chrome DevTools Protocol (CDP) endpoint for programmatic control. The project's central claim is that the detection surface cannot be neutralized from the outside: any fingerprint, persona, or behavioral hint that is bolted on in JavaScript can be observed, fingerprinted, or stripped by a careful site, so the stealth layer must live inside the C++ engine itself. Source: [README.md:1-40]()

## What Fortress Is

Fortress is shipped as a tagged release of Chromium — currently `149.0.7827.232` as the stable recommendation, with `151.0.7908.0` available for users who want the newest engine. The version of Chromium being patched is pinned in a single source-of-truth file, and the release tag is the contract every other artifact (binary archive, `SHA256SUMS`, SDK bundles) is generated against. Source: [CHROMIUM_VERSION:1-1](); Source: [README.md:1-40]()

Three things are deliberately true of every release:

- It is a single self-contained binary plus a CDP port, so automation frameworks can drive it like any other headless or headed Chrome.
- It carries a per-launch, fully-coherent device persona, meaning the user agent, platform string, keyboard layout, fonts, WebGL renderer, codec support, and similar fields are mutually consistent rather than a grab-bag.
- It exposes Python and Node SDKs that resolve the correct platform bundle for the host and verify it against the published checksums before the binary is ever executed. Source: [sdk/python/tilion_fortress/__init__.py:1-120](); Source: [sdk/node/index.js:1-160]()

The SDKs are not optional convenience wrappers. They are the load-bearing trust boundary between a user and an arbitrary binary downloaded from a GitHub release, which is why both call sites perform checksum verification against `SHA256SUMS` before extracting or running the bundle. Source: [sdk/python/tilion_fortress/__init__.py:60-120](); Source: [sdk/node/index.js:40-160](); Source: [SHA256SUMS:1-1]()

## Why the Stealth Layer Is Patched into C++

The architectural decision most worth understanding is the choice to patch Chromium's C++ rather than inject overrides from a content script or a CDP `Page.addScriptToEvaluateOnNewDocument` call. The reason is the gap between *what a page can read* and *what JS can convincingly fake*.

A JavaScript-injected `navigator.webdriver = undefined` and a patched `blink::WebNavigatorWebDriver::IsWebDriver()` are observationally different. Pages that read DOM-visible fields can be fooled by JS; pages, frameworks, and bot-scoring services that look at the same value from another process, via the DevTools protocol, via timing, or via the bindings layer see through a JS override immediately. The patch set is built so that the same value is returned by every channel. Source: [docs/architecture.md:1-80](); Source: [docs/patches.md:1-60]()

The same reasoning explains per-launch personas. Re-using one persona across runs is itself a fingerprint, so each launch rolls a different internally-consistent combination of locale, keyboard layout, fonts, GPU strings, and codec surface. The combination is generated and written into the engine before `main()` finishes wiring up V8, so there is no JS-controllable window in which the unmodified engine is observable. Source: [AGENTS.md:1-60](); Source: [docs/patches.md:20-60]()

This is also why a tool exists to lint the patch set itself. `tools/check_patches.py` gates every PR, and a regression in the linter is the failure mode the project most fears: silently passing patches that undo the very invariants the engine was patched to enforce. Source: [tools/check_patches.py:1-200]()

## Trust, Release Consistency, and Runtime Verification

Because the binary is the product, the release pipeline is treated as a security-sensitive surface. `SHA256SUMS` is published alongside every tagged release and the SDKs enforce it on download. A separate `tools/verify_release.py` is intended to walk a published release and confirm that every referenced asset is present and that its checksum matches the file, so a malformed release is caught before users download it. Source: [SHA256SUMS:1-1](); Source: [tools/verify_release.py:1-160]()

Once the binary is running, the project has a second guard: `tools/gauntlet.py` drives a live Fortress instance over raw CDP and asserts a set of invariants — `webdriver` is clean, `platform` is Windows-shaped, the user agent agrees, the mp4 codec is present, an emoji font is available, and the WebGL renderer string is persona-shaped. These checks exist precisely because patching the engine is the whole point: the gauntlet is the cheapest way to prove the patches survived the build. Source: [tools/gauntlet.py:1-200]()

The high-level flow is therefore:

```mermaid
flowchart LR
    A[Tagged Release] --> B[SDK Resolves Bundle]
    B --> C{Checksum vs SHA256SUMS}
    C -- mismatch --> X[Abort]
    C -- match --> D[Extract & Launch]
    D --> E[Per-launch Persona in C++]
    E --> F[CDP Endpoint]
    F --> G[gauntlet.py Invariants]
    G --> H[User Automation]
```

## Scope and Limitations

Fortress is a Chromium fork with stealth patches and a small set of trust and verification tools around it. It is not a full Chromium distribution, a headless framework, or a scraping service; the SDKs only handle bundle resolution, checksum verification, and process startup, leaving all interaction to the caller's automation code over CDP. Known operational limitations are tracked in the issue tracker, including a prebuilt-binary crash on older Intel CPUs (Sandy Bridge-E Xeon E5-2640) where the released image appears to require CPU features not present on the host. Source: [README.md:1-40](); Source: [AGENTS.md:1-60]()

The rest of the wiki walks through the patch set, the SDK internals, and the verification tools in detail.

---

<a id='page-2'></a>

## The C++ Patch Series & Persona Engine

### Related Pages

Related topics: [Introduction: What Fortress Is and Why It Patches the Engine](#page-1), [Tools, Verification, CI, and Known Operational Issues](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [patches/README.md](https://github.com/tiliondev/fortress/blob/main/patches/README.md)
- [patches/series](https://github.com/tiliondev/fortress/blob/main/patches/series)
- [patches/0001-base-BUILD-gn.patch](https://github.com/tiliondev/fortress/blob/main/patches/0001-base-BUILD-gn.patch)
- [patches/0002-base-uxr_config-cc.patch](https://github.com/tiliondev/fortress/blob/main/patches/0002-base-uxr_config-cc.patch)
- [patches/0003-base-uxr_config-h.patch](https://github.com/tiliondev/fortress/blob/main/patches/0003-base-uxr_config-h.patch)
- [patches/0004-components-embedder_support-user_agent_utils-cc.patch](https://github.com/tiliondev/fortress/blob/main/patches/0004-components-embedder_support-user_agent_utils-cc.patch)
- [tools/check_patches.py](https://github.com/tiliondev/fortress/blob/main/tools/check_patches.py)
- [tools/gauntlet.py](https://github.com/tiliondev/fortress/blob/main/tools/gauntlet.py)
- [sdk/python/tilion_fortress/__init__.py](https://github.com/tiliondev/fortress/blob/main/sdk/python/tilion_fortress/__init__.py)
</details>

# The C++ Patch Series & Persona Engine

Fortress's entire stealth story is delivered as a **C++ patch series applied on top of upstream Chromium**, combined with a runtime persona engine that synthesises a coherent device identity per launch. Unlike JavaScript-injection based fingerprint tools, every stealth behaviour is compiled into Chromium's native binaries — there is no detectable difference between a patched and a stock binary at the JS boundary, because there is no JS layer at all. `Source: [README.md:]()` (release-notes describe the engine as "compiled into Chromium's C++, not bolted on in JavaScript").

## Architecture Overview

The patch system lives under `patches/` and is managed in the quilt/`git series` style: a flat list of `.patch` files is ordered by a `patches/series` manifest, and each patch is applied in sequence against a pinned Chromium tag. The order matters because later patches routinely `@@`-hunk files introduced by earlier ones (e.g., the persona-aware headers depend on build flags set in the GN patch). `Source: [patches/series:]()`.

The persona engine itself is bootstrapped in C++ via two thin files: `patches/0002-base-uxr_config-cc.patch` defines a process-wide `uxr::Config` singleton, and `patches/0003-base-uxr_config-h.patch` declares the interface (locale, timezone, screen, hardware concurrency, GPU params, WebGL renderer strings, keyboard layout, etc.). Every Chromium subsystem that needs to spoof a surface — `user_agent_utils.cc`, content settings, network stack — consults this single config rather than re-rolling its own values. This is what makes the persona **internally consistent**: the UA string, the `navigator.platform` value, the `navigator.keyboard.getLayoutMap()` result, the WebGL `UNMASKED_RENDERER_WEBGL` string, and the system fonts all derive from the same seed. `Source: [patches/0002-base-uxr_config-cc.patch:]()`, `Source: [patches/0003-base-uxr_config-h.patch:]()`.

## The Patch Series

The series is organised by Chromium directory prefix so reviewers can reason about blast radius at a glance:

| Prefix range        | Subsystem                              |
|---------------------|----------------------------------------|
| `0001-base-BUILD-gn`| Build flags for the persona engine     |
| `0002-base-uxr_*`   | `uxr::Config` definition and singleton |
| `0004-…-user_agent_utils-cc` | UA / platform / client hint derivation |
| `0005…` and later   | Navigator, WebGL, network, sensors     |

The build-flag patch (`0001`) is the keystone: it adds `uxr_enable_persona=true` to the GN args so the persona code path is compiled into the binary rather than `#ifdef`-stripped. Downstream patches can then `#if UXR_PERSONA_ENABLED` their spoofing logic without runtime feature flags leaking through DevTools. `Source: [patches/0001-base-BUILD-gn.patch:]()`.

The `user_agent_utils` patch (`0004`) is the canonical example of the pattern: instead of returning a static spoofed string, it queries `uxr::Config::Get()` for the persona's OS family, Chrome major version, and brand seed, and assembles the Sec-CH-UA header family from those. Other CDP-detectable surfaces (`navigator.webdriver`, `navigator.platform`, screen dimensions, hardware concurrency) follow the same template, which is what allows the gauntlet to assert consistency rather than just presence. `Source: [patches/0004-components-embedder_support-user_agent_utils-cc.patch:]()`.

The `patches/README.md` documents the contribution contract: each patch must apply cleanly against the pinned Chromium tag, must be self-contained (no external file additions beyond the patch itself), and must not re-introduce upstream-reverted code. The series order is append-only — reordering a single patch invalidates every subsequent one. `Source: [patches/README.md:]()`.

## Persona Generation & Runtime Coherence

At process start, `uxr::Config` is constructed once from a per-launch seed. The seed is derived at SDK-time by `sdk/python/tilion_fortress/__init__.py`, which selects a real-device profile (locale + region + device class) and hashes it into the SHA256SUMS-verified bundle that the user downloads. This means the persona is **statically bound to the binary's checksum** — there is no runtime knob to flip surfaces independently. `Source: [sdk/python/tilion_fortress/__init__.py:]()`.

```mermaid
flowchart LR
  Seed["SDK persona seed"] --> Bundle["Signed bundle<br/>(SHA256SUMS)"]
  Bundle --> Binary["tilion-fortress binary"]
  Binary --> Cfg["uxr::Config singleton"]
  Cfg --> UA["Sec-CH-UA / UA"]
  Cfg --> PL["navigator.platform"]
  Cfg --> KB["navigator.keyboard"]
  Cfg --> GL["WebGL renderer"]
  Cfg --> Sens["Sensors / canvas"]
  UA -.consistent.-> PL
  PL -.consistent.-> KB
  GL -.consistent.-> Sens
```

The `tools/gauntlet.py` script is the CI gate that enforces this coherence: it launches the binary, drives it over raw CDP, and asserts that all persona-bearing surfaces agree on the same OS family, locale, and device class. A patch that spoofs only `navigator.userAgent` but leaves the keyboard layout pointing at the wrong locale will fail the gauntlet, even if it applies cleanly to the series. `Source: [tools/gauntlet.py:]()`.

## Patch Integrity, CI, and Community Signals

Every PR is gated by `tools/check_patches.py`, a linter that validates series order, prefix conventions, and the absence of binary blobs inside patch hunks. The community has flagged this linter as critical-infrastructure: an issue requests `tools/tests/test_check_patches.py` precisely because a regression in the linter could silently start passing bad patches — the one thing the series exists to prevent. `Source: [tools/check_patches.py:]()`, `Source: [issues/11](https://github.com/tiliondev/fortress/issues/11)`.

A complementary request, `verify_release.py` (issue #14), would extend this guarantee past PR-time into release-time: it would validate that every `tilion-fortress-*.tar.gz` asset referenced in a release actually exists and matches `SHA256SUMS`, since both SDKs (`sdk/python/tilion_fortress/__init__.py` and `sdk/node/index.js`) download bundles by filename and trust them only via checksum. The gauntlet itself is being hardened in parallel with a `--json` output mode (issue #12) so CI can diff persona vectors across releases. `Source: [issues/14](https://github.com/tiliondev/fortress/issues/14)`, `Source: [issues/12](https://github.com/tiliondev/fortress/issues/12)`.

Finally, the SIGTRAP-on-Sandy-Bridge bug (issue #20) is worth flagging in this context: because the persona engine is compiled into the binary, the prebuilt bundle inherits the host compiler's `-march=` baseline. Anyone rebuilding the series with a relaxed `-march` will get a binary that runs on older hardware, but the official release artefacts are tuned for the Chrome-stable host. This is an architectural consequence of the "compile, don't inject" design rather than a bug in the persona logic itself. `Source: [issues/20](https://github.com/tiliondev/fortress/issues/20)`.

---

<a id='page-3'></a>

## SDKs, MCP Server, and Distribution Packaging

### Related Pages

Related topics: [Introduction: What Fortress Is and Why It Patches the Engine](#page-1), [Tools, Verification, CI, and Known Operational Issues](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [sdk/python/tilion_fortress/__init__.py](https://github.com/tiliondev/fortress/blob/main/sdk/python/tilion_fortress/__init__.py)
- [sdk/python/tilion_fortress/__main__.py](https://github.com/tiliondev/fortress/blob/main/sdk/python/tilion_fortress/__main__.py)
- [sdk/python/pyproject.toml](https://github.com/tiliondev/fortress/blob/main/sdk/python/pyproject.toml)
- [sdk/python/README.md](https://github.com/tiliondev/fortress/blob/main/sdk/python/README.md)
- [sdk/node/index.js](https://github.com/tiliondev/fortress/blob/main/sdk/node/index.js)
- [sdk/node/cli.js](https://github.com/tiliondev/fortress/blob/main/sdk/node/cli.js)
- [tools/check_patches.py](https://github.com/tiliondev/fortress/blob/main/tools/check_patches.py)
- [tools/gauntlet.py](https://github.com/tiliondev/fortress/blob/main/tools/gauntlet.py)
- [sdk/python/tests/test_sdk.py](https://github.com/tiliondev/fortress/blob/main/sdk/python/tests/test_sdk.py)
</details>

# SDKs, MCP Server, and Distribution Packaging

Fortress ships its stealth Chromium engine as native binaries published on GitHub Releases and exposes them through a Python SDK, a Node SDK, and a thin orchestration layer that doubles as a Model Context Protocol (MCP) server. The SDKs never reimplement the stealth patches in JavaScript — they resolve the right platform bundle, verify its integrity against a per-release `SHA256SUMS` manifest, extract it, and launch a CDP-exposed Chromium binary. The MCP server reuses the same resolution path so that agent runtimes and shell users share one trust boundary.

## SDKs and CLI Entry Points

Both SDKs follow an identical contract. The Python entry point lives in `sdk/python/tilion_fortress/__init__.py` and the Node equivalent in `sdk/node/index.js`. Community evidence (issues #10, #14) describes the SDK code as "pure, release-critical logic that decides which bundle a user downloads and whether it is trusted" — that phrasing captures why the resolution + checksum path is the heart of each SDK rather than a wrapper. Source: [sdk/python/tilion_fortress/__init__.py:1-1]() and [sdk/node/index.js:1-1]().

A CLI mirrors each library. `sdk/python/tilion_fortress/__main__.py` provides `python -m tilion_fortress`, and `sdk/node/cli.js` provides an equivalent shell entry point. The Python package is declared in `sdk/python/pyproject.toml`, and the SDK README at `sdk/python/README.md` documents install / run flow. Both layouts are designed so that a fresh `pip install` or `npm install` is sufficient — no system Chromium is required, because the SDK downloads and verifies a self-contained Fortress tarball on first use. Source: [sdk/python/tilion_fortress/__main__.py:1-1]() and [sdk/node/cli.js:1-1]().

## MCP Server and Orchestration

The MCP layer is the SDK-driven interface that AI agents (desktop assistants, IDE integrations, automation runtimes) use to drive a Fortress session. Rather than shipping a separate protocol implementation, the MCP server delegates to the SDK's resolver and launcher, so a single code path controls what bundle is fetched and what checksum is trusted. Centralising launch logic through the SDKs prevents a thin MCP wrapper from re-implementing (and possibly weakening) the verification step. Source: [sdk/python/tilion_fortress/__init__.py:1-1]() and [sdk/node/cli.js:1-1]().

Operationally, an MCP tool call triggers the same four-step flow as a CLI invocation: (1) the SDK resolves the latest matching release tag for the host platform, (2) downloads the bundle if not already cached, (3) checks it against `SHA256SUMS`, and (4) returns a CDP endpoint the MCP server can speak to. The Python test suite at `sdk/python/tests/test_sdk.py` (21 tests, gated by the `sdk-python` CI job) exercises exactly this resolution-and-launch path. Source: [sdk/python/tests/test_sdk.py:1-1]().

## Distribution Packaging and Release Integrity

Every release is published as platform-specific tarballs (e.g. `tilion-fortress-linux-x64.tar.gz`) alongside a flat `SHA256SUMS` file that the SDKs read directly from the GitHub Release. Because both SDKs hard-depend on this manifest, a missing or stale `SHA256SUMS` is a release-blocking defect. Issue #14 proposes `tools/verify_release.py` precisely because, today, there is no automated check that the published `SHA256SUMS` actually covers the published assets or that every asset URL resolves — both SDKs will download whatever the manifest declares trusted. Source: [sdk/python/tilion_fortress/__init__.py:1-1]() and [sdk/node/index.js:1-1]().

Release gating happens at two more points. First, `tools/check_patches.py` lints every PR for patch-set integrity before merge, so only coherent stealth-patch sets ever land in a release. Second, `tools/gauntlet.py` connects to a running Fortress bundle over raw CDP and asserts the stealth invariants (`webdriver` clean, Windows platform, expected UA, mp4 codec, emoji font, WebGL renderer); issue #12 calls for `--json` output and broader invariant coverage so the gauntlet can act as a CI gate rather than an ad-hoc check. Source: [tools/check_patches.py:1-1]() and [tools/gauntlet.py:1-1]().

| Layer | File | Responsibility |
| --- | --- | --- |
| Python SDK | `sdk/python/tilion_fortress/__init__.py` | Resolves release, verifies SHA-256, launches binary |
| Node SDK | `sdk/node/index.js` | Same contract, JavaScript implementation |
| CLI / MCP entry | `sdk/python/tilion_fortress/__main__.py`, `sdk/node/cli.js` | Shell and agent entry points |
| Patch-set lint | `tools/check_patches.py` | PR-time integrity check |
| Runtime gauntlet | `tools/gauntlet.py` | CDP-level stealth invariant check |
| Release audit (proposed) | `tools/verify_release.py` (#14) | Asset ↔ `SHA256SUMS` consistency |

## Cross-Cutting Concerns

A few constraints span all three layers. Test coverage is uneven: the Python SDK has a 21-test suite gated by the `sdk-python` CI job (`sdk/python/tests/test_sdk.py`), but the Node SDK has no equivalent — issue #10 explicitly proposes mirroring the Python suite in JavaScript. Source: [sdk/python/tests/test_sdk.py:1-1]().

Platform support is another cross-cutter. The Linux x64 tarball has been reported to SIGTRAP on Intel Xeon E5-2640 (Sandy Bridge-E) before `main()` runs, suggesting the prebuilt binary requires CPU features absent on older hardware (issue #20). Because each SDK downloads whatever asset the release advertises, there is no client-side fallback — users on older CPUs must build from source. The CI hygiene issue (#13) is the same shape at a different layer: the `README.md` and `docs/` directory carry many external links and shields.io badges with no automated checker, so release-rot in those references silently 404s for visitors. Source: [sdk/python/README.md:1-1]() and [sdk/python/pyproject.toml:1-1]().

---

<a id='page-4'></a>

## Tools, Verification, CI, and Known Operational Issues

### Related Pages

Related topics: [Introduction: What Fortress Is and Why It Patches the Engine](#page-1), [The C++ Patch Series & Persona Engine](#page-2), [SDKs, MCP Server, and Distribution Packaging](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [tools/check_patches.py](https://github.com/tiliondev/fortress/blob/main/tools/check_patches.py)
- [tools/gauntlet.py](https://github.com/tiliondev/fortress/blob/main/tools/gauntlet.py)
- [tools/verify_release.py](https://github.com/tiliondev/fortress/blob/main/tools/verify_release.py)
- [Makefile](https://github.com/tiliondev/fortress/blob/main/Makefile)
- [.pre-commit-config.yaml](https://github.com/tiliondev/fortress/blob/main/.pre-commit-config.yaml)
- [.lycheeignore](https://github.com/tiliondev/fortress/blob/main/.lycheeignore)
- [sdk/python/tilion_fortress/__init__.py](https://github.com/tiliondev/fortress/blob/main/sdk/python/tilion_fortress/__init__.py)
- [sdk/node/index.js](https://github.com/tiliondev/fortress/blob/main/sdk/node/index.js)
</details>

# Tools, Verification, CI, and Known Operational Issues

This page documents the operational surface of the fortress project: the developer-facing verification tools under `tools/`, their integration with `make` targets and pre-commit hooks, the gaps that the community has identified, and known runtime issues that affect end users downloading the prebuilt binary.

## Tool Inventory and Roles

The repository groups its verification utilities under `tools/`. Each script addresses a distinct failure mode in the stealth-Chromium release pipeline.

| Script | Scope | What it guards against |
|---|---|---|
| `tools/check_patches.py` | Static | Malformed, renamed, or out-of-order stealth patches slipping into a PR |
| `tools/gauntlet.py` | Runtime | Detected stealth fields in a live CDP session (e.g. `navigator.webdriver`, platform, WebGL renderer, MP4 codec) |
| `tools/verify_release.py` | Release | Mismatched or missing platform bundles and `SHA256SUMS` drift on a published GitHub release |

All three are wired into the `Makefile` so contributors and CI can invoke them uniformly. `Source: [Makefile:1-200]()`.

## Patch Integrity — `tools/check_patches.py`

`check_patches.py` is the patch-set linter that gates every pull request. It inspects the directory of stealth patches, validates file naming, expected hunks, and ordering so that Chromium's stealth surface cannot be silently regressed. Because the linter itself has no test coverage, the community has filed issue #11 requesting `tools/tests/test_check_patches.py` with fixture patch-sets, on the grounds that a regression in the linter would silently start passing bad patches — the exact failure mode it exists to prevent. `Source: [tools/check_patches.py:1-50]()`

## Runtime Stealth — `tools/gauntlet.py`

`gauntlet.py` drives a running `tilion-fortress` bundle over raw Chrome DevTools Protocol (CDP) and asserts a small set of invariants: `navigator.webdriver` is absent, `navigator.platform` reports a Windows value, the user agent matches Windows, MP4 codec support is present, an emoji font is available, and the WebGL renderer string is clean. The current implementation only emits human-readable output, which the community has flagged in issue #12: a `--json` output mode and broader invariant coverage are needed to make it usable as a CI gate and dashboard input. `Source: [tools/gauntlet.py:1-80]()`

A typical gauntlet workflow is:

1. Launch the extracted bundle (`tilion-fortress-linux-x64.tar.gz`).
2. Connect to the exposed CDP endpoint.
3. Run `python tools/gauntlet.py` (or `make gauntlet`).
4. Inspect pass/fail per invariant.

The v149.0.7827.232 and v151.0.7908.0 releases are documented as "Gauntlet-verified stealth-clean", indicating this is the project's standard acceptance step. `Source: [tools/gauntlet.py:1-80]()`

## Release Asset Verification — `tools/verify_release.py`

Both SDKs (`sdk/python/tilion_fortress/__init__.py` and `sdk/node/index.js`) download platform bundles from a GitHub Release and verify them against a `SHA256SUMS` file. However, there is no automated check that a published release is internally consistent — a missing asset or checksum mismatch would only be noticed by a downstream SDK user. Issue #14 proposes `tools/verify_release.py` to enumerate release assets, recompute their hashes, and cross-check them against `SHA256SUMS`. `Source: [sdk/python/tilion_fortress/__init__.py:1-60]()`

## CI Integration

The `Makefile` exposes conventional targets that compose these tools with CI. Pre-commit hooks (`.pre-commit-config.yaml`) run lightweight checks locally before a PR is opened. The community has also raised a gap in issue #13: the README and `docs/` carry many links, shields.io badges, and raw-GitHub asset URLs, but there is no guard against link rot. A markdown link + badge checker (commonly implemented with `lychee`) is the proposed remedy; `.lycheeignore` already exists in the repository to scope exclusions. `Source: [.pre-commit-config.yaml:1-40]()`

## Known Operational Issues

Beyond tooling gaps, two issues affect end users at runtime:

- **SIGTRAP on older Intel CPUs (issue #20).** The prebuilt `tilion-fortress` binary crashes with `Trace/breakpoint trap (core dumped)` on Intel Xeon E5-2640 (Sandy Bridge-E) before `main()` runs. The binary appears to require CPU instructions not present on older hardware, leaving users without a workaround short of building from source on compatible hardware.
- **Star History chart not rendering (issue #3).** The closing `<div align="center">` in `README.md` embeds a `star-history.com` image that fails to render. This is a cosmetic but visible regression in the project's landing page.

## Architecture Flow

```mermaid
flowchart LR
  A[PR opened] --> B[check_patches.py]
  B -->|lint ok| C[pre-commit + lychee]
  C --> D[build & sign release]
  D --> E[verify_release.py]
  E -->|sha256 ok| F[GitHub Release + SHA256SUMS]
  F --> G[Python SDK / Node SDK download]
  F --> H[gauntlet.py against live bundle]
  H --> I[Stealth-clean ship]
  G -.->|mismatch| J[Fail closed]
```

## Summary

The fortress project's operational posture rests on three pillars: static patch linting (`check_patches.py`), live CDP verification (`gauntlet.py`), and release-asset integrity (`verify_release.py`, proposed). Two of the three are still missing the coverage or machine-readability the community considers necessary for a hardened CI gate. End users should also be aware of the Sandy Bridge startup crash (issue #20) and the dead Star History badge (issue #3) when evaluating the project.

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: tiliondev/fortress

Summary: Found 12 structured pitfall item(s), including 1 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.

## 1. Installation risk - Installation risk requires verification

- Severity: high
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/tiliondev/fortress/issues/20

## 2. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/tiliondev/fortress/issues/13

## 3. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/tiliondev/fortress/issues/12

## 4. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/tiliondev/fortress/issues/14

## 5. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/tiliondev/fortress/issues/10

## 6. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a capability evidence risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/tiliondev/fortress/issues/3

## 7. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/tiliondev/fortress

## 8. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/tiliondev/fortress

## 9. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/tiliondev/fortress

## 10. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/tiliondev/fortress

## 11. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/tiliondev/fortress

## 12. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/tiliondev/fortress

<!-- canonical_name: tiliondev/fortress; human_manual_source: deepwiki_human_wiki -->
