Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/windows-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ jobs:
- run: native/build-release/Release/cfb27_startup_smoke.exe native/build-release/Release/cfb27_lua_host.dll
- run: native/build-release/Release/cfb27_memory_reader_smoke.exe
- run: native/build-release/Release/cfb27_telemetry_smoke.exe
- run: native/build-release/Release/cfb27_memory_transaction_smoke.exe
- run: native/build-release/Release/cfb27_protocol_smoke.exe native/build-release/Release/cfb27_lua_host.dll
env:
CFB27_SMOKE_ALLOW_WRITES: '1'
- run: npm run pack:preview
- uses: actions/upload-artifact@v4
with:
name: cfb27-lua-hook-0.2.0-dev.1
name: cfb27-lua-hook-0.2.0-dev.2
path: dist/
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Offline Lua scripting runtime, Node SDK, and MMC startup tooling for EA SPORTS
College Football 27 on PC.

> Developer preview `0.2.0-dev.1`. The runtime supports one verified game
> Developer preview `0.2.0-dev.2`. The runtime supports one verified game
> build, is intended only for offline play, and does not include or provide an
> anticheat bypass.

Expand Down Expand Up @@ -35,7 +35,7 @@ cfb27lua logs [--follow]
cfb27lua doctor
```

These commands are implemented in the `0.2.0-dev.1` developer preview. One-shot
These commands are implemented in the `0.2.0-dev.2` developer preview. One-shot
`--json` output is a single object; followed logs use JSON Lines.

## Start here
Expand Down
23 changes: 20 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ node packages/cli/bin/cfb27lua.cjs --help
- `events [--after N]` — read a cursor page.
- `memory scan` — scan bounded private readable memory through the validated SDK.
- `memory read` — read one or more bounded canonical address ranges through the validated SDK.
- `memory transact <file.json>` — apply one guarded transaction from a JSON request file.
- `telemetry register <type...>` — register structured telemetry type names for the host session.

The memory commands are read-only developer diagnostics. A scan requires
The memory scan and read commands are read-only developer diagnostics. A scan requires
`--pattern`, `--mask`, `--max-matches`, and `--context`; context is applied on
each side of a match. The CLI automatically follows native continuation pages,
uses a ten-second timeout for each scan page, and accepts `--max-pages` from 1
Expand All @@ -30,6 +31,14 @@ ranges. A read accepts one or more
example, `0x7FF612340000`, not a lowercase or zero-padded form). Write-like
options are not accepted.

A guarded transaction accepts exactly one `.json` file containing the SDK request
object with `transactionId` and `operations`; it does not accept stdin. The CLI resolves
the current directory and existing input through the filesystem before containment
checks, so links cannot escape the current directory. An outside target requires the
explicit `--allow-external-file` flag. `--json` and `--allow-external-file` are the only
transaction controls; scan, read, follow, cursor, and directory controls are rejected.
The SDK validates and clones the request before opening a host connection.

Use `--allow-unsupported-build` only when intentionally running a memory
diagnostic against an unsupported build. Without that explicit flag, the SDK
rejects an unsupported-build result. The flag does not enable writes.
Expand All @@ -46,13 +55,21 @@ node packages/cli/bin/cfb27lua.cjs memory scan `
node packages/cli/bin/cfb27lua.cjs memory read `
--range 0x7FF612340000:192 --allow-unsupported-build --json

node packages/cli/bin/cfb27lua.cjs memory transact `
proof-transaction.json --json

node packages/cli/bin/cfb27lua.cjs telemetry register `
recruiting.snapshot recruiting.stability --json
```

Human memory output reports bounded counts and the canonical addresses returned
by the SDK. JSON output keeps the validated SDK result unchanged under the
standard `{ "ok": true, "command": "...", "result": ... }` CLI envelope.
by the SDK. Scan and read JSON output keep the validated SDK result unchanged under
the standard `{ "ok": true, "command": "...", "result": ... }` CLI envelope.
Transaction `--json` output is the validated SDK result object itself, without an
envelope.
Human transaction output is narrower: it reports only the transaction ID, status,
and operation/applied/verified counts, never addresses or byte values. Transaction
errors use constant code-derived messages and omit host details in both output modes.
Only `memory scan` selects the ten-second per-page client timeout; all other
commands retain the SDK default timeout.

Expand Down
92 changes: 67 additions & 25 deletions docs/development/release-checklist.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,73 @@
# Developer-preview release checklist

