Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
3ac7add
Add opt-in Node runtime and upstream framework suites
dnnsjsk Oct 23, 2026
2938003
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 23, 2026
0cef9bc
Preserve runtime state across compiled calls and VM realms
dnnsjsk Oct 23, 2026
486033e
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 23, 2026
f788706
Preserve lexical lifetimes and track actual this-binding instructions
dnnsjsk Oct 23, 2026
d9cba68
Compare filesystem link targets after resolving host aliases
dnnsjsk Oct 23, 2026
088a983
fix: release deep WeakMap value chains iteratively
dnnsjsk Oct 23, 2026
ef390db
perf: defer ordinary function prototype allocation
dnnsjsk Oct 23, 2026
962c303
Compile ordered array destructuring assignments
dnnsjsk Oct 23, 2026
d44dced
Compile optional chains with shared tail-call resolution
dnnsjsk Oct 23, 2026
4f6d1e9
Bound Hono workers with configurable memory for full DOM inventories
dnnsjsk Oct 23, 2026
59890c2
Model weak-reference liveness across collection in prototype tests
dnnsjsk Oct 23, 2026
7710866
Preserve proxy traps and receivers for symbol writes
dnnsjsk Oct 23, 2026
c4a798c
Compile reference-preserving updates to environment bindings
dnnsjsk Oct 23, 2026
8bf8ad8
Format the update binding oracle regression
dnnsjsk Oct 23, 2026
404eb73
Preserve strict program assignment references during compilation
dnnsjsk Oct 23, 2026
a3dc370
Accelerate numeric typed-array writes with preserved coercion order
dnnsjsk Oct 23, 2026
81cb8a7
Compile independent const blocks with proven binding lifetimes
dnnsjsk Oct 23, 2026
f75d0f1
Report Express case durations without changing upstream deadlines
dnnsjsk Oct 23, 2026
f16b549
Clamp array-like lengths before typed-array copy bounds checks
dnnsjsk Oct 23, 2026
6ece1d1
Document runtime fixes and link canonical compliance results
dnnsjsk Oct 23, 2026
abadb98
Inline compiled functions with tail-call returns
dnnsjsk Oct 23, 2026
7d21bda
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 23, 2026
700c5d6
Format runtime oracle fixtures for the full code-standard gate
dnnsjsk Oct 23, 2026
48d8e9f
Restore the verified 100 percent test262 result
dnnsjsk Oct 23, 2026
0ee2334
Keep array iterator state in native internal slots
dnnsjsk Oct 23, 2026
388d277
Avoid unused AST allocations in primitive property lookup
dnnsjsk Oct 23, 2026
547293b
Capture array iterator index before observable length reads
dnnsjsk Oct 23, 2026
d41bdd2
Reuse cached callback layouts before activation setup
dnnsjsk Oct 23, 2026
a472e73
Avoid redundant compiled hoists and literal-key capture bailouts
dnnsjsk Oct 23, 2026
5d06047
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 23, 2026
fa287ff
Reuse declarative binding values on bytecode cache misses
dnnsjsk Oct 23, 2026
d2435c9
Initialize captured bindings from compiled function metadata
dnnsjsk Oct 23, 2026
2fdbe4c
Retain realm array prototypes independently of mutable globals
dnnsjsk Oct 23, 2026
609724c
Store retained array intrinsics in private realm state
dnnsjsk Oct 23, 2026
d6c4e96
Preserve complete case titles in native Hono reports
dnnsjsk Oct 23, 2026
54417c3
Inline primitive numeric String charCodeAt calls in the VM
dnnsjsk Oct 23, 2026
77b0d83
Fix primitive property Reference receiver semantics
dnnsjsk Oct 23, 2026
6cefe17
Compile property increment and decrement updates
dnnsjsk Oct 23, 2026
bcced36
Read numeric TypedArray elements through indexed getters
dnnsjsk Oct 23, 2026
fb4108c
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 23, 2026
53731b6
Honor callable iterator proxies and primitive iterator overrides
dnnsjsk Oct 23, 2026
e083162
Preserve RegExp legacy state in custom matching
dnnsjsk Oct 23, 2026
0b0ee1e
Compile ordinary for-of loops with shared iterator semantics
dnnsjsk Oct 23, 2026
667f8c2
Invalidate cached reads after binding declarations and deletion
dnnsjsk Oct 23, 2026
d266a72
Preserve callee realms through optimized calls and string lookups
dnnsjsk Oct 23, 2026
d8f1070
Compile guarded read-only ASCII string loops
dnnsjsk Oct 23, 2026
08ba382
Preserve lexical scope for exited block bindings
dnnsjsk Oct 23, 2026
e78b8d6
Compile switch selection and fallthrough with scoped control flow
dnnsjsk Oct 23, 2026
1b4ddd0
Compile simple rest parameters with existing binding semantics
dnnsjsk Oct 23, 2026
cf102e6
Align while checkpoints across interpreter and compiled tiers
dnnsjsk Oct 23, 2026
e73f224
Separate loop deadlines from successful iteration counts
dnnsjsk Oct 24, 2026
7190416
Preserve double precision in generated numeric literals
dnnsjsk Oct 24, 2026
8ba4d17
Exclude runtime JavaScript fixtures from PHP coding standards
dnnsjsk Oct 24, 2026
e91c799
Preserve object literal realms across generated calls
dnnsjsk Oct 24, 2026
de8262e
Compile guarded class constructor bodies with shared super semantics
dnnsjsk Oct 24, 2026
0124d75
Avoid uncaptured hoisted function environment cycles
dnnsjsk Oct 24, 2026
e66b18b
Check numeric bridge bounds before integer casts
dnnsjsk Oct 24, 2026
0ed62f0
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
f014c2d
Compile guarded pure segments of string while loops
dnnsjsk Oct 24, 2026
430f54b
Respect nested lexical shadows in block binding proofs
dnnsjsk Oct 24, 2026
ba525bc
Speed numeric Uint8Array indexed writes
dnnsjsk Oct 24, 2026
cb6029a
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
6b895cc
Fix realm prototypes for Node host byte views
dnnsjsk Oct 24, 2026
b7089d7
Preserve foreign realms in inline Array callbacks
dnnsjsk Oct 24, 2026
b45ceb7
Reuse immutable custom regular expression syntax trees
dnnsjsk Oct 24, 2026
20f0271
Resolve TypedArray copy prototype before source validation
dnnsjsk Oct 24, 2026
e0395d2
Clone same-type TypedArray bytes without element boxing
dnnsjsk Oct 24, 2026
a208f3c
Guard VM array index casts with numeric bounds
dnnsjsk Oct 24, 2026
1786bdb
Preserve double precision in compiled literal properties
dnnsjsk Oct 24, 2026
75915d0
Prevent compiled functions from replaying effects on bailout
dnnsjsk Oct 24, 2026
3e3cda7
Store string iterator state in private slots
dnnsjsk Oct 24, 2026
d8c5162
Match JavaScript number truthiness in generated PHP
dnnsjsk Oct 24, 2026
737dfe3
Read ordinary computed data properties without coercion dispatch
dnnsjsk Oct 24, 2026
8d1d20a
Use byte offsets for native ASCII string operations
dnnsjsk Oct 24, 2026
aec1e4f
Document generated execution and byte-copy correctness fixes
dnnsjsk Oct 24, 2026
b326f0d
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
58f50e6
Fail canonical CI when the completed report contains failures
dnnsjsk Oct 24, 2026
76bac88
Keep observable PHP-generated calls on tracked activations
dnnsjsk Oct 24, 2026
1a09c05
Validate TypedArray set bounds before content type
dnnsjsk Oct 24, 2026
2d9b2f9
Copy matching TypedArray set elements as raw bytes
dnnsjsk Oct 24, 2026
c586372
Clear completed frame slots with a bulk allocation
dnnsjsk Oct 24, 2026
3972421
Document caller tracking and typed-array copy fixes
dnnsjsk Oct 24, 2026
eae33b5
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
0222e6c
Keep host descriptor callbacks outside generated preflight
dnnsjsk Oct 24, 2026
dbd441a
Avoid redundant initial function descriptor allocation
dnnsjsk Oct 24, 2026
ab864d4
Document host preflight and function allocation fixes
dnnsjsk Oct 24, 2026
4c3cf39
Clarify generated execution and runtime guards in docs
dnnsjsk Oct 24, 2026
ae6a572
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
232ec2c
Fix operand decoding for template string coercion
dnnsjsk Oct 24, 2026
4d349cf
Reject host metadata overrides before string scanner execution
dnnsjsk Oct 24, 2026
094a3e4
Document scanner guard and opcode decoding fixes
dnnsjsk Oct 24, 2026
b56afe5
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
e08f2f2
Document experimental framework support and relaxed CI timeouts
dnnsjsk Oct 24, 2026
314fe49
Add explicit Hono framework timeout scaling
dnnsjsk Oct 24, 2026
af483e2
Verify scaled Hono deadlines still reject late work
dnnsjsk Oct 24, 2026
ba89283
Allow bounded timeout scaling for Express framework checks
dnnsjsk Oct 24, 2026
b4624b7
Prepare v0.9.0 release
dnnsjsk Oct 24, 2026
a60d51b
Update COMPAT.md from CI [skip ci]
github-actions[bot] Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
23 changes: 23 additions & 0 deletions .github/workflows/compat-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,26 @@ jobs:
echo "Push failed; snapshot is in the compat-report artifact."
exit 0
fi

