Skip to content

Commit c437f20

Browse files
committed
build: separate the runtime into its own repository
1 parent f2ff3b9 commit c437f20

17 files changed

Lines changed: 824 additions & 6 deletions

.github/workflows/ci.yml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Pull-request and main-branch gate.
2+
#
3+
# The sweep is split into independent jobs so a failure names its own lane and the slow native lanes
4+
# run in parallel with the fast metadata ones. Within a job every gate step carries `if: always()`,
5+
# preserving the property `npm run check` has locally: these gates are independent, so stopping at
6+
# the first failure would hide the rest.
7+
#
8+
# The runtime lanes need no Node. Only the metadata gates and the pinned-compiler integration lane
9+
# do, and only the latter rehydrates a sibling checkout.
10+
name: CI
11+
12+
on:
13+
pull_request:
14+
push:
15+
branches: [main]
16+
17+
permissions:
18+
contents: read
19+
20+
concurrency:
21+
group: ci-${{ github.ref }}
22+
cancel-in-progress: true
23+
24+
jobs:
25+
bazel-runtime:
26+
name: Bazel runtime (${{ matrix.os }})
27+
strategy:
28+
fail-fast: false
29+
matrix:
30+
include:
31+
- os: ubuntu-latest
32+
toolchain_config: local-posix
33+
- os: macos-latest
34+
toolchain_config: local-posix
35+
- os: windows-latest
36+
toolchain_config: local-msvc
37+
runs-on: ${{ matrix.os }}
38+
steps:
39+
- uses: actions/checkout@v4
40+
# setup-bazel 0.19.0 is pinned so the build bootstrap is reproducible as well as the Bazel version.
41+
- uses: bazel-contrib/setup-bazel@c5acdfb288317d0b5c0bbd7a396a3dc868bb0f86
42+
with:
43+
bazelisk-cache: true
44+
cache-save: ${{ github.event_name != 'pull_request' }}
45+
disk-cache: bazel-runtime-${{ matrix.os }}
46+
repository-cache: true
47+
- name: Build and test runtime
48+
run: bazel --config=${{ matrix.toolchain_config }} --config=ci test //...
49+
- name: Run Bazel performance smoke gate
50+
if: matrix.os == 'ubuntu-latest'
51+
run: bazel --config=${{ matrix.toolchain_config }} --config=release test //benchmarks:runtime_benchmark
52+
53+
cpp-runtime:
54+
name: C++ runtime (${{ matrix.compiler }})
55+
strategy:
56+
fail-fast: false
57+
matrix:
58+
include:
59+
- compiler: GCC
60+
os: ubuntu-latest
61+
cmake-args: -DCMAKE_CXX_COMPILER=g++ -DFLIGHT_CPP_BUILD_BENCHMARKS=ON
62+
- compiler: GCC ASan+UBSan
63+
os: ubuntu-latest
64+
cmake-args: -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Debug -DFLIGHT_CPP_ENABLE_SANITIZERS=ON
65+
- compiler: Clang
66+
os: ubuntu-latest
67+
cmake-args: -DCMAKE_CXX_COMPILER=clang++
68+
- compiler: Clang shared ABI
69+
os: ubuntu-latest
70+
cmake-args: -DCMAKE_CXX_COMPILER=clang++ -DBUILD_SHARED_LIBS=ON
71+
- compiler: AppleClang
72+
os: macos-latest
73+
cmake-args: -DCMAKE_CXX_COMPILER=clang++
74+
- compiler: MSVC
75+
os: windows-latest
76+
cmake-args: ''
77+
- compiler: MSVC shared ABI
78+
os: windows-latest
79+
cmake-args: -DBUILD_SHARED_LIBS=ON
80+
runs-on: ${{ matrix.os }}
81+
steps:
82+
- uses: actions/checkout@v4
83+
- name: Configure runtime
84+
run: cmake -S . -B build -DBUILD_TESTING=ON -DFLIGHT_CPP_WARNINGS_AS_ERRORS=ON -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake-args }}
85+
- name: Build runtime
86+
run: cmake --build build --config Release
87+
- name: Test runtime
88+
run: ctest --test-dir build --build-config Release --output-on-failure
89+
- name: Install runtime
90+
run: cmake --install build --config Release --prefix out/install
91+
- name: Configure installed consumer
92+
run: cmake -S tests/consumer -B out/consumer -DCMAKE_PREFIX_PATH=${{ github.workspace }}/out/install -DCMAKE_BUILD_TYPE=Release
93+
- name: Build installed consumer
94+
run: cmake --build out/consumer --config Release
95+
- name: Test installed consumer
96+
run: ctest --test-dir out/consumer --build-config Release --output-on-failure
97+
98+
metadata:
99+
name: Release metadata gates
100+
runs-on: ubuntu-latest
101+
steps:
102+
- uses: actions/checkout@v4
103+
- uses: actions/setup-node@v4
104+
with:
105+
node-version: 22
106+
- run: npm run abi:check
107+
if: always()
108+
- run: npm run build:check
109+
if: always()
110+
- run: npm run release:check
111+
if: always()
112+
113+
pinned-compiler:
114+
name: Pinned compiler integration
115+
runs-on: ubuntu-latest
116+
steps:
117+
- uses: actions/checkout@v4
118+
- uses: actions/setup-node@v4
119+
with:
120+
node-version: 22
121+
- name: Rehydrate pinned checkouts
122+
run: npm run rehydrate
123+
- name: Compile the pinned compiler's emitted C++
124+
run: npm run compile:check

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
/CMakeUserPresets.json
44
/.bazelrc.local
55
/bazel-*
6+
/.dependencies/
7+
/node_modules/