- [ ] Complete the read-only memory and telemetry automated gate before changing
the preview version.
- [ ] Run `npm ci`, `npm run check`, and `npm test`.
- [ ] Configure and build all native targets with Windows x64 MSVC.
- [ ] Run startup, memory-reader, telemetry, and framed-protocol smoke
executables from the full Release build.
- [ ] Confirm CLI memory scans automatically follow continuation pages with a
This is the release ledger for `0.2.0-dev.2`, not a reusable blank template.
Checked items were completed for this release; unchecked items still require
external GitHub or post-merge work. For a later preview, copy the sequence and
reset every checkbox.

## Reviewed candidate gate

- [x] Complete independent task-level specification and quality reviews, then a
different-reviewer whole-branch review, before candidate installation.
- [x] Run `npm ci`, `npm run check`, and `npm test`.
- [x] Configure and build all native targets with Windows x64 MSVC.
- [x] Run startup, memory-reader, telemetry, memory-transaction, and
framed-protocol smoke executables from the full Release build.
- [x] Confirm CLI memory scans automatically follow continuation pages with a
bounded `--max-pages` value and retain the scan-only timeout.
- [ ] Set `CFB27_NATIVE_ARTIFACTS` to the absolute path of that exact Release
- [x] Set `CFB27_NATIVE_ARTIFACTS` to the absolute path of that exact Release
directory, then run `npm run pack:preview`.
- [ ] Run `git diff --check`.
- [ ] Confirm the staged package and both npm tarballs contain no archive,
- [x] Run `git diff --check`.
- [x] Confirm the staged package and both npm tarballs contain no archive,
game/save data, schema, logs, dependencies, or build intermediates.
- [ ] Verify the external `dist/SHA256SUMS.txt` against the preview zip. The ZIP
- [x] Verify the external `dist/SHA256SUMS.txt` against the preview ZIP. The ZIP
checksum cannot be embedded in documentation inside that same ZIP.
- [ ] Confirm Windows CI is green.
- [ ] With the game closed, install the exact automated-gate candidate host and
relaunch MMC offline so no previous DLL remains loaded.
- [ ] Perform the documented offline read-only runtime checklist: confirm hello
capabilities, bounded sentinel scan/read, advancing registered telemetry,
ten minutes of responsiveness, and a Dynasty hub transition. Do not use or
attempt a memory write.
- [ ] Record the date, executable hash, exact commands, and observed results in
`docs/research/runtime-verification.md` only after observing them.
- [ ] After the manual gate succeeds, set root, SDK, CLI, lockfile, release
packager, and native hello versions to `0.2.0-dev.1`, then repeat every
automated build, test, smoke, package-inspection, and diff-check step.
- [ ] Close the game and verify uninstall restores both known MMC hashes.
- [ ] Publish GitHub artifacts only; npm publication is not part of this preview.

## Reversible offline live gate

- [x] With both applications closed, verify the original active proxies, install
the exact reviewed candidate through the supported SDK or CLI, and
independently verify the installed proxy and host hashes.
- [x] Relaunch MMC and CFB27 offline to the Dynasty hub. Confirm the supported
executable, PID, session, capabilities, write eligibility, and exact
selected-save recipes before opting into any read-only scan.
- [x] Calibrate authority with bounded scans, stable batch rereads, allocation
topology, and a hub-to-Recruiting-to-hub lifecycle transition. Proceed
only when exactly one authoritative permission record remains; reject
presentation copies, stale neighborhoods, and unresolved replicas.
- [x] Immediately revalidate the complete record, change only the byte containing
the two-bit enum through one guarded transaction, verify the complete
alternate record and responsiveness, then restore through a second guarded
transaction and verify the complete original record. Require no lockdown
and continued write eligibility. Do not advance or write recruiting data.
- [x] Explicitly close both applications and confirm both processes are absent.
- [x] Use the supported uninstall and independently verify both original active
proxy hashes. Keep both applications closed for release preparation.
- [x] Record the date, executable hash, observed commands and results in
`docs/research/runtime-verification.md`. Retain hashes, counts, and topology
relationships, never addresses or raw bytes.

## Final `0.2.0-dev.2` preparation

- [x] Only after live cleanup, set root, SDK, CLI, lockfile, release packager,
SDK dependency, native hello, public documentation, CI artifact, and
policy-test versions to `0.2.0-dev.2`.
- [x] Repeat `npm ci`, syntax checks, the full Node suite, a clean Windows x64
Release build, every native smoke, package preview and inspection,
internal and external checksum verification, and `git diff --check`.
- [x] Confirm the final bumped host was automated- and smoke-tested only. It was
not installed or exercised in the live session; live evidence applies to
the separately hashed reviewed recovery candidate.

## External publication and immutable verification