# Preserve and publish the full failure report before failing the gate.
# A complete run may still contain failing tests.
- name: Require a complete passing canonical snapshot
run: |
php <<'PHP'
<?php
$snapshot = json_decode(file_get_contents('compat.json'), true, 512, JSON_THROW_ON_ERROR);
$total = $snapshot['discovery']['testFileCount'] ?? null;
$totals = $snapshot['test262']['totals'] ?? [];
$passed = ($snapshot['complete'] ?? false) === true && is_int($total) && $total > 0
&& ($snapshot['test262']['skippedFeatures'] ?? null) === [];
foreach (['pass', 'attempted', 'known', 'total'] as $key) {
$passed = $passed && ($totals[$key] ?? null) === $total;
}
foreach (['fail', 'skip', 'blocked', 'pending', 'running'] as $key) {
$passed = $passed && ($totals[$key] ?? null) === 0;
}
if (!$passed) {
fwrite(STDERR, "Canonical test262 did not pass every discovered file. See compat.json and COMPAT.md.\n");
exit(1);
}
PHP
143 changes: 143 additions & 0 deletions .github/workflows/frameworks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Framework Compatibility

on:
push:
branches: [main]
paths:
- 'src/**'
- 'tests/Frameworks/**'
- 'scripts/node-*/**'
- 'composer.json'
- 'composer.lock'
- '.github/workflows/frameworks.yml'
pull_request:
branches: [main]
paths:
- 'src/**'
- 'tests/Frameworks/**'
- 'scripts/node-*/**'
- 'composer.json'
- 'composer.lock'
- '.github/workflows/frameworks.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: frameworks-${{ github.ref }}
cancel-in-progress: true