AGENTS.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# flight-cpp contributor contract
22

3-
`flight-cpp` is an independently buildable C++20 runtime incubator. It is versioned beside the compiler only while their contract is changing quickly; do not couple it to the npm workspace, compiler implementation modules, or paths outside this directory.
3+
`flight-cpp` is an independently buildable C++20 runtime. It was incubated inside `flight-compiler` and carries that history; it is now its own repository. Do not couple the runtime to the compiler's implementation modules, its npm workspace, or any path outside this one.
44

55
The public boundary is the installed `flight/` header tree and the `Flight::Cpp` CMake target. Preserve TypeScript observable semantics over superficial resemblance to STL APIs. Reference identity, absence, equality, ordering, exceptions, and task settlement must be deliberate and directly tested.
66

@@ -15,3 +15,17 @@ ctest --test-dir build --output-on-failure
1515
```
1616

1717
Do not claim a compiler capability or runtime ABI version in `contract.hpp` until its semantic tests exist. Document known gaps in `docs/` rather than hiding them behind permissive fallback behavior.
18+
19+
## Repository automation
20+
21+
`scripts/` is repository automation, not runtime source. The rules above constrain what ships in `include/` and `src/`; they do not govern these scripts, which are plain ESM run directly by Node with no dependencies and no build step. Keep it that way: a contributor who only builds the runtime must never need `npm install`.
22+
23+
`npm run check` runs every gate even after an earlier one fails, because the gates are independent and stopping at the first failure hides the rest. Gates read; nothing here rewrites a committed baseline except `rehydrate:update`, which re-pins the lock deliberately.
24+
25+
## Pinned siblings
26+
27+
The runtime and the compiler evolve against each other, so each repository pins the other instead of sharing a tree. `dependencies.lock.json` names the exact commit of `flight` and `flight-compiler` this checkout is verified against, and `npm run rehydrate` materializes them under the gitignored `.dependencies/`.
28+
29+
Nothing in `.dependencies/` is committed and no gate may treat it as a source of truth. It is a disposable build input; the lock is the only thing that decides which revision is read. A gate that needs a checkout reports and skips when it is absent rather than failing, so a fresh clone stays runnable.
30+
31+
Move a pin deliberately, in its own commit, with the gate result that motivated it. `flight` is pinned for the SDK compilation lane and no gate consumes it yet; do not add one until it can pass.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

LICENSE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# MIT License
2+
3+
Copyright (c) 2013-2026 Joshua Granick and other contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# flight-cpp
22

3-
`flight-cpp` is the incubating C++20 runtime for TypeScript compiled by Flight Compiler. It lives in the compiler repository while the generated-code boundary is still changing quickly, but it is deliberately an independent CMake project so it can move to its own repository without a build-system migration.
3+
`flight-cpp` is the incubating C++20 runtime for TypeScript compiled by Flight Compiler. It was incubated inside the compiler repository while the generated-code boundary settled and now stands on its own, carrying that history with it. The runtime builds with CMake or Bazel and needs no Node.js.
44

55
This is a working foundation, not yet a production-support claim. Version 0.1.0 provides tested representations for shared arrays, insertion-ordered maps and sets, typed-array views, explicit `undefined`/`null` presence, SameValueZero equality, UTF-16 strings, source-style errors and number formatting, UTC date instants, shared coroutine tasks, and closed multi-member unions with distinct C++ alternatives. Tasks use an explicit non-reentrant executor and implement first-settlement-wins construction, exact rejection values, queued continuation, recovery, cleanup, assimilation, and ordered aggregation. Full Unicode case conversion is supplied through a host service. Compiler-generated conformance exercises collections, strings, classes, typed arrays, optional access, coroutines, and checker-proven union narrowing; cancellation, time zones, captured mutation, duplicate union representations, and optional variants remain open.
66

@@ -53,6 +53,33 @@ The installed `flight/` headers and `Flight::Cpp` target are the extraction boun
5353

5454
The compiler emits semantic runtime types such as `flight::Array<T>` and `flight::Map<K, V>` when `runtimeProfile: "flight-cpp"` is elected. The separate `standard-library` profile preserves generic provisional output without claiming TypeScript-equivalent collection behavior. See [compiler integration](docs/compiler-integration.md) and [runtime semantics](docs/runtime-semantics.md).
5555

56-
The supported input boundary is versioned as [`flight-portable-typescript/1`](conformance/portable-typescript-v1.json). [`known-exceptions.json`](conformance/known-exceptions.json) owns every checked-in C++ refusal and is verified by `npm run cpp:exceptions:check`; an exception that starts emitting or changes its rule fails the gate until the ledger is deliberately updated. See [production readiness](docs/production-readiness.md) for proof and release policy.
56+
The supported input boundary is versioned as [`flight-portable-typescript/1`](conformance/portable-typescript-v1.json). [`known-exceptions.json`](conformance/known-exceptions.json) owns every checked-in C++ refusal. The compiler repository verifies it against its own fixture corpus, because a refusal changes when the compiler changes; this repository owns the file, and that gate reads it from a pinned checkout of this repository.
5757

58-
The root repository license applies while this project is incubated here.
58+
## Pinned siblings
59+
60+
The runtime and the compiler are separate repositories that must keep agreeing, so each pins the other rather than sharing a tree. [`dependencies.lock.json`](dependencies.lock.json) names the exact commit of `flight` and `flight-compiler` this checkout is verified against:
61+
62+
```sh
63+
npm run rehydrate # materialize the pinned checkouts under .dependencies/
64+
npm run rehydrate:check # fail if a checkout is missing or off its pin
65+
npm run rehydrate:update # re-pin each dependency to its tracking branch head
66+
```
67+
68+
The checkouts are gitignored, disposable build inputs. Nothing in `.dependencies/` is committed, and the lock is the only thing that decides which revision a gate reads.
69+
70+
## Repository gates
71+
72+
The native build is the runtime's own gate and is run directly with CMake or Bazel. `npm run check` covers what building cannot show:
73+
74+
| Gate | Question |
75+
| --- | --- |
76+
| `npm run abi:check` | Do the C header, its implementation, and the committed ABI snapshot name the same symbols? |
77+
| `npm run build:check` | Do the CMake and Bazel graphs describe the same headers, sources, tests, and benchmarks? |
78+
| `npm run release:check` | Do the version, ABI, C++ standard, and conformance profile agree across every file that states them? |
79+
| `npm run compile:check` | Does the pinned compiler's emitted C++ still compile against this runtime? |
80+
81+
`compile:check` reports and skips when the checkout is absent or no C++ compiler is installed, so a fresh clone stays runnable. The compiler repository asks the same question from its side against the runtime revision it pins; both are wanted, because each side owns the pin it can move and a failure names which one changed.
82+
83+
## License
84+
85+
MIT. See [LICENSE.md](LICENSE.md).

dependencies.lock.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"schema": "flight-dependency-lock/1",
3+
"directory": ".dependencies",
4+
"dependencies": [
5+
{
6+
"name": "flight",
7+
"repository": "https://github.com/flighthq/flight",
8+
"branch": "main",
9+
"commit": "1274ec5c923947dc64d5ffedcbd8169fc758cd9f"
10+
},
11+
{
12+
"name": "flight-compiler",
13+
"repository": "https://github.com/flighthq/flight-compiler",
14+
"branch": "main",
15+
"commit": "4b44279c9a47786f003f2360841c4a19da7a9499"
16+
}
17+
]
18+
}

docs/c-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ Reference-count changes are atomic and const operations on the same immutable ha
1818

1919
The surface is deliberately additive. New opaque value types and calls may be introduced without changing ABI 1. Removing a function, changing a status value, changing ownership, or changing a structure layout requires a new ABI number. Callback APIs will not be added until executor, thread-affinity, and cancellation behavior can be stated in this document.
2020

21-
`abi/c-api-v1.txt` snapshots normalized public signatures and numeric status values. `npm run cpp:abi:check` also requires a matching C-linkage definition for every declaration and selects the snapshot from `FLIGHT_CPP_ABI_VERSION`; changing the ABI number therefore requires committing a new contract snapshot.
21+
`abi/c-api-v1.txt` snapshots normalized public signatures and numeric status values. `npm run abi:check` also requires a matching C-linkage definition for every declaration and selects the snapshot from `FLIGHT_CPP_ABI_VERSION`; changing the ABI number therefore requires committing a new contract snapshot.

docs/compiler-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The packaged `flight-compile --target cpp` command elects `flight-cpp` by defaul
99

1010
`runtimeHeader` overrides the automatic header spelling without changing the selected bindings, which lets an embedding codebase vendor or wrap the runtime. Adding methods to namespace `std` remains undefined behavior and is not an acceptable bridge.
1111

12-
The compiler owns `tests/generated/semantic_runtime.hpp`: a package test regenerates it from `semantic_runtime.ts` and refuses drift, while CMake compiles and executes it against this runtime. Run `npm run cpp:conformance:update` at the repository root after an intentional emitter change.
12+
The compiler owns `tests/generated/semantic_runtime.hpp`: a gate in the compiler repository regenerates it from `semantic_runtime.ts` against its pinned checkout of this repository and refuses drift, while CMake here compiles and executes it against this runtime. After an intentional emitter change, run `npm run cpp:conformance:update` in the compiler repository, then commit the rewritten header here.
1313

1414
## Current maturity boundary
1515

package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "flight-cpp-repository",
3+
"version": "0.1.0",
4+
"private": true,
5+
"description": "Repository automation for the Flight C++20 runtime. The runtime itself is built with CMake or Bazel and needs no Node.",
6+
"license": "MIT",
7+
"type": "module",
8+
"engines": {
9+
"node": ">=22"
10+
},
11+
"scripts": {
12+
"abi:check": "node ./scripts/abiHealth.mjs",
13+
"build:check": "node ./scripts/buildHealth.mjs",
14+
"check": "node ./scripts/check.mjs",
15+
"compile:check": "node ./scripts/emittedSourceCompile.mjs",
16+
"rehydrate": "node ./scripts/rehydrate.mjs",
17+
"rehydrate:check": "node ./scripts/rehydrate.mjs --check",
18+
"rehydrate:update": "node ./scripts/rehydrate.mjs --update",
19+
"release:check": "node ./scripts/releaseHealth.mjs"
20+
}
21+
}

0 commit comments

Comments
 (0)