- [ ] Push the branch and open a draft PR against `main`; confirm Windows CI is
green, including the memory-transaction smoke and `0.2.0-dev.2` artifact.
- [ ] Complete PR review and merge into `main`.
- [ ] Tag the exact merged commit as `v0.2.0-dev.2`.
- [ ] Publish a GitHub prerelease with the immutable preview ZIP and external
checksum file. npm publication is not part of this preview.
- [ ] Download both published assets afresh and independently recompute the ZIP
SHA-256; require an exact match to the downloaded checksum file.
- [ ] Only after the immutable download verification passes, begin the Brooks
integration gate.
23 changes: 22 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Getting started

CFB27 Lua Hook `0.2.0-dev.1` is a Windows x64 developer preview. It requires
CFB27 Lua Hook `0.2.0-dev.2` is a Windows x64 developer preview. It requires
Node.js 20 or later, CMake 3.24 or later, Visual Studio 2022 C++ build tools,
MMC, and a separately launched offline CFB27 session.

Expand Down Expand Up @@ -70,6 +70,7 @@ const scan = await client.scanMemory({
contextBefore: 4,
contextAfter: 4,
maxPages: 4096,
includeAllocationMetadata: true,
});

const read = await client.readMemory({
Expand All @@ -89,6 +90,26 @@ A batch read contains at most 64 ranges of 64 KiB each and at most 256 KiB
total. Unsupported game builds
require `allowUnsupportedBuild: true` and report `supportedBuild: false`.

Allocation metadata is opt-in. The SDK first requires the host's
`memoryScanAllocationMetadata` capability, then returns `allocationBase`,
`allocationSize`, `allocationProtect`, and `offsetInAllocation` on every match.
Without the option, or with `includeAllocationMetadata: false`, the legacy
six-property match shape is unchanged. The equivalent CLI diagnostic is:

```powershell
node packages/cli/bin/cfb27lua.cjs memory scan `
--pattern CFB27A1100A1B2C3D4E5F60718293A4B `
--mask FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF `
--max-matches 2 --context 4 `
--include-allocation-metadata --json
```

The CLI preserves the SDK-validated extended JSON only for that invocation; it
does not persist it. Treat allocation addresses and topology as session-only:
discard them after a PID, host session, allocation, or validation change.
Allocation size and address order do not establish which copy is authoritative.
Use independently validated record content and lifecycle behavior instead.

All memory methods validate requests before opening the pipe and every host
response field before returning it. A multi-page scan observes a live,
non-atomic memory map, so re-read and validate every selected candidate before
Expand Down
78 changes: 74 additions & 4 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,20 @@ Error response:
- `registerTelemetry { types }` — add trusted structured event names for the
current host session.
- `scanMemory { patternHex, maskHex, maxMatches, contextBefore,
contextAfter, allowUnsupportedBuild?, cursor? }` — scan one bounded page of
readable private memory and optionally resume from a continuation cursor.
contextAfter, allowUnsupportedBuild?, cursor?, includeAllocationMetadata? }`
— scan one bounded page of readable private memory and optionally resume from
a continuation cursor.
- `readMemory { ranges, allowUnsupportedBuild? }` — read a bounded batch of
readable private-memory ranges.
- `writeTransaction { transactionId, operations }` — apply a bounded guarded
batch with complete preflight comparison, readback, and rollback.

`hello.capabilities` advertises the memory commands as `memoryScan` and
`memoryRead`, and structured event registration as `telemetry`. They are
read-only host operations and do not expose a write API.
`memoryRead`, allocation-aware scans as `memoryScanAllocationMetadata`, guarded
writes as `memoryWriteTransaction`, and structured event registration as
`telemetry`. `status.sessionWritesDisabled` reports whether an
unverifiable rollback has permanently disabled writes for the current host
session.

### Structured telemetry

Expand Down Expand Up @@ -104,6 +110,24 @@ Result:
{"supportedBuild":false,"complete":false,"nextCursor":"0x7FF614340000","scannedBytes":33554432,"matches":[{"address":"0x7FF612340080","regionBase":"0x7FF612340000","regionSize":65536,"protection":4,"contextAddress":"0x7FF61234007C","contextHex":"00000000CFB27A1100A1B2C3D4E5F60718293A4B00000000"}]}
```

When `includeAllocationMetadata` is absent or the JSON boolean `false`, each
match has exactly the six legacy properties shown above. When it is `true`, the
host adds exactly four properties to every match:

```json
{"address":"0x7FF612340080","regionBase":"0x7FF612340000","regionSize":4096,"protection":4,"contextAddress":"0x7FF61234007C","contextHex":"00000000CFB27A1100A1B2C3D4E5F60718293A4B00000000","allocationBase":"0x7FF612300000","allocationSize":4194304,"allocationProtect":4,"offsetInAllocation":262272}
```

`allocationBase` is the allocation identity reported by the operating system.
`allocationSize` is the checked contiguous extent of adjacent virtual-memory
regions that retain that identity. `allocationProtect` is the allocation's
initial protection, while `protection` remains the current protection of the
matched region. `offsetInAllocation` is the checked byte difference from the
allocation base, and therefore
`BigInt(address) === BigInt(allocationBase) + BigInt(offsetInAllocation)`.
Failure to discover a complete consistent extent fails the whole page with
`MEMORY_ACCESS_DENIED`; partial matches are not returned.

Every successful page contains exactly `complete`, `nextCursor`,
`scannedBytes`, `matches`, and `supportedBuild`. A partial page has
`complete:false` and a canonical string `nextCursor`; a terminal page has
Expand All @@ -120,6 +144,15 @@ cursors. The default bounds total eligible-byte work to 128 GiB. Before using a
candidate for interpretation, re-read it and validate its expected structure;
the live memory map can change between pages.

Before an opt-in request, the SDK negotiates `hello` and requires
`memoryScanAllocationMetadata`; older hosts fail closed with
`PROTOCOL_MISMATCH`. Allocation addresses and topology are opaque, session-only
observations. They must not be persisted or reused after a PID, host session,
allocation lifecycle, or validation change. Allocation size and address order
are never authority signals: use independently validated content and lifecycle
behavior to distinguish authoritative state from replicas, caches, or stale
allocations.

### Memory read

`ranges` contains 1–64 objects with exactly `address` and `length` keys.
Expand All @@ -145,6 +178,38 @@ keys. On an unsupported executable, `allowUnsupportedBuild` must be the JSON
boolean `true` or the command returns `UNSUPPORTED_BUILD`. Successful diagnostic
requests then return `supportedBuild:false`. This override never enables writes.

### Memory write transactions

`transactionId` is 1–64 ASCII letters, digits, dots, underscores, or hyphens.
`operations` contains 1–32 objects with exactly `address`, `expectedHex`, and
`replacementHex`. Addresses use the same canonical uppercase format as memory
reads. Hex strings are nonempty uppercase byte sequences of equal length. One
operation is limited to 4,096 bytes and the request is limited to 65,536 bytes.

```json
{"protocol":1,"id":"write-1","command":"writeTransaction","params":{"transactionId":"recruiting.proof-1","operations":[{"address":"0x7FF612340080","expectedHex":"1020","replacementHex":"1121"}]}}
```

A successful result records the verified outcome for every operation:

```json
{"transactionId":"recruiting.proof-1","status":"applied_verified","operations":[{"index":0,"applied":true,"verified":true}]}
```

The host validates every range and compares every expected byte before the
first write. It then applies and verifies operations in request order. If an
apply or readback step fails, it restores attempted operations in reverse order
and verifies the originals. A verified rollback is returned as
`TRANSACTION_APPLY_FAILED`, with `rolled_back_verified` transaction details. An
unverifiable rollback returns `ROLLBACK_VERIFICATION_FAILED`, with
`rollback_unverified` details, and permanently rejects subsequent transaction
and Lua writes with `SESSION_WRITES_DISABLED` until the host restarts.

This is request-level host sequencing, not game-thread atomicity: the game may
mutate memory while preflight, apply, verification, or rollback is running.
Callers must establish a stable window appropriate to the target data before
submitting a transaction.

The host retains at most 512 log entries and 1,024 events. Event cursors are
monotonic for one host session. Tick events are coalesced to at most one per
second; Lua tick callbacks still run at their normal cadence.
Expand All @@ -160,6 +225,11 @@ Memory commands additionally return `MEMORY_ACCESS_DENIED` when a requested
range is not wholly readable private memory, `SCAN_LIMIT_EXCEEDED` when the
aggregate scan bound would be crossed, and `TOO_MANY_MATCHES` rather than
silently truncating a scan. These errors do not include memory or region dumps.
Guarded writes additionally return `MEMORY_MISMATCH`,
`TRANSACTION_LIMIT_EXCEEDED`, `TRANSACTION_APPLY_FAILED`,
`ROLLBACK_VERIFICATION_FAILED`, and `SESSION_WRITES_DISABLED`. Malformed
transaction shapes, addresses, hex, and overlapping operations return
`INVALID_REQUEST`.

The unversioned legacy text pipe remains temporarily available for migration,
but it is not the integration contract for new tools.
Loading
Loading