env:
XDEBUG_MODE: 'off'
TZ: UTC

jobs:
upstream:
name: PHP ${{ matrix.php }} / ${{ matrix.suite }}
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
php: ['8.4', '8.5']
suite: [express, hono-main, hono-jsx-runtime-default, hono-jsx-runtime-dom, hono-node, http2]
steps:
- uses: actions/checkout@v5

- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, bcmath, curl, intl, openssl, sodium, zlib, sockets
coverage: none

- uses: actions/setup-node@v6
with:
node-version: '26.12.0'
cache: npm
cache-dependency-path: tests/Frameworks/package-lock.json

- uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: Install pinned dependencies
run: |
composer install --no-interaction --prefer-dist
npm ci --prefix tests/Frameworks

- name: Prepare Express source
if: matrix.suite == 'express'
run: python3 -B tests/Frameworks/express/setup.py

- name: Prepare Hono source
if: startsWith(matrix.suite, 'hono-')
run: python3 -B tests/Frameworks/hono/setup.py

- name: Express original tests
if: matrix.suite == 'express'
run: |
python3 -B tests/Frameworks/express/test_runner.py
python3 -B tests/Frameworks/express/run.py --runtime both --jobs 1 --timeout-scale 10 --output framework-results/express

- name: Hono harness deadline differential
if: startsWith(matrix.suite, 'hono-')
run: |
python3 -B tests/Frameworks/hono/test_runner.py
python3 -B tests/Frameworks/hono/selftest.py

