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
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,21 @@ jobs:
- name: Setup Node and dependencies
uses: ./.github/actions/setup-node-cached

- name: Stage declared npm for Cloud bootstrap acceptance fixtures
id: cloud-platform-npm
shell: bash
run: |
package_manager=$(node -p 'require("./package.json").packageManager')
if [[ ! "$package_manager" =~ ^npm@([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
echo "Cloud bootstrap fixtures require an exact npm packageManager version" >&2
exit 1
fi
bootstrap_npm_version="${BASH_REMATCH[1]}"
bootstrap_npm_home="$RUNNER_TEMP/cloud-platform-npm"
# Exact packageManager pin; intentionally lockfile-free in a disposable runner-only prefix.
npm install --prefix "$bootstrap_npm_home/npm" --ignore-scripts --no-save --package-lock=false --no-audit --no-fund "npm@$bootstrap_npm_version"
echo "home=$bootstrap_npm_home" >> "$GITHUB_OUTPUT"

- name: Install deterministic Python PDF test prerequisite
run: python3 -m pip install --disable-pip-version-check "PyMuPDF==1.28.0"

Expand All @@ -743,6 +758,8 @@ jobs:
# worker that never exits) is what this catches: the step now fails at 13 minutes instead,
# 7 minutes sooner, with the same red result. Nothing is skipped or retried.
timeout-minutes: 13
env:
CLOUD_PLATFORM_NPM_HOME: ${{ steps.cloud-platform-npm.outputs.home }}
run: >-
node scripts/run-vitest.mjs run --config=vitest.coverage-shard.config.mts
--coverage --shard=${{ matrix.shard }}/2 --reporter=default --reporter=blob
Expand Down
71 changes: 71 additions & 0 deletions .github/workflows/cloud-contracts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Cloud source contracts

on:
pull_request:
branches: [main]
paths:
- "README.md"
- ".nvmrc"
- "AGENTS.md"
- "CLAUDE.md"
- "GEMINI.md"
- "PROJECT-INSTRUCTIONS-CONTINUATION.md"
- "package.json"
- "package-lock.json"
- "scripts/*codex-cloud*"
- "scripts/check-cross-repo-cloud-contracts.mjs"
- "scripts/lib/codex-cloud*"
- "tests/cross-repo-cloud-contracts.test.ts"
- "docs/agents/*cloud*"
- "docs/task-receipts.md"
- ".github/workflows/cloud-contracts.yml"
push:
branches: [main]
paths:
- "README.md"
- ".nvmrc"
- "AGENTS.md"
- "CLAUDE.md"
- "GEMINI.md"
- "PROJECT-INSTRUCTIONS-CONTINUATION.md"
- "package.json"
- "package-lock.json"
- "scripts/*codex-cloud*"
- "scripts/check-cross-repo-cloud-contracts.mjs"
- "scripts/lib/codex-cloud*"
- "tests/cross-repo-cloud-contracts.test.ts"
- "docs/agents/*cloud*"
- "docs/task-receipts.md"
- ".github/workflows/cloud-contracts.yml"
workflow_dispatch:
inputs:
audit_public_main:
description: "Read maintained repositories' main anonymously; inaccessible sources fail as unverified."
type: boolean
default: false

permissions:
contents: read

concurrency:
group: cloud-contracts-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
source-contracts:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: ".nvmrc"
package-manager-cache: false
- name: Check this checkout's static Cloud contracts
run: node scripts/check-cross-repo-cloud-contracts.mjs --root .
# No dependencies, foreign scripts, tokens, provider clients or remote workflow execution.
- name: Audit maintained public main revisions (explicit request only)
if: github.event_name == 'workflow_dispatch' && inputs.audit_public_main
run: node scripts/check-cross-repo-cloud-contracts.mjs --root . --fetch-maintained
60 changes: 60 additions & 0 deletions .github/workflows/cloud-platform-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Cloud platform smoke

on:
pull_request:
paths:
- ".github/workflows/cloud-platform-smoke.yml"
- "scripts/check-cloud-platform-smoke.mjs"
- "scripts/setup-codex-worktree.mjs"
- "scripts/check-installed-lock-parity.mjs"
- "scripts/install-git-hooks.mjs"
- "scripts/lib/is-entrypoint.mjs"
- "tests/cloud-platform-smoke.test.ts"
- "docs/agents/cloud-platform-acceptance.md"
- "package.json"
- ".node-version"
- ".nvmrc"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: cloud-platform-smoke-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
windows-bootstrap:
name: Native Windows bootstrap fixture
runs-on: windows-2025
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: ".node-version"
package-manager-cache: false

# Match the real bootstrap's npm lookup with an isolated job-local APPDATA.
# No global install and no application dependency installation are needed.
- name: Stage the declared npm in the runner temporary directory
shell: pwsh
run: |
$manifest = Get-Content package.json -Raw | ConvertFrom-Json
if ($manifest.packageManager -notmatch '^npm@(\d+\.\d+\.\d+)$') { throw 'Expected an exact npm packageManager version' }
$version = $Matches[1]
$toolAppData = Join-Path $env:RUNNER_TEMP 'cloud-platform-appdata'
$toolPrefix = Join-Path $toolAppData 'npm'
# Exact packageManager pin; intentionally lockfile-free in a disposable runner-only prefix.
npm install --prefix $toolPrefix --ignore-scripts --no-save --package-lock=false --no-audit --no-fund "npm@$version"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
"APPDATA=$toolAppData" >> $env:GITHUB_ENV

- name: Exercise native Windows Git Bash paths, donor copy, and hook installation
shell: pwsh
run: node scripts/check-cloud-platform-smoke.mjs --windows
15 changes: 15 additions & 0 deletions data/repo-awareness-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -3943,6 +3943,11 @@
"section": "root",
"catalogued": true
},
{
"path": "docs/agents/cross-repo-cloud-contracts.md",
"section": "agents",
"catalogued": true
},
{
"path": "docs/medication-lexicon-review-worklist.md",
"section": "root",
Expand Down Expand Up @@ -4208,6 +4213,11 @@
"section": "prompts",
"catalogued": true
},
{
"path": "docs/agents/cloud-platform-acceptance.md",
"section": "agents",
"catalogued": true
},
{
"path": "docs/agents/claude-hook-scripts.md",
"section": "agents",
Expand Down Expand Up @@ -5233,6 +5243,11 @@
"section": "decisions",
"catalogued": true
},
{
"path": "docs/agents/cloud-build-resources.md",
"section": "agents",
"catalogued": true
},
{
"path": "docs/superpowers/rag-upgrade/cloud/plans/2026-08-20-rag-adaptive-answer.md",
"section": "superpowers",
Expand Down
81 changes: 81 additions & 0 deletions docs/agents/cloud-build-resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Cloud production-build resources

Use the read-only preflight before a production build or the canonical production
Playwright command on a cloud runner:

```bash
node scripts/check-cloud-build-resources.mjs
node scripts/check-cloud-build-resources.mjs --json
```

Both forms exit `0` when the recommended planning envelope is available, `1` when
heap/resource diagnostics need attention, and `2` for invalid arguments. The script
does not build, start a server, acquire the heavy-run lease, change the environment,
resize the host, or suppress any check. A pass is resource-planning evidence; the
existing build, typecheck and browser commands still supply their own acceptance
evidence. Follow [verification gates](verification-gates.md) for scope and reporting.

## Heap inherited by Next.js workers

In the prior cloud acceptance run, compilation completed with the default heap,
then Next.js typechecking exhausted roughly 4 GiB. Repeating the canonical
production Playwright run with command-scoped
`NODE_OPTIONS=--max-old-space-size=8192` completed 107 browser tests. That observed
result motivates the recommendation; it does not establish a universal minimum
or guarantee every future build fits.

The preflight measures V8's heap limit in a short Node subprocess inheriting the
current environment. A heap flag on the preflight process alone cannot make it
pass. This matters because a parent `node --max-old-space-size=8192` flag does not
establish what a separately launched Next.js worker receives. The measured V8
limit includes a little overhead beyond the old-space setting.

When `NODE_OPTIONS` is unset or empty, a Bash invocation can keep the setting scoped
to the preflight and the existing command:

```bash
NODE_OPTIONS=--max-old-space-size=8192 node scripts/check-cloud-build-resources.mjs &&
NODE_OPTIONS=--max-old-space-size=8192 npm run build
```

Use the same command-scoped setting on the browser command selected for the task
when its runner builds the production app. Do not permanently export this setting
or replace existing `NODE_OPTIONS` wholesale. If other options are already set,
retain them; review any explicit heap option before editing it. Node accepts both
`--max-old-space-size` and `--max_old_space_size`, with values supplied using `=` or
as a separate argument. The preflight lets Node interpret these options rather
than rewriting or guessing their meaning. A small explicit heap produces a clear
diagnostic and remains unchanged. A larger heap increases the memory envelope.

## Runner capacity and headroom

Plan for an 8 GiB old-space heap **plus 4 GiB of headroom** for native allocations,
other Node workers, the browser and the OS: approximately 12 GiB total. The actual
check uses the measured V8 heap plus 4 GiB, including V8's small overhead. A 16 GiB
runner with adequate current availability is a practical starting point. An 8 GiB
runner cannot safely accommodate an 8 GiB heap. The headroom is a conservative
planning recommendation, not a measured worst-case bound for every worker mix.

The report limits capacity to the smallest visible host/cgroup limit. Linux
discovery resolves cgroup v2 `memory.max`/`memory.current` or v1
`memory.limit_in_bytes`/`memory.usage_in_bytes` using this process's membership and
mount information, then checks visible ancestors. Unlimited cgroups fall back to
finite host capacity. Host availability uses `MemAvailable` where provided,
otherwise free memory. Cgroup availability subtracts current usage and credits
bounded inactive file cache as reclaimable. A visible memory mount with unresolved
process membership, any unreadable visible ancestor limit, invalid limits, or
missing usage for a finite limit fails the preflight instead of trusting the
larger host. Mount paths must be absolute and normalized, and ancestor traversal
is bounded. Unlimited fallback requires explicit readable `max` or sentinel
bounds through the visible hierarchy, except that the global cgroup v2 root
(mount root `/`) legitimately has no `memory.max`. Only `ENOENT` at that root is
accepted; permission errors and unreadable intermediate bounds still fail. All
finite ancestors below the root remain checked. A namespace-hidden root (including
the kernel's `/..` mount-root marker) without a readable bound is reported as not
ready. See the kernel's [memory controller reference](https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files).

This is a snapshot: another process can consume memory after it passes, and hidden
ancestors cannot be inspected. Keep the existing heavy-run admission mechanism,
rerun immediately before the build, and wait for other work or choose a larger
runner when availability is insufficient. Do not reduce verification or change
host memory limits to obtain a passing report.
47 changes: 47 additions & 0 deletions docs/agents/cloud-instruction-activation.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,46 @@ record its revision separately. Do not edit a generated policy snapshot or infer
repository updates every saved environment. If the supported configuration view is unavailable,
report that layer as unverified and continue independent repository work.

## Collect bounded local evidence

From the selected checkout, run the provider-free collector with the full expected commit:

```bash
node scripts/cloud-activation-evidence.mjs --expected-revision <full-commit-sha>
```

It reports the physical checkout, current branch/revision, dirty state and SHA-256 of known
instruction/bootstrap sources, including the Claude profile guidance tree. Hashes describe the
current bytes, which may include uncommitted changes; they do not attest an installation. Missing
source entries stay explicit. The command never sources profiles, launches agents, calls providers,
reads environment values or opens authentication files.

Installation inspection is opt-in. Add `--installed-home /absolute/scoped/home` for known Codex
legacy profile/shim artifacts; add `--codex-home /absolute/scoped/codex` if that installation used a
separate Codex home. Add `--claude-config-dir /absolute/scoped/claude` to inspect its ownership
manifest and compare currently recognized owned files to both recorded hashes and current sources.
The collector rejects symlink components, unsafe entries and mismatched checkout owners. It does
not read Codex config, Claude settings, memory seeds or unrecognized retired host files. A modified
owned file remains untouched and produces a mismatch. Config/settings activation stays unverified.

A legacy generated marker and checkout line are provenance clues; no trusted legacy content
manifest exists. Their reported hashes never become a claim that generated content is correct.
A markerless historical profile has unknown ownership and remains eligible for the existing
explicit legacy migration procedure; collecting evidence neither migrates nor rejects that
migration. A Claude ownership manifest establishes recorded ownership, while matching bytes
establish only the inspected file state. Neither proves native loading.

The JSON report always marks `activeSession.status` as `unverified`. Supplement it separately with
supported native context-inspection evidence from the actual session, naming its client/session,
selected revision and loaded entry/continuation/topic instructions. A chat's own assertion or a
manually authored receipt is not an independent inspection result. If the client exposes no such
inspection, keep loading unverified even after a fresh chat starts. No dummy dispatch is needed.

Exit `0` means evidence collection found no detected mismatch; it does not mean operational
acceptance. Exit `1` records an exact revision, ownership, hash or safe-artifact mismatch in JSON.
Exit `2` means invalid arguments or evidence could not be safely collected. All modes are read-only;
review before storing a report because paths and revision metadata identify the selected checkout.

## Client loading matrix

Verify only clients actually supported by the selected host. Do this at the next useful task;
Expand All @@ -49,6 +89,13 @@ chats can retain previous prompts. Do not overwrite personal memory or delete hi
to simulate a context refresh. Use the managed installer’s ownership-aware reconciliation for
retired installed files; preserve modified/unowned content for explicit review.

## Related operational checks

Use [Cloud build resources](cloud-build-resources.md) to distinguish source checks from a
resource-backed build, [Cloud platform acceptance](cloud-platform-acceptance.md) for the next
useful task on each supported platform, and [cross-repository Cloud contracts](cross-repo-cloud-contracts.md)
when comparing shared guidance. Those checks retain their own authority and evidence boundaries.

## Completion evidence

Report the source revision, checks run, installation status and session-loading status separately.
Expand Down
Loading
Loading