- name: Hono original runtime tests
if: startsWith(matrix.suite, 'hono-')
env:
FRAMEWORK_SUITE: ${{ matrix.suite }}
run: python3 -B tests/Frameworks/hono/run.py --project "${FRAMEWORK_SUITE#hono-}" --timeout 1800 --timeout-scale 10

- name: Hono independent native Vitest baseline
if: startsWith(matrix.suite, 'hono-') && !cancelled()
env:
FRAMEWORK_SUITE: ${{ matrix.suite }}
run: |
mkdir -p framework-results
if [ "$FRAMEWORK_SUITE" = 'hono-main' ]; then
node tests/Frameworks/hono/prepare-toolchain.mjs
fi
PHASIS_HONO_PROJECT="${FRAMEWORK_SUITE#hono-}" node tests/Frameworks/node_modules/vitest/vitest.mjs run \
--config tests/Frameworks/hono/vitest.config.mjs \
--reporter=json --outputFile="$PWD/framework-results/hono-native.json"

- name: Compare every Hono case with native Vitest
if: startsWith(matrix.suite, 'hono-') && !cancelled()
run: |
python3 -B - <<'PY'
import json
from pathlib import Path
import subprocess
results = Path('tests/Frameworks/hono/results')
run_id = json.loads((results / 'manifest.json').read_text())['id']
manifest = results / 'runs' / run_id / 'manifest.json'
statuses = [subprocess.run([
'python3', '-B', 'tests/Frameworks/hono/compare-native.py',
'framework-results/hono-native.json', str(manifest), '--runtime', runtime,
]).returncode for runtime in ['node', 'phasis']]
raise SystemExit(int(any(statuses)))
PY

- name: Hono original declaration tests
if: matrix.suite == 'hono-main' && !cancelled()
run: python3 -B tests/Frameworks/hono/run-toolchain.py

- name: HTTP2 native Node interoperability
if: matrix.suite == 'http2'
run: |
mkdir -p framework-results
node tests/Frameworks/http2/interop.mjs | tee framework-results/http2.jsonl

- name: Preserve complete manifests and failure logs
if: always()
uses: actions/upload-artifact@v6
with:
name: frameworks-php${{ matrix.php }}-${{ matrix.suite }}-${{ github.sha }}
path: |
framework-results/
tests/Frameworks/hono/results/runs/
if-no-files-found: warn
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ Keep agent instructions in `AGENTS.md` only. Use nested `AGENTS.md` files when
guidance needs a narrower scope. Do not add `CLAUDE.md` files, symlinks, or
forwarding stubs for repository guidance.

Node compatibility is opt-in through `Engine::enableNode()` or `phasis --node`.
JavaScript still executes entirely in PHP. Node/npm may prepare pinned assets or
run test oracles, but must never become an execution backend. Explicit
`child_process` operations use PHP host processes; a JavaScript child launched
through `process.execPath` runs the Phasis PHP entry point. New host resources
must register cleanup with their owning NodeRuntime. Keep original framework
assertions, report all discovered cases and upstream skips, and retain source
identity for complete-run claims. Express and Hono support is experimental;
their CI runners explicitly use `--timeout-scale 10` while performance work is
deferred. Preserve original timeout values and record effective limits in the
results; a scaled run is a functional compatibility result, not a claim to meet
upstream performance deadlines. Never relax test262 assertions, coverage or
timeouts to accommodate framework workloads. Close and reap owned test
processes and listeners after every run.

## Releases

Follow the [shared release rule](https://github.com/inline0/_cp/blob/main/AGENTS.md#canonical-github-releases).
Expand Down
28 changes: 27 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,30 @@

## [Unreleased]

## [0.9.0] - 2026-10-24

### Added
- Opt-in Node-compatible realms and `phasis --node`, with CommonJS package loading, Buffer and streams, filesystem and process I/O, HTTP/HTTPS/HTTP2, TLS, compression, timers, async context, and isolated VM realms.
- Experimental Express and Hono support with pinned upstream runners, original assertions, case inventories, source hashes, bounded workers and real network interoperability checks.
- Ed25519 WebCrypto keys, MessageEvent and in-process BroadcastChannel support.
- Keyed Promise combinators, iterator chunk/window/zip helpers, and immutable ArrayBuffers with protected typed-array, DataView, and Atomics writes.
- Locale variants and locale-specific calendar, collation, hour-cycle, text-direction, and week information.

### Fixed
- Live Fetch request and response bodies retain streaming, cancellation and clone behavior; Node fetch can communicate with servers in the same engine.
- Promise reactions preserve registration-time async context; cross-realm generators preserve their realm prototypes; global-property deletion and CommonJS cache behavior remain observable.
- JSON property names and Unicode separators, callable proxies, and UTF-16 string indexing preserve JavaScript behavior across framework workloads.
- Recursive compiled calls keep captured bindings separate, completed VM frames release their references, and WeakMap entries release unreachable keys without overflowing the host stack on deep chains.
- Symbol property writes preserve Proxy traps and receivers; typed-array copies clamp array-like lengths before checking destination bounds.
- Array literals and built-in array results retain their realm's intrinsic prototype when the global Array constructor is replaced.
- Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects.
- Generated PHP preserves numeric truthiness and literal precision, evaluates operands once, and falls back before observable effects.
- Generated binding and string-method preflight checks do not invoke host property-map or descriptor overrides.
- Template strings outside pure loops no longer prevent those loops from using verified compiled code.
- Calls, getters and constructors retain caller and argument records; non-callable errors do not invoke object conversion hooks.
- Same-type typed-array copies preserve byte payloads and prototype-validation order; host byte views and inlined callbacks retain their defining realms.
- Typed-array `set` checks bounds before content-type mismatches and copies matching native element types without changing stored bits.
- Stream controllers, readers and writers retain their originating realm after VM context creation; pending Promise finalizers retain their registered async context.
- Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation.
- Module evaluation, source and typed imports, resource disposal, cross-realm intrinsics, numeric serialization, and compiled global bindings follow current language semantics.
- Array callbacks observe mutations and holes, and global declarations create own properties without invoking inherited accessors.
Expand All @@ -15,8 +34,15 @@
- Intl option precedence, legacy constructors, plural notation, numbering systems, and plain date/time formatting.

### Changed
- Framework runners accept an explicit timeout scale and record original and effective limits. Experimental Express/Hono CI uses a scale of 10 while performance work is deferred; test262 limits and engine budgets are unchanged.
- Bytecode compilation handles captured bindings, default initializers, array bindings and assignments, optional chains, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate.
- Proven disjoint lexical scopes reuse frame slots, ordinary function prototypes materialize when observed, and numeric typed-array writes avoid redundant conversions while retaining buffer-resize and detachment behavior.
- Completed frames clear their local slots in one allocation while releasing activation references.
- Fresh functions initialize their name and length descriptors without redundant allocation while preserving host subclass hooks.
- Protected returns preserve finalizer completion order in bytecode, and logical assignments and object relational operators use the shared JavaScript semantics.
- Bounded regular-expression preparation and cached UTF-16 searches reduce repeated work while preserving fresh objects and observable coercions.
- The test262 runner executes both variants of unflagged scripts, preserves raw sources and module parse goals, requires async completion, and checks negative-test error types and phases.
- Compatibility shards retain full file manifests; merging rejects overlapping or stale results and keeps missing coverage visible. Incomplete or failing coverage cannot round up to 100%.
- Compatibility shards retain full file manifests; merging rejects overlapping or stale results and keeps missing coverage visible. Incomplete or failing coverage cannot round up to 100%; the canonical workflow fails on nonpassing results after preserving the report.

## [0.8.0] - 2026-10-16

Expand Down
